diff --git a/core/method_bind.h b/core/method_bind.h index 3f08c70af8bc..6ea9340ad542 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -178,6 +178,7 @@ public: #ifdef DEBUG_METHODS_ENABLED _FORCE_INLINE_ void set_return_type(const StringName& p_type) { ret_type=p_type; } + _FORCE_INLINE_ StringName get_return_type() const { return ret_type; } _FORCE_INLINE_ Variant::Type get_argument_type(int p_argument) const { diff --git a/core/object_type_db.cpp b/core/object_type_db.cpp index efd92542ce82..f7917b741840 100644 --- a/core/object_type_db.cpp +++ b/core/object_type_db.cpp @@ -191,6 +191,7 @@ MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,co HashMap ObjectTypeDB::types; HashMap ObjectTypeDB::resource_base_extensions; +HashMap ObjectTypeDB::compat_types; ObjectTypeDB::TypeInfo::TypeInfo() { @@ -263,12 +264,22 @@ bool ObjectTypeDB::type_exists(const String &p_type) { return types.has(p_type); } +void ObjectTypeDB::add_compatibility_type(const StringName& p_type,const StringName& p_fallback) { + + compat_types[p_type]=p_fallback; +} + Object *ObjectTypeDB::instance(const String &p_type) { TypeInfo *ti; { OBJTYPE_LOCK; ti=types.getptr(p_type); + if (!ti || ti->disabled || !ti->creation_func) { + if (compat_types.has(p_type)) { + ti=types.getptr(compat_types[p_type]); + } + } ERR_FAIL_COND_V(!ti,NULL); ERR_FAIL_COND_V(ti->disabled,NULL); ERR_FAIL_COND_V(!ti->creation_func,NULL); @@ -914,6 +925,7 @@ void ObjectTypeDB::cleanup() { } types.clear(); resource_base_extensions.clear(); + compat_types.clear(); } // diff --git a/core/object_type_db.h b/core/object_type_db.h index f2ff194e28bc..617a0a7c20cd 100644 --- a/core/object_type_db.h +++ b/core/object_type_db.h @@ -151,6 +151,7 @@ class ObjectTypeDB { static Mutex *lock; static HashMap types; static HashMap resource_base_extensions; + static HashMap compat_types; #ifdef DEBUG_METHODS_ENABLED static MethodBind* bind_methodfi(uint32_t p_flags, MethodBind *p_bind , const MethodDefinition &method_name, const Variant **p_defs, int p_defcount); @@ -482,6 +483,7 @@ public: static void get_resource_base_extensions(List *p_extensions); static void get_extensions_for_type(const StringName& p_type,List *p_extensions); + static void add_compatibility_type(const StringName& p_type,const StringName& p_fallback); static void init(); static void cleanup(); }; diff --git a/demos/2d/platformer/player.gd b/demos/2d/platformer/player.gd index 481f340ab8c9..b08105212ceb 100644 --- a/demos/2d/platformer/player.gd +++ b/demos/2d/platformer/player.gd @@ -53,12 +53,15 @@ var enemy func _integrate_forces(s): + + var lv = s.get_linear_velocity() var step = s.get_step() var new_anim=anim var new_siding_left=siding_left + # Get the controls var move_left = Input.is_action_pressed("move_left") var move_right = Input.is_action_pressed("move_right") diff --git a/demos/2d/platformer/player.xml b/demos/2d/platformer/player.xml index c129d01f0dfd..196881dee439 100644 --- a/demos/2d/platformer/player.xml +++ b/demos/2d/platformer/player.xml @@ -1,13 +1,13 @@ - + - - + + @@ -50,7 +50,52 @@ - "run" + "jumping" + 0.5 + True + 0.25 + "value" + "sprite:frame" + 1 + + "cont" + False + "transitions" + 1, 1, 1 + "values" + + 23 + 24 + 23 + + "times" + 0, 0.25, 0.5 + + + + + "idle_weapon" + 0.5 + True + 0.25 + "value" + "sprite:frame" + 1 + + "cont" + False + "transitions" + 1 + "values" + + 25 + + "times" + 0 + + + + 1.25 True 0.25 @@ -75,55 +120,6 @@ 0, 0.25, 0.5, 0.75, 1, 1.25 - - - "run_gun_fire" - 1.25 - True - 0.25 - "value" - "sprite:frame" - 1 - - "cont" - False - "transitions" - 1, 1, 1, 1, 1, 1 - "values" - - 10 - 11 - 12 - 13 - 14 - 5 - - "times" - 0, 0.25, 0.5, 0.75, 1, 1.25 - - - - - "jumping_weapon" - 0.5 - True - 0.25 - "value" - "sprite:frame" - 1 - - "cont" - False - "transitions" - 1 - "values" - - 26 - - "times" - 0 - - "crouch" @@ -148,7 +144,55 @@ - "jumping" + "falling" + 0.01 + True + 0.25 + "value" + "sprite:frame" + 1 + + "cont" + False + "transitions" + 1 + "values" + + 21 + + "times" + 0 + + + + + 1.25 + True + 0.25 + "value" + "sprite:frame" + 1 + + "cont" + False + "transitions" + 1, 1, 1, 1, 1, 1 + "values" + + 10 + 11 + 12 + 13 + 14 + 5 + + "times" + 0, 0.25, 0.5, 0.75, 1, 1.25 + + + + + "falling_weapon" 0.5 True 0.25 @@ -159,20 +203,17 @@ "cont" False "transitions" - 1, 1, 1 + 1 "values" - - 23 - 24 - 23 + + 26 "times" - 0, 0.25, 0.5 + 0 - - "run_weapon" + 1.25 True 0.25 @@ -198,30 +239,7 @@ - - "idle_weapon" - 0.5 - True - 0.25 - "value" - "sprite:frame" - 1 - - "cont" - False - "transitions" - 1 - "values" - - 25 - - "times" - 0 - - - - - "falling_weapon" + 0.5 True 0.25 @@ -241,28 +259,6 @@ 0 - - - "falling" - 0.01 - True - 0.25 - "value" - "sprite:frame" - 1 - - "cont" - False - "transitions" - 1 - "values" - - 21 - - "times" - 0 - - @@ -294,9 +290,10 @@ "names" - + "player" "RigidBody2D" + "_import_path" "visibility/visible" "visibility/opacity" "visibility/self_opacity" @@ -311,6 +308,7 @@ "shapes/1/shape" "shapes/1/transform" "shapes/1/trigger" + "layers" "mode" "mass" "friction" @@ -319,7 +317,7 @@ "continuous_cd" "contacts_reported" "contact_monitor" - "active" + "sleeping" "can_sleep" "velocity/linear" "velocity/angular" @@ -354,6 +352,8 @@ "config/flip_h" "config/flip_v" "config/texture" + "config/h_frames" + "config/v_frames" "params/direction" "params/spread" "params/linear_velocity" @@ -364,9 +364,12 @@ "params/radial_accel" "params/tangential_accel" "params/damping" + "params/initial_angle" "params/initial_size" "params/final_size" "params/hue_variation" + "params/anim_speed_scale" + "params/anim_initial_pos" "randomness/direction" "randomness/spread" "randomness/linear_velocity" @@ -377,9 +380,12 @@ "randomness/radial_accel" "randomness/tangential_accel" "randomness/damping" + "randomness/initial_angle" "randomness/initial_size" "randomness/final_size" "randomness/hue_variation" + "randomness/anim_speed_scale" + "randomness/anim_initial_pos" "color_phases/count" "phase_0/pos" "phase_0/color" @@ -396,15 +402,15 @@ "playback/default_blend_time" "root/root" "anims/idle" - "anims/run" - "anims/standing_weapon_ready" - "anims/jumping_weapon" - "anims/crouch" "anims/jumping" - "anims/run_weapon" "anims/idle_weapon" - "anims/falling_weapon" + "anims/run" + "anims/crouch" "anims/falling" + "anims/standing_weapon_ready" + "anims/falling_weapon" + "anims/run_weapon" + "anims/jumping_weapon" "playback/active" "playback/speed" "blend_times" @@ -473,7 +479,8 @@ "node_count" 14 "variants" - + + "" True 1 False @@ -485,6 +492,7 @@ 1, -0, 0, 1.76469, 0.291992, -12.1587 1, -0, 0, 1, 0, 0 + 1 3 0 3 @@ -507,11 +515,17 @@ False "zoom" 2.272073 + "use_snap" + False "ofs" -181.946, -86.2812 + "snap" + 10 "3D" + "deflight_rot_y" + 0.628319 "zfar" 500 "fov" @@ -525,10 +539,12 @@ 0 "y_rot" 0 - "use_orthogonal" - False + "listener" + True "use_environment" False + "use_orthogonal" + False "pos" 0, 0, 0 @@ -539,10 +555,12 @@ 0 "y_rot" 0 - "use_orthogonal" + "listener" False "use_environment" False + "use_orthogonal" + False "pos" 0, 0, 0 @@ -553,10 +571,12 @@ 0 "y_rot" 0 - "use_orthogonal" + "listener" False "use_environment" False + "use_orthogonal" + False "pos" 0, 0, 0 @@ -567,10 +587,12 @@ 0 "y_rot" 0 - "use_orthogonal" + "listener" False "use_environment" False + "use_orthogonal" + False "pos" 0, 0, 0 @@ -579,12 +601,18 @@ 1 "default_light" True + "ambient_light_color" + 0.15, 0.15, 0.15, 1 "show_grid" True "show_origin" True "znear" 0.1 + "default_srgb" + False + "deflight_rot_x" + 0.942478 "__editor_run_settings__" @@ -595,14 +623,13 @@ 0 "__editor_plugin_screen__" - "3D" + "Script" 16 1, 1, 1, 1 0, 0, 0, 0 0.363636 - 1 20.7312, 3.21187 83.450417 4 @@ -654,7 +681,7 @@ "shoot" "nodes" - -1, -1, 1, 0, -1, 28, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 8, 12, 2, 13, 9, 14, 10, 15, 2, 16, 6, 17, 11, 18, 4, 19, 4, 20, 0, 21, 12, 22, 13, 23, 2, 24, 0, 25, 0, 26, 3, 27, 4, 28, 14, 29, 15, 0, 0, 0, 31, 30, -1, 18, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 32, 16, 33, 0, 34, 3, 35, 2, 36, 2, 37, 6, 38, 17, 39, 12, 40, 18, 41, 2, 42, 19, 0, 1, 0, 44, 43, -1, 57, 2, 0, 3, 1, 4, 20, 5, 2, 45, 21, 6, 22, 7, 23, 8, 5, 46, 24, 47, 25, 48, 1, 49, 4, 50, 25, 51, 2, 52, 3, 53, 3, 54, 2, 55, 26, 56, 2, 57, 2, 58, 27, 59, 4, 60, 28, 61, 29, 62, 1, 63, 4, 64, 4, 65, 30, 66, 4, 67, 4, 68, 4, 69, 31, 70, 31, 71, 4, 72, 4, 73, 4, 74, 4, 75, 31, 76, 4, 77, 4, 78, 4, 79, 4, 80, 4, 81, 4, 82, 4, 83, 4, 84, 4, 85, 6, 86, 4, 87, 18, 88, 1, 89, 32, 90, 1, 91, 33, 92, 1, 93, 34, 94, 35, 0, 0, 0, 96, 95, -1, 17, 97, 21, 98, 4, 99, 36, 100, 37, 101, 38, 102, 39, 103, 40, 104, 41, 105, 42, 106, 43, 107, 44, 108, 45, 109, 46, 110, 0, 111, 31, 112, 47, 113, 48, 0, 0, 0, 115, 114, -1, 22, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 33, 0, 116, 2, 117, 0, 118, 4, 119, 5, 120, 12, 121, 12, 122, 49, 123, 49, 124, 0, 125, 0, 126, 50, 127, 50, 128, 50, 129, 50, 0, 0, 0, 131, 130, -1, 7, 2, 0, 3, 1, 4, 1, 5, 2, 6, 51, 7, 4, 8, 5, 0, 0, 0, 132, 132, -1, 9, 2, 0, 3, 1, 4, 1, 5, 2, 6, 52, 7, 4, 8, 53, 133, 7, 134, 2, 0, 0, 0, 136, 135, -1, 14, 137, 13, 138, 54, 139, 4, 140, 1, 141, 4, 142, 4, 143, 4, 144, 55, 145, 55, 146, 55, 147, 55, 148, 6, 149, 4, 150, 4, 0, 0, 0, 151, 151, -1, 9, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 152, 12, 153, 56, 0, 0, 0, 155, 154, -1, 4, 156, 12, 34, 3, 157, 4, 158, 5, 0, 9, 0, 160, 159, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 57, 7, 4, 8, 58, 161, 59, 162, 60, 163, 60, 164, 0, 165, 61, 166, 21, 0, 9, 0, 160, 167, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 62, 7, 4, 8, 58, 161, 63, 162, 60, 163, 60, 164, 0, 165, 64, 166, 21, 0, 9, 0, 160, 168, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 65, 7, 4, 8, 58, 161, 66, 162, 60, 163, 60, 164, 2, 165, 67, 166, 21, 0, 9, 0, 160, 169, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 68, 7, 4, 8, 58, 161, 69, 162, 60, 163, 60, 164, 2, 165, 70, 166, 21, 0 + -1, -1, 1, 0, -1, 30, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 8, 12, 9, 13, 3, 14, 10, 15, 11, 16, 3, 17, 12, 18, 7, 19, 13, 20, 5, 21, 5, 22, 1, 23, 14, 24, 15, 25, 3, 26, 3, 27, 1, 28, 4, 29, 5, 30, 16, 31, 17, 0, 0, 0, 33, 32, -1, 19, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 34, 18, 35, 1, 36, 4, 37, 3, 38, 3, 39, 7, 40, 19, 41, 14, 42, 20, 43, 3, 44, 21, 0, 1, 0, 46, 45, -1, 66, 2, 0, 3, 1, 4, 2, 5, 22, 6, 3, 47, 12, 7, 23, 8, 24, 9, 6, 48, 25, 49, 26, 50, 2, 51, 5, 52, 26, 53, 3, 54, 4, 55, 4, 56, 3, 57, 27, 58, 3, 59, 3, 60, 28, 61, 12, 62, 12, 63, 5, 64, 29, 65, 30, 66, 2, 67, 5, 68, 5, 69, 31, 70, 5, 71, 5, 72, 5, 73, 5, 74, 32, 75, 32, 76, 5, 77, 2, 78, 5, 79, 5, 80, 5, 81, 5, 82, 32, 83, 5, 84, 5, 85, 5, 86, 5, 87, 5, 88, 5, 89, 5, 90, 5, 91, 5, 92, 5, 93, 5, 94, 5, 95, 7, 96, 5, 97, 20, 98, 2, 99, 33, 100, 2, 101, 34, 102, 2, 103, 35, 104, 36, 0, 0, 0, 106, 105, -1, 18, 2, 0, 107, 12, 108, 5, 109, 37, 110, 38, 111, 39, 112, 40, 113, 41, 114, 42, 115, 43, 116, 44, 117, 45, 118, 46, 119, 47, 120, 1, 121, 32, 122, 48, 123, 49, 0, 0, 0, 125, 124, -1, 23, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 35, 1, 126, 3, 127, 1, 128, 5, 129, 6, 130, 14, 131, 14, 132, 50, 133, 50, 134, 1, 135, 1, 136, 51, 137, 51, 138, 51, 139, 51, 0, 0, 0, 141, 140, -1, 8, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 52, 8, 5, 9, 6, 0, 0, 0, 142, 142, -1, 10, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 53, 8, 5, 9, 54, 143, 8, 144, 3, 0, 0, 0, 146, 145, -1, 15, 2, 0, 147, 15, 148, 55, 149, 5, 150, 2, 151, 5, 152, 5, 153, 5, 154, 56, 155, 56, 156, 56, 157, 56, 158, 7, 159, 5, 160, 5, 0, 0, 0, 161, 161, -1, 10, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 162, 14, 163, 57, 0, 0, 0, 165, 164, -1, 5, 2, 0, 166, 14, 36, 4, 167, 5, 168, 6, 0, 9, 0, 170, 169, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 58, 8, 5, 9, 59, 171, 60, 172, 61, 173, 61, 174, 1, 175, 62, 176, 12, 0, 9, 0, 170, 177, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 63, 8, 5, 9, 59, 171, 64, 172, 61, 173, 61, 174, 1, 175, 65, 176, 12, 0, 9, 0, 170, 178, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 66, 8, 5, 9, 59, 171, 67, 172, 61, 173, 61, 174, 3, 175, 68, 176, 12, 0, 9, 0, 170, 179, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 69, 8, 5, 9, 59, 171, 70, 172, 61, 173, 61, 174, 3, 175, 71, 176, 12, 0 "conns" diff --git a/drivers/builtin_openssl2/openssl/md5.h b/drivers/builtin_openssl2/openssl/md5.h index 8f392f0ec640..765be94335a6 100644 --- a/drivers/builtin_openssl2/openssl/md5.h +++ b/drivers/builtin_openssl2/openssl/md5.h @@ -105,9 +105,9 @@ typedef struct MD5state_st unsigned int num; } MD5_CTX; -#ifdef OPENSSL_FIPS +//#ifdef OPENSSL_FIPS int private_MD5_Init(MD5_CTX *c); -#endif +//#endif //#define MD5_Init _SSL_MD5_Init #define MD5_Final _SSL_MD5_Final diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index ccbba2f51c83..0816396385ed 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -969,7 +969,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu - if (img.detect_alpha()==Image::ALPHA_BLEND) { + if ((!texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) { texture->has_alpha=true; } @@ -4224,7 +4224,6 @@ void RasterizerGLES2::capture_viewport(Image* r_capture) { } w=DVector::Write(); - r_capture->create(viewport.width,viewport.height,0,Image::FORMAT_RGBA,pixels); //r_capture->flip_y(); diff --git a/drivers/mpc/audio_stream_mpc.cpp b/drivers/mpc/audio_stream_mpc.cpp index d94f57e68349..cd8125c9af9f 100644 --- a/drivers/mpc/audio_stream_mpc.cpp +++ b/drivers/mpc/audio_stream_mpc.cpp @@ -8,6 +8,7 @@ Error AudioStreamMPC::_open_file() { f=NULL; } Error err; + //printf("mpc open file %ls\n", file.c_str()); f=FileAccess::open(file,FileAccess::READ,&err); if (err) { @@ -16,9 +17,10 @@ Error AudioStreamMPC::_open_file() { return err; } - f->seek_end(0); - streamlen=f->get_pos(); - f->seek(0); + //printf("file size is %i\n", f->get_len()); + //f->seek_end(0); + streamlen=f->get_len(); + //f->seek(0); if (streamlen<=0) { memdelete(f); f=NULL; diff --git a/drivers/theoraplayer/SCsub b/drivers/theoraplayer/SCsub index cd8cabcc9489..419f2b65ae6c 100644 --- a/drivers/theoraplayer/SCsub +++ b/drivers/theoraplayer/SCsub @@ -61,13 +61,17 @@ src/YUV/C/yuv420_rgb_c.c src/TheoraVideoFrame.cpp """) +env_theora = env.Clone() + if env["platform"] == "iphone": sources.append("src/AVFoundation/TheoraVideoClip_AVFoundation.mm") env.Append(LINKFLAGS=['-framework', 'CoreVideo', '-framework', 'CoreMedia', '-framework', 'AVFoundation']) + if env["target"] == "release": + env_theora.Append(CPPFLAGS=["-D_IOS", "-D__ARM_NEON__", "-fstrict-aliasing", "-fmessage-length=210", "-fdiagnostics-show-note-include-stack", "-fmacro-backtrace-limit=0", "-fcolor-diagnostics", "-Wno-trigraphs", "-fpascal-strings", "-fvisibility=hidden", "-fvisibility-inlines-hidden"]) -env_theora = env.Clone() - -env_theora.Append(CPPFLAGS=["-D_YUV_C", "-D_LIB", "-D__THEORA"]) +env_theora.Append(CPPFLAGS=["-D_LIB", "-D__THEORA"]) # removed -D_YUV_C +env_theora.Append(CPPFLAGS=["-D_YUV_LIBYUV", "-DLIBYUV_NEON"]) +#env_theora.Append(CPPFLAGS=["-D_YUV_C"]) if env["platform"] == "iphone": env_theora.Append(CPPFLAGS=["-D__AVFOUNDATION"]) diff --git a/drivers/theoraplayer/src/TheoraVideoClip.cpp b/drivers/theoraplayer/src/TheoraVideoClip.cpp index ed9f2c22daca..16897ee80eb5 100644 --- a/drivers/theoraplayer/src/TheoraVideoClip.cpp +++ b/drivers/theoraplayer/src/TheoraVideoClip.cpp @@ -249,6 +249,7 @@ int TheoraVideoClip::discardOutdatedFrames(float absTime) if (nPop > 0) { +#define _DEBUG #ifdef _DEBUG std::string log = getName() + ": dropped frame "; diff --git a/drivers/theoraplayer/video_stream_theoraplayer.cpp b/drivers/theoraplayer/video_stream_theoraplayer.cpp index 62dee1336a7d..9f4a44ae9d9b 100644 --- a/drivers/theoraplayer/video_stream_theoraplayer.cpp +++ b/drivers/theoraplayer/video_stream_theoraplayer.cpp @@ -215,7 +215,7 @@ public: channels = p_channels; freq = p_freq; total_wrote = 0; - rb_power = 12; + rb_power = 22; rb.resize(rb_power); }; @@ -258,10 +258,12 @@ public: void update(float time_increase) { + float prev_time = mTime; //mTime = (float)(stream->get_total_wrote()) / freq; //mTime = MAX(0,mTime-AudioServer::get_singleton()->get_output_delay()); //mTime = (float)sample_count / channels / freq; mTime += time_increase; + if (mTime - prev_time > .02) printf("time increase %f secs\n", mTime - prev_time); //float duration=mClip->getDuration(); //if (mTime > duration) mTime=duration; //printf("time at timer is %f, %f, samples %i\n", mTime, time_increase, sample_count); @@ -386,7 +388,7 @@ void VideoStreamTheoraplayer::pop_frame(Ref p_tex) { { DVector::Write wr = data.write(); uint8_t* ptr = wr.ptr(); - copymem(ptr, f->getBuffer(), imgsize); + memcpy(ptr, f->getBuffer(), imgsize); } /* for (int i=0; inext == ringptr) && (ringptr->prev == ringptr); bool is_list = ( ringlist == ringptr ); - RingPtr *new_ringptr=(RingPtr*)::realloc(ringptr, p_bytes+sizeof(RingPtr)); ERR_FAIL_COND_V( new_ringptr == 0, NULL ); /// reallocation failed @@ -213,7 +211,7 @@ void MemoryPoolStaticMalloc::free(void *p_ptr) { ERR_FAIL_COND( !MemoryPoolStatic::get_singleton()); - #if DFAULT_ALIGNMENT == 1 + #if DEFAULT_ALIGNMENT == 1 _free(p_ptr); #else diff --git a/drivers/webp/dsp/dsp.h b/drivers/webp/dsp/dsp.h index 9ff53174d495..afe30413c641 100644 --- a/drivers/webp/dsp/dsp.h +++ b/drivers/webp/dsp/dsp.h @@ -33,7 +33,7 @@ extern "C" { #define WEBP_ANDROID_NEON // Android targets that might support NEON #endif -#if (defined(__ARM_NEON__) || defined(WEBP_ANDROID_NEON)) && !defined(PSP2_ENABLED) +#if ( (defined(__ARM_NEON__) && !defined(__aarch64__)) || defined(WEBP_ANDROID_NEON)) && !defined(PSP2_ENABLED) #define WEBP_USE_NEON #endif diff --git a/drivers/webp/utils/bit_reader.h b/drivers/webp/utils/bit_reader.h index d80b49714901..43cd948fd4f3 100644 --- a/drivers/webp/utils/bit_reader.h +++ b/drivers/webp/utils/bit_reader.h @@ -1,3 +1,4 @@ +// // Copyright 2010 Google Inc. All Rights Reserved. // // This code is licensed under the same terms as WebM: diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index 0d11734bbd2d..fcfbbb04da3d 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -1166,6 +1166,8 @@ MethodInfo GDFunctions::get_info(Function p_func) { MethodInfo mi("weakref",PropertyInfo(Variant::OBJECT,"obj")); mi.return_val.type=Variant::OBJECT; + mi.return_val.name="WeakRef"; + return mi; } break; @@ -1173,6 +1175,7 @@ MethodInfo GDFunctions::get_info(Function p_func) { MethodInfo mi("funcref",PropertyInfo(Variant::OBJECT,"instance"),PropertyInfo(Variant::STRING,"funcname")); mi.return_val.type=Variant::OBJECT; + mi.return_val.name="FuncRef"; return mi; } break; @@ -1231,6 +1234,7 @@ MethodInfo GDFunctions::get_info(Function p_func) { MethodInfo mi("load",PropertyInfo(Variant::STRING,"path")); mi.return_val.type=Variant::OBJECT; + mi.return_val.name="Resource"; return mi; } break; case INST2DICT: { diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index 93345be73023..f8d86a3c7a6a 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -54,20 +54,35 @@ def configure(env): env['AR'] = 'ar' import string - #env['CCFLAGS'] = string.split('-arch armv7 -Wall -fno-strict-aliasing -fno-common -D__IPHONE_OS_VERSION_MIN_REQUIRED=20000 -isysroot $IPHONESDK -fvisibility=hidden -mmacosx-version-min=10.5 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\" -DNO_THUMB') - env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -MMD -MT dependencies -isysroot $IPHONESDK') + if (env["bits"]=="64"): + #env['CCFLAGS'] = string.split('-arch arm64 -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -Wno-trigraphs -fpascal-strings -O0 -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-return-type -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wno-unused-variable -Wunused-value -Wno-empty-body -Wno-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-constant-conversion -Wno-int-conversion -Wno-bool-conversion -Wno-enum-conversion -Wshorten-64-to-32 -Wno-newline-eof -Wno-c++11-extensions -fstrict-aliasing -Wdeprecated-declarations -Winvalid-offsetof -g -Wno-sign-conversion -miphoneos-version-min=5.1.1 -Wmost -Wno-four-char-constants -Wno-unknown-pragmas -Wno-invalid-offsetof -ffast-math -m64 -DDEBUG -D_DEBUG -MMD -MT dependencies -isysroot $IPHONESDK') + env['CCFLAGS'] = string.split('-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -MMD -MT dependencies -miphoneos-version-min=5.1.1 -isysroot $IPHONESDK') + env.Append(CPPFLAGS=['-DNEED_LONG_INT']) + env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON']) + else: + env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -MMD -MT dependencies -isysroot $IPHONESDK') - -#/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ fno-objc-arc -arch armv7 -fmessage-length=0 -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -MMD -MT dependencies -v -Os -ffast-math -DSTOREKIT_ENABLED -DIPHONE_ENABLED -DUNIX_ENABLED -DGLES2_ENABLED -DNO_THREADS -DMODULE_GRIDMAP_ENABLED -DMUSEPACK_ENABLED -DOLD_SCENE_FORMAT_ENABLED -DSQUIRREL_ENABLED -DVORBIS_ENABLED -DTHEORA_ENABLED -DPNG_ENABLED -DDDS_ENABLED -DPVR_ENABLED -DJPG_ENABLED -DSPEEX_ENABLED -DTOOLS_ENABLED -DGDSCRIPT_ENABLED -DMINIZIP_ENABLED -DXML_ENABLED -Icore -Icore/math -Itools -Idrivers -I. -Iplatform/iphone -Iplatform/iphone/include -Iplatform/iphone/scoreloop/SDKs -I/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenGLES.framework/Headers -Iscript/squirrel/src -Iscript/vorbis script/gdscript/gd_script.cpp -#/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -x objective-c -arch armv7 -fmessage-length=0 -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -std=gnu99 -fobjc-arc -Wno-trigraphs -fpascal-strings -Os -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -iquote /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-generated-files.hmap -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-own-target-headers.hmap -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-all-target-headers.hmap -iquote /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-project-headers.hmap -I/Users/red/test2/build/Release-iphoneos/include -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/DerivedSources/armv7 -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/DerivedSources -F/Users/red/test2/build/Release-iphoneos -DNS_BLOCK_ASSERTIONS=1 -include /var/folders/LX/LXYXHTeSHSqbkhuPJRIsuE+++TI/-Caches-/com.apple.Xcode.501/SharedPrecompiledHeaders/test2-Prefix-dvdhnltoisfpmyalexovdrmfyeky/test2-Prefix.pch -MMD -MT dependencies -MF /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/Objects-normal/armv7/main.d -c /Users/red/test2/test2/main.m -o /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/Objects-normal/armv7/main.o - - - - - - env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=4.3', + if (env["bits"]=="64"): + env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=5.1.1', + '-isysroot', '$IPHONESDK', + #'-stdlib=libc++', + '-framework', 'Foundation', + '-framework', 'UIKit', + '-framework', 'CoreGraphics', + '-framework', 'OpenGLES', + '-framework', 'QuartzCore', + '-framework', 'CoreAudio', + '-framework', 'AudioToolbox', + '-framework', 'SystemConfiguration', + '-framework', 'Security', + #'-framework', 'AdSupport', + '-framework', 'MediaPlayer', + '-framework', 'AVFoundation', + '-framework', 'CoreMedia', + ]) + else: + env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=4.3', '-isysroot', '$IPHONESDK', - #'-mmacosx-version-min=10.5', '-framework', 'Foundation', '-framework', 'UIKit', '-framework', 'CoreGraphics', @@ -128,4 +143,4 @@ def configure(env): env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } ) env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } ) -# /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x objective-c-header -arch armv7s -fmessage-length=0 -std=gnu99 -fobjc-arc -Wno-trigraphs -fpascal-strings -Os -Wno-missing-field-initializers -Wno-missing-prototypes -Wreturn-type -Wno-implicit-atomic-properties -Wno-receiver-is-weak -Wduplicate-method-match -Wformat -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-shorten-64-to-32 -Wpointer-sign -Wno-newline-eof -Wno-selector -Wno-strict-selector-match -Wno-undeclared-selector -Wno-deprecated-implementations -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk -Wprotocol -Wdeprecated-declarations -g -fvisibility=hidden -Wno-sign-conversion "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -iquote /Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-generated-files.hmap -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-own-target-headers.hmap -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-all-target-headers.hmap -iquote /Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-project-headers.hmap -I/Users/lucasgondolo/test/build/Release-iphoneos/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/DerivedSources/armv7s -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/DerivedSources -F/Users/lucasgondolo/test/build/Release-iphoneos -DNS_BLOCK_ASSERTIONS=1 --serialize-diagnostics /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.dia -c /Users/lucasgondolo/test/test/test-Prefix.pch -o /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.pth -MMD -MT dependencies -MF /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.d + diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h index df50d30f408a..7e961176d9d1 100644 --- a/platform/iphone/platform_config.h +++ b/platform/iphone/platform_config.h @@ -30,3 +30,4 @@ #define GLES2_INCLUDE_H #define GLES1_INCLUDE_H +#define PLATFORM_REFCOUNT diff --git a/platform/iphone/platform_refcount.h b/platform/iphone/platform_refcount.h new file mode 100644 index 000000000000..45391e651ae2 --- /dev/null +++ b/platform/iphone/platform_refcount.h @@ -0,0 +1,18 @@ +#include "safe_refcount.h" + +#ifdef IPHONE_ENABLED + +#define REFCOUNT_T int +#define REFCOUNT_GET_T int const volatile& + +#include + +inline int atomic_conditional_increment(volatile int* v) { + return (*v==0)? 0 : OSAtomicIncrement32(v); +} + +inline int atomic_decrement(volatile int* v) { + return OSAtomicDecrement32(v); +} + +#endif diff --git a/platform/winrt/include/angle_windowsstore.h b/platform/winrt/include/angle_windowsstore.h new file mode 100644 index 000000000000..fe587bf26905 --- /dev/null +++ b/platform/winrt/include/angle_windowsstore.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// angle_windowsstore.h: + +#ifndef ANGLE_WINDOWSSTORE_H_ +#define ANGLE_WINDOWSSTORE_H_ + +// The following properties can be set on the CoreApplication to support additional +// ANGLE configuration options. +// +// The Visual Studio sample templates provided with this version of ANGLE have examples +// of how to set these property values. + +// +// Property: EGLNativeWindowTypeProperty +// Type: IInspectable +// Description: Set this property to specify the window type to use for creating a surface. +// If this property is missing, surface creation will fail. +// +const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty"; + +// +// Property: EGLRenderSurfaceSizeProperty +// Type: Size +// Description: Set this property to specify a preferred size in pixels of the render surface. +// The render surface size width and height must be greater than 0. +// If this property is set, then the render surface size is fixed. +// If this property is missing, a default behavior will be provided. +// The default behavior uses the window size if a CoreWindow is specified or +// the size of the SwapChainPanel control if one is specified. +// +const wchar_t EGLRenderSurfaceSizeProperty[] = L"EGLRenderSurfaceSizeProperty"; + +#endif // ANGLE_WINDOWSSTORE_H_ diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index 82158405ea7a..9c388a28834e 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -47,6 +47,11 @@ void CollisionObject::_notification(int p_what) { case NOTIFICATION_ENTER_WORLD: { + if (area) + PhysicsServer::get_singleton()->area_set_transform(rid,get_global_transform()); + else + PhysicsServer::get_singleton()->body_set_state(rid,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform()); + RID space = get_world()->get_space(); if (area) { PhysicsServer::get_singleton()->area_set_space(rid,space); diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index 6bc0c677c0dd..639a86e75936 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -95,18 +95,6 @@ void RayCast::_notification(int p_what) { if (enabled && !get_tree()->is_editor_hint()) { set_fixed_process(true); - Node *p = get_parent(); - while( p && p->cast_to() ) { - - CollisionObject *co = p->cast_to(); - if (co) { - - exception=co->get_rid(); - exceptions.insert(exception); - } - - p=p->get_parent(); - } } else set_fixed_process(false); @@ -119,7 +107,6 @@ void RayCast::_notification(int p_what) { set_fixed_process(false); } - exceptions.erase(exception); } break; case NOTIFICATION_FIXED_PROCESS: { @@ -143,7 +130,7 @@ void RayCast::_notification(int p_what) { PhysicsDirectSpaceState::RayResult rr; - if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exceptions)) { + if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude)) { collided=true; against=rr.collider_id; @@ -160,6 +147,41 @@ void RayCast::_notification(int p_what) { } } +void RayCast::add_exception_rid(const RID& p_rid) { + + exclude.insert(p_rid); +} + +void RayCast::add_exception(const Object* p_object){ + + ERR_FAIL_NULL(p_object); + CollisionObject *co=((Object*)p_object)->cast_to(); + if (!co) + return; + add_exception_rid(co->get_rid()); +} + +void RayCast::remove_exception_rid(const RID& p_rid) { + + exclude.erase(p_rid); +} + +void RayCast::remove_exception(const Object* p_object){ + + ERR_FAIL_NULL(p_object); + CollisionObject *co=((Object*)p_object)->cast_to(); + if (!co) + return; + remove_exception_rid(co->get_rid()); +} + + +void RayCast::clear_exceptions(){ + + exclude.clear(); +} + + void RayCast::_bind_methods() { @@ -176,6 +198,14 @@ void RayCast::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_point"),&RayCast::get_collision_point); ObjectTypeDB::bind_method(_MD("get_collision_normal"),&RayCast::get_collision_normal); + ObjectTypeDB::bind_method(_MD("add_exception_rid","rid"),&RayCast::add_exception_rid); + ObjectTypeDB::bind_method(_MD("add_exception","node"),&RayCast::add_exception); + + ObjectTypeDB::bind_method(_MD("remove_exception_rid","rid"),&RayCast::remove_exception_rid); + ObjectTypeDB::bind_method(_MD("remove_exception","node"),&RayCast::remove_exception); + + ObjectTypeDB::bind_method(_MD("clear_exceptions"),&RayCast::clear_exceptions); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to")); } diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h index 96606b1628a6..0239c61b6782 100644 --- a/scene/3d/ray_cast.h +++ b/scene/3d/ray_cast.h @@ -45,8 +45,7 @@ class RayCast : public Spatial { Vector3 cast_to; - RID exception; - Set exceptions; + Set exclude; protected: @@ -66,6 +65,12 @@ public: Vector3 get_collision_point() const; Vector3 get_collision_normal() const; + void add_exception_rid(const RID& p_rid); + void add_exception(const Object* p_object); + void remove_exception_rid(const RID& p_rid); + void remove_exception(const Object* p_object); + void clear_exceptions(); + RayCast(); }; diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp new file mode 100644 index 000000000000..957e63e3ce12 --- /dev/null +++ b/scene/gui/graph_edit.cpp @@ -0,0 +1,517 @@ +#include "graph_edit.h" + +bool GraphEditFilter::has_point(const Point2& p_point) const { + + return ge->_filter_input(p_point); +} + + +GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) { + + ge=p_edit; +} + + +Error GraphEdit::connect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port) { + + if (is_node_connected(p_from,p_from_port,p_to,p_to_port)) + return OK; + Connection c; + c.from=p_from; + c.from_port=p_from_port; + c.to=p_to; + c.to_port=p_to_port; + connections.push_back(c); + top_layer->update(); + + return OK; +} + +bool GraphEdit::is_node_connected(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port) { + + for(List::Element *E=connections.front();E;E=E->next()) { + + if (E->get().from==p_from && E->get().from_port==p_from_port && E->get().to==p_to && E->get().to_port==p_to_port) + return true; + } + + return false; + +} + +void GraphEdit::disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port){ + + + for(List::Element *E=connections.front();E;E=E->next()) { + + if (E->get().from==p_from && E->get().from_port==p_from_port && E->get().to==p_to && E->get().to_port==p_to_port) { + + connections.erase(E); + top_layer->update(); + return; + } + } +} + +void GraphEdit::get_connection_list(List *r_connections) { + + *r_connections=connections; +} + + +void GraphEdit::_scroll_moved(double) { + + + _update_scroll_offset(); + top_layer->update(); +} + +void GraphEdit::_update_scroll_offset() { + + for(int i=0;icast_to(); + if (!gn) + continue; + + Point2 pos=gn->get_offset(); + pos-=Point2(h_scroll->get_val(),v_scroll->get_val()); + gn->set_pos(pos); + } + +} + +void GraphEdit::_update_scroll() { + + if (updating) + return; + + updating=true; + Rect2 screen; + screen.size=get_size(); + for(int i=0;icast_to(); + if (!gn) + continue; + + Rect2 r; + r.pos=gn->get_offset(); + r.size=gn->get_size(); + screen = screen.merge(r); + } + + h_scroll->set_min(screen.pos.x); + h_scroll->set_max(screen.pos.x+screen.size.x); + h_scroll->set_page(get_size().x); + if (h_scroll->get_max() - h_scroll->get_min() <= h_scroll->get_page()) + h_scroll->hide(); + else + h_scroll->show(); + + v_scroll->set_min(screen.pos.y); + v_scroll->set_max(screen.pos.y+screen.size.y); + v_scroll->set_page(get_size().y); + + if (v_scroll->get_max() - v_scroll->get_min() <= v_scroll->get_page()) + v_scroll->hide(); + else + v_scroll->show(); + + _update_scroll_offset(); + updating=false; +} + + +void GraphEdit::_graph_node_raised(Node* p_gn) { + + GraphNode *gn=p_gn->cast_to(); + ERR_FAIL_COND(!gn); + gn->raise(); + top_layer->raise(); + +} + + +void GraphEdit::_graph_node_moved(Node *p_gn) { + + GraphNode *gn=p_gn->cast_to(); + ERR_FAIL_COND(!gn); + + //gn->set_pos(gn->get_offset()+scroll_offset); + + top_layer->update(); +} + +void GraphEdit::add_child_notify(Node *p_child) { + + top_layer->call_deferred("raise"); //top layer always on top! + GraphNode *gn = p_child->cast_to(); + if (gn) { + gn->connect("offset_changed",this,"_graph_node_moved",varray(gn)); + gn->connect("raise_request",this,"_graph_node_raised",varray(gn)); + _graph_node_moved(gn); + gn->set_stop_mouse(false); + } +} + +void GraphEdit::remove_child_notify(Node *p_child) { + + top_layer->call_deferred("raise"); //top layer always on top! + GraphNode *gn = p_child->cast_to(); + if (gn) { + gn->disconnect("offset_changed",this,"_graph_node_moved"); + gn->disconnect("raise_request",this,"_graph_node_raised"); + } +} + +void GraphEdit::_notification(int p_what) { + + if (p_what==NOTIFICATION_READY) { + Size2 size = top_layer->get_size(); + Size2 hmin = h_scroll->get_combined_minimum_size(); + Size2 vmin = v_scroll->get_combined_minimum_size(); + + v_scroll->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,vmin.width); + v_scroll->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0); + v_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,0); + v_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0); + + h_scroll->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,0); + h_scroll->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0); + h_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,hmin.height); + h_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0); + + } + if (p_what==NOTIFICATION_DRAW) { + VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true); + + } + + if (p_what==NOTIFICATION_RESIZED) { + _update_scroll(); + top_layer->update(); + } +} + +bool GraphEdit::_filter_input(const Point2& p_point) { + + Ref port =get_icon("port","GraphNode"); + + float grab_r=port->get_width()*0.5; + for(int i=get_child_count()-1;i>=0;i--) { + + GraphNode *gn=get_child(i)->cast_to(); + if (!gn) + continue; + + for(int j=0;jget_connection_output_count();j++) { + + Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos(); + if (pos.distance_to(p_point)get_connection_input_count();j++) { + + Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos(); + if (pos.distance_to(p_point) port =get_icon("port","GraphNode"); + Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y); + float grab_r=port->get_width()*0.5; + for(int i=get_child_count()-1;i>=0;i--) { + + GraphNode *gn=get_child(i)->cast_to(); + if (!gn) + continue; + + for(int j=0;jget_connection_output_count();j++) { + + Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos(); + if (pos.distance_to(mpos)get_name(); + connecting_index=j; + connecting_out=true; + connecting_type=gn->get_connection_output_type(j); + connecting_color=gn->get_connection_output_color(j); + connecting_target=false; + connecting_to=pos; + return; + } + + + } + + for(int j=0;jget_connection_input_count();j++) { + + Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos(); + + if (pos.distance_to(mpos)get_name(); + connecting_index=j; + connecting_out=false; + connecting_type=gn->get_connection_input_type(j); + connecting_color=gn->get_connection_input_color(j); + connecting_target=false; + connecting_to=pos; + return; + } + + + } + } + } + + if (p_ev.type==InputEvent::MOUSE_MOTION && connecting) { + + connecting_to=Vector2(p_ev.mouse_motion.x,p_ev.mouse_motion.y); + connecting_target=false; + top_layer->update(); + + Ref port =get_icon("port","GraphNode"); + Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y); + float grab_r=port->get_width()*0.5; + for(int i=get_child_count()-1;i>=0;i--) { + + GraphNode *gn=get_child(i)->cast_to(); + if (!gn) + continue; + + if (!connecting_out) { + for(int j=0;jget_connection_output_count();j++) { + + Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos(); + int type =gn->get_connection_output_type(j); + if (type==connecting_type && pos.distance_to(mpos)get_name(); + connecting_target_index=j; + return; + } + + + } + } else { + + for(int j=0;jget_connection_input_count();j++) { + + Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos(); + int type =gn->get_connection_input_type(j); + if (type==connecting_type && pos.distance_to(mpos)get_name(); + connecting_target_index=j; + return; + } + } + } + } + } + + if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.button_index==BUTTON_LEFT && !p_ev.mouse_button.pressed) { + + if (connecting && connecting_target) { + + String from = connecting_from; + int from_slot = connecting_index; + String to =connecting_target_to; + int to_slot = connecting_target_index; + + if (!connecting_out) { + SWAP(from,to); + SWAP(from_slot,to_slot); + } + emit_signal("connection_request",from,from_slot,to,to_slot); + + } + connecting=false; + top_layer->update(); + + } + + + +} + +void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color) { + + static const int steps = 20; + + Rect2 r; + r.pos=p_from; + r.expand_to(p_to); + Vector2 sign=Vector2((p_from.x < p_to.x) ? 1 : -1,(p_from.y < p_to.y) ? 1 : -1); + bool flip = sign.x * sign.y < 0; + + Vector2 prev; + for(int i=0;i<=steps;i++) { + + float d = i/float(steps); + float c=-Math::cos(d*Math_PI) * 0.5+0.5; + if (flip) + c=1.0-c; + Vector2 p = r.pos+Vector2(d*r.size.width,c*r.size.height); + + if (i>0) { + + top_layer->draw_line(prev,p,p_color,2); + } + + prev=p; + } +} + +void GraphEdit::_top_layer_draw() { + + _update_scroll(); + + if (connecting) { + + Node *fromn = get_node(connecting_from); + ERR_FAIL_COND(!fromn); + GraphNode *from = fromn->cast_to(); + ERR_FAIL_COND(!from); + Vector2 pos; + if (connecting_out) + pos=from->get_connection_output_pos(connecting_index); + else + pos=from->get_connection_input_pos(connecting_index); + pos+=from->get_pos(); + + Vector2 topos; + topos=connecting_to; + + Color col=connecting_color; + + if (connecting_target) { + col.r+=0.4; + col.g+=0.4; + col.b+=0.4; + } + _draw_cos_line(pos,topos,col); + } + + List::Element* > to_erase; + for(List::Element *E=connections.front();E;E=E->next()) { + + NodePath fromnp(E->get().from); + + Node * from = get_node(fromnp); + if (!from) { + to_erase.push_back(E); + continue; + } + + GraphNode *gfrom = from->cast_to(); + + if (!gfrom) { + to_erase.push_back(E); + continue; + } + + NodePath tonp(E->get().to); + Node * to = get_node(tonp); + if (!to) { + to_erase.push_back(E); + continue; + } + + GraphNode *gto = to->cast_to(); + + if (!gto) { + to_erase.push_back(E); + continue; + } + + Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_pos(); + Color color = gfrom->get_connection_output_color(E->get().from_port); + Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_pos(); + _draw_cos_line(frompos,topos,color); + + } + + while(to_erase.size()) { + connections.erase(to_erase.front()->get()); + to_erase.pop_front(); + } + //draw connections +} + +void GraphEdit::_input_event(const InputEvent& p_ev) { + + if (p_ev.type==InputEvent::MOUSE_MOTION && p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE) { + h_scroll->set_val( h_scroll->get_val() - p_ev.mouse_motion.relative_x ); + v_scroll->set_val( v_scroll->get_val() - p_ev.mouse_motion.relative_y ); + } +} + +void GraphEdit::clear_connections() { + + connections.clear(); + update(); +} + + +void GraphEdit::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("connect_node:Error","from","from_port","to","to_port"),&GraphEdit::connect_node); + ObjectTypeDB::bind_method(_MD("is_node_connected","from","from_port","to","to_port"),&GraphEdit::is_node_connected); + ObjectTypeDB::bind_method(_MD("disconnect_node","from","from_port","to","to_port"),&GraphEdit::disconnect_node); + ObjectTypeDB::bind_method(_MD("_graph_node_moved"),&GraphEdit::_graph_node_moved); + ObjectTypeDB::bind_method(_MD("_graph_node_raised"),&GraphEdit::_graph_node_raised); + + ObjectTypeDB::bind_method(_MD("_top_layer_input"),&GraphEdit::_top_layer_input); + ObjectTypeDB::bind_method(_MD("_top_layer_draw"),&GraphEdit::_top_layer_draw); + ObjectTypeDB::bind_method(_MD("_scroll_moved"),&GraphEdit::_scroll_moved); + + ObjectTypeDB::bind_method(_MD("_input_event"),&GraphEdit::_input_event); + + ADD_SIGNAL(MethodInfo("connection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot"))); + +} + +GraphEdit::GraphEdit() { + top_layer=NULL; + top_layer=memnew(GraphEditFilter(this)); + add_child(top_layer); + top_layer->set_stop_mouse(false); + top_layer->set_area_as_parent_rect(); + top_layer->connect("draw",this,"_top_layer_draw"); + top_layer->set_stop_mouse(false); + top_layer->connect("input_event",this,"_top_layer_input"); + + h_scroll = memnew(HScrollBar); + h_scroll->set_name("_h_scroll"); + top_layer->add_child(h_scroll); + + v_scroll = memnew(VScrollBar); + v_scroll->set_name("_v_scroll"); + top_layer->add_child(v_scroll); + updating=false; + connecting=false; + + h_scroll->connect("value_changed", this,"_scroll_moved"); + v_scroll->connect("value_changed", this,"_scroll_moved"); +} diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h new file mode 100644 index 000000000000..f8a2f3fee730 --- /dev/null +++ b/scene/gui/graph_edit.h @@ -0,0 +1,93 @@ +#ifndef GRAPH_EDIT_H +#define GRAPH_EDIT_H + +#include "scene/gui/graph_node.h" +#include "scene/gui/scroll_bar.h" + +class GraphEdit; + +class GraphEditFilter : public Control { + + OBJ_TYPE(GraphEditFilter,Control); + +friend class GraphEdit; + GraphEdit *ge; + virtual bool has_point(const Point2& p_point) const; + +public: + + + GraphEditFilter(GraphEdit *p_edit); +}; + +class GraphEdit : public Control { + + OBJ_TYPE(GraphEdit,Control); +public: + + struct Connection { + StringName from; + StringName to; + int from_port; + int to_port; + + }; +private: + + HScrollBar* h_scroll; + VScrollBar* v_scroll; + + + bool connecting; + String connecting_from; + bool connecting_out; + int connecting_index; + int connecting_type; + Color connecting_color; + bool connecting_target; + Vector2 connecting_to; + String connecting_target_to; + int connecting_target_index; + + + + bool updating; + List connections; + + void _draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color); + + void _graph_node_raised(Node* p_gn); + void _graph_node_moved(Node *p_gn); + + void _update_scroll(); + void _scroll_moved(double); + void _input_event(const InputEvent& p_ev); + + GraphEditFilter *top_layer; + void _top_layer_input(const InputEvent& p_ev); + void _top_layer_draw(); + void _update_scroll_offset(); + +friend class GraphEditFilter; + bool _filter_input(const Point2& p_point); +protected: + + static void _bind_methods(); + virtual void add_child_notify(Node *p_child); + virtual void remove_child_notify(Node *p_child); + void _notification(int p_what); + +public: + + Error connect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port); + bool is_node_connected(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port); + void disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port); + void clear_connections(); + + void get_connection_list(List *r_connections); + + + GraphEdit(); +}; + +#endif // GRAPHEdit_H diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 6e3afeefd013..50ee9abcf820 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -76,7 +76,7 @@ void GraphNode::_get_property_list( List *p_list) const{ int idx=0; for(int i=0;icast_to(); - if (!c || c->is_set_as_toplevel() || !c->get_owner()) + if (!c || c->is_set_as_toplevel() ) continue; String base="slot/"+itos(idx)+"/"; @@ -122,6 +122,7 @@ void GraphNode::_resort() { } + int vofs=0; int w = get_size().x - sb->get_minimum_size().x; @@ -131,7 +132,7 @@ void GraphNode::_resort() { Control *c=get_child(i)->cast_to(); if (!c) continue; - if (c->is_set_as_toplevel() || !c->get_owner()) + if (c->is_set_as_toplevel()) continue; Size2i size=c->get_combined_minimum_size(); @@ -150,6 +151,8 @@ void GraphNode::_resort() { _change_notify(); update(); + connpos_dirty=true; + } @@ -160,14 +163,34 @@ void GraphNode::_notification(int p_what) { Ref sb=get_stylebox("frame"); Ref port =get_icon("port"); + Ref close =get_icon("close"); + int close_offset = get_constant("close_offset"); + Ref title_font = get_font("title_font"); + int title_offset = get_constant("title_offset"); + Color title_color = get_color("title_color"); Point2i icofs = -port->get_size()*0.5; - int edgeofs=3; + int edgeofs=get_constant("port_offset"); icofs.y+=sb->get_margin(MARGIN_TOP); draw_style_box(sb,Rect2(Point2(),get_size())); + int w = get_size().width-sb->get_minimum_size().x; + + if (show_close) + w-=close->get_width(); + + draw_string(title_font,Point2(sb->get_margin(MARGIN_LEFT),-title_font->get_height()+title_font->get_ascent()+title_offset),title,title_color,w); + if (show_close) { + Vector2 cpos = Point2(w+sb->get_margin(MARGIN_LEFT),-close->get_height()+close_offset); + draw_texture(close,cpos); + close_rect.pos=cpos; + close_rect.size=close->get_size(); + } else { + close_rect=Rect2(); + } + for (Map::Element *E=slot_info.front();E;E=E->next()) { - if (E->key()>cache_y.size()) + if (E->key() < 0 || E->key()>=cache_y.size()) continue; if (!slot_info.has(E->key())) continue; @@ -180,6 +203,7 @@ void GraphNode::_notification(int p_what) { } } + if (p_what==NOTIFICATION_SORT_CHILDREN) { _resort(); @@ -187,16 +211,6 @@ void GraphNode::_notification(int p_what) { } -void GraphNode::set_title(const String& p_title) { - - title=p_title; - update(); -} - -String GraphNode::get_title() const { - - return title; -} void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right) { @@ -216,17 +230,23 @@ void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Colo s.color_right=p_color_right; slot_info[p_idx]=s; update(); + connpos_dirty=true; + } void GraphNode::clear_slot(int p_idx){ slot_info.erase(p_idx); update(); + connpos_dirty=true; + } void GraphNode::clear_all_slots(){ slot_info.clear(); update(); + connpos_dirty=true; + } bool GraphNode::is_slot_enabled_left(int p_idx) const{ @@ -280,18 +300,26 @@ Color GraphNode::get_slot_color_right(int p_idx) const{ Size2 GraphNode::get_minimum_size() const { + Ref title_font = get_font("title_font"); + int sep=get_constant("separation"); Ref sb=get_stylebox("frame"); bool first=true; Size2 minsize; + minsize.x=title_font->get_string_size(title).x; + if (show_close) { + Ref close =get_icon("close"); + minsize.x+=sep+close->get_width(); + } + for(int i=0;icast_to(); if (!c) continue; - if (c->is_set_as_toplevel() || !c->get_owner()) + if (c->is_set_as_toplevel()) continue; Size2i size=c->get_combined_minimum_size(); @@ -308,13 +336,225 @@ Size2 GraphNode::get_minimum_size() const { return minsize+sb->get_minimum_size(); } +void GraphNode::set_title(const String& p_title) { + + title=p_title; + minimum_size_changed(); + update(); + +} + +String GraphNode::get_title() const{ + + return title; +} + +void GraphNode::set_offset(const Vector2& p_offset) { + + offset=p_offset; + emit_signal("offset_changed"); + update(); +} + +Vector2 GraphNode::get_offset() const { + + return offset; +} + + + +void GraphNode::set_show_close_button(bool p_enable){ + + show_close=p_enable; + update(); +} +bool GraphNode::is_close_button_visible() const{ + + return show_close; +} + +void GraphNode::_connpos_update() { + + + int edgeofs=get_constant("port_offset"); + int sep=get_constant("separation"); + + Ref sb=get_stylebox("frame"); + Ref port =get_icon("port"); + conn_input_cache.clear(); + conn_output_cache.clear(); + int vofs=0; + + int idx=0; + + for(int i=0;icast_to(); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + + Size2i size=c->get_combined_minimum_size(); + + int y = sb->get_margin(MARGIN_TOP)+vofs; + int h = size.y; + + + if (slot_info.has(idx)) { + + if (slot_info[idx].enable_left) { + ConnCache cc; + cc.pos=Point2i(edgeofs,y+h/2); + cc.type=slot_info[idx].type_left; + cc.color=slot_info[idx].color_left; + conn_input_cache.push_back(cc); + } + if (slot_info[idx].enable_right) { + ConnCache cc; + cc.pos=Point2i(get_size().width-edgeofs,y+h/2); + cc.type=slot_info[idx].type_right; + cc.color=slot_info[idx].color_right; + conn_output_cache.push_back(cc); + } + } + + if (vofs>0) + vofs+=sep; + vofs+=size.y; + idx++; + + } + + + connpos_dirty=false; +} + +int GraphNode::get_connection_input_count() { + + if (connpos_dirty) + _connpos_update(); + + return conn_input_cache.size(); + +} +int GraphNode::get_connection_output_count() { + + if (connpos_dirty) + _connpos_update(); + + return conn_output_cache.size(); + +} + + +Vector2 GraphNode::get_connection_input_pos(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),Vector2()); + return conn_input_cache[p_idx].pos; +} + +int GraphNode::get_connection_input_type(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),0); + return conn_input_cache[p_idx].type; +} + +Color GraphNode::get_connection_input_color(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),Color()); + return conn_input_cache[p_idx].color; +} + +Vector2 GraphNode::get_connection_output_pos(int p_idx){ + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),Vector2()); + return conn_output_cache[p_idx].pos; + +} + +int GraphNode::get_connection_output_type(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),0); + return conn_output_cache[p_idx].type; +} + +Color GraphNode::get_connection_output_color(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),Color()); + return conn_output_cache[p_idx].color; +} + +void GraphNode::_input_event(const InputEvent& p_ev) { + + if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) { + + Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y); + if (close_rect.size!=Size2() && close_rect.has_point(mpos)) { + emit_signal("close_request"); + return; + } + + drag_from=get_offset(); + drag_accum=Vector2(); + dragging=true; + emit_signal("raise_request"); + + } + + if (p_ev.type==InputEvent::MOUSE_BUTTON && !p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) { + + dragging=false; + emit_signal("dragged",drag_from,get_offset()); //useful for undo/redo + } + + if (p_ev.type==InputEvent::MOUSE_MOTION && dragging) { + + drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y); + set_offset(drag_from+drag_accum); + } + +} + void GraphNode::_bind_methods() { + ObjectTypeDB::bind_method(_MD("set_title","title"),&GraphNode::set_title); + ObjectTypeDB::bind_method(_MD("get_title"),&GraphNode::get_title); + ObjectTypeDB::bind_method(_MD("_input_event"),&GraphNode::_input_event); + ObjectTypeDB::bind_method(_MD("set_show_close_button","show"),&GraphNode::set_show_close_button); + ObjectTypeDB::bind_method(_MD("is_close_button_visible"),&GraphNode::is_close_button_visible); + + ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"show_close"),_SCS("set_show_close_button"),_SCS("is_close_button_visible")); + + ADD_SIGNAL(MethodInfo("offset_changed")); + ADD_SIGNAL(MethodInfo("dragged",PropertyInfo(Variant::VECTOR2,"from"),PropertyInfo(Variant::VECTOR2,"to"))); + ADD_SIGNAL(MethodInfo("raise_request")); + ADD_SIGNAL(MethodInfo("close_request")); } GraphNode::GraphNode() { - + dragging=false; + show_close=false; + connpos_dirty=true; } diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 3b89da9f0f22..0d5cbf8dd333 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -8,7 +8,7 @@ class GraphNode : public Container { OBJ_TYPE(GraphNode,Container); - String title; + struct Slot { bool enable_left; int type_left; @@ -21,13 +21,36 @@ class GraphNode : public Container { Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); }; }; + String title; + bool show_close; + Vector2 offset; + + Rect2 close_rect; + Vector cache_y; + struct ConnCache { + Vector2 pos; + int type; + Color color; + }; + + Vector conn_input_cache; + Vector conn_output_cache; + Map slot_info; + bool connpos_dirty; + + void _connpos_update(); void _resort(); + + Vector2 drag_from; + Vector2 drag_accum; + bool dragging; protected: + void _input_event(const InputEvent& p_ev); void _notification(int p_what); static void _bind_methods(); @@ -39,8 +62,6 @@ public: - void set_title(const String& p_title); - String get_title() const; void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right); void clear_slot(int p_idx); @@ -52,6 +73,25 @@ public: int get_slot_type_right(int p_idx) const; Color get_slot_color_right(int p_idx) const; + void set_title(const String& p_title); + String get_title() const; + + void set_offset(const Vector2& p_offset); + Vector2 get_offset() const; + + void set_show_close_button(bool p_enable); + bool is_close_button_visible() const; + + int get_connection_input_count() ; + int get_connection_output_count() ; + Vector2 get_connection_input_pos(int p_idx); + int get_connection_input_type(int p_idx); + Color get_connection_input_color(int p_idx); + Vector2 get_connection_output_pos(int p_idx); + int get_connection_output_type(int p_idx); + Color get_connection_output_color(int p_idx); + + virtual Size2 get_minimum_size() const; GraphNode(); diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 7353744d0773..d10ca20fc3f6 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -84,6 +84,7 @@ void MenuButton::pressed() { popup->set_parent_rect( Rect2(Point2(gp-popup->get_global_pos()),get_size())); popup->popup(); popup->call_deferred("grab_click_focus"); + popup->set_invalidate_click_until_motion(); } diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 0ba3bdb7c65e..1fd1d8adc8c1 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -30,6 +30,7 @@ #include "print_string.h" #include "os/keyboard.h" #include "translation.h" +#include "os/input.h" String PopupMenu::_get_accel_text(uint32_t p_accel) const { @@ -318,6 +319,10 @@ void PopupMenu::_input_event(const InputEvent &p_event) { int over=_get_mouse_over(Point2(b.x,b.y)); + if (invalidated_click) { + invalidated_click=false; + break; + } if (over<0 || items[over].separator || items[over].disabled) break; //non-activable @@ -336,6 +341,13 @@ void PopupMenu::_input_event(const InputEvent &p_event) { case InputEvent::MOUSE_MOTION: { + if (invalidated_click) { + moved+=Vector2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y); + if (moved.length()>4) + invalidated_click=false; + + } + const InputEventMouseMotion &m=p_event.mouse_motion; for(List::Element *E=autohide_areas.front();E;E=E->next()) { @@ -893,12 +905,17 @@ void PopupMenu::_bind_methods() { } + +void PopupMenu::set_invalidate_click_until_motion() { + moved=Vector2(); + invalidated_click=true; +} + PopupMenu::PopupMenu() { idcount=0; mouse_over=-1; - set_focus_mode(FOCUS_ALL); set_as_toplevel(true); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index b150be10086b..c2e988de9546 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -70,6 +70,8 @@ class PopupMenu : public Popup { void _activate_submenu(int over); void _submenu_timeout(); + bool invalidated_click; + Vector2 moved; Array _get_items() const; void _set_items(const Array& p_items); @@ -134,6 +136,8 @@ public: void add_autohide_area(const Rect2& p_area); void clear_autohide_areas(); + void set_invalidate_click_until_motion(); + PopupMenu(); ~PopupMenu(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 962e8c26e0d5..ee6b481a9fb4 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -76,6 +76,7 @@ #include "scene/gui/video_player.h" #include "scene/gui/reference_frame.h" #include "scene/gui/graph_node.h" +#include "scene/gui/graph_edit.h" #include "scene/resources/video_stream.h" #include "scene/2d/particles_2d.h" #include "scene/2d/path_2d.h" @@ -153,6 +154,8 @@ #include "scene/resources/mesh.h" #include "scene/resources/room.h" +#include "scene/resources/shader_graph.h" + #include "scene/resources/world.h" #include "scene/resources/world_2d.h" #include "scene/resources/volume.h" @@ -305,6 +308,7 @@ void register_scene_types() { ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); OS::get_singleton()->yield(); //may take time to init @@ -496,11 +500,17 @@ void register_scene_types() { ObjectTypeDB::register_type(); ObjectTypeDB::register_virtual_type(); ObjectTypeDB::register_type(); - ObjectTypeDB::register_type(); - ObjectTypeDB::register_type(); + //ObjectTypeDB::register_type(); + //ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); - ObjectTypeDB::register_type(); + ObjectTypeDB::register_virtual_type(); + ObjectTypeDB::register_virtual_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::add_compatibility_type("Shader","MaterialShader"); + ObjectTypeDB::add_compatibility_type("ParticleSystemMaterial","FixedMaterial"); + ObjectTypeDB::add_compatibility_type("UnshadedMaterial","FixedMaterial"); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 050e46290263..e7f0d9b1f56e 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -417,12 +417,18 @@ void make_default_theme() { t->set_constant("hseparation","PopupMenu",2); t->set_constant("vseparation","PopupMenu",1); - Ref graphsb = make_stylebox(graph_node_png,6,21,6,5,16,21,16,5); + Ref graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5); //graphsb->set_expand_margin_size(MARGIN_LEFT,10); //graphsb->set_expand_margin_size(MARGIN_RIGHT,10); t->set_stylebox("frame","GraphNode", graphsb ); t->set_constant("separation","GraphNode", 1 ); t->set_icon("port","GraphNode", make_icon( graph_port_png ) ); + t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) ); + t->set_font("title_font","GraphNode", default_font ); + t->set_color("title_color","GraphNode", Color(0,0,0,1)); + t->set_constant("title_offset","GraphNode", 18); + t->set_constant("close_offset","GraphNode", 18); + t->set_constant("port_offset","GraphNode", 3); t->set_stylebox("bg","Tree", make_stylebox( tree_bg_png,4,4,4,5,3,3,3,3) ); diff --git a/scene/resources/default_theme/graph_node_close.png b/scene/resources/default_theme/graph_node_close.png new file mode 100644 index 000000000000..ea5b510418eb Binary files /dev/null and b/scene/resources/default_theme/graph_node_close.png differ diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index 9fe77b322364..a0f3dcd9883a 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -104,6 +104,11 @@ static const unsigned char graph_node_png[]={ }; +static const unsigned char graph_node_close_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0xc,0x15,0x14,0x15,0x39,0x35,0x48,0xf8,0xe3,0x0,0x0,0x0,0x80,0x49,0x44,0x41,0x54,0x28,0xcf,0xa5,0xd1,0xb1,0xa,0xc2,0x40,0x10,0x84,0xe1,0x4f,0xe5,0x30,0xad,0x9d,0xb5,0x60,0xeb,0x3,0x88,0x2f,0x6d,0xfa,0xb4,0x29,0x83,0xbd,0xb5,0xb5,0x9d,0x68,0x15,0x9b,0x3d,0xb9,0x4,0x11,0xe,0x7,0xb6,0xd9,0xfd,0x67,0xb9,0xb9,0xa5,0x52,0xab,0xa8,0x13,0xb6,0x78,0xe0,0x39,0x63,0x36,0x38,0x60,0x87,0x1b,0x34,0xb8,0x60,0xc4,0x19,0xa9,0x80,0x53,0xf4,0xc6,0x60,0x9a,0x72,0xd0,0xc6,0xa0,0x2b,0xc,0x5d,0xf4,0xda,0xd9,0xa2,0x8f,0x29,0x3,0x43,0x54,0x5e,0x90,0x7e,0xe5,0xca,0x60,0x36,0x4e,0xb4,0xf4,0x87,0xaa,0x9e,0x54,0x15,0xba,0xea,0x5b,0x17,0x71,0xb8,0x23,0x5e,0xb8,0xe2,0xfe,0xe5,0x70,0x7b,0xac,0xd1,0x57,0x7,0x7d,0x3,0x51,0x8f,0x29,0x6b,0x3c,0x49,0x28,0x81,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + static const unsigned char graph_port_png[]={ 0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0xa,0x8,0x6,0x0,0x0,0x0,0x8d,0x32,0xcf,0xbd,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0xf9,0x43,0xbb,0x7f,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0xc,0x14,0x17,0x20,0x3,0xeb,0x8f,0x3a,0xdb,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x65,0x49,0x44,0x41,0x54,0x18,0xd3,0x4d,0xd0,0x4f,0x6b,0xda,0x70,0x1c,0x7,0xe0,0xcf,0x37,0x7f,0x7e,0x49,0x66,0xd2,0x64,0x61,0x5,0x61,0x76,0x47,0xf1,0xa4,0x2d,0xdb,0x75,0x5,0x11,0x84,0xb0,0x5e,0xeb,0xd9,0xeb,0xf4,0x6d,0xec,0x2d,0xf8,0x26,0xb6,0x77,0xe0,0x45,0xba,0xa3,0x6c,0xa0,0x3b,0xad,0x39,0xb6,0x36,0x8,0x1b,0x4b,0x32,0xd2,0xc6,0x6c,0x9a,0x4f,0x4f,0x85,0x3e,0x2f,0xe1,0x11,0x0,0x20,0x29,0xd3,0xe9,0xd4,0xda,0x6e,0xb7,0x23,0xdf,0xf7,0xbb,0x0,0x90,0xe7,0xf9,0x8f,0x66,0xb3,0xf9,0x79,0x36,0x9b,0x55,0x22,0x42,0x83,0xa4,0x44,0x51,0xf4,0xea,0xe2,0xe2,0xc3,0xf7,0xf1,0x78,0xdc,0xa,0x82,0x40,0x8,0x20,0xcf,0x32,0x2e,0x97,0xcb,0x4f,0x51,0x14,0xbd,0x25,0xf9,0x5b,0x26,0x93,0x89,0xdd,0xe9,0x74,0xe2,0xf7,0xe7,0xe7,0x27,0x59,0xfa,0x87,0x65,0xb9,0x13,0x0,0xb0,0x1d,0x9b,0xe1,0xcb,0x50,0xbe,0x5e,0x5d,0xdd,0xfe,0xbc,0xbe,0x6e,0x6b,0x49,0x92,0x8c,0x4e,0x7b,0xa7,0xad,0xbf,0x79,0x4e,0xd3,0x54,0x12,0x86,0x21,0xc2,0x30,0x84,0x32,0x95,0xe4,0x79,0xc6,0xde,0xd9,0x59,0x2b,0x49,0xee,0x46,0x86,0xeb,0xba,0x5d,0xfb,0x85,0x23,0x87,0xfd,0x1e,0xb6,0xed,0x40,0xd7,0x35,0x0,0x40,0x7d,0x38,0xa0,0xdc,0xed,0x44,0x37,0x74,0xb8,0xae,0xd7,0x35,0x48,0x62,0xff,0xff,0x1f,0xfc,0x20,0x80,0xae,0xe9,0x78,0x42,0x0,0xca,0xb2,0x90,0x65,0x19,0x58,0xd7,0xd0,0x8a,0xa2,0x58,0xa7,0x69,0x56,0x6b,0xa2,0x51,0x29,0x5,0xcb,0x52,0xb0,0x94,0x5,0x4b,0x29,0x88,0x8,0xd3,0x34,0xad,0x8b,0xfb,0x62,0xad,0xf,0x6,0x83,0xb8,0xaa,0xaa,0xb1,0xe7,0x79,0xbe,0x77,0x74,0x44,0xb7,0xe1,0x89,0x69,0x1a,0x28,0xcb,0x92,0x9b,0xcd,0x46,0x56,0xab,0xd5,0x86,0xe4,0x47,0x21,0x29,0xc3,0xe1,0xf0,0xb8,0xdf,0xef,0x7f,0x6b,0xb7,0xdb,0xaf,0x1b,0x8d,0x86,0x46,0x10,0xf,0xf7,0xf,0x75,0x1c,0xc7,0x77,0x8b,0xc5,0xe2,0xdd,0x7c,0x3e,0xff,0x25,0xcf,0xc3,0x6f,0x6e,0x6f,0x2e,0x1d,0xdb,0xe9,0x9,0x80,0xb2,0x2a,0xd7,0x27,0xad,0x37,0x5f,0x9e,0xc2,0x1f,0x1,0x3a,0xe6,0xa5,0x7b,0xef,0xf2,0xf3,0xcd,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index e3427cbe2ce5..faba339fe1d7 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -501,7 +501,7 @@ bool ShaderMaterial::_get(const StringName& p_name,Variant &r_ret) const { void ShaderMaterial::_get_property_list( List *p_list) const { - p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"Shader" ) ); + p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"MaterialShader,MaterialShaderGraph" ) ); if (!shader.is_null()) { diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index cc6bed3148cb..e47b2432f24d 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -33,12 +33,6 @@ #include "scene/scene_string_names.h" -void Shader::set_mode(Mode p_mode) { - - ERR_FAIL_INDEX(p_mode,2); - VisualServer::get_singleton()->shader_set_mode(shader,VisualServer::ShaderMode(p_mode)); - emit_signal(SceneStringNames::get_singleton()->changed); -} Shader::Mode Shader::get_mode() const { @@ -176,7 +170,6 @@ void Shader::get_default_texture_param_list(List* r_textures) const{ void Shader::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_mode","mode"),&Shader::set_mode); ObjectTypeDB::bind_method(_MD("get_mode"),&Shader::get_mode); ObjectTypeDB::bind_method(_MD("set_code","vcode","fcode","lcode","fofs","lofs"),&Shader::set_code,DEFVAL(0),DEFVAL(0)); @@ -203,9 +196,9 @@ void Shader::_bind_methods() { } -Shader::Shader() { +Shader::Shader(Mode p_mode) { - shader = VisualServer::get_singleton()->shader_create(); + shader = VisualServer::get_singleton()->shader_create(VS::ShaderMode(p_mode)); params_cache_dirty=true; } @@ -237,7 +230,7 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin String base_path = p_path.get_base_dir(); - Ref shader( memnew( Shader ) ); + Ref shader;//( memnew( Shader ) ); int line=0; diff --git a/scene/resources/shader.h b/scene/resources/shader.h index e1b8288c51b8..8c15ca43d483 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -50,6 +50,8 @@ class Shader : public Resource { mutable Map params_cache; //map a shader param to a material param.. Map > default_textures; + + protected: @@ -59,10 +61,11 @@ public: MODE_MATERIAL, MODE_CANVAS_ITEM, - MODE_POST_PROCESS + MODE_POST_PROCESS, + MODE_MAX }; - void set_mode(Mode p_mode); + //void set_mode(Mode p_mode); Mode get_mode() const; void set_code( const String& p_vertex, const String& p_fragment, const String& p_light,int p_fragment_ofs=0,int p_light_ofs=0); @@ -79,13 +82,22 @@ public: virtual RID get_rid() const; - Shader(); + Shader(Mode p_mode); ~Shader(); }; VARIANT_ENUM_CAST( Shader::Mode ); +class MaterialShader : public Shader { + + OBJ_TYPE(MaterialShader,Shader); + +public: + + MaterialShader() : Shader(MODE_MATERIAL) {}; +}; + class ResourceFormatLoaderShader : public ResourceFormatLoader { diff --git a/scene/resources/shader_graph.cpp b/scene/resources/shader_graph.cpp index 3ed6cebf0745..a06a70be9f79 100644 --- a/scene/resources/shader_graph.cpp +++ b/scene/resources/shader_graph.cpp @@ -30,118 +30,249 @@ -# if 0 -void ShaderGraph::_set(const String& p_name, const Variant& p_value) { - - if (p_name.begins_with("nodes/")) { - int idx=p_name.get_slice("/",1).to_int(); - Dictionary data=p_value; - - ERR_FAIL_COND(!data.has("type")); - String type=data["type"]; - - VS::NodeType node_type=VS::NODE_TYPE_MAX; - for(int i=0;i connections; - get_connections(&connections); - ERR_FAIL_INDEX_V( idx,connections.size(), Variant() ); - Connection c = connections[idx]; - - data["src_id"]=c.src_id; - data["src_slot"]=c.src_slot; - data["dst_id"]=c.dst_id; - data["dst_slot"]=c.dst_slot; - return data; - } - - return Variant(); -} -void ShaderGraph::_get_property_list( List *p_list) const { +Array ShaderGraph::_get_node_list(ShaderType p_type) const { List nodes; - get_node_list(&nodes); - - for(List::Element *E=nodes.front();E;E=E->next()) { - - int idx=E->get(); - p_list->push_back(PropertyInfo( Variant::DICTIONARY , "nodes/"+itos(idx),PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_STORAGE ) ); - } - - List connections; - get_connections(&connections); - int idx=0; - for(List::Element *E=connections.front();E;E=E->next()) { - p_list->push_back(PropertyInfo( Variant::DICTIONARY , "conns/"+itos(idx++),PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_STORAGE ) ); - } - + 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 { -#endif -#if 0 -Array ShaderGraph::_get_connections_helper() const { - - Array connections_ret; List connections; - get_connections(&connections); - connections_ret.resize(connections.size()); + get_node_connections(p_type,&connections); + Array arr(true); + for (List::Element *E=connections.front();E;E=E->next()) { - int idx=0; - 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); - Connection c = E->get(); - Dictionary data; - data["src_id"]=c.src_id; - data["src_slot"]=c.src_slot; - data["dst_id"]=c.dst_id; - data["dst_slot"]=c.dst_slot; - connections_ret.set(idx++,data); } - - return connections_ret; + return arr; } 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("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_set_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_set_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_set_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_set_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_set_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_set_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","c"),&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("rgb_op_node_get_c","shader_type","id"),&ShaderGraph::rgb_op_node_get_c); + + 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("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:var","shader_type","id"),&ShaderGraph::node_get_state); + + //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_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_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 ); + + +#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 ); @@ -212,73 +343,154 @@ void ShaderGraph::_bind_methods() { BIND_CONSTANT( NODE_TEXTURE_2D_PARAMETER ); BIND_CONSTANT( NODE_TEXTURE_CUBE_PARAMETER ); BIND_CONSTANT( NODE_TYPE_MAX ); +#endif } -void ShaderGraph::node_add(NodeType p_type,int p_id) { + +String ShaderGraph::_find_unique_name(ShaderType p_which, const String& p_base) { - ERR_FAIL_COND( node_map.has(p_id ) ); - ERR_FAIL_INDEX( p_type, NODE_TYPE_MAX ); + + int idx=1; + while(true) { + String tocmp=p_base; + if (idx>1) { + tocmp+="_"+itos(idx); + } + bool valid=true; + for (Map::Element *E=shader[p_which].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; - node.type=p_type; - node.id=p_id; - node.x=0; - node.y=0; - - node_map[p_id]=node; - -} - -void ShaderGraph::node_set_pos(int p_id, const Vector2& p_pos) { - - ERR_FAIL_COND(!node_map.has(p_id)); - node_map[p_id].x=p_pos.x; - node_map[p_id].y=p_pos.y; -} -Vector2 ShaderGraph::node_get_pos(int p_id) const { - - ERR_FAIL_COND_V(!node_map.has(p_id),Vector2()); - return Vector2(node_map[p_id].x,node_map[p_id].y); -} - - -void ShaderGraph::node_remove(int p_id) { - - ERR_FAIL_COND(!node_map.has(p_id)); - - //erase connections associated with node - List::Element *N,*E=connections.front(); - while(E) { - N=E->next(); - const Connection &c = E->get(); - if (c.src_id==p_id || c.dst_id==p_id) { - - connections.erase(E); + 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); + } } - E=N; + } + 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_SCALAR_INPUT: {node.param1=_find_unique_name(p_type,"Scalar"); node.param2=0;} break; // scalar uniform (assignable in material) + case NODE_VEC_INPUT: {node.param1=_find_unique_name(p_type,"Vec3");node.param2=Vector3();} break; // vec3 uniform (assignable in material) + case NODE_RGB_INPUT: {node.param1=_find_unique_name(p_type,"Color");node.param2=Color();} break; // color uniform (assignable in material) + case NODE_XFORM_INPUT: {node.param1=_find_unique_name(p_type,"XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material) + case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name(p_type,"Tex"); } break; // texture input (assignable in material) + case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name(p_type,"Cube"); } break; // cubemap input (assignable in material) + case NODE_OUTPUT: {} break; // output (shader type dependent) + case NODE_COMMENT: {} break; // comment + case NODE_TYPE_MAX: {}; } - node_map.erase(p_id); + shader[p_type].node_map[p_id]=node; + _request_update(); } -void ShaderGraph::node_change_type(int p_id, NodeType p_type) { +void ShaderGraph::node_set_pos(ShaderType p_type,int p_id, const Vector2& p_pos) { + ERR_FAIL_INDEX(p_type,3); - ERR_FAIL_COND(!node_map.has(p_id)); - node_map[p_id].type=p_type; - node_map[p_id].param=Variant(); + 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); + print_line("erased node, amount left: "+itos(shader[p_type].node_map.size())); + _request_update(); } -void ShaderGraph::node_set_param(int p_id, const Variant& p_value) { - ERR_FAIL_COND(!node_map.has(p_id)); - node_map[p_id].param=p_value; -} -void ShaderGraph::get_node_list(List *p_node_list) const { +void ShaderGraph::get_node_list(ShaderType p_type,List *p_node_list) const { - Map::Element *E = node_map.front(); + ERR_FAIL_INDEX(p_type,3); + + Map::Element *E = shader[p_type].node_map.front(); while(E) { @@ -288,183 +500,593 @@ void ShaderGraph::get_node_list(List *p_node_list) const { } -ShaderGraph::NodeType ShaderGraph::node_get_type(int p_id) const { +ShaderGraph::NodeType ShaderGraph::node_get_type(ShaderType p_type,int p_id) const { - ERR_FAIL_COND_V(!node_map.has(p_id),NODE_TYPE_MAX); - return node_map[p_id].type; -} + ERR_FAIL_INDEX_V(p_type,3,NODE_TYPE_MAX); -Variant ShaderGraph::node_get_param(int p_id) const { - - ERR_FAIL_COND_V(!node_map.has(p_id),Variant()); - return node_map[p_id].param; + 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(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) { +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(!node_map.has(p_src_id), ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!node_map.has(p_dst_id), ERR_INVALID_PARAMETER); - NodeType type_src=node_map[p_src_id].type; - NodeType type_dst=node_map[p_dst_id].type; - //ERR_FAIL_INDEX_V( p_src_slot, VisualServer::shader_get_output_count(type_src), ERR_INVALID_PARAMETER ); - //ERR_FAIL_INDEX_V( p_dst_slot, VisualServer::shader_get_input_count(type_dst), ERR_INVALID_PARAMETER ); - //ERR_FAIL_COND_V(VisualServer::shader_is_output_vector(type_src,p_src_slot) != VisualServer::shader_is_input_vector(type_dst,p_dst_slot), 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 ); - List::Element *E=connections.front(); - while(E) { - const Connection &c = E->get(); - ERR_FAIL_COND_V(c.dst_slot==p_dst_slot && c.dst_id == p_dst_id, ERR_ALREADY_EXISTS); - - E=E->next(); - } - - Connection c; - c.src_slot=p_src_slot; - c.src_id=p_src_id; - c.dst_slot=p_dst_slot; - c.dst_id=p_dst_id; - - connections.push_back(c); + 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_connected(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const { +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 { - const List::Element *E=connections.front(); - while(E) { - const Connection &c = E->get(); - if (c.dst_slot==p_dst_slot && c.dst_id == p_dst_id && c.src_slot==p_src_slot && c.src_id == p_src_id) - return true; + ERR_FAIL_INDEX_V(p_type,3,false); - E=E->next(); - } - - return 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(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) { +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); - List::Element *N,*E=connections.front(); - while(E) { - N=E->next(); - const Connection &c = E->get(); - if (c.src_slot==p_src_slot && c.src_id==p_src_id && c.dst_slot==p_dst_slot && c.dst_id == p_dst_id) { + print_line("** dsisconnect"); + 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); - connections.erase(E); + } + _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); } - E=N; - } - - -} - -void ShaderGraph::get_connections(List *p_connections) const { - - const List::Element*E=connections.front(); - while(E) { - p_connections->push_back(E->get()); - E=E->next(); - } - - -} - - -void ShaderGraph::clear() { - - connections.clear(); - node_map.clear(); -} - - -#if 0 -void ShaderGraph::node_add(NodeType p_type,int p_id) { - - ShaderNode sn; - sn.type=p_type; - nodes[p_id]=sn; - version++; -} -void ShaderGraph::node_remove(int p_id) { - - nodes.erase(p_id); - -} -void ShaderGraph::node_set_param( int p_id, const Variant& p_value) { - - VisualServer::get_singleton()->shader_node_set_param(shader,p_id,p_value); - version++; -} - -void ShaderGraph::get_node_list(List *p_node_list) const { - - VisualServer::get_singleton()->shader_get_node_list(shader,p_node_list); -} -ShaderGraph::NodeType ShaderGraph::node_get_type(int p_id) const { - - return (NodeType)VisualServer::get_singleton()->shader_node_get_type(shader,p_id); -} -Variant ShaderGraph::node_get_param(int p_id) const { - - return VisualServer::get_singleton()->shader_node_get_param(shader,p_id); -} - -void ShaderGraph::connect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) { - - VisualServer::get_singleton()->shader_connect(shader,p_src_id,p_src_slot,p_dst_id,p_dst_slot); - version++; -} -void ShaderGraph::disconnect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) { - - VisualServer::get_singleton()->shader_disconnect(shader,p_src_id,p_src_slot,p_dst_id,p_dst_slot); - version++; -} - -void ShaderGraph::get_connections(List *p_connections) const { - - List connections; - VisualServer::get_singleton()->shader_get_connections(shader,&connections); - for( List::Element *E=connections.front();E;E=E->next()) { - - Connection c; - c.src_id=E->get().src_id; - c.src_slot=E->get().src_slot; - c.dst_id=E->get().dst_id; - c.dst_slot=E->get().dst_slot; - p_connections->push_back(c); } } -void ShaderGraph::node_set_pos(int p_id,const Point2& p_pos) { -#ifdef TOOLS_ENABLED - ERR_FAIL_COND(!positions.has(p_id)); - positions[p_id]=p_pos; -#endif +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(); + } -Point2 ShaderGraph::node_get_pos(int p_id) const { -#ifdef TOOLS_ENABLED - ERR_FAIL_COND_V(!positions.has(p_id),Point2()); - return positions[p_id]; -#endif + +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(); + } -void ShaderGraph::clear() { +float ShaderGraph::scalar_const_node_get_value(ShaderType p_type,int p_id) const{ - VisualServer::get_singleton()->shader_clear(shader); - version++; + 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; } -#endif -ShaderGraph::ShaderGraph() { +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::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,float p_c){ + + 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; + n.param2=p_c; + _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); + +} +float ShaderGraph::rgb_op_node_get_c(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_RGB_OP,0); + return n.param2; + +} + +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); + n.param1=p_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::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); + n.param1=p_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::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_type,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; + 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")); + n.pos=d["pos"]; + n.param1=d["param1"]; + n.param2=d["param2"]; + +} + +ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) { //shader = VisualServer::get_singleton()->shader_create(); - version = 1; + _pending_update_shader=false; + Node out; + out.id=0; + out.pos=Vector2(250,20); + out.type=NODE_OUTPUT; + for(int i=0;i<3;i++) { + + shader[i].node_map.insert(0,out); + } } ShaderGraph::~ShaderGraph() { @@ -472,556 +1094,681 @@ ShaderGraph::~ShaderGraph() { //VisualServer::get_singleton()->free(shader); } -#if 0 -void ShaderGraph::shader_get_default_input_nodes(Mode p_type,List *p_inputs) { - switch(p_type) { +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,"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}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Time","TIME",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",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","UV2",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",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","UV",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV2","UV2",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UVScreen","SCREEN_UV",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,"Time","TIME",SLOT_TYPE_SCALAR,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","SPECULAR",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",SLOT_TYPE_SCALAR,SLOT_OUT}, + //end + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT}, - case SHADER_VERTEX: { +}; - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"vertex") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") ); - p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - } break; - case SHADER_FRAGMENT: { +void ShaderGraph::get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List *r_slots) { - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"position") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") ); - p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - - } break; - case SHADER_POST_PROCESS: { - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") ); - p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - } break; + 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++; } - -} -void ShaderGraph::shader_get_default_output_nodes(ShaderGraphType p_type,List *p_outputs) { - - switch(p_type) { - - case SHADER_VERTEX: { - - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"vertex") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"color") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - } break; - case SHADER_FRAGMENT: { - - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"diffuse") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"specular") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"emission") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"spec_exp") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"glow") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha_discard") ); - - } break; - case SHADER_POST_PROCESS: { - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"color") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - } break; - - } - } -PropertyInfo ShaderGraph::shader_node_get_type_info(NodeType p_type) { +const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[]= { - switch(p_type) { + {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_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_TYPE_SCALAR},{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_XFORM,SLOT_TYPE_VEC,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_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_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_COMMENT,{SLOT_MAX},{SLOT_MAX}}, // comment + {NODE_TYPE_MAX,{SLOT_MAX},{SLOT_MAX}} +}; - case NODE_IN: return PropertyInfo(Variant::STRING,"in"); - case NODE_OUT: return PropertyInfo(Variant::STRING,"out"); - case NODE_CONSTANT: return PropertyInfo(Variant::REAL,"const"); - case NODE_PARAMETER: return PropertyInfo(Variant::STRING,"param"); - case NODE_ADD: return PropertyInfo(Variant::NIL,"add"); - case NODE_SUB: return PropertyInfo(Variant::NIL,"sub"); - case NODE_MUL: return PropertyInfo(Variant::NIL,"mul"); - case NODE_DIV: return PropertyInfo(Variant::NIL,"div"); - case NODE_MOD: return PropertyInfo(Variant::NIL,"rem"); - case NODE_SIN: return PropertyInfo(Variant::NIL,"sin"); - case NODE_COS: return PropertyInfo(Variant::NIL,"cos"); - case NODE_TAN: return PropertyInfo(Variant::NIL,"tan"); - case NODE_ARCSIN: return PropertyInfo(Variant::NIL,"arcsin"); - case NODE_ARCCOS: return PropertyInfo(Variant::NIL,"arccos"); - case NODE_ARCTAN: return PropertyInfo(Variant::NIL,"arctan"); - case NODE_POW: return PropertyInfo(Variant::NIL,"pow"); - case NODE_LOG: return PropertyInfo(Variant::NIL,"log"); - case NODE_MAX: return PropertyInfo(Variant::NIL,"max"); - case NODE_MIN: return PropertyInfo(Variant::NIL,"min"); - case NODE_COMPARE: return PropertyInfo(Variant::NIL,"cmp"); - case NODE_TEXTURE: return PropertyInfo(Variant::_RID,"texture1D",PROPERTY_HINT_RESOURCE_TYPE,"Texture"); - case NODE_TIME: return PropertyInfo(Variant::NIL,"time"); - case NODE_NOISE: return PropertyInfo(Variant::NIL,"noise"); - case NODE_PASS: return PropertyInfo(Variant::NIL,"pass"); - case NODE_VEC_IN: return PropertyInfo(Variant::STRING,"vin"); - case NODE_VEC_OUT: return PropertyInfo(Variant::STRING,"vout"); - case NODE_VEC_CONSTANT: return PropertyInfo(Variant::VECTOR3,"vconst"); - case NODE_VEC_PARAMETER: return PropertyInfo(Variant::STRING,"vparam"); - case NODE_VEC_ADD: return PropertyInfo(Variant::NIL,"vadd"); - case NODE_VEC_SUB: return PropertyInfo(Variant::NIL,"vsub"); - case NODE_VEC_MUL: return PropertyInfo(Variant::NIL,"vmul"); - case NODE_VEC_DIV: return PropertyInfo(Variant::NIL,"vdiv"); - case NODE_VEC_MOD: return PropertyInfo(Variant::NIL,"vrem"); - case NODE_VEC_CROSS: return PropertyInfo(Variant::NIL,"cross"); - case NODE_VEC_DOT: return PropertyInfo(Variant::NIL,"dot"); - case NODE_VEC_POW: return PropertyInfo(Variant::NIL,"vpow"); - case NODE_VEC_NORMALIZE: return PropertyInfo(Variant::NIL,"normalize"); - case NODE_VEC_INTERPOLATE: return PropertyInfo(Variant::NIL,"mix"); - case NODE_VEC_SCREEN_TO_UV: return PropertyInfo(Variant::NIL,"scrn2uv"); - case NODE_VEC_TRANSFORM3: return PropertyInfo(Variant::NIL,"xform3"); - case NODE_VEC_TRANSFORM4: return PropertyInfo(Variant::NIL,"xform4"); - case NODE_VEC_COMPARE: return PropertyInfo(Variant::_RID,"vcmp",PROPERTY_HINT_RESOURCE_TYPE,"Texture"); - case NODE_VEC_TEXTURE_2D: return PropertyInfo(Variant::_RID,"texture2D",PROPERTY_HINT_RESOURCE_TYPE,"Texture"); - case NODE_VEC_TEXTURE_CUBE: return PropertyInfo(Variant::NIL,"texcube"); - case NODE_VEC_NOISE: return PropertyInfo(Variant::NIL,"vec_noise"); - case NODE_VEC_0: return PropertyInfo(Variant::NIL,"vec_0"); - case NODE_VEC_1: return PropertyInfo(Variant::NIL,"vec_1"); - case NODE_VEC_2: return PropertyInfo(Variant::NIL,"vec_2"); - case NODE_VEC_BUILD: return PropertyInfo(Variant::NIL,"vbuild"); - case NODE_VEC_PASS: return PropertyInfo(Variant::NIL,"vpass"); - case NODE_COLOR_CONSTANT: return PropertyInfo(Variant::COLOR,"color_const"); - case NODE_COLOR_PARAMETER: return PropertyInfo(Variant::STRING,"color_param"); - case NODE_TEXTURE_PARAMETER: return PropertyInfo(Variant::STRING,"tex1D_param"); - case NODE_TEXTURE_2D_PARAMETER: return PropertyInfo(Variant::STRING,"tex2D_param"); - case NODE_TEXTURE_CUBE_PARAMETER: return PropertyInfo(Variant::STRING,"texcube_param"); - case NODE_TRANSFORM_CONSTANT: return PropertyInfo(Variant::TRANSFORM,"xform_const"); - case NODE_TRANSFORM_PARAMETER: return PropertyInfo(Variant::STRING,"xform_param"); - case NODE_LABEL: return PropertyInfo(Variant::STRING,"label"); +int ShaderGraph::get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type) { - default: {} + 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;iins[i]==SLOT_MAX) + break; + pc++; + } + return pc; + } + + nsi++; + } + + return 0; } - - ERR_FAIL_V( PropertyInfo(Variant::NIL,"error") ); } -int ShaderGraph::shader_get_input_count(NodeType p_type) { - switch(p_type) { - case NODE_IN: return 0; - case NODE_OUT: return 1; - case NODE_CONSTANT: return 0; - case NODE_PARAMETER: return 0; - case NODE_ADD: return 2; - case NODE_SUB: return 2; - case NODE_MUL: return 2; - case NODE_DIV: return 2; - case NODE_MOD: return 2; - case NODE_SIN: return 1; - case NODE_COS: return 1; - case NODE_TAN: return 1; - case NODE_ARCSIN: return 1; - case NODE_ARCCOS: return 1; - case NODE_ARCTAN: return 1; - case NODE_POW: return 2; - case NODE_LOG: return 1; - case NODE_MAX: return 2; - case NODE_MIN: return 2; - case NODE_COMPARE: return 4; - case NODE_TEXTURE: return 1; ///< param 0: texture - case NODE_TIME: return 1; ///< param 0: interval length - case NODE_NOISE: return 0; - case NODE_PASS: return 1; - case NODE_VEC_IN: return 0; ///< param 0: name - case NODE_VEC_OUT: return 1; ///< param 0: name - case NODE_VEC_CONSTANT: return 0; ///< param 0: value - case NODE_VEC_PARAMETER: return 0; ///< param 0: name - case NODE_VEC_ADD: return 2; - case NODE_VEC_SUB: return 2; - case NODE_VEC_MUL: return 2; - case NODE_VEC_DIV: return 2; - case NODE_VEC_MOD: return 2; - case NODE_VEC_CROSS: return 2; - case NODE_VEC_DOT: return 2; - case NODE_VEC_POW: return 2; - case NODE_VEC_NORMALIZE: return 1; - case NODE_VEC_INTERPOLATE: return 3; - case NODE_VEC_SCREEN_TO_UV: return 1; - case NODE_VEC_TRANSFORM3: return 4; - case NODE_VEC_TRANSFORM4: return 5; - case NODE_VEC_COMPARE: return 4; - case NODE_VEC_TEXTURE_2D: return 1; - case NODE_VEC_TEXTURE_CUBE: return 1; - case NODE_VEC_NOISE: return 0; - case NODE_VEC_0: return 1; - case NODE_VEC_1: return 1; - case NODE_VEC_2: return 1; - case NODE_VEC_BUILD: return 3; - case NODE_VEC_PASS: return 1; - case NODE_COLOR_CONSTANT: return 0; - case NODE_COLOR_PARAMETER: return 0; - case NODE_TEXTURE_PARAMETER: return 1; - case NODE_TEXTURE_2D_PARAMETER: return 1; - case NODE_TEXTURE_CUBE_PARAMETER: return 1; - case NODE_TRANSFORM_CONSTANT: return 1; - case NODE_TRANSFORM_PARAMETER: return 1; - case NODE_LABEL: return 0; - default: {} +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;iouts[i]==SLOT_MAX) + break; + pc++; + } + return pc; + } + + nsi++; + } + + return 0; + } - ERR_FAIL_V( 0 ); } -int ShaderGraph::shader_get_output_count(NodeType p_type) { +ShaderGraph::SlotType ShaderGraph::get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){ - switch(p_type) { - case NODE_IN: return 1; - case NODE_OUT: return 0; - case NODE_CONSTANT: return 1; - case NODE_PARAMETER: return 1; - case NODE_ADD: return 1; - case NODE_SUB: return 1; - case NODE_MUL: return 1; - case NODE_DIV: return 1; - case NODE_MOD: return 1; - case NODE_SIN: return 1; - case NODE_COS: return 1; - case NODE_TAN: return 1; - case NODE_ARCSIN: return 1; - case NODE_ARCCOS: return 1; - case NODE_ARCTAN: return 1; - case NODE_POW: return 1; - case NODE_LOG: return 1; - case NODE_MAX: return 1; - case NODE_MIN: return 1; - case NODE_COMPARE: return 2; - case NODE_TEXTURE: return 3; ///< param 0: texture - case NODE_TIME: return 1; ///< param 0: interval length - case NODE_NOISE: return 1; - case NODE_PASS: return 1; - case NODE_VEC_IN: return 1; ///< param 0: name - case NODE_VEC_OUT: return 0; ///< param 0: name - case NODE_VEC_CONSTANT: return 1; ///< param 0: value - case NODE_VEC_PARAMETER: return 1; ///< param 0: name - case NODE_VEC_ADD: return 1; - case NODE_VEC_SUB: return 1; - case NODE_VEC_MUL: return 1; - case NODE_VEC_DIV: return 1; - case NODE_VEC_MOD: return 1; - case NODE_VEC_CROSS: return 1; - case NODE_VEC_DOT: return 1; - case NODE_VEC_POW: return 1; - case NODE_VEC_NORMALIZE: return 1; - case NODE_VEC_INTERPOLATE: return 1; - case NODE_VEC_SCREEN_TO_UV: return 1; - case NODE_VEC_TRANSFORM3: return 1; - case NODE_VEC_TRANSFORM4: return 1; - case NODE_VEC_COMPARE: return 2; - case NODE_VEC_TEXTURE_2D: return 3; - case NODE_VEC_TEXTURE_CUBE: return 3; - case NODE_VEC_NOISE: return 1; - case NODE_VEC_0: return 1; - case NODE_VEC_1: return 1; - case NODE_VEC_2: return 1; - case NODE_VEC_BUILD: return 1; - case NODE_VEC_PASS: return 1; - case NODE_COLOR_CONSTANT: return 2; - case NODE_COLOR_PARAMETER: return 2; - case NODE_TEXTURE_PARAMETER: return 3; - case NODE_TEXTURE_2D_PARAMETER: return 3; - case NODE_TEXTURE_CUBE_PARAMETER: return 3; - case NODE_TRANSFORM_CONSTANT: return 1; - case NODE_TRANSFORM_PARAMETER: return 1; - case NODE_LABEL: return 0; + 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;iins[i]==SLOT_MAX) + break; + if (i==p_idx) + return nsi->ins[i]; + } + } + + nsi++; + } + + ERR_FAIL_V(SLOT_MAX); - default: {} } - ERR_FAIL_V( 0 ); +} +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;iouts[i]==SLOT_MAX) + break; + if (i==p_idx) + return nsi->outs[i]; + } + } + + nsi++; + } + + ERR_FAIL_V(SLOT_MAX); + } } -#define RET2(m_a,m_b) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else return ""; -#define RET3(m_a,m_b,m_c) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else return ""; -#define RET4(m_a,m_b,m_c,m_d) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else if (p_idx==3) return m_d; else return ""; -#define RET5(m_a,m_b,m_c,m_d,m_e) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else if (p_idx==3) return m_d; else if (p_idx==4) return m_e; else return ""; -String ShaderGraph::shader_get_input_name(NodeType p_type,int p_idx) { - switch(p_type) { - case NODE_IN: return ""; - case NODE_OUT: return "out"; - case NODE_CONSTANT: return ""; - case NODE_PARAMETER: return ""; - case NODE_ADD: RET2("a","b"); - case NODE_SUB: RET2("a","b"); - case NODE_MUL: RET2("a","b"); - case NODE_DIV: RET2("a","b"); - case NODE_MOD: RET2("a","b"); - case NODE_SIN: return "rad"; - case NODE_COS: return "rad"; - case NODE_TAN: return "rad"; - case NODE_ARCSIN: return "in"; - case NODE_ARCCOS: return "in"; - case NODE_ARCTAN: return "in"; - case NODE_POW: RET2("in","exp"); - case NODE_LOG: return "in"; - case NODE_MAX: return "in"; - case NODE_MIN: return "in"; - case NODE_COMPARE: RET4("a","b","ret1","ret2"); - case NODE_TEXTURE: return "u"; - case NODE_TIME: return ""; - case NODE_NOISE: return ""; - case NODE_PASS: return "in"; - case NODE_VEC_IN: return ""; - case NODE_VEC_OUT: return "out"; - case NODE_VEC_CONSTANT: return ""; - case NODE_VEC_PARAMETER: return ""; - case NODE_VEC_ADD: RET2("a","b"); - case NODE_VEC_SUB: RET2("a","b"); - case NODE_VEC_MUL: RET2("a","b"); - case NODE_VEC_DIV: RET2("a","b"); - case NODE_VEC_MOD: RET2("a","b"); - case NODE_VEC_CROSS: RET2("a","b"); - case NODE_VEC_DOT: RET2("a","b"); - case NODE_VEC_POW: RET2("a","b"); - case NODE_VEC_NORMALIZE: return "vec"; - case NODE_VEC_INTERPOLATE: RET3("a","b","c"); - case NODE_VEC_SCREEN_TO_UV: return "scr"; - case NODE_VEC_TRANSFORM3: RET4("in","col0","col1","col2"); - case NODE_VEC_TRANSFORM4: RET5("in","col0","col1","col2","col3"); - case NODE_VEC_COMPARE: RET4("a","b","ret1","ret2"); - case NODE_VEC_TEXTURE_2D: return "uv"; - case NODE_VEC_TEXTURE_CUBE: return "uvw"; - case NODE_VEC_NOISE: return ""; - case NODE_VEC_0: return "vec"; - case NODE_VEC_1: return "vec"; - case NODE_VEC_2: return "vec"; - case NODE_VEC_BUILD: RET3("x/r","y/g","z/b"); - case NODE_VEC_PASS: return "in"; - case NODE_COLOR_CONSTANT: return ""; - case NODE_COLOR_PARAMETER: return ""; - case NODE_TEXTURE_PARAMETER: return "u"; - case NODE_TEXTURE_2D_PARAMETER: return "uv"; - case NODE_TEXTURE_CUBE_PARAMETER: return "uvw"; - case NODE_TRANSFORM_CONSTANT: return "in"; - case NODE_TRANSFORM_PARAMETER: return "in"; - case NODE_LABEL: return ""; +void ShaderGraph::_update_shader() { - default: {} + + String code[3]; + + 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);"; + code[i]+="float ALPHA_OUT=0;"; + } + + Map inputs_xlate; + Set inputs_used; + + for(int j=0;jtype==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"; + 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+";\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.rgb=DIFFUSE_OUT;\n"; + code[i]+="DIFFUSE_ALPHA.a=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;kconnections.has(k)) { + shader[i].error=GRAPH_ERROR_MISSING_CONNECTIONS; + failed=true; + break; + } + String iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot); + inputs.push_back(iname); + if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) + inputs_used.insert(iname); + + } + + if (failed) + break; + _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]; + } + shader[i].error=GRAPH_OK; + print_line("ShADER: "+code[i]); } - ERR_FAIL_V(""); -} -String ShaderGraph::shader_get_output_name(NodeType p_type,int p_idx) { - - switch(p_type) { - - case NODE_IN: return "in"; - case NODE_OUT: return ""; - case NODE_CONSTANT: return "out"; - case NODE_PARAMETER: return "out"; - case NODE_ADD: return "sum"; - case NODE_SUB: return "dif"; - case NODE_MUL: return "prod"; - case NODE_DIV: return "quot"; - case NODE_MOD: return "rem"; - case NODE_SIN: return "out"; - case NODE_COS: return "out"; - case NODE_TAN: return "out"; - case NODE_ARCSIN: return "rad"; - case NODE_ARCCOS: return "rad"; - case NODE_ARCTAN: return "rad"; - case NODE_POW: RET2("in","exp"); - case NODE_LOG: return "out"; - case NODE_MAX: return "out"; - case NODE_MIN: return "out"; - case NODE_COMPARE: RET2("a/b","a/b"); - case NODE_TEXTURE: RET3("rgb","a","v"); - case NODE_TIME: return "out"; - case NODE_NOISE: return "out"; - case NODE_PASS: return "out"; - case NODE_VEC_IN: return "in"; - case NODE_VEC_OUT: return ""; - case NODE_VEC_CONSTANT: return "out"; - case NODE_VEC_PARAMETER: return "out"; - case NODE_VEC_ADD: return "sum"; - case NODE_VEC_SUB: return "sub"; - case NODE_VEC_MUL: return "mul"; - case NODE_VEC_DIV: return "div"; - case NODE_VEC_MOD: return "rem"; - case NODE_VEC_CROSS: return "crs"; - case NODE_VEC_DOT: return "prod"; - case NODE_VEC_POW: return "out"; - case NODE_VEC_NORMALIZE: return "norm"; - case NODE_VEC_INTERPOLATE: return "out"; - case NODE_VEC_SCREEN_TO_UV: return "uv"; - case NODE_VEC_TRANSFORM3: return "prod"; - case NODE_VEC_TRANSFORM4: return "prod"; - case NODE_VEC_COMPARE: RET2("a/b","a/b"); - case NODE_VEC_TEXTURE_2D: RET3("rgb","a","v"); - case NODE_VEC_TEXTURE_CUBE: RET3("rgb","a","v"); - case NODE_VEC_NOISE: return "out"; - case NODE_VEC_0: return "x/r"; - case NODE_VEC_1: return "y/g"; - case NODE_VEC_2: return "z/b"; - case NODE_VEC_BUILD: return "vec"; - case NODE_VEC_PASS: return "out"; - case NODE_COLOR_CONSTANT: RET2("rgb","a"); - case NODE_COLOR_PARAMETER: RET2("rgb","a"); - case NODE_TEXTURE_PARAMETER: RET3("rgb","a","v"); - case NODE_TEXTURE_2D_PARAMETER: RET3("rgb","a","v"); - case NODE_TEXTURE_CUBE_PARAMETER: RET3("rgb","a","v"); - case NODE_TRANSFORM_CONSTANT: return "out"; - case NODE_TRANSFORM_PARAMETER: return "out"; - case NODE_LABEL: return ""; - - default: {} + bool all_ok=true; + for(int i=0;i<3;i++) { + if (shader[i].error!=GRAPH_OK) + all_ok=false; } - ERR_FAIL_V(""); -} -bool ShaderGraph::shader_is_input_vector(NodeType p_type,int p_input) { - - switch(p_type) { - - case NODE_IN: return false; - case NODE_OUT: return false; - case NODE_CONSTANT: return false; - case NODE_PARAMETER: return false; - case NODE_ADD: return false; - case NODE_SUB: return false; - case NODE_MUL: return false; - case NODE_DIV: return false; - case NODE_MOD: return false; - case NODE_SIN: return false; - case NODE_COS: return false; - case NODE_TAN: return false; - case NODE_ARCSIN: return false; - case NODE_ARCCOS: return false; - case NODE_ARCTAN: return false; - case NODE_POW: return false; - case NODE_LOG: return false; - case NODE_MAX: return false; - case NODE_MIN: return false; - case NODE_COMPARE: return false; - case NODE_TEXTURE: return false; - case NODE_TIME: return false; - case NODE_NOISE: return false; - case NODE_PASS: return false; - case NODE_VEC_IN: return false; - case NODE_VEC_OUT: return true; - case NODE_VEC_CONSTANT: return false; - case NODE_VEC_PARAMETER: return false; - case NODE_VEC_ADD: return true; - case NODE_VEC_SUB: return true; - case NODE_VEC_MUL: return true; - case NODE_VEC_DIV: return true; - case NODE_VEC_MOD: return true; - case NODE_VEC_CROSS: return true; - case NODE_VEC_DOT: return true; - case NODE_VEC_POW: return (p_input==0)?true:false; - case NODE_VEC_NORMALIZE: return true; - case NODE_VEC_INTERPOLATE: return (p_input<2)?true:false; - case NODE_VEC_SCREEN_TO_UV: return true; - case NODE_VEC_TRANSFORM3: return true; - case NODE_VEC_TRANSFORM4: return true; - case NODE_VEC_COMPARE: return (p_input<2)?false:true; - case NODE_VEC_TEXTURE_2D: return true; - case NODE_VEC_TEXTURE_CUBE: return true; - case NODE_VEC_NOISE: return false; - case NODE_VEC_0: return true; - case NODE_VEC_1: return true; - case NODE_VEC_2: return true; - case NODE_VEC_BUILD: return false; - case NODE_VEC_PASS: return true; - case NODE_COLOR_CONSTANT: return false; - case NODE_COLOR_PARAMETER: return false; - case NODE_TEXTURE_PARAMETER: return false; - case NODE_TEXTURE_2D_PARAMETER: return true; - case NODE_TEXTURE_CUBE_PARAMETER: return true; - case NODE_TRANSFORM_CONSTANT: return true; - case NODE_TRANSFORM_PARAMETER: return true; - case NODE_LABEL: return false; - - default: {} + if (all_ok) { + set_code(code[0],code[1],code[2]); } - - ERR_FAIL_V(false); + //do shader here + print_line("UPDATING SHADER"); + _pending_update_shader=false; } -bool ShaderGraph::shader_is_output_vector(NodeType p_type,int p_input) { - switch(p_type) { +void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector& p_inputs,String& code) { - case NODE_IN: return false; - case NODE_OUT: return false ; - case NODE_CONSTANT: return false; - case NODE_PARAMETER: return false; - case NODE_ADD: return false; - case NODE_SUB: return false; - case NODE_MUL: return false; - case NODE_DIV: return false; - case NODE_MOD: return false; - case NODE_SIN: return false; - case NODE_COS: return false; - case NODE_TAN: return false; - case NODE_ARCSIN: return false; - case NODE_ARCCOS: return false; - case NODE_ARCTAN: return false; - case NODE_POW: return false; - case NODE_LOG: return false; - case NODE_MAX: return false; - case NODE_MIN: return false; - case NODE_COMPARE: return false; - case NODE_TEXTURE: return false; - case NODE_TIME: return false; - case NODE_NOISE: return false; - case NODE_PASS: return false; - case NODE_VEC_IN: return true; - case NODE_VEC_OUT: return false; - case NODE_VEC_CONSTANT: return true; - case NODE_VEC_PARAMETER: return true; - case NODE_VEC_ADD: return true; - case NODE_VEC_SUB: return true; - case NODE_VEC_MUL: return true; - case NODE_VEC_DIV: return true; - case NODE_VEC_MOD: return true; - case NODE_VEC_CROSS: return true; - case NODE_VEC_DOT: return false; - case NODE_VEC_POW: return true; - case NODE_VEC_NORMALIZE: return true; - case NODE_VEC_INTERPOLATE: return true; - case NODE_VEC_SCREEN_TO_UV: return true; - case NODE_VEC_TRANSFORM3: return true; - case NODE_VEC_TRANSFORM4: return true; - case NODE_VEC_COMPARE: return true; - case NODE_VEC_TEXTURE_2D: return (p_input==0)?true:false; - case NODE_VEC_TEXTURE_CUBE: return (p_input==0)?true:false; - case NODE_VEC_NOISE: return true; - case NODE_VEC_0: return false; - case NODE_VEC_1: return false; - case NODE_VEC_2: return false; - case NODE_VEC_BUILD: return true; - case NODE_VEC_PASS: return true; - case NODE_COLOR_CONSTANT: return (p_input==0)?true:false; - case NODE_COLOR_PARAMETER: return (p_input==0)?true:false; - case NODE_TEXTURE_PARAMETER: return (p_input==0)?true:false; - case NODE_TEXTURE_2D_PARAMETER: return (p_input==0)?true:false; - case NODE_TEXTURE_CUBE_PARAMETER: return (p_input==0)?true:false; - case NODE_TRANSFORM_CONSTANT: return true; - case NODE_TRANSFORM_PARAMETER: return true; - case NODE_LABEL: return false; - default: {} + 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))) + + 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"; + }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: { + code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+");\n"; + }break; + case NODE_SCALAR_OP: { + 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: { + 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: { + int op = p_node->param1; + String optxt; + switch(op) { + 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_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break; + } + code+=OUTNAME(p_node->id,0)+"="+optxt+"\n"; + + }break; + case NODE_RGB_OP: { + + + }break; + case NODE_XFORM_MULT: { + + code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*"+p_inputs[1]+";\n"; + + }break; + case NODE_XFORM_VEC_MULT: { + + bool no_translation = p_node->param1; + if (no_translation) { + code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*vec4("+p_inputs[1]+",0);\n"; + } else { + code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*vec4("+p_inputs[1]+",1);\n"; + } + + }break; + case NODE_XFORM_VEC_INV_MULT: { + bool no_translation = p_node->param1; + if (no_translation) { + code += OUTNAME(p_node->id,0)+"="+p_inputs[1]+"*vec4("+p_inputs[0]+",0);\n"; + } else { + code += OUTNAME(p_node->id,0)+"="+p_inputs[1]+"*vec4("+p_inputs[0]+",1);\n"; + } + }break; + case NODE_SCALAR_FUNC: { + + + }break; + case NODE_VEC_FUNC: { + + }break; + case NODE_VEC_LEN: { + + code += OUTNAME(p_node->id,0)+"=length("+p_inputs[1]+");\n"; + + }break; + case NODE_DOT_PROD: { + code += OUTNAME(p_node->id,0)+"=dot("+p_inputs[1]+","+p_inputs[0]+");\n"; + + }break; + case NODE_VEC_TO_SCALAR: { + 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: { + code += OUTNAME(p_node->id,0)+"=vec3("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+""+");\n"; + + }break; + case NODE_VEC_TO_XFORM: { + code += OUTNAME(p_node->id,0)+"=xform("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+","+","+p_inputs[3]+");\n"; + + }break; + case NODE_XFORM_TO_VEC: { + 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"; + code += OUTNAME(p_node->id,3)+"="+p_inputs[0]+".o;\n"; + }break; + case NODE_SCALAR_INTERP: { + + code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n"; + + }break; + case NODE_VEC_INTERP: { + code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\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 float "+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.g)+","+rtos(dv.a)+");\n"; + code += OUTNAME(p_node->id,0)+"="+name+".rgb;\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: { + String name = p_node->param1; + String rname="_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: { + + String name = p_node->param1; + code +="uniform cubemap "+name+";"; + String rname="_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_OUTPUT: { + + + }break; + case NODE_COMMENT: { + + }break; + case NODE_TYPE_MAX: { + + } } - - ERR_FAIL_V(""); } - -#endif -#endif diff --git a/scene/resources/shader_graph.h b/scene/resources/shader_graph.h index e20e010c6b0c..c73895db8a57 100644 --- a/scene/resources/shader_graph.h +++ b/scene/resources/shader_graph.h @@ -29,87 +29,54 @@ #ifndef SHADER_GRAPH_H #define SHADER_GRAPH_H -#if 0 + #include "map.h" #include "scene/resources/shader.h" -class ShaderGraph : public Resource { +class ShaderGraph : public Shader { - OBJ_TYPE( ShaderGraph, Resource ); + OBJ_TYPE( ShaderGraph, Shader ); RES_BASE_EXTENSION("sgp"); public: enum NodeType { - NODE_IN, ///< param 0: name - NODE_OUT, ///< param 0: name - NODE_CONSTANT, ///< param 0: value - NODE_PARAMETER, ///< param 0: name - NODE_ADD, - NODE_SUB, - NODE_MUL, - NODE_DIV, - NODE_MOD, - NODE_SIN, - NODE_COS, - NODE_TAN, - NODE_ARCSIN, - NODE_ARCCOS, - NODE_ARCTAN, - NODE_POW, - NODE_LOG, - NODE_MAX, - NODE_MIN, - NODE_COMPARE, - NODE_TEXTURE, ///< param 0: texture - NODE_TIME, ///< param 0: interval length - NODE_NOISE, - NODE_PASS, - NODE_VEC_IN, ///< param 0: name - NODE_VEC_OUT, ///< param 0: name - NODE_VEC_CONSTANT, ///< param 0: value - NODE_VEC_PARAMETER, ///< param 0: name - NODE_VEC_ADD, - NODE_VEC_SUB, - NODE_VEC_MUL, - NODE_VEC_DIV, - NODE_VEC_MOD, - NODE_VEC_CROSS, - NODE_VEC_DOT, - NODE_VEC_POW, - NODE_VEC_NORMALIZE, - NODE_VEC_INTERPOLATE, - NODE_VEC_SCREEN_TO_UV, - NODE_VEC_TRANSFORM3, - NODE_VEC_TRANSFORM4, - NODE_VEC_COMPARE, - NODE_VEC_TEXTURE_2D, - NODE_VEC_TEXTURE_CUBE, - NODE_VEC_NOISE, - NODE_VEC_0, - NODE_VEC_1, - NODE_VEC_2, - NODE_VEC_BUILD, - NODE_VEC_PASS, - NODE_COLOR_CONSTANT, - NODE_COLOR_PARAMETER, - NODE_TEXTURE_PARAMETER, - NODE_TEXTURE_2D_PARAMETER, - NODE_TEXTURE_CUBE_PARAMETER, - NODE_TRANSFORM_CONSTANT, - NODE_TRANSFORM_PARAMETER, - NODE_LABEL, + NODE_INPUT, // all inputs (shader type dependent) + NODE_SCALAR_CONST, //scalar constant + NODE_VEC_CONST, //vec3 constant + NODE_RGB_CONST, //rgb constant (shows a color picker instead) + NODE_XFORM_CONST, // 4x4 matrix constant + NODE_TIME, // time in seconds + NODE_SCREEN_TEX, // screen texture sampler (takes UV) (only usable in fragment shader) + NODE_SCALAR_OP, // scalar vs scalar op (mul, add, div, etc) + NODE_VEC_OP, // vec3 vs vec3 op (mul,ad,div,crossprod,etc) + NODE_VEC_SCALAR_OP, // vec3 vs scalar op (mul, add, div, etc) + NODE_RGB_OP, // vec3 vs vec3 rgb op (with scalar amount), like brighten, darken, burn, dodge, multiply, etc. + NODE_XFORM_MULT, // mat4 x mat4 + NODE_XFORM_VEC_MULT, // mat4 x vec3 mult (with no-translation option) + NODE_XFORM_VEC_INV_MULT, // mat4 x vec3 inverse mult (with no-translation option) + NODE_SCALAR_FUNC, // scalar function (sin, cos, etc) + NODE_VEC_FUNC, // vector function (normalize, negate, reciprocal, rgb2hsv, hsv2rgb, etc, etc) + NODE_VEC_LEN, // vec3 length + NODE_DOT_PROD, // vec3 . vec3 (dot product -> scalar output) + NODE_VEC_TO_SCALAR, // 1 vec3 input, 3 scalar outputs + NODE_SCALAR_TO_VEC, // 3 scalar input, 1 vec3 output + NODE_XFORM_TO_VEC, // 3 vec input, 1 xform output + NODE_VEC_TO_XFORM, // 3 vec input, 1 xform output + NODE_SCALAR_INTERP, // scalar interpolation (with optional curve) + NODE_VEC_INTERP, // vec3 interpolation (with optional curve) + NODE_SCALAR_INPUT, // scalar uniform (assignable in material) + NODE_VEC_INPUT, // vec3 uniform (assignable in material) + NODE_RGB_INPUT, // color uniform (assignable in material) + NODE_XFORM_INPUT, // mat4 uniform (assignable in material) + NODE_TEXTURE_INPUT, // texture input (assignable in material) + NODE_CUBEMAP_INPUT, // cubemap input (assignable in material) + NODE_OUTPUT, // output (shader type dependent) + NODE_COMMENT, // comment NODE_TYPE_MAX }; - enum ShaderType { - SHADER_VERTEX, - SHADER_FRAGMENT, - SHADER_LIGHT - }; - -private: struct Connection { @@ -119,70 +86,287 @@ private: int dst_slot; }; + enum SlotType { + + SLOT_TYPE_SCALAR, + SLOT_TYPE_VEC, + SLOT_TYPE_XFORM, + SLOT_TYPE_TEXTURE, + SLOT_MAX + }; + + enum ShaderType { + SHADER_TYPE_VERTEX, + SHADER_TYPE_FRAGMENT, + SHADER_TYPE_LIGHT, + SHADER_TYPE_MAX + }; + + enum SlotDir { + SLOT_IN, + SLOT_OUT + }; + + enum GraphError { + GRAPH_OK, + GRAPH_ERROR_CYCLIC, + GRAPH_ERROR_MISSING_CONNECTIONS + }; + +private: + + String _find_unique_name(ShaderType p_which, const String& p_base); + + struct SourceSlot { + + int id; + int slot; + bool operator==(const SourceSlot& p_slot) const { + return id==p_slot.id && slot==p_slot.slot; + } + }; + struct Node { - int16_t x,y; + Vector2 pos; NodeType type; - Variant param; + Variant param1; + Variant param2; int id; mutable int order; // used for sorting - mutable bool out_valid; - mutable bool in_valid; + int sort_order; + Map connections; + }; struct ShaderData { Map node_map; - List connections; + GraphError error; } shader[3]; - uint64_t version; + + + struct InOutParamInfo { + Mode shader_mode; + ShaderType shader_type; + const char *name; + const char *variable; + SlotType slot_type; + SlotDir dir; + }; + + static const InOutParamInfo inout_param_info[]; + + struct NodeSlotInfo { + + enum { MAX_INS=3, MAX_OUTS=3 }; + NodeType type; + const SlotType ins[MAX_INS]; + const SlotType outs[MAX_OUTS]; + }; + + static const NodeSlotInfo node_slot_info[]; + + bool _pending_update_shader; + void _update_shader(); + void _request_update(); + + void _add_node_code(ShaderType p_type,Node *p_node,const Vector& p_inputs,String& code); + + Array _get_node_list(ShaderType p_type) const; + Array _get_connections(ShaderType p_type) const; protected: -/* bool _set(const StringName& p_name, const Variant& p_value); - bool _get(const StringName& p_name,Variant &r_ret) const; - void _get_property_list( List *p_list) const;*/ - static void _bind_methods(); - Array _get_connections_helper() const; - public: - void node_add(ShaderType p_which, NodeType p_type,int p_id); + void node_add(ShaderType p_type, NodeType p_node_type, int p_id); void node_remove(ShaderType p_which,int p_id); - void node_set_param(ShaderType p_which, int p_id, const Variant& p_value); void node_set_pos(ShaderType p_which,int p_id,const Point2& p_pos); - void node_change_type(ShaderType p_which,int p_id, NodeType p_type); Point2 node_get_pos(ShaderType p_which,int p_id) const; void get_node_list(ShaderType p_which,List *p_node_list) const; NodeType node_get_type(ShaderType p_which,int p_id) const; - Variant node_get_param(ShaderType p_which,int p_id) const; - Error connect(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot); - bool is_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const; - void disconnect(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot); + void scalar_const_node_set_value(ShaderType p_which,int p_id,float p_value); + float scalar_const_node_get_value(ShaderType p_which,int p_id) const; - void get_connections(ShaderType p_which,List *p_connections) const; + void vec_const_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value); + Vector3 vec_const_node_get_value(ShaderType p_which,int p_id) const; - void clear(); + void rgb_const_node_set_value(ShaderType p_which,int p_id,const Color& p_value); + Color rgb_const_node_get_value(ShaderType p_which,int p_id) const; - uint64_t get_version() const { return version; } + void xform_const_node_set_value(ShaderType p_which,int p_id,const Transform& p_value); + Transform xform_const_node_get_value(ShaderType p_which,int p_id) const; - static void get_default_input_nodes(Mode p_type,List *p_inputs); - static void get_default_output_nodes(Mode p_type,List *p_outputs); + void texture_node_set_filter_size(ShaderType p_which,int p_id,int p_size); + int texture_node_get_filter_size(ShaderType p_which,int p_id) const; - static PropertyInfo node_get_type_info(NodeType p_type); - static int get_input_count(NodeType p_type); - static int get_output_count(NodeType p_type); - static String get_input_name(NodeType p_type,int p_input); - static String get_output_name(NodeType p_type,int p_output); - static bool is_input_vector(NodeType p_type,int p_input); - static bool is_output_vector(NodeType p_type,int p_input); + void texture_node_set_filter_strength(ShaderType p_which,float p_id,float p_strength); + float texture_node_get_filter_strength(ShaderType p_which,float p_id) const; + + enum ScalarOp { + SCALAR_OP_ADD, + SCALAR_OP_SUB, + SCALAR_OP_MUL, + SCALAR_OP_DIV, + SCALAR_OP_MOD, + SCALAR_OP_POW, + SCALAR_OP_MAX, + SCALAR_OP_MIN, + SCALAR_OP_ATAN2, + SCALAR_MAX_OP + }; + + void scalar_op_node_set_op(ShaderType p_which,float p_id,ScalarOp p_op); + ScalarOp scalar_op_node_get_op(ShaderType p_which,float p_id) const; + + enum VecOp { + VEC_OP_ADD, + VEC_OP_SUB, + VEC_OP_MUL, + VEC_OP_DIV, + VEC_OP_MOD, + VEC_OP_POW, + VEC_OP_MAX, + VEC_OP_MIN, + VEC_OP_CROSS, + VEC_MAX_OP + }; + + void vec_op_node_set_op(ShaderType p_which,float p_id,VecOp p_op); + VecOp vec_op_node_get_op(ShaderType p_which,float p_id) const; + + enum VecScalarOp { + VEC_SCALAR_OP_MUL, + VEC_SCALAR_OP_DIV, + VEC_SCALAR_OP_POW, + VEC_SCALAR_MAX_OP + }; + + void vec_scalar_op_node_set_op(ShaderType p_which,float p_id,VecScalarOp p_op); + VecScalarOp vec_scalar_op_node_get_op(ShaderType p_which,float p_id) const; + + enum RGBOp { + RGB_OP_SCREEN, + RGB_OP_DIFFERENCE, + RGB_OP_DARKEN, + RGB_OP_LIGHTEN, + RGB_OP_OVERLAY, + RGB_OP_DODGE, + RGB_OP_BURN, + RGB_OP_SOFT_LIGHT, + RGB_OP_HARD_LIGHT, + RGB_MAX_OP + }; + + void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op,float p_c); + RGBOp rgb_op_node_get_op(ShaderType p_which,float p_id) const; + float rgb_op_node_get_c(ShaderType p_which,float p_id) const; + + void xform_vec_mult_node_set_no_translation(ShaderType p_which,int p_id,bool p_no_translation); + bool xform_vec_mult_node_get_no_translation(ShaderType p_which,int p_id) const; + + enum ScalarFunc { + SCALAR_FUNC_SIN, + SCALAR_FUNC_COS, + SCALAR_FUNC_TAN, + SCALAR_FUNC_ASIN, + SCALAR_FUNC_ACOS, + SCALAR_FUNC_ATAN, + SCALAR_FUNC_SINH, + SCALAR_FUNC_COSH, + SCALAR_FUNC_TANH, + SCALAR_FUNC_LOG, + SCALAR_FUNC_EXP, + SCALAR_FUNC_SQRT, + SCALAR_FUNC_ABS, + SCALAR_FUNC_SIGN, + SCALAR_FUNC_FLOOR, + SCALAR_FUNC_ROUND, + SCALAR_FUNC_CEIL, + SCALAR_FUNC_FRAC, + SCALAR_FUNC_SATURATE, + SCALAR_FUNC_NEGATE, + SCALAR_MAX_FUNC + }; + + void scalar_func_node_set_function(ShaderType p_which,int p_id,ScalarFunc p_func); + ScalarFunc scalar_func_node_get_function(ShaderType p_which,int p_id) const; + + enum VecFunc { + VEC_FUNC_NORMALIZE, + VEC_FUNC_SATURATE, + VEC_FUNC_NEGATE, + VEC_FUNC_RECIPROCAL, + VEC_FUNC_RGB2HSV, + VEC_FUNC_HSV2RGB, + VEC_MAX_FUNC + }; + + void vec_func_node_set_function(ShaderType p_which,int p_id,VecFunc p_func); + VecFunc vec_func_node_get_function(ShaderType p_which,int p_id) const; + + void input_node_set_name(ShaderType p_which,int p_id,const String& p_name); + String input_node_get_name(ShaderType p_which,int p_id); + + void scalar_input_node_set_value(ShaderType p_which,int p_id,float p_value); + float scalar_input_node_get_value(ShaderType p_which,int p_id) const; + + void vec_input_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value); + Vector3 vec_input_node_get_value(ShaderType p_which,int p_id) const; + + void rgb_input_node_set_value(ShaderType p_which,int p_id,const Color& p_value); + Color rgb_input_node_get_value(ShaderType p_which,int p_id) const; + + void xform_input_node_set_value(ShaderType p_which,int p_id,const Transform& p_value); + Transform xform_input_node_get_value(ShaderType p_which,int p_id) const; + + void texture_input_node_set_value(ShaderType p_which,int p_id,const Ref& p_texture); + Ref texture_input_node_get_value(ShaderType p_which,int p_id) const; + + void cubemap_input_node_set_value(ShaderType p_which,int p_id,const Ref& p_cubemap); + Ref cubemap_input_node_get_value(ShaderType p_which,int p_id) const; + + void comment_node_set_text(ShaderType p_which,int p_id,const String& p_comment); + String comment_node_get_text(ShaderType p_which,int p_id) const; + + Error connect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot); + bool is_node_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const; + void disconnect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot); + + void get_node_connections(ShaderType p_which,List *p_connections) const; + + void clear(ShaderType p_which); + + Variant node_get_state(ShaderType p_type, int p_node) const; + void node_set_state(ShaderType p_type, int p_id, const Variant& p_state); + + static int get_type_input_count(NodeType p_type); + static int get_type_output_count(NodeType p_type); + static SlotType get_type_input_type(NodeType p_type,int p_idx); + static SlotType get_type_output_type(NodeType p_type,int p_idx); + static bool is_type_valid(Mode p_mode,ShaderType p_type); - ShaderGraph(); + struct SlotInfo { + String name; + SlotType type; + SlotDir dir; + }; + + static void get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List *r_slots); + + static int get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type); + static int get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type); + static SlotType get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx); + static SlotType get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx); + + + ShaderGraph(Mode p_mode); ~ShaderGraph(); }; @@ -192,6 +376,27 @@ public: VARIANT_ENUM_CAST( ShaderGraph::NodeType ); +VARIANT_ENUM_CAST( ShaderGraph::ShaderType ); +VARIANT_ENUM_CAST( ShaderGraph::SlotType ); +VARIANT_ENUM_CAST( ShaderGraph::ScalarOp ); +VARIANT_ENUM_CAST( ShaderGraph::VecOp ); +VARIANT_ENUM_CAST( ShaderGraph::VecScalarOp ); +VARIANT_ENUM_CAST( ShaderGraph::RGBOp ); +VARIANT_ENUM_CAST( ShaderGraph::ScalarFunc ); +VARIANT_ENUM_CAST( ShaderGraph::VecFunc ); + + +class MaterialShaderGraph : public ShaderGraph { + + OBJ_TYPE( MaterialShaderGraph, ShaderGraph ); + RES_BASE_EXTENSION("sgp"); + +public: + + + MaterialShaderGraph() : ShaderGraph(MODE_MATERIAL) { + + } +}; -#endif #endif // SHADER_GRAPH_H diff --git a/servers/visual/shader_graph.h b/servers/visual/shader_graph.h index 5c5079202ffd..fe305f395581 100644 --- a/servers/visual/shader_graph.h +++ b/servers/visual/shader_graph.h @@ -26,8 +26,6 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SHADER_GRAPH_H -#define SHADER_GRAPH_H #if 0 @@ -109,4 +107,3 @@ public: }; #endif -#endif diff --git a/tools/SCsub b/tools/SCsub index 875663b84984..4d8b05fe794a 100644 --- a/tools/SCsub +++ b/tools/SCsub @@ -5,13 +5,16 @@ env.add_source_files(env.tool_sources,"*.cpp") Export('env') -SConscript('editor/SCsub'); -#SConscript('scintilla/SCsub'); -SConscript('collada/SCsub'); -SConscript('docdump/SCsub'); -SConscript('freetype/SCsub'); -SConscript('doc/SCsub'); -SConscript('pck/SCsub'); +if (env["tools"]!="no"): + SConscript('editor/SCsub'); + #SConscript('scintilla/SCsub'); + SConscript('collada/SCsub'); + SConscript('docdump/SCsub'); + SConscript('freetype/SCsub'); + SConscript('doc/SCsub') + SConscript('pck/SCsub') + + lib = env.Library("tool",env.tool_sources) diff --git a/tools/doc/doc_data.cpp b/tools/doc/doc_data.cpp index d13c7ea73c31..75759e7d3060 100644 --- a/tools/doc/doc_data.cpp +++ b/tools/doc/doc_data.cpp @@ -186,8 +186,10 @@ void DocData::generate(bool p_basic_types) { arginfo=E->get().return_val; if (arginfo.type==Variant::NIL) continue; - - method.return_type=(arginfo.hint==PROPERTY_HINT_RESOURCE_TYPE)?arginfo.hint_string:Variant::get_type_name(arginfo.type); + if (m && m->get_return_type()!=StringName()) + method.return_type=m->get_return_type(); + else + method.return_type=(arginfo.hint==PROPERTY_HINT_RESOURCE_TYPE)?arginfo.hint_string:Variant::get_type_name(arginfo.type); } else { diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index dbc896cbb9e6..b2fdd2fe03f1 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -75,6 +75,7 @@ #include "plugins/tile_map_editor_plugin.h" #include "plugins/cube_grid_theme_editor_plugin.h" #include "plugins/shader_editor_plugin.h" +#include "plugins/shader_graph_editor_plugin.h" #include "plugins/path_editor_plugin.h" #include "plugins/rich_text_editor_plugin.h" #include "plugins/collision_polygon_editor_plugin.h" @@ -3245,7 +3246,7 @@ EditorNode::EditorNode() { gui_base->set_area_as_parent_rect(); - Ref theme( memnew( Theme ) ); + theme = Ref( memnew( Theme ) ); gui_base->set_theme( theme ); editor_register_icons(theme); editor_register_fonts(theme); @@ -4016,6 +4017,7 @@ EditorNode::EditorNode() { add_editor_plugin( memnew( ScriptEditorPlugin(this) ) ); add_editor_plugin( memnew( EditorHelpPlugin(this) ) ); add_editor_plugin( memnew( AnimationPlayerEditorPlugin(this) ) ); + add_editor_plugin( memnew( ShaderGraphEditorPlugin(this) ) ); add_editor_plugin( memnew( ShaderEditorPlugin(this) ) ); add_editor_plugin( memnew( CameraEditorPlugin(this) ) ); add_editor_plugin( memnew( SampleEditorPlugin(this) ) ); diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index 7b66a7809e0e..381993646ed3 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -212,6 +212,7 @@ class EditorNode : public Node { AcceptDialog *load_error_dialog; Control *scene_root_base; + Ref theme; PopupMenu *recent_scenes; Button *property_back; @@ -472,6 +473,9 @@ public: void stop_child_process(); + Ref get_editor_theme() const { return theme; } + + Error export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after=false); static void register_editor_types(); diff --git a/tools/editor/icons/icon_canvas_item_shader.png b/tools/editor/icons/icon_canvas_item_shader.png new file mode 100644 index 000000000000..a5f4e7bf850b Binary files /dev/null and b/tools/editor/icons/icon_canvas_item_shader.png differ diff --git a/tools/editor/icons/icon_canvas_item_shader_graph.png b/tools/editor/icons/icon_canvas_item_shader_graph.png new file mode 100644 index 000000000000..bba966b43e88 Binary files /dev/null and b/tools/editor/icons/icon_canvas_item_shader_graph.png differ diff --git a/tools/editor/icons/icon_material_shader.png b/tools/editor/icons/icon_material_shader.png new file mode 100644 index 000000000000..0e476b25407d Binary files /dev/null and b/tools/editor/icons/icon_material_shader.png differ diff --git a/tools/editor/icons/icon_material_shader_graph.png b/tools/editor/icons/icon_material_shader_graph.png new file mode 100644 index 000000000000..68d8b4cb4905 Binary files /dev/null and b/tools/editor/icons/icon_material_shader_graph.png differ diff --git a/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp index 6bae0d2fd0cb..ed228e9a1cc3 100644 --- a/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp +++ b/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp @@ -398,11 +398,13 @@ CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) { add_child(button_create); button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE)); button_create->set_toggle_mode(true); + button_create->set_tooltip("Create a new polygon from scratch"); button_edit = memnew( ToolButton ); add_child(button_edit); button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT)); button_edit->set_toggle_mode(true); + button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point."); //add_constant_override("separation",0); diff --git a/tools/editor/plugins/shader_graph_editor_plugin.cpp b/tools/editor/plugins/shader_graph_editor_plugin.cpp index 2686ca895e8a..710f11e72686 100644 --- a/tools/editor/plugins/shader_graph_editor_plugin.cpp +++ b/tools/editor/plugins/shader_graph_editor_plugin.cpp @@ -28,1082 +28,1427 @@ /*************************************************************************/ #include "shader_graph_editor_plugin.h" -#if 0 + #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" +#include "spatial_editor_plugin.h" -class _ShaderTester : public ShaderCodeGenerator { -public: +////cbacks +/// +void ShaderGraphView::_scalar_const_changed(double p_value,int p_id) { - Set *_set; + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change Scalar Constant",true); + ur->add_do_method(graph.ptr(),"scalar_const_node_set_value",type,p_id,p_value); + ur->add_undo_method(graph.ptr(),"scalar_const_node_set_value",type,p_id,graph->scalar_const_node_get_value(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; +} - virtual void begin() {} - virtual Error add_node(VS::ShaderNodeType p_type,int p_node_pos,int p_id,const Variant& p_param,const Vector& p_in_connections,const Vector& p_out_connections,const Vector& p_out_connection_outputs) { if (_set) _set->insert(p_id); return OK; } - virtual void end() {} +void ShaderGraphView::_vec_const_changed(double p_value, int p_id,Array p_arr){ - _ShaderTester() { _set=NULL; } -}; + Vector3 val; + for(int i=0;iget_undo_redo(); + ur->create_action("Change Vec Constant",true); + ur->add_do_method(graph.ptr(),"vec_const_node_set_value",type,p_id,val); + ur->add_undo_method(graph.ptr(),"vec_const_node_set_value",type,p_id,graph->vec_const_node_get_value(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; + +} +void ShaderGraphView::_rgb_const_changed(const Color& p_color, int p_id){ + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change RGB Constant",true); + ur->add_do_method(graph.ptr(),"rgb_const_node_set_value",type,p_id,p_color); + ur->add_undo_method(graph.ptr(),"rgb_const_node_set_value",type,p_id,graph->rgb_const_node_get_value(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; + +} +void ShaderGraphView::_scalar_op_changed(int p_op, int p_id){ + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change Scalar Operator"); + ur->add_do_method(graph.ptr(),"scalar_op_node_set_op",type,p_id,p_op); + ur->add_undo_method(graph.ptr(),"scalar_op_node_set_op",type,p_id,graph->scalar_op_node_get_op(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; + +} +void ShaderGraphView::_vec_op_changed(int p_op, int p_id){ + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change Vec Operator"); + ur->add_do_method(graph.ptr(),"vec_op_node_set_op",type,p_id,p_op); + ur->add_undo_method(graph.ptr(),"vec_op_node_set_op",type,p_id,graph->vec_op_node_get_op(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; +} +void ShaderGraphView::_vec_scalar_op_changed(int p_op, int p_id){ + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change VecxScalar Operator"); + ur->add_do_method(graph.ptr(),"vec_scalar_op_node_set_op",type,p_id,p_op); + ur->add_undo_method(graph.ptr(),"vec_scalar_op_node_set_op",type,p_id,graph->vec_scalar_op_node_get_op(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; + +} +void ShaderGraphView::_rgb_op_changed(int p_op, int p_id){ + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change RGB Operator"); + ur->add_do_method(graph.ptr(),"rgb_op_node_set_op",type,p_id,p_op); + ur->add_undo_method(graph.ptr(),"rgb_op_node_set_op",type,p_id,graph->rgb_op_node_get_op(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; +} +void ShaderGraphView::_xform_inv_rev_changed(bool p_enabled, int p_id){ + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Toggle Rot Only"); + ur->add_do_method(graph.ptr(),"xform_vec_mult_node_set_no_translation",type,p_id,p_enabled); + ur->add_undo_method(graph.ptr(),"xform_vec_mult_node_set_no_translation",type,p_id,graph->xform_vec_mult_node_get_no_translation(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; +} +void ShaderGraphView::_scalar_func_changed(int p_func, int p_id){ + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change Scalar Function"); + ur->add_do_method(graph.ptr(),"scalar_func_node_set_function",type,p_id,p_func); + ur->add_undo_method(graph.ptr(),"scalar_func_node_set_function",type,p_id,graph->scalar_func_node_get_function(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; +} +void ShaderGraphView::_vec_func_changed(int p_func, int p_id){ -void ShaderEditor::edit(Ref p_shader) { + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change Vec Function"); + ur->add_do_method(graph.ptr(),"vec_func_node_set_function",type,p_id,p_func); + ur->add_undo_method(graph.ptr(),"vec_func_node_set_function",type,p_id,graph->vec_func_node_get_function(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; + +} +void ShaderGraphView::_scalar_input_changed(double p_value,int p_id){ + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change Scalar Uniform",true); + ur->add_do_method(graph.ptr(),"scalar_input_node_set_value",type,p_id,p_value); + ur->add_undo_method(graph.ptr(),"scalar_input_node_set_value",type,p_id,graph->scalar_input_node_get_value(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; + +} +void ShaderGraphView::_vec_input_changed(double p_value, int p_id,Array p_arr){ + + Vector3 val; + for(int i=0;iget_undo_redo(); + ur->create_action("Change Vec Uniform",true); + ur->add_do_method(graph.ptr(),"vec_input_node_set_value",type,p_id,val); + ur->add_undo_method(graph.ptr(),"vec_input_node_set_value",type,p_id,graph->vec_input_node_get_value(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; + +} +void ShaderGraphView::_xform_input_changed(int p_id, Node *p_button){ + + print_line("XFIC"); + ToolButton *tb = p_button->cast_to(); + ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height)); + ped_popup->set_size(tb->get_size()); + edited_id=p_id; + ped_popup->edit(NULL,"",Variant::TRANSFORM,graph->xform_input_node_get_value(type,p_id),PROPERTY_HINT_NONE,""); + ped_popup->popup(); + +} +void ShaderGraphView::_xform_const_changed(int p_id, Node *p_button){ + + ToolButton *tb = p_button->cast_to(); + ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height)); + ped_popup->set_size(tb->get_size()); + edited_id=p_id; + ped_popup->edit(NULL,"",Variant::TRANSFORM,graph->xform_const_node_get_value(type,p_id),PROPERTY_HINT_NONE,""); + ped_popup->popup(); + +} + +void ShaderGraphView::_rgb_input_changed(const Color& p_color, int p_id){ - shader=p_shader; + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change RGB Uniform",true); + ur->add_do_method(graph.ptr(),"rgb_input_node_set_value",type,p_id,p_color); + ur->add_undo_method(graph.ptr(),"rgb_input_node_set_value",type,p_id,graph->rgb_input_node_get_value(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; +} +void ShaderGraphView::_tex_input_change(int p_id, Node *p_button){ - if (shader.is_null()) - hide(); - else { - _read_shader_graph(); + +} +void ShaderGraphView::_cube_input_change(int p_id){ + + +} + +void ShaderGraphView::_variant_edited() { + + if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_XFORM_CONST) { + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change XForm Uniform"); + ur->add_do_method(graph.ptr(),"xform_const_node_set_value",type,edited_id,ped_popup->get_variant()); + ur->add_undo_method(graph.ptr(),"xform_const_node_set_value",type,edited_id,graph->xform_const_node_get_value(type,edited_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + ur->commit_action(); + } + + + if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_XFORM_INPUT) { + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change XForm Uniform"); + ur->add_do_method(graph.ptr(),"xform_input_node_set_value",type,edited_id,ped_popup->get_variant()); + ur->add_undo_method(graph.ptr(),"xform_input_node_set_value",type,edited_id,graph->xform_input_node_get_value(type,edited_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + ur->commit_action(); + } + + if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_TEXTURE_INPUT) { + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change Texture Uniform"); + ur->add_do_method(graph.ptr(),"texture_input_node_set_value",type,edited_id,ped_popup->get_variant()); + ur->add_undo_method(graph.ptr(),"texture_input_node_set_value",type,edited_id,graph->texture_input_node_get_value(type,edited_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + ur->commit_action(); + } + + if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_CUBEMAP_INPUT) { + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change Cubemap Uniform"); + ur->add_do_method(graph.ptr(),"cubemap_input_node_set_value",type,edited_id,ped_popup->get_variant()); + ur->add_undo_method(graph.ptr(),"cubemap_input_node_set_value",type,edited_id,graph->cubemap_input_node_get_value(type,edited_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + ur->commit_action(); } } -Size2 ShaderEditor::_get_maximum_size() { +void ShaderGraphView::_comment_edited(int p_id,Node* p_button) { - Size2 max; + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + TextEdit *te=p_button->cast_to(); + ur->create_action("Change Comment",true); + ur->add_do_method(graph.ptr(),"comment_node_set_text",type,p_id,te->get_text()); + ur->add_undo_method(graph.ptr(),"comment_node_set_text",type,p_id,graph->comment_node_get_text(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; - for(List::Element *E=order.front();E;E=E->next()) { +} - Point2 pos = Point2( shader_graph.node_get_pos_x(E->get()), shader_graph.node_get_pos_y(E->get()) ); - if (click_type==CLICK_NODE && click_node==E->get()) { +void ShaderGraphView::_input_name_changed(const String& p_name, int p_id, Node *p_line_edit) { - pos+=click_motion-click_pos; + LineEdit *le=p_line_edit->cast_to(); + ERR_FAIL_COND(!le); + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Change Input Name"); + ur->add_do_method(graph.ptr(),"input_node_set_name",type,p_id,p_name); + ur->add_undo_method(graph.ptr(),"input_node_set_name",type,p_id,graph->input_node_get_name(type,p_id)); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + block_update=true; + ur->commit_action(); + block_update=false; + le->set_text(graph->input_node_get_name(type,p_id)); +} + +void ShaderGraphView::_tex_edited(int p_id,Node* p_button) { + + ToolButton *tb = p_button->cast_to(); + ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height)); + ped_popup->set_size(tb->get_size()); + edited_id=p_id; + ped_popup->edit(NULL,"",Variant::OBJECT,graph->texture_input_node_get_value(type,p_id),PROPERTY_HINT_RESOURCE_TYPE,"Texture"); +} + +void ShaderGraphView::_cube_edited(int p_id,Node* p_button) { + + ToolButton *tb = p_button->cast_to(); + ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height)); + ped_popup->set_size(tb->get_size()); + edited_id=p_id; + ped_popup->edit(NULL,"",Variant::OBJECT,graph->cubemap_input_node_get_value(type,p_id),PROPERTY_HINT_RESOURCE_TYPE,"CubeMap"); +} + + +//////////////view///////////// + + +void ShaderGraphView::_connection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot) { + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + + int from_idx=-1; + int to_idx=-1; + for (Map::Element *E=node_map.front();E;E=E->next()) { + + if (p_from==E->get()->get_name()) + from_idx=E->key(); + if (p_to==E->get()->get_name()) + to_idx=E->key(); + } + + ERR_FAIL_COND(from_idx==-1); + ERR_FAIL_COND(to_idx==-1); + + ur->create_action("Connect Graph Nodes"); + + List conns; + + graph->get_node_connections(type,&conns); + //disconnect/reconnect dependencies + ur->add_undo_method(graph.ptr(),"disconnect_node",type,from_idx,p_from_slot,to_idx,p_to_slot); + for(List::Element *E=conns.front();E;E=E->next()) { + + if (E->get().dst_id==to_idx && E->get().dst_slot==p_to_slot) { + ur->add_do_method(graph.ptr(),"disconnect_node",type,E->get().src_id,E->get().src_slot,E->get().dst_id,E->get().dst_slot); + ur->add_undo_method(graph.ptr(),"connect_node",type,E->get().src_id,E->get().src_slot,E->get().dst_id,E->get().dst_slot); } - pos+=get_node_size(E->get()); - if (pos.x>max.x) - max.x=pos.x; - if (pos.y>max.y) - max.y=pos.y; - } + ur->add_do_method(graph.ptr(),"connect_node",type,from_idx,p_from_slot,to_idx,p_to_slot); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + ur->commit_action(); + - return max; } -Size2 ShaderEditor::get_node_size(int p_node) const { +void ShaderGraphView::_node_removed(int p_id) { - VisualServer::ShaderNodeType type=shader_graph.node_get_type(p_node); - Ref style = get_stylebox("panel","PopupMenu"); - Ref font = get_font("font","PopupMenu"); - Color font_color = get_color("font_color","PopupMenu"); + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Remove Shader Graph Node"); - Size2 size = style->get_minimum_size(); + ur->add_do_method(graph.ptr(),"node_remove",type,p_id); + ur->add_undo_method(graph.ptr(),"node_add",type,graph->node_get_type(type,p_id),p_id); + ur->add_undo_method(graph.ptr(),"node_set_state",type,p_id,graph->node_get_state(type,p_id)); + List conns; - int count=1; // title - count += VisualServer::shader_get_input_count( type) + VisualServer::shader_get_output_count( type); + graph->get_node_connections(type,&conns); + for(List::Element *E=conns.front();E;E=E->next()) { - float max_w=font->get_string_size( VisualServer::shader_node_get_type_info(type).name ).width; - - for(int i=0;iget_string_size( VisualServer::shader_get_input_name(type,i) ).width ); - - - for(int i=0;iget_string_size( VisualServer::shader_get_output_name(type,i) ).width ); - - - - - switch(type) { - - case VS::NODE_IN: - case VS::NODE_OUT: - case VS::NODE_VEC_IN: - case VS::NODE_VEC_OUT: - case VS::NODE_PARAMETER: - case VS::NODE_VEC_PARAMETER: - case VS::NODE_COLOR_PARAMETER: - case VS::NODE_TEXTURE_PARAMETER: - case VS::NODE_TEXTURE_2D_PARAMETER: - case VS::NODE_TEXTURE_CUBE_PARAMETER: - case VS::NODE_TRANSFORM_PARAMETER: - case VS::NODE_LABEL: { - - max_w=MAX( max_w, font->get_string_size( shader_graph.node_get_param(p_node) ).width ); - count++; - } break; - case VS::NODE_TIME: - case VS::NODE_CONSTANT: - case VS::NODE_VEC_CONSTANT: - case VS::NODE_COLOR_CONSTANT: - case VS::NODE_TRANSFORM_CONSTANT: { - count++; - } break; - case VS::NODE_TEXTURE: - case VS::NODE_VEC_TEXTURE_2D: - case VS::NODE_VEC_TEXTURE_CUBE: { - - RefPtr res = shader_graph.node_get_param(p_node); - Ref texture = res; - if (texture.is_null() || texture->get_width()==0) { - - size.y+=max_w; - } else { - - size.y+=max_w * texture->get_height() / texture->get_width(); - } - } break; - default: {} - - } - - size.x+=max_w; - size.y+=count*(font->get_height()+get_constant("vseparation","PopupMenu")); - - return size; -} - - -Error ShaderEditor::validate_graph() { - - _ShaderTester st; - active_nodes.clear(); - st._set=&active_nodes; - return shader_graph.generate(&st); -} - -void ShaderEditor::_draw_node(int p_node) { - - VisualServer::ShaderNodeType type=shader_graph.node_get_type(p_node); - Ref style = active_nodes.has(p_node)?get_stylebox("panel","PopupMenu"):get_stylebox("panel_disabled","PopupMenu"); - Ref font = get_font("font","PopupMenu"); - Color font_color = get_color("font_color","PopupMenu"); - Color font_color_title = get_color("font_color_hover","PopupMenu"); - Size2 size=get_node_size(p_node); - Point2 pos = Point2( shader_graph.node_get_pos_x(p_node), shader_graph.node_get_pos_y(p_node) )-offset; - - if (click_type==CLICK_NODE && click_node==p_node) { - - pos+=click_motion-click_pos; - } - - RID ci = get_canvas_item(); - style->draw(ci,Rect2(pos,size)); - - Point2 ofs=style->get_offset()+pos; - Point2 ascent=Point2(0,font->get_ascent()); - float w = size.width-style->get_minimum_size().width; - float h = font->get_height()+get_constant("vseparation","PopupMenu"); - - font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, VisualServer::shader_node_get_type_info(type).name,font_color_title); - ofs.y+=h; - - Ref vec_icon = get_icon("NodeVecSlot","EditorIcons"); - Ref real_icon = get_icon("NodeRealSlot","EditorIcons"); - float icon_h_ofs = Math::floor(( font->get_height()-vec_icon->get_height())/2.0 )+1; - - - for(int i=0;idraw_halign( ci, ofs+ascent, HALIGN_LEFT,w, name,font_color); - Ref icon = VisualServer::shader_is_input_vector(type,i)?vec_icon:real_icon; - icon->draw(ci,ofs+Point2(-real_icon->get_width(),icon_h_ofs)); - ofs.y+=h; - } - - for(int i=0;idraw_halign( ci, ofs+ascent, HALIGN_RIGHT,w, name,font_color); - Ref icon = VisualServer::shader_is_output_vector(type,i)?vec_icon:real_icon; - icon->draw(ci,ofs+Point2(w,icon_h_ofs)); - ofs.y+=h; - } - - switch(type) { - - case VS::NODE_IN: - case VS::NODE_OUT: - case VS::NODE_PARAMETER: - case VS::NODE_VEC_IN: - case VS::NODE_COLOR_PARAMETER: - case VS::NODE_VEC_OUT: - case VS::NODE_TEXTURE_PARAMETER: - case VS::NODE_TEXTURE_2D_PARAMETER: - case VS::NODE_TEXTURE_CUBE_PARAMETER: - case VS::NODE_TRANSFORM_CONSTANT: - case VS::NODE_TRANSFORM_PARAMETER: - case VS::NODE_VEC_PARAMETER: - case VS::NODE_LABEL: { - String text = shader_graph.node_get_param(p_node); - font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, text,font_color); - } break; - case VS::NODE_TIME: - case VS::NODE_CONSTANT: { - String text = rtos(shader_graph.node_get_param(p_node)); - font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, text,font_color); - - } break; - case VS::NODE_VEC_CONSTANT: { - String text = Vector3(shader_graph.node_get_param(p_node)); - font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, text,font_color); - } break; - case VS::NODE_COLOR_CONSTANT: { - - Color color = shader_graph.node_get_param(p_node); - Rect2 r(ofs,Size2(w,h)); - VisualServer::get_singleton()->canvas_item_add_rect(ci,r,color); - } break; - case VS::NODE_TEXTURE: - case VS::NODE_VEC_TEXTURE_2D: - case VS::NODE_VEC_TEXTURE_CUBE: { - - Rect2 r(ofs,Size2(w,(pos.y+size.y-style->get_margin(MARGIN_BOTTOM))-ofs.y)); - Vector points; - Vector uvs; - points.resize(4); - uvs.resize(4); - points[0]=r.pos; - points[1]=r.pos+Point2(r.size.x,0); - points[2]=r.pos+r.size; - points[3]=r.pos+Point2(0,r.size.y); - uvs[0]=Point2(0,0); - uvs[1]=Point2(1,0); - uvs[2]=Point2(1,1); - uvs[3]=Point2(0,1); - - Ref texture = shader_graph.node_get_param(p_node).operator RefPtr(); - if (texture.is_null() || texture->get_width()==0) { - texture=get_icon("Click2Edit","EditorIcons"); - } - - VisualServer::get_singleton()->canvas_item_add_primitive(ci,points,Vector(),uvs,texture->get_rid()); - } break; - default: {} - } -} - -void ShaderEditor::_node_param_changed() { - - shader_graph.node_set_param( click_node,property_editor->get_variant() ); - update(); - _write_shader_graph(); -} - -ShaderEditor::ClickType ShaderEditor::_locate_click(const Point2& p_click,int *p_node_id,int *p_slot_index) const { - - Ref style = get_stylebox("panel","PopupMenu"); - Ref real_icon = get_icon("NodeRealSlot","EditorIcons"); - Ref font = get_font("font","PopupMenu"); - float h = font->get_height()+get_constant("vseparation","PopupMenu"); - float extra_left=MAX( real_icon->get_width()-style->get_margin(MARGIN_LEFT), 0 ); - float extra_right=MAX( real_icon->get_width()-style->get_margin(MARGIN_RIGHT), 0 ); - - - for(const List::Element *E=order.back();E;E=E->prev()) { - - Size2 size=get_node_size(E->get()); - size.width+=extra_left+extra_right; - Point2 pos = Point2( shader_graph.node_get_pos_x(E->get()), shader_graph.node_get_pos_y(E->get()) )-offset; - pos.x-=extra_left; - - Rect2 rect( pos, size ); - if (!rect.has_point(p_click)) - continue; - VisualServer::ShaderNodeType type=shader_graph.node_get_type(E->get()); - if (p_node_id) - *p_node_id=E->get(); - float y=p_click.y-(pos.y+style->get_margin(MARGIN_TOP)); - if (yget().dst_id==p_id || E->get().src_id==p_id) { + ur->add_undo_method(graph.ptr(),"connect_node",type,E->get().src_id,E->get().src_slot,E->get().dst_id,E->get().dst_slot); } + } + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + ur->commit_action(); - for(int i=0;iget_undo_redo(); + ur->create_action("Move Shader Graph Node"); + ur->add_do_method(this,"_move_node",p_id,p_to); + ur->add_undo_method(this,"_move_node",p_id,p_from); + ur->commit_action(); +} + +void ShaderGraphView::_move_node(int p_id,const Vector2& p_to) { + + ERR_FAIL_COND(!node_map.has(p_id)); + node_map[p_id]->set_offset(p_to); + graph->node_set_pos(type,p_id,p_to); +} + + +void ShaderGraphView::_create_node(int p_id) { + + + GraphNode *gn = memnew( GraphNode ); + gn->set_show_close_button(true); + Color typecol[4]={ + Color(0.2,1,0.2), + Color(0.7,0.1,1), + Color(1,0.2,0.2), + Color(0,1,1) + }; + + + switch(graph->node_get_type(type,p_id)) { + + case ShaderGraph::NODE_INPUT: { + + gn->set_title("Input"); + + List si; + ShaderGraph::get_input_output_node_slot_info(graph->get_mode(),type,&si); + + int idx=0; + for (List::Element *E=si.front();E;E=E->next()) { + ShaderGraph::SlotInfo& s=E->get(); + if (s.dir==ShaderGraph::SLOT_IN) { + + Label *l= memnew( Label ); + l->set_text(s.name); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child(l); + gn->set_slot(idx,false,0,Color(),true,s.type,typecol[s.type]); + idx++; + } } - y-=h; - } - if (p_click.y<(rect.pos.y+rect.size.height-style->get_margin(MARGIN_BOTTOM))) - return CLICK_PARAMETER; - else - return CLICK_NODE; + } break; // all inputs (case Shader type dependent) + case ShaderGraph::NODE_SCALAR_CONST: { + gn->set_title("Scalar"); + SpinBox *sb = memnew( SpinBox ); + sb->set_min(-100000); + sb->set_max(100000); + sb->set_step(0.001); + sb->set_val(graph->scalar_const_node_get_value(type,p_id)); + sb->connect("value_changed",this,"_scalar_const_changed",varray(p_id)); + gn->add_child(sb); + gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + } break; //scalar constant + case ShaderGraph::NODE_VEC_CONST: { + + gn->set_title("Vector"); + Array v3p(true); + for(int i=0;i<3;i++) { + HBoxContainer *hbc = memnew( HBoxContainer ); + Label *l = memnew( Label ); + l->set_text(String::chr('X'+i)); + hbc->add_child(l); + SpinBox *sb = memnew( SpinBox ); + sb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + sb->set_min(-100000); + sb->set_max(100000); + sb->set_step(0.001); + sb->set_val(graph->vec_const_node_get_value(type,p_id)[i]); + sb->connect("value_changed",this,"_vec_const_changed",varray(p_id,v3p)); + v3p.push_back(sb); + hbc->add_child(sb); + gn->add_child(hbc); + } + gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + + } break; //vec3 constant + case ShaderGraph::NODE_RGB_CONST: { + + gn->set_title("Color"); + ColorPickerButton *cpb = memnew( ColorPickerButton ); + cpb->set_color(graph->rgb_const_node_get_value(type,p_id)); + cpb->connect("color_changed",this,"_rgb_const_changed",varray(p_id)); + gn->add_child(cpb); + Label *l = memnew( Label ); + l->set_text("RGB"); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child(l); + l = memnew( Label ); + l->set_text("Alpha"); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child(l); + + gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + } break; //rgb constant (shows a color picker instead) + case ShaderGraph::NODE_XFORM_CONST: { + gn->set_title("XForm"); + ToolButton *edit = memnew( ToolButton ); + edit->set_text("edit.."); + edit->connect("pressed",this,"_xform_const_changed",varray(p_id,edit)); + gn->add_child(edit); + gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]); + + } break; // 4x4 matrix constant + case ShaderGraph::NODE_TIME: { + + gn->set_title("Time"); + Label *l = memnew( Label ); + l->set_text("(s)"); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child(l); + gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + } break; // time in seconds + case ShaderGraph::NODE_SCREEN_TEX: { + + gn->set_title("ScreenTex"); + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("UV"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("RGB"))); + gn->add_child(hbc); + gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + + } break; // screen texture sampler (takes UV) (only usable in fragment case Shader) + case ShaderGraph::NODE_SCALAR_OP: { + + gn->set_title("ScalarOp"); + static const char* op_name[ShaderGraph::SCALAR_MAX_OP]={ + "Add", + "Sub", + "Mul", + "Div", + "Mod", + "Pow", + "Max", + "Min", + "Atan2" + }; + + OptionButton *ob = memnew( OptionButton ); + for(int i=0;iadd_item(op_name[i],i); + } + + ob->select(graph->scalar_op_node_get_op(type,p_id)); + ob->connect("item_selected",this,"_scalar_op_changed",varray(p_id)); + gn->add_child(ob); + + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("a"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("out"))); + gn->add_child(hbc); + gn->add_child( memnew(Label("b"))); + + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color()); + + + } break; // scalar vs scalar op (mul: { } break; add: { } break; div: { } break; etc) + case ShaderGraph::NODE_VEC_OP: { + + gn->set_title("VecOp"); + static const char* op_name[ShaderGraph::VEC_MAX_OP]={ + "Add", + "Sub", + "Mul", + "Div", + "Mod", + "Pow", + "Max", + "Min", + "Cross" + }; + + OptionButton *ob = memnew( OptionButton ); + for(int i=0;iadd_item(op_name[i],i); + } + + ob->select(graph->vec_op_node_get_op(type,p_id)); + ob->connect("item_selected",this,"_vec_op_changed",varray(p_id)); + gn->add_child(ob); + + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("a"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("out"))); + gn->add_child(hbc); + gn->add_child( memnew(Label("b"))); + + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color()); + + + } break; // vec3 vs vec3 op (mul: { } break;ad: { } break;div: { } break;crossprod: { } break;etc) + case ShaderGraph::NODE_VEC_SCALAR_OP: { + + gn->set_title("VecScalarOp"); + static const char* op_name[ShaderGraph::VEC_SCALAR_MAX_OP]={ + "Mul", + "Div", + "Pow", + }; + + OptionButton *ob = memnew( OptionButton ); + for(int i=0;iadd_item(op_name[i],i); + } + + ob->select(graph->vec_scalar_op_node_get_op(type,p_id)); + ob->connect("item_selected",this,"_vec_scalar_op_changed",varray(p_id)); + gn->add_child(ob); + + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("a"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("out"))); + gn->add_child(hbc); + gn->add_child( memnew(Label("b"))); + + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color()); + + + } break; // vec3 vs scalar op (mul: { } break; add: { } break; div: { } break; etc) + case ShaderGraph::NODE_RGB_OP: { + + gn->set_title("RGB Op"); + static const char* op_name[ShaderGraph::RGB_MAX_OP]={ + "Screen", + "Difference", + "Darken", + "Lighten", + "Overlay", + "Dodge", + "Burn", + "SoftLight", + "HardLight" + }; + + OptionButton *ob = memnew( OptionButton ); + for(int i=0;iadd_item(op_name[i],i); + } + + ob->select(graph->rgb_op_node_get_op(type,p_id)); + ob->connect("item_selected",this,"_rgb_op_changed",varray(p_id)); + gn->add_child(ob); + + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("a"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("out"))); + gn->add_child(hbc); + gn->add_child( memnew(Label("b"))); + + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color()); + + } break; // vec3 vs vec3 rgb op (with scalar amount): { } break; like brighten: { } break; darken: { } break; burn: { } break; dodge: { } break; multiply: { } break; etc. + case ShaderGraph::NODE_XFORM_MULT: { + + gn->set_title("XFMult"); + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_child( memnew(Label("a"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("out"))); + gn->add_child(hbc); + gn->add_child( memnew(Label("b"))); + + gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]); + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],false,0,Color()); + + + } break; // mat4 x mat4 + case ShaderGraph::NODE_XFORM_VEC_MULT: + case ShaderGraph::NODE_XFORM_VEC_INV_MULT: { + + if (graph->node_get_type(type,p_id)==ShaderGraph::NODE_XFORM_VEC_INV_MULT) + gn->set_title("XFVecMult"); + else + gn->set_title("XFVecInvMult"); + + + Button *button = memnew( Button("RotOnly")); + button->set_toggle_mode(true); + button->set_pressed(graph->xform_vec_mult_node_get_no_translation(type,p_id)); + button->connect("toggled",this,"_xform_inv_rev_changed",varray(p_id)); + + gn->add_child(button); + + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("xf"))); + hbc->add_spacer(); + Label *l = memnew(Label("out")); + l->set_align(Label::ALIGN_RIGHT); + hbc->add_child( l); + gn->add_child(hbc); + gn->add_child( memnew(Label("vec"))); + + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color()); + + + } break; // mat4 x vec3 inverse mult (with no-translation option) + case ShaderGraph::NODE_SCALAR_FUNC: { + + gn->set_title("ScalarFunc"); + static const char* func_name[ShaderGraph::SCALAR_MAX_FUNC]={ + "Sin", + "Cos", + "Tan", + "ASin", + "ACos", + "ATan", + "SinH", + "CosH", + "TanH", + "Log", + "Exp", + "Sqrt", + "Abs", + "Sign", + "Floor", + "Round", + "Ceil", + "Frac", + "Satr", + "Neg" + }; + + OptionButton *ob = memnew( OptionButton ); + for(int i=0;iadd_item(func_name[i],i); + } + + ob->select(graph->scalar_func_node_get_function(type,p_id)); + ob->connect("item_selected",this,"_scalar_func_changed",varray(p_id)); + gn->add_child(ob); + + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_child( memnew(Label("in"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("out"))); + gn->add_child(hbc); + + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + + } break; // scalar function (sin: { } break; cos: { } break; etc) + case ShaderGraph::NODE_VEC_FUNC: { + + + + gn->set_title("VecFunc"); + static const char* func_name[ShaderGraph::VEC_MAX_FUNC]={ + "Normalize", + "Saturate", + "Negate", + "Reciprocal", + "RGB to HSV", + "HSV to RGB", + }; + + OptionButton *ob = memnew( OptionButton ); + for(int i=0;iadd_item(func_name[i],i); + } + + ob->select(graph->vec_func_node_get_function(type,p_id)); + ob->connect("item_selected",this,"_vec_func_changed",varray(p_id)); + gn->add_child(ob); + + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("in"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("out"))); + gn->add_child(hbc); + + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + + } break; // vector function (normalize: { } break; negate: { } break; reciprocal: { } break; rgb2hsv: { } break; hsv2rgb: { } break; etc: { } break; etc) + case ShaderGraph::NODE_VEC_LEN: { + gn->set_title("VecLength"); + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_child( memnew(Label("in"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("len"))); + gn->add_child(hbc); + + gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + } break; // vec3 length + case ShaderGraph::NODE_DOT_PROD: { + + gn->set_title("DotProduct"); + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("a"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("dp"))); + gn->add_child(hbc); + gn->add_child( memnew(Label("b"))); + + gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color()); + + } break; // vec3 . vec3 (dot product -> scalar output) + case ShaderGraph::NODE_VEC_TO_SCALAR: { + + gn->set_title("Vec2Scalar"); + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("vec"))); + hbc->add_spacer(); + Label *l=memnew(Label("x")); + l->set_align(Label::ALIGN_RIGHT); + hbc->add_child( l); + gn->add_child(hbc); + l=memnew(Label("y")); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child( l ); + l=memnew(Label("z")); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child( l); + + gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + + + + } break; // 1 vec3 input: { } break; 3 scalar outputs + case ShaderGraph::NODE_SCALAR_TO_VEC: { + + gn->set_title("Scalar2Vec"); + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_child( memnew(Label("x"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("vec"))); + gn->add_child(hbc); + gn->add_child( memnew(Label("y"))); + gn->add_child( memnew(Label("z"))); + + gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color()); + gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color()); + + } break; // 3 scalar input: { } break; 1 vec3 output + case ShaderGraph::NODE_VEC_TO_XFORM: { + + gn->set_title("Vec2XForm"); + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("x"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("xf"))); + gn->add_child(hbc); + gn->add_child( memnew(Label("y"))); + gn->add_child( memnew(Label("z"))); + gn->add_child( memnew(Label("ofs"))); + + gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]); + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color()); + gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color()); + gn->set_slot(3,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color()); + + } break; // 3 vec input: { } break; 1 xform output + case ShaderGraph::NODE_XFORM_TO_VEC: { + + gn->set_title("XForm2Vec"); + + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("xf"))); + hbc->add_spacer(); + Label *l=memnew(Label("x")); + l->set_align(Label::ALIGN_RIGHT); + hbc->add_child( l); + gn->add_child(hbc); + l=memnew(Label("y")); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child( l ); + l=memnew(Label("z")); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child( l); + l=memnew(Label("ofs")); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child( l); + + gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + + } break; // 3 vec input: { } break; 1 xform output + case ShaderGraph::NODE_SCALAR_INTERP: { + + gn->set_title("ScalarInterp"); + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("a"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("interp"))); + gn->add_child(hbc); + gn->add_child( memnew(Label("b"))); + gn->add_child( memnew(Label("c"))); + + gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color()); + gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color()); + + + } break; // scalar interpolation (with optional curve) + case ShaderGraph::NODE_VEC_INTERP: { + + gn->set_title("VecInterp"); + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_child( memnew(Label("a"))); + hbc->add_spacer(); + hbc->add_child( memnew(Label("interp"))); + gn->add_child(hbc); + gn->add_child( memnew(Label("b"))); + gn->add_child( memnew(Label("c"))); + + gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color()); + gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color()); + + } break; // vec3 interpolation (with optional curve) + case ShaderGraph::NODE_SCALAR_INPUT: { + + gn->set_title("ScalarUniform"); + LineEdit *le = memnew( LineEdit ); + gn->add_child(le); + le->set_text(graph->input_node_get_name(type,p_id)); + le->connect("text_entered",this,"_input_name_changed",varray(p_id,le)); + SpinBox *sb = memnew( SpinBox ); + sb->set_min(-100000); + sb->set_max(100000); + sb->set_step(0.001); + sb->set_val(graph->scalar_input_node_get_value(type,p_id)); + sb->connect("value_changed",this,"_scalar_input_changed",varray(p_id)); + gn->add_child(sb); + gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + } break; // scalar uniform (assignable in material) + case ShaderGraph::NODE_VEC_INPUT: { + + gn->set_title("VectorUniform"); + LineEdit *le = memnew( LineEdit ); + gn->add_child(le); + le->set_text(graph->input_node_get_name(type,p_id)); + le->connect("text_entered",this,"_input_name_changed",varray(p_id,le)); + Array v3p(true); + for(int i=0;i<3;i++) { + HBoxContainer *hbc = memnew( HBoxContainer ); + Label *l = memnew( Label ); + l->set_text(String::chr('X'+i)); + hbc->add_child(l); + SpinBox *sb = memnew( SpinBox ); + sb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + sb->set_min(-100000); + sb->set_max(100000); + sb->set_step(0.001); + sb->set_val(graph->vec_input_node_get_value(type,p_id)[i]); + sb->connect("value_changed",this,"_vec_input_changed",varray(p_id,v3p)); + v3p.push_back(sb); + hbc->add_child(sb); + gn->add_child(hbc); + } + gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + + } break; // vec3 uniform (assignable in material) + case ShaderGraph::NODE_RGB_INPUT: { + + gn->set_title("ColorUniform"); + LineEdit *le = memnew( LineEdit ); + gn->add_child(le); + le->set_text(graph->input_node_get_name(type,p_id)); + le->connect("text_entered",this,"_input_name_changed",varray(p_id,le)); + ColorPickerButton *cpb = memnew( ColorPickerButton ); + cpb->set_color(graph->rgb_input_node_get_value(type,p_id)); + cpb->connect("color_changed",this,"_rgb_input_changed",varray(p_id)); + gn->add_child(cpb); + Label *l = memnew( Label ); + l->set_text("RGB"); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child(l); + l = memnew( Label ); + l->set_text("Alpha"); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child(l); + + gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + + } break; // color uniform (assignable in material) + case ShaderGraph::NODE_XFORM_INPUT: { + gn->set_title("XFUniform"); + LineEdit *le = memnew( LineEdit ); + gn->add_child(le); + le->set_text(graph->input_node_get_name(type,p_id)); + le->connect("text_entered",this,"_input_name_changed",varray(p_id,le)); + ToolButton *edit = memnew( ToolButton ); + edit->set_text("edit.."); + edit->connect("pressed",this,"_xform_input_changed",varray(p_id,edit)); + gn->add_child(edit); + gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]); + + } break; // mat4 uniform (assignable in material) + case ShaderGraph::NODE_TEXTURE_INPUT: { + + gn->set_title("TexUniform"); + LineEdit *le = memnew( LineEdit ); + gn->add_child(le); + le->set_text(graph->input_node_get_name(type,p_id)); + le->connect("text_entered",this,"_input_name_changed",varray(p_id,le)); + TextureFrame *tex = memnew( TextureFrame ); + tex->set_expand(true); + tex->set_custom_minimum_size(Size2(80,80)); + gn->add_child(tex); + tex->set_texture(graph->texture_input_node_get_value(type,p_id)); + ToolButton *edit = memnew( ToolButton ); + edit->set_text("edit.."); + edit->connect("pressed",this,"_tex_edited",varray(p_id,edit)); + gn->add_child(edit); + + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("UV"))); + hbc->add_spacer(); + Label *l=memnew(Label("RGB")); + l->set_align(Label::ALIGN_RIGHT); + hbc->add_child(l); + gn->add_child(hbc); + l = memnew( Label ); + l->set_text("Alpha"); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child(l); + + gn->set_slot(3,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(4,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + } break; // texture input (assignable in material) + case ShaderGraph::NODE_CUBEMAP_INPUT: { + + gn->set_title("TexUniform"); + LineEdit *le = memnew( LineEdit ); + gn->add_child(le); + le->set_text(graph->input_node_get_name(type,p_id)); + le->connect("text_entered",this,"_input_name_changed",varray(p_id,le)); + + ToolButton *edit = memnew( ToolButton ); + edit->set_text("edit.."); + edit->connect("pressed",this,"_cube_edited",varray(p_id,edit)); + gn->add_child(edit); + + + HBoxContainer *hbc = memnew( HBoxContainer ); + hbc->add_constant_override("separation",0); + hbc->add_child( memnew(Label("UV"))); + hbc->add_spacer(); + Label *l=memnew(Label("RGB")); + l->set_align(Label::ALIGN_RIGHT); + hbc->add_child(l); + gn->add_child(hbc); + l = memnew( Label ); + l->set_text("Alpha"); + l->set_align(Label::ALIGN_RIGHT); + gn->add_child(l); + + gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); + gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + } break; // cubemap input (assignable in material) + case ShaderGraph::NODE_OUTPUT: { + gn->set_title("Output"); + + List si; + ShaderGraph::get_input_output_node_slot_info(graph->get_mode(),type,&si); + + int idx=0; + for (List::Element *E=si.front();E;E=E->next()) { + ShaderGraph::SlotInfo& s=E->get(); + if (s.dir==ShaderGraph::SLOT_OUT) { + + Label *l= memnew( Label ); + l->set_text(s.name); + l->set_align(Label::ALIGN_LEFT); + gn->add_child(l); + gn->set_slot(idx,true,s.type,typecol[s.type],false,0,Color()); + idx++; + } + } + + } break; // output (case Shader type dependent) + case ShaderGraph::NODE_COMMENT: { + gn->set_title("Comment"); + TextEdit *te = memnew(TextEdit); + te->set_custom_minimum_size(Size2(100,100)); + gn->add_child(te); + te->set_text(graph->comment_node_get_text(type,p_id)); + te->connect("text_changed",this,"_comment_edited",varray(p_id,te)); + + } break; // comment + + } - return CLICK_NONE; + gn->connect("dragged",this,"_node_moved",varray(p_id)); + gn->connect("close_request",this,"_node_removed",varray(p_id),CONNECT_DEFERRED); + graph_edit->add_child(gn); + node_map[p_id]=gn; + gn->set_offset(graph->node_get_pos(type,p_id)); + print_line("NODE "+itos(p_id)+" OFS "+gn->get_offset()); } -Point2 ShaderEditor::_get_slot_pos(int p_node_id,bool p_input,int p_slot) { +void ShaderGraphView::_update_graph() { - Ref style = get_stylebox("panel","PopupMenu"); - float w = get_node_size(p_node_id).width; - Ref font = get_font("font","PopupMenu"); - float h = font->get_height()+get_constant("vseparation","PopupMenu"); - Ref vec_icon = get_icon("NodeVecSlot","EditorIcons"); - Point2 pos = Point2( shader_graph.node_get_pos_x(p_node_id), shader_graph.node_get_pos_y(p_node_id) )-offset; - pos+=style->get_offset(); - pos.y+=h; - if(p_input) { - - pos.y+=p_slot*h; - pos+=Point2( -vec_icon->get_width()/2.0, h/2.0).floor(); - return pos; - } else { - - pos.y+=VisualServer::shader_get_input_count( shader_graph.node_get_type(p_node_id ) )*h; - } - - pos.y+=p_slot*h; - pos+=Point2( w-style->get_minimum_size().width+vec_icon->get_width()/2.0, h/2.0).floor(); - - return pos; - -} - -void ShaderEditor::_node_edit_property(int p_node) { - - Ref style = get_stylebox("panel","PopupMenu"); - Size2 size = get_node_size(p_node); - Point2 pos = Point2( shader_graph.node_get_pos_x(p_node), shader_graph.node_get_pos_y(p_node) )-offset; - - VisualServer::ShaderNodeType type=shader_graph.node_get_type(p_node); - - PropertyInfo ph = VisualServer::get_singleton()->shader_node_get_type_info(type); - if (ph.type==Variant::NIL) + if (block_update) return; - if (ph.type==Variant::_RID) - ph.type=Variant::OBJECT; - property_editor->edit(NULL,ph.name,ph.type,shader_graph.node_get_param(p_node),ph.hint,ph.hint_string); + for (Map::Element *E=node_map.front();E;E=E->next()) { - Point2 popup_pos=Point2( pos.x+(size.width-property_editor->get_size().width)/2.0,pos.y+(size.y-style->get_margin(MARGIN_BOTTOM))).floor(); - popup_pos+=get_global_pos(); - property_editor->set_pos(popup_pos); - - property_editor->popup(); - -} - -bool ShaderEditor::has_point(const Point2& p_point) const { - - int n,si; - - return _locate_click(p_point,&n,&si)!=CLICK_NONE; -} - -void ShaderEditor::_input_event(InputEvent p_event) { - - switch(p_event.type) { - - case InputEvent::MOUSE_BUTTON: { - - if (p_event.mouse_button.pressed) { - - - if (p_event.mouse_button.button_index==1) { - click_pos=Point2(p_event.mouse_button.x,p_event.mouse_button.y); - click_motion=click_pos; - click_type = _locate_click(click_pos,&click_node,&click_slot); - if( click_type!=CLICK_NONE) { - - order.erase(click_node); - order.push_back(click_node); - update(); - } - switch(click_type) { - case CLICK_INPUT_SLOT: { - click_pos=_get_slot_pos(click_node,true,click_slot); - } break; - case CLICK_OUTPUT_SLOT: { - click_pos=_get_slot_pos(click_node,false,click_slot); - } break; - case CLICK_PARAMETER: { - //open editor - _node_edit_property(click_node); - } break; - } - } - if (p_event.mouse_button.button_index==2) { - - if (click_type!=CLICK_NONE) { - click_type=CLICK_NONE; - update(); - } else { - // try to disconnect/remove - - Point2 rclick_pos=Point2(p_event.mouse_button.x,p_event.mouse_button.y); - rclick_type = _locate_click(rclick_pos,&rclick_node,&rclick_slot); - if (rclick_type==CLICK_INPUT_SLOT || rclick_type==CLICK_OUTPUT_SLOT) { - - node_popup->clear(); - node_popup->add_item("Disconnect",NODE_DISCONNECT); - node_popup->set_pos(rclick_pos); - node_popup->popup(); - - } - - if (rclick_type==CLICK_NODE) { - node_popup->clear(); - node_popup->add_item("Remove",NODE_ERASE); - node_popup->set_pos(rclick_pos); - node_popup->popup(); - } - - - } - } - } else { - - if (p_event.mouse_button.button_index==1 && click_type!=CLICK_NONE) { - - switch(click_type) { - case CLICK_INPUT_SLOT: - case CLICK_OUTPUT_SLOT: { - - Point2 dst_click_pos=Point2(p_event.mouse_button.x,p_event.mouse_button.y); - int id; - int slot; - ClickType dst_click_type = _locate_click(dst_click_pos,&id,&slot); - if (dst_click_type==CLICK_INPUT_SLOT && click_type==CLICK_OUTPUT_SLOT) { - - shader_graph.connect(click_node,click_slot,id,slot); - - Error err = validate_graph(); - if (err==ERR_CYCLIC_LINK) - shader_graph.disconnect(click_node,click_slot,id,slot); - _write_shader_graph(); - - } - if (click_type==CLICK_INPUT_SLOT && dst_click_type==CLICK_OUTPUT_SLOT) { - - shader_graph.connect(id,slot,click_node,click_slot); - - Error err = validate_graph(); - if (err==ERR_CYCLIC_LINK) - shader_graph.disconnect(id,slot,click_node,click_slot); - _write_shader_graph(); - } - - } break; - case CLICK_NODE: { - int new_x=shader_graph.node_get_pos_x(click_node)+(click_motion.x-click_pos.x); - int new_y=shader_graph.node_get_pos_y(click_node)+(click_motion.y-click_pos.y); - shader_graph.node_set_pos(click_node,new_x,new_y); - _write_shader_graph(); - - } break; - } - - click_type=CLICK_NONE; - update(); - } - } - - } - - case InputEvent::MOUSE_MOTION: { - - if (p_event.mouse_motion.button_mask&1 && click_type!=CLICK_NONE) { - - click_motion=Point2(p_event.mouse_button.x,p_event.mouse_button.y); - update(); - } - - } break; - } -} - -void ShaderEditor::_notification(int p_what) { - - - switch(p_what) { - - case NOTIFICATION_DRAW: { - - _update_scrollbars(); - //VisualServer::get_singleton()->canvas_item_add_rect(get_canvas_item(),Rect2(Point2(),get_size()),Color(0,0,0,1)); - - for(List::Element *E=order.front();E;E=E->next()) { - - _draw_node(E->get()); - } - - if (click_type==CLICK_INPUT_SLOT || click_type==CLICK_OUTPUT_SLOT) { - - VisualServer::get_singleton()->canvas_item_add_line(get_canvas_item(),click_pos,click_motion,Color(0.5,1,0.5,0.8),2); - } - - List connections = shader_graph.get_connection_list(); - for(List::Element *E=connections.front();E;E=E->next()) { - - const ShaderGraph::Connection &c=E->get(); - Point2 source = _get_slot_pos(c.src_id,false,c.src_slot); - Point2 dest = _get_slot_pos(c.dst_id,true,c.dst_slot); - bool vec = VisualServer::shader_is_input_vector( shader_graph.node_get_type(c.dst_id), c.dst_slot ); - Color col = vec?Color(1,0.5,0.5,0.8):Color(1,1,0.5,0.8); - - if (click_type==CLICK_NODE && click_node==c.src_id) { - - source+=click_motion-click_pos; - } - - if (click_type==CLICK_NODE && click_node==c.dst_id) { - - dest+=click_motion-click_pos; - } - - VisualServer::get_singleton()->canvas_item_add_line(get_canvas_item(),source,dest,col,2); - - } - } break; + memdelete(E->get()); } -} + node_map.clear(); -void ShaderEditor::_update_scrollbars() { - - Size2 size = get_size(); - Size2 hmin = h_scroll->get_minimum_size(); - Size2 vmin = v_scroll->get_minimum_size(); - - v_scroll->set_begin( Point2(size.width - vmin.width, 0) ); - v_scroll->set_end( Point2(size.width, size.height) ); - - h_scroll->set_begin( Point2( 0, size.height - hmin.height) ); - h_scroll->set_end( Point2(size.width-vmin.width, size.height) ); + if (!graph.is_valid()) + return; - Size2 min = _get_maximum_size(); + List nl; + graph->get_node_list(type,&nl); + print_line("graph nodes: "+itos(nl.size())); + for(List::Element *E=nl.front();E;E=E->next()) { - if (min.height < size.height - hmin.height) { - - v_scroll->hide(); - offset.y=0; - } else { - - v_scroll->show(); - v_scroll->set_max(min.height); - v_scroll->set_page(size.height - hmin.height); - offset.y=v_scroll->get_val(); + _create_node(E->get()); } + graph_edit->clear_connections(); - if (min.width < size.width - vmin.width) { - - h_scroll->hide(); - offset.x=0; - } else { - - h_scroll->show(); - h_scroll->set_max(min.width); - h_scroll->set_page(size.width - vmin.width); - offset.x=h_scroll->get_val(); - } -} - -void ShaderEditor::_scroll_moved() { - - offset.x=h_scroll->get_val(); - offset.y=v_scroll->get_val(); - update(); -} - -void ShaderEditor::_bind_methods() { - - ObjectTypeDB::bind_method( "_node_menu_item", &ShaderEditor::_node_menu_item ); - ObjectTypeDB::bind_method( "_node_add_callback", &ShaderEditor::_node_add_callback ); - ObjectTypeDB::bind_method( "_input_event", &ShaderEditor::_input_event ); - ObjectTypeDB::bind_method( "_node_param_changed", &ShaderEditor::_node_param_changed ); - ObjectTypeDB::bind_method( "_scroll_moved", &ShaderEditor::_scroll_moved ); - ObjectTypeDB::bind_method( "_vertex_item", &ShaderEditor::_vertex_item ); - ObjectTypeDB::bind_method( "_fragment_item", &ShaderEditor::_fragment_item ); - ObjectTypeDB::bind_method( "_post_item", &ShaderEditor::_post_item ); -} - -void ShaderEditor::_read_shader_graph() { - - shader_graph.clear();; - order.clear(); - List nodes; - shader->get_node_list(&nodes); - int larger_id=0; - for(List::Element *E=nodes.front();E;E=E->next()) { - - if (E->get() > larger_id) - larger_id = E->get(); - - shader_graph.node_add( (VS::ShaderNodeType)shader->node_get_type(E->get()), E->get() ); - shader_graph.node_set_param( E->get(), shader->node_get_param( E->get() ) ); - Point2 pos = shader->node_get_pos(E->get()); - shader_graph.node_set_pos( E->get(), pos.x,pos.y ); - order.push_back(E->get()); - } - - last_id=larger_id+1; - - List connections; - shader->get_connections(&connections); - - for(List::Element *E=connections.front();E;E=E->next()) { - - Shader::Connection &c=E->get(); - shader_graph.connect(c.src_id,c.src_slot,c.dst_id,c.dst_slot); - } - - validate_graph(); - update(); -} - -void ShaderEditor::_write_shader_graph() { - - shader->clear(); - List nodes; - shader_graph.get_node_list(&nodes); - for(List::Element *E=nodes.front();E;E=E->next()) { - - shader->node_add((Shader::NodeType)shader_graph.node_get_type(E->get()),E->get()); - shader->node_set_param(E->get(),shader_graph.node_get_param(E->get())); - shader->node_set_pos(E->get(),Point2( shader_graph.node_get_pos_x(E->get()),shader_graph.node_get_pos_y(E->get()) ) ); - } - - List connections = shader_graph.get_connection_list(); + List connections; + graph->get_node_connections(type,&connections); for(List::Element *E=connections.front();E;E=E->next()) { - const ShaderGraph::Connection &c=E->get(); - shader->connect(c.src_id,c.src_slot,c.dst_id,c.dst_slot); + ERR_CONTINUE(!node_map.has(E->get().src_id) || !node_map.has(E->get().dst_id)); + graph_edit->connect_node(node_map[E->get().src_id]->get_name(),E->get().src_slot,node_map[E->get().dst_id]->get_name(),E->get().dst_slot); } + + + } -void ShaderEditor::_add_node_from_text(const String& p_text) { +void ShaderGraphView::set_graph(Ref p_graph){ - ERR_FAIL_COND( p_text.get_slice_count(" ") != 3 ); - bool input = p_text.get_slice(" ",0)=="In:"; - String name = p_text.get_slice(" ",1); - bool vec = p_text.get_slice(" ",2)=="(vec3)"; + print_line("GRAPH EDIT: "+itos(p_graph.is_valid())); + graph=p_graph; + _update_graph(); - _node_add( input? - ( vec? VisualServer::NODE_VEC_IN : VisualServer::NODE_IN ) : - ( vec? VisualServer::NODE_VEC_OUT : VisualServer::NODE_OUT ) ); - - shader_graph.node_set_param( last_id-1,name ); - _write_shader_graph(); } -void ShaderEditor::_vertex_item(int p_item) { +void ShaderGraphView::_notification(int p_what) { - _add_node_from_text(vertex_popup->get_item_text(p_item)); -} -void ShaderEditor::_fragment_item(int p_item) { + if (p_what==NOTIFICATION_ENTER_TREE) { - _add_node_from_text(fragment_popup->get_item_text(p_item)); -} -void ShaderEditor::_post_item(int p_item) { + ped_popup->connect("variant_changed",this,"_variant_edited"); + } + } - _add_node_from_text(post_popup->get_item_text(p_item)); -} +void ShaderGraphView::add_node(int p_type) { + List existing; + graph->get_node_list(type,&existing); + existing.sort(); + int newid=1; + for(List::Element *E=existing.front();E;E=E->next()) { + if (!E->next() || (E->get()+1!=E->next()->get())){ + newid=E->get()+1; + break; + } + } -void ShaderEditor::_node_menu_item(int p_item) { + Vector2 init_ofs(20,20); + while(true) { + bool valid=true; + for(List::Element *E=existing.front();E;E=E->next()) { + Vector2 pos = graph->node_get_pos(type,E->get()); + if (init_ofs==pos) { + init_ofs+=Vector2(20,20); + valid=false; + break; - switch(p_item) { - - case GRAPH_ADD_NODE: { - add_popup->popup_centered_ratio(); - validate_graph(); - } break; - case NODE_DISCONNECT: { - - if (rclick_type==CLICK_INPUT_SLOT) { - - List connections = shader_graph.get_connection_list(); - for(List::Element *E=connections.front();E;E=E->next()) { - - const ShaderGraph::Connection &c=E->get(); - if( c.dst_id==rclick_node && c.dst_slot==rclick_slot) { - - shader_graph.disconnect(c.src_id,c.src_slot,c.dst_id,c.dst_slot); - } - } - update(); - _write_shader_graph(); - validate_graph(); } + } - if (rclick_type==CLICK_OUTPUT_SLOT) { - - List connections = shader_graph.get_connection_list(); - for(List::Element *E=connections.front();E;E=E->next()) { - - const ShaderGraph::Connection &c=E->get(); - if( c.src_id==rclick_node && c.src_slot==rclick_slot) { - - shader_graph.disconnect(c.src_id,c.src_slot,c.dst_id,c.dst_slot); - } - } - update(); - _write_shader_graph(); - validate_graph(); - } - - } break; - case NODE_ERASE: { - - order.erase(rclick_node); - shader_graph.node_remove(rclick_node); - update(); - _write_shader_graph(); - validate_graph(); - } break; - case GRAPH_CLEAR: { - - order.clear(); - shader_graph.clear(); - last_id=1; - last_x=20; - last_y=20; - update(); - _write_shader_graph(); - validate_graph(); - - } break; + if (valid) + break; } -} - -void ShaderEditor::_node_add(VisualServer::ShaderNodeType p_type) { - - shader_graph.node_add(p_type,last_id ); - shader_graph.node_set_pos(last_id ,last_x,last_y); - String test_param; - - switch(p_type) { - case VS::NODE_PARAMETER: { - - test_param="param"; - } break; - case VS::NODE_VEC_PARAMETER: { - - test_param="vec"; - } break; - case VS::NODE_COLOR_PARAMETER: { - - test_param="color"; - } break; - case VS::NODE_TEXTURE_PARAMETER: { - - test_param="tex"; - } break; - case VS::NODE_TEXTURE_2D_PARAMETER: { - - test_param="tex2D"; - } break; - case VS::NODE_TEXTURE_CUBE_PARAMETER: { - - test_param="cubemap"; - } break; - case VS::NODE_TRANSFORM_PARAMETER: { - test_param="xform"; - } break; - case VS::NODE_LABEL: { - - test_param="label"; - } break; - } - - if(test_param!="") { - - int iter=0; - List l; - - shader_graph.get_node_list(&l); - - bool found; - String test; - do { - iter++; - test=test_param; - if (iter>1) - test+="_"+itos(iter); - found=false; - for(List::Element *E=l.front();E;E=E->next()) { - - - String param = shader_graph.node_get_param( E->get() ); - if (param==test) { - found=true; - break; - } - } - - } while (found); - - - shader_graph.node_set_param(last_id,test); - - } - order.push_back(last_id); - last_x+=10; - last_y+=10; - last_id++; - last_x=last_x % (int)get_size().width; - last_y=last_y % (int)get_size().height; - update(); - add_popup->hide();; - _write_shader_graph(); + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Add Shader Graph Node"); + ur->add_do_method(graph.ptr(),"node_add",type,p_type,newid); + ur->add_do_method(graph.ptr(),"node_set_pos",type,newid,init_ofs); + ur->add_undo_method(graph.ptr(),"node_remove",type,newid); + ur->add_do_method(this,"_update_graph"); + ur->add_undo_method(this,"_update_graph"); + ur->commit_action(); } -void ShaderEditor::_node_add_callback() { +void ShaderGraphView::_bind_methods() { + + ObjectTypeDB::bind_method("_update_graph",&ShaderGraphView::_update_graph); + ObjectTypeDB::bind_method("_node_moved",&ShaderGraphView::_node_moved); + ObjectTypeDB::bind_method("_move_node",&ShaderGraphView::_move_node); + ObjectTypeDB::bind_method("_node_removed",&ShaderGraphView::_node_removed); + ObjectTypeDB::bind_method("_connection_request",&ShaderGraphView::_connection_request); + + ObjectTypeDB::bind_method("_scalar_const_changed",&ShaderGraphView::_scalar_const_changed); + ObjectTypeDB::bind_method("_vec_const_changed",&ShaderGraphView::_vec_const_changed); + ObjectTypeDB::bind_method("_rgb_const_changed",&ShaderGraphView::_rgb_const_changed); + ObjectTypeDB::bind_method("_xform_const_changed",&ShaderGraphView::_xform_const_changed); + ObjectTypeDB::bind_method("_scalar_op_changed",&ShaderGraphView::_scalar_op_changed); + ObjectTypeDB::bind_method("_vec_op_changed",&ShaderGraphView::_vec_op_changed); + ObjectTypeDB::bind_method("_vec_scalar_op_changed",&ShaderGraphView::_vec_scalar_op_changed); + ObjectTypeDB::bind_method("_rgb_op_changed",&ShaderGraphView::_rgb_op_changed); + ObjectTypeDB::bind_method("_xform_inv_rev_changed",&ShaderGraphView::_xform_inv_rev_changed); + ObjectTypeDB::bind_method("_scalar_func_changed",&ShaderGraphView::_scalar_func_changed); + ObjectTypeDB::bind_method("_vec_func_changed",&ShaderGraphView::_vec_func_changed); + ObjectTypeDB::bind_method("_scalar_input_changed",&ShaderGraphView::_scalar_input_changed); + ObjectTypeDB::bind_method("_vec_input_changed",&ShaderGraphView::_vec_input_changed); + ObjectTypeDB::bind_method("_xform_input_changed",&ShaderGraphView::_xform_input_changed); + ObjectTypeDB::bind_method("_rgb_input_changed",&ShaderGraphView::_rgb_input_changed); + ObjectTypeDB::bind_method("_tex_input_change",&ShaderGraphView::_tex_input_change); + ObjectTypeDB::bind_method("_cube_input_change",&ShaderGraphView::_cube_input_change); + ObjectTypeDB::bind_method("_input_name_changed",&ShaderGraphView::_input_name_changed); + ObjectTypeDB::bind_method("_tex_edited",&ShaderGraphView::_tex_edited); + ObjectTypeDB::bind_method("_variant_edited",&ShaderGraphView::_variant_edited); + ObjectTypeDB::bind_method("_cube_edited",&ShaderGraphView::_cube_edited); + ObjectTypeDB::bind_method("_comment_edited",&ShaderGraphView::_comment_edited); - TreeItem * item = add_types->get_selected(); - ERR_FAIL_COND(!item); - _node_add((VisualServer::ShaderNodeType)(int)item->get_metadata(0)); - add_popup->hide() ; } -ShaderEditor::ShaderEditor() { +ShaderGraphView::ShaderGraphView(ShaderGraph::ShaderType p_type) { - set_focus_mode(FOCUS_ALL); + type=p_type; + graph_edit = memnew( GraphEdit ); + block_update=false; + ped_popup = memnew( CustomPropertyEditor ); + graph_edit->add_child(ped_popup); - Panel* menu_panel = memnew( Panel ); - menu_panel->set_anchor( MARGIN_RIGHT, Control::ANCHOR_END ); - menu_panel->set_end( Point2(0,22) ); - - add_child( menu_panel ); - - PopupMenu *p; - List defaults; - - MenuButton* node_menu = memnew( MenuButton ); - node_menu->set_text("Graph"); - node_menu->set_pos( Point2( 5,0) ); - menu_panel->add_child( node_menu ); - - p=node_menu->get_popup(); - p->add_item("Add Node",GRAPH_ADD_NODE); - p->add_separator(); - p->add_item("Clear",GRAPH_CLEAR); - p->connect("item_pressed", this,"_node_menu_item"); - - MenuButton* vertex_menu = memnew( MenuButton ); - vertex_menu->set_text("Vertex"); - vertex_menu->set_pos( Point2( 49,0) ); - menu_panel->add_child( vertex_menu ); - - p=vertex_menu->get_popup(); - defaults.clear(); - VisualServer::shader_get_default_input_nodes(VisualServer::SHADER_VERTEX,&defaults); - - int id=0; - for(int i=0;iadd_item("In: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++); - } - p->add_separator(); - id++; - - defaults.clear(); - VisualServer::shader_get_default_output_nodes(VisualServer::SHADER_VERTEX,&defaults); - - for(int i=0;iadd_item("Out: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++); - } - - vertex_popup=p; - vertex_popup->connect("item_pressed", this,"_vertex_item"); - MenuButton* fragment_menu = memnew( MenuButton ); - fragment_menu->set_text("Fragment"); - fragment_menu->set_pos( Point2( 95 ,0) ); - menu_panel->add_child( fragment_menu ); - - p=fragment_menu->get_popup(); - defaults.clear(); - VisualServer::shader_get_default_input_nodes(VisualServer::SHADER_FRAGMENT,&defaults); - id=0; - for(int i=0;iadd_item("In: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++); - } - p->add_separator(); - id++; - defaults.clear(); - VisualServer::shader_get_default_output_nodes(VisualServer::SHADER_FRAGMENT,&defaults); - - for(int i=0;iadd_item("Out: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++); - } - - fragment_popup=p; - fragment_popup->connect("item_pressed", this,"_fragment_item"); - - MenuButton* post_menu = memnew( MenuButton ); - post_menu->set_text("Post"); - post_menu->set_pos( Point2( 161,0) ); - menu_panel->add_child( post_menu ); - - p=post_menu->get_popup(); - defaults.clear(); - VisualServer::shader_get_default_input_nodes(VisualServer::SHADER_POST_PROCESS,&defaults); - id=0; - for(int i=0;iadd_item("In: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++); - } - p->add_separator(); - id++; - - defaults.clear(); - VisualServer::shader_get_default_output_nodes(VisualServer::SHADER_POST_PROCESS,&defaults); - - for(int i=0;iadd_item("Out: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++); - } - - post_popup=p; - post_popup->connect("item_pressed", this,"_post_item"); - - - /* add popup */ - - add_popup = memnew( Popup ); - add_child(add_popup); - add_popup->set_as_toplevel(true); - Panel *add_panel = memnew( Panel ); - add_popup->add_child(add_panel); - add_panel->set_area_as_parent_rect(); - - Label *add_label = memnew (Label ); - add_label->set_pos(Point2(5,5)); - add_label->set_text("Available Nodes:"); - add_panel->add_child(add_label); - - - add_types = memnew( Tree ); - add_types->set_anchor( MARGIN_RIGHT, ANCHOR_END ); - add_types->set_anchor( MARGIN_BOTTOM, ANCHOR_END ); - add_types->set_begin( Point2( 20,25 ) ); - add_types->set_end( Point2( 10, 30 ) ); - add_types->set_hide_root(true); - add_types->set_columns(4); - add_types->set_select_mode(Tree::SELECT_ROW); - - - TreeItem *add_types_root = add_types->create_item(NULL); - TreeItem *info_item = add_types->create_item(add_types_root); - - for(int i=0;icreate_item(add_types_root); - PropertyInfo prop = VisualServer::shader_node_get_type_info((VisualServer::ShaderNodeType)i); - item->set_text(0,prop.name); - item->set_text(1,itos(VisualServer::shader_get_input_count((VisualServer::ShaderNodeType)i))); - item->set_text(2,itos(VisualServer::shader_get_output_count((VisualServer::ShaderNodeType)i))); - String hint = (prop.type==Variant::_RID)?prop.hint_string:Variant::get_type_name(prop.type); - item->set_text(3,hint); - item->set_metadata(0,i); - } - info_item->set_text(0,"::NODE::"); - info_item->set_custom_color(0,Color(0.6,0.1,0.1)); - info_item->set_text(1,"::INPUTS::"); - info_item->set_custom_color(1,Color(0.6,0.1,0.1)); - info_item->set_text(2,"::OUTPUTS::"); - info_item->set_custom_color(2,Color(0.6,0.1,0.1)); - info_item->set_text(3,"::PARAM::"); - info_item->set_custom_color(3,Color(0.6,0.1,0.1)); - info_item->set_selectable(0,false); - info_item->set_selectable(1,false); - info_item->set_selectable(2,false); - info_item->set_selectable(3,false); - - add_panel->add_child(add_types); - - add_confirm = memnew( Button ); - add_confirm->set_anchor( MARGIN_LEFT, ANCHOR_END ); - add_confirm->set_anchor( MARGIN_TOP, ANCHOR_END ); - add_confirm->set_anchor( MARGIN_RIGHT, ANCHOR_END ); - add_confirm->set_anchor( MARGIN_BOTTOM, ANCHOR_END ); - add_confirm->set_begin( Point2( 75, 29 ) ); - add_confirm->set_end( Point2( 10, 15 ) ); - add_confirm->set_text("Add"); - add_panel->add_child(add_confirm); - add_confirm->connect("pressed", this,"_node_add_callback"); - - last_id=1; - last_x=20; - last_y=20; - - property_editor = memnew( CustomPropertyEditor ); - add_child(property_editor); - property_editor->connect("variant_changed", this,"_node_param_changed"); - - h_scroll = memnew( HScrollBar ); - v_scroll = memnew( VScrollBar ); - - add_child(h_scroll); - add_child(v_scroll); - - h_scroll->connect("value_changed", this,"_scroll_moved"); - v_scroll->connect("value_changed", this,"_scroll_moved"); - - node_popup= memnew(PopupMenu ); - add_child(node_popup); - node_popup->set_as_toplevel(true); - - node_popup->connect("item_pressed", this,"_node_menu_item"); } -void ShaderEditorPlugin::edit(Object *p_object) { +//////////////edit////////////// +void ShaderGraphEditor::edit(Ref p_shader) { - shader_editor->edit(p_object->cast_to()); + for(int i=0;iset_graph(p_shader); + } } -bool ShaderEditorPlugin::handles(Object *p_object) const { +void ShaderGraphEditor::_add_node(int p_type) { - return p_object->is_type("Shader"); + ShaderGraph::ShaderType shader_type=ShaderGraph::ShaderType(tabs->get_current_tab()); + + graph_edits[shader_type]->add_node(p_type); } -void ShaderEditorPlugin::make_visible(bool p_visible) { + +void ShaderGraphEditor::_notification(int p_what) { + if (p_what==NOTIFICATION_ENTER_TREE) { + menu->get_popup()->connect("item_pressed",this,"_add_node"); + + + } +} + +void ShaderGraphEditor::_bind_methods() { + + ObjectTypeDB::bind_method("_add_node",&ShaderGraphEditor::_add_node); + +} + + +const char* ShaderGraphEditor::node_names[ShaderGraph::NODE_TYPE_MAX]={ + "Input", // all inputs (shader type dependent) + "Scalar Constant", //scalar constant + "Vector Constant", //vec3 constant + "RGB Constant", //rgb constant (shows a color picker instead) + "XForm Constant", // 4x4 matrix constant + "Time:", // time in seconds + "Screen Sample", // screen texture sampler (takes uv) (only usable in fragment shader) + "Scalar Operator", // scalar vs scalar op (mul", add", div", etc) + "Vector Operator", // vec3 vs vec3 op (mul",ad",div",crossprod",etc) + "Scalar+Vector Operator", // vec3 vs scalar op (mul", add", div", etc) + "RGB Operator:", // vec3 vs vec3 rgb op (with scalar amount)", like brighten", darken", burn", dodge", multiply", etc. + "XForm Multiply", // mat4 x mat4 + "XForm+Vector Multiply", // mat4 x vec3 mult (with no-translation option) + "XForm+Vector InvMultiply:", // mat4 x vec3 inverse mult (with no-translation option) + "Scalar Function", // scalar function (sin", cos", etc) + "Vector Function", // vector function (normalize", negate", reciprocal", rgb2hsv", hsv2rgb", etc", etc) + "Vector Length", // vec3 length + "Dot Product:", // vec3 . vec3 (dot product -> scalar output) + "Vector -> Scalars", // 1 vec3 input", 3 scalar outputs + "Scalars -> Vector", // 3 scalar input", 1 vec3 output + "XForm -> Vectors", // 3 vec input", 1 xform output + "Vectors -> XForm:", // 3 vec input", 1 xform output + "Scalar Interpolate", // scalar interpolation (with optional curve) + "Vector Interpolate:", // vec3 interpolation (with optional curve) + "Scalar Uniform", // scalar uniform (assignable in material) + "Vector Uniform", // vec3 uniform (assignable in material) + "RGB Uniform", // color uniform (assignable in material) + "XForm Uniform", // mat4 uniform (assignable in material) + "Texture Uniform", // texture input (assignable in material) + "CubeMap Uniform:", // cubemap input (assignable in material) + "Output", // output (shader type dependent) + "Comment", // comment + + +}; +ShaderGraphEditor::ShaderGraphEditor() { + + HBoxContainer *hbc = memnew( HBoxContainer ); + menu = memnew( MenuButton ); + menu->set_text("Add.."); + hbc->add_child(menu); + add_child(hbc); + for(int i=0;iget_popup()->add_item(v,i); + if (addsep) + menu->get_popup()->add_separator(); + } + + tabs = memnew(TabContainer); + tabs->set_v_size_flags(SIZE_EXPAND_FILL); + add_child(tabs); + const char* sname[ShaderGraph::SHADER_TYPE_MAX]={ + "Vertex", + "Fragment", + "Light" + }; + for(int i=0;iget_graph_edit()->set_name(sname[i]); + tabs->add_child(graph_edits[i]->get_graph_edit()); + graph_edits[i]->get_graph_edit()->connect("connection_request",graph_edits[i],"_connection_request"); + } + + set_custom_minimum_size(Size2(100,300)); +} + + +void ShaderGraphEditorPlugin::edit(Object *p_object) { + + shader_editor->edit(p_object->cast_to()); +} + +bool ShaderGraphEditorPlugin::handles(Object *p_object) const { + + return p_object->is_type("ShaderGraph"); +} + +void ShaderGraphEditorPlugin::make_visible(bool p_visible) { if (p_visible) { shader_editor->show(); - shader_editor->set_process(true); } else { shader_editor->hide(); - shader_editor->set_process(false); } } -ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node) { +ShaderGraphEditorPlugin::ShaderGraphEditorPlugin(EditorNode *p_node) { editor=p_node; - shader_editor = memnew( ShaderEditor ); - editor->get_viewport()->add_child(shader_editor); - shader_editor->set_area_as_parent_rect(); + shader_editor = memnew( ShaderGraphEditor ); shader_editor->hide(); + SpatialEditor::get_singleton()->get_shader_split()->add_child(shader_editor); +// editor->get_viewport()->add_child(shader_editor); +// shader_editor->set_area_as_parent_rect(); +// shader_editor->hide(); } -ShaderEditorPlugin::~ShaderEditorPlugin() +ShaderGraphEditorPlugin::~ShaderGraphEditorPlugin() { } -#endif + diff --git a/tools/editor/plugins/shader_graph_editor_plugin.h b/tools/editor/plugins/shader_graph_editor_plugin.h index 5b0767dc82b9..26dbd1ac6eb3 100644 --- a/tools/editor/plugins/shader_graph_editor_plugin.h +++ b/tools/editor/plugins/shader_graph_editor_plugin.h @@ -29,122 +29,121 @@ #ifndef SHADER_GRAPH_EDITOR_PLUGIN_H #define SHADER_GRAPH_EDITOR_PLUGIN_H -#if 0 + #include "tools/editor/editor_plugin.h" #include "tools/editor/editor_node.h" #include "scene/resources/shader.h" #include "servers/visual/shader_graph.h" #include "scene/gui/tree.h" #include "scene/gui/button.h" +#include "scene/gui/graph_edit.h" #include "scene/gui/popup.h" #include "tools/editor/property_editor.h" +#include "scene/resources/shader_graph.h" /** @author Juan Linietsky */ -class ShaderEditor : public Control { - OBJ_TYPE(ShaderEditor, Control ); +class ShaderGraphView : public Node { - enum MenuAction { + OBJ_TYPE(ShaderGraphView,Node); - GRAPH_ADD_NODE, - GRAPH_CLEAR, - NODE_DISCONNECT, - NODE_ERASE, - }; - enum ClickType { - CLICK_NONE, - CLICK_NODE, - CLICK_INPUT_SLOT, - CLICK_OUTPUT_SLOT, - CLICK_PARAMETER - }; + CustomPropertyEditor *ped_popup; + bool block_update; - PopupMenu *node_popup; - Popup *add_popup; - PopupMenu *vertex_popup; - PopupMenu *fragment_popup; - PopupMenu *post_popup; - Tree *add_types; - Button *add_confirm; - HScrollBar *h_scroll; - VScrollBar *v_scroll; + GraphEdit *graph_edit; + Ref graph; + int edited_id; - Ref shader; - List order; - Set active_nodes; - ShaderGraph shader_graph; - int last_x,last_y; - uint32_t last_id; + ShaderGraph::ShaderType type; - CustomPropertyEditor *property_editor; + void _update_graph(); + void _create_node(int p_id); - Point2 offset; - ClickType click_type; - Point2 click_pos; - int click_node; - int click_slot; - Point2 click_motion; - ClickType rclick_type; - int rclick_node; - int rclick_slot; - Size2 _get_maximum_size(); - Size2 get_node_size(int p_node) const; - void _draw_node(int p_node); - void _add_node_from_text(const String& p_text); - void _update_scrollbars(); - void _scroll_moved(); - void _node_param_changed(); - void _node_add_callback(); - void _node_add(VisualServer::ShaderNodeType p_type); - void _node_edit_property(int p_node); - void _node_menu_item(int p_item); - void _vertex_item(int p_item); - void _fragment_item(int p_item); - void _post_item(int p_item); + void _connection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot); + void _node_removed(int p_id); + void _node_moved(const Vector2& p_from, const Vector2& p_to,int p_id); + void _move_node(int p_id,const Vector2& p_to); - ClickType _locate_click(const Point2& p_click,int *p_node_id,int *p_slot_index) const; - Point2 _get_slot_pos(int p_node_id,bool p_input,int p_slot); + void _scalar_const_changed(double p_value,int p_id); + void _vec_const_changed(double p_value, int p_id, Array p_arr); + void _rgb_const_changed(const Color& p_color, int p_id); + void _xform_const_changed(int p_id,Node* p_button); + void _scalar_op_changed(int p_op, int p_id); + void _vec_op_changed(int p_op, int p_id); + void _vec_scalar_op_changed(int p_op, int p_id); + void _rgb_op_changed(int p_op, int p_id); + void _xform_inv_rev_changed(bool p_enabled, int p_id); + void _scalar_func_changed(int p_func, int p_id); + void _vec_func_changed(int p_func, int p_id); + void _scalar_input_changed(double p_value,int p_id); + void _vec_input_changed(double p_value, int p_id, Array p_arr); + void _xform_input_changed(int p_id,Node* p_button); + void _rgb_input_changed(const Color& p_color, int p_id); + void _tex_input_change(int p_id,Node* p_button); + void _cube_input_change(int p_id); + void _input_name_changed(const String& p_name,int p_id,Node* p_line_edit); + void _tex_edited(int p_id,Node* p_button); + void _cube_edited(int p_id,Node* p_button); + void _variant_edited(); + void _comment_edited(int p_id,Node* p_button); - Error validate_graph(); - void _read_shader_graph(); - void _write_shader_graph(); - - virtual bool has_point(const Point2& p_point) const; + Map node_map; protected: void _notification(int p_what); - void _input_event(InputEvent p_event); static void _bind_methods(); public: - void edit(Ref p_shader); - ShaderEditor(); + void add_node(int p_type); + GraphEdit *get_graph_edit() { return graph_edit; } + void set_graph(Ref p_graph); + + ShaderGraphView(ShaderGraph::ShaderType p_type=ShaderGraph::SHADER_TYPE_FRAGMENT); }; -class ShaderEditorPlugin : public EditorPlugin { +class ShaderGraphEditor : public VBoxContainer { - OBJ_TYPE( ShaderEditorPlugin, EditorPlugin ); + OBJ_TYPE(ShaderGraphEditor,VBoxContainer); - ShaderEditor *shader_editor; + MenuButton *menu; + TabContainer *tabs; + ShaderGraphView *graph_edits[ShaderGraph::SHADER_TYPE_MAX]; + static const char* node_names[ShaderGraph::NODE_TYPE_MAX]; + + void _add_node(int p_type); +protected: + void _notification(int p_what); + static void _bind_methods(); +public: + + void edit(Ref p_shader); + ShaderGraphEditor(); +}; + +class ShaderGraphEditorPlugin : public EditorPlugin { + + OBJ_TYPE( ShaderGraphEditorPlugin, EditorPlugin ); + + ShaderGraphEditor *shader_editor; EditorNode *editor; public: - virtual String get_name() const { return "Shader"; } + virtual String get_name() const { return "ShaderGraph"; } bool has_main_screen() const { return false; } virtual void edit(Object *p_node); virtual bool handles(Object *p_node) const; virtual void make_visible(bool p_visible); - ShaderEditorPlugin(EditorNode *p_node); - ~ShaderEditorPlugin(); + ShaderGraphEditorPlugin(EditorNode *p_node); + ~ShaderGraphEditorPlugin(); }; #endif -#endif // SHADER_GRAPH_EDITOR_PLUGIN_H + diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index 777694481b89..195d3c01a501 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -142,7 +142,7 @@ void CustomPropertyEditor::_menu_option(int p_which) { } String orig_type = res_orig->get_type(); - print_line("orig type: "+orig_type); + Object *inst = ObjectTypeDB::instance( orig_type ); Ref res = Ref( inst->cast_to() ); @@ -187,6 +187,7 @@ void CustomPropertyEditor::_menu_option(int p_which) { ERR_FAIL_COND( inheritors_array.empty() ); + String intype=inheritors_array[p_which-TYPE_BASE_ID]; Object *obj = ObjectTypeDB::instance(intype); @@ -603,6 +604,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty if (hint_text!="") { + int idx=0; for(int i=0;inext(); } - int idx=0; for(Set::Element *E=valid_inheritors.front();E;E=E->next()) { String t = E->get(); if (!ObjectTypeDB::can_instance(t)) continue; inheritors_array.push_back(t); + int id = TYPE_BASE_ID+idx; if (has_icon(t,"EditorIcons")) { - menu->add_icon_item(get_icon(t,"EditorIcons"),"New "+t,TYPE_BASE_ID+idx); + menu->add_icon_item(get_icon(t,"EditorIcons"),"New "+t,id); } else { - menu->add_item("New "+t,TYPE_BASE_ID+idx); + menu->add_item("New "+t,id); } idx++; @@ -970,9 +972,11 @@ void CustomPropertyEditor::_action_pressed(int p_which) { if (p_which==0) { + ERR_FAIL_COND( inheritors_array.empty() ); String intype=inheritors_array[0]; + if (hint==PROPERTY_HINT_RESOURCE_TYPE) {