diff options
Diffstat (limited to 'scene/resources')
147 files changed, 6571 insertions, 91 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 7a1fffaa26..8acfdc482a 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -32,6 +32,8 @@ #include "geometry.h" +#define ANIM_MIN_LENGTH 0.001 + bool Animation::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; @@ -54,6 +56,15 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { } else if (type == "method") { add_track(TYPE_METHOD); + } else if (type == "bezier") { + + add_track(TYPE_BEZIER); + } else if (type == "audio") { + + add_track(TYPE_AUDIO); + } else if (type == "animation") { + + add_track(TYPE_ANIMATION); } else { return false; @@ -123,8 +134,8 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { int um = d["update"]; if (um < 0) um = 0; - else if (um > 2) - um = 2; + else if (um > 3) + um = 3; vt->update_mode = UpdateMode(um); } @@ -163,7 +174,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { return true; - } else { + } else if (track_get_type(track) == TYPE_METHOD) { while (track_get_key_count(track)) track_remove_key(track, 0); //well shouldn't be set anyway @@ -201,6 +212,114 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { } } } + } else if (track_get_type(track) == TYPE_BEZIER) { + + BezierTrack *bt = static_cast<BezierTrack *>(tracks[track]); + Dictionary d = p_value; + ERR_FAIL_COND_V(!d.has("times"), false); + ERR_FAIL_COND_V(!d.has("points"), false); + + PoolVector<float> times = d["times"]; + PoolRealArray values = d["points"]; + + ERR_FAIL_COND_V(times.size() * 5 != values.size(), false); + + if (times.size()) { + + int valcount = times.size(); + + PoolVector<float>::Read rt = times.read(); + PoolVector<float>::Read rv = values.read(); + + bt->values.resize(valcount); + + for (int i = 0; i < valcount; i++) { + + bt->values[i].time = rt[i]; + bt->values[i].transition = 0; //unused in bezier + bt->values[i].value.value = rv[i * 5 + 0]; + bt->values[i].value.in_handle.x = rv[i * 5 + 1]; + bt->values[i].value.in_handle.y = rv[i * 5 + 2]; + bt->values[i].value.out_handle.x = rv[i * 5 + 3]; + bt->values[i].value.out_handle.y = rv[i * 5 + 4]; + } + } + + return true; + } else if (track_get_type(track) == TYPE_AUDIO) { + + AudioTrack *ad = static_cast<AudioTrack *>(tracks[track]); + Dictionary d = p_value; + ERR_FAIL_COND_V(!d.has("times"), false); + ERR_FAIL_COND_V(!d.has("clips"), false); + + PoolVector<float> times = d["times"]; + Array clips = d["clips"]; + + ERR_FAIL_COND_V(clips.size() != times.size(), false); + + if (times.size()) { + + int valcount = times.size(); + + PoolVector<float>::Read rt = times.read(); + + ad->values.clear(); + + for (int i = 0; i < valcount; i++) { + + Dictionary d = clips[i]; + if (!d.has("start_offset")) + continue; + if (!d.has("end_offset")) + continue; + if (!d.has("stream")) + continue; + + TKey<AudioKey> ak; + ak.time = rt[i]; + ak.value.start_offset = d["start_offset"]; + ak.value.end_offset = d["end_offset"]; + ak.value.stream = d["stream"]; + + ad->values.push_back(ak); + } + } + + return true; + } else if (track_get_type(track) == TYPE_ANIMATION) { + + AnimationTrack *an = static_cast<AnimationTrack *>(tracks[track]); + Dictionary d = p_value; + ERR_FAIL_COND_V(!d.has("times"), false); + ERR_FAIL_COND_V(!d.has("clips"), false); + + PoolVector<float> times = d["times"]; + PoolVector<String> clips = d["clips"]; + + ERR_FAIL_COND_V(clips.size() != times.size(), false); + + if (times.size()) { + + int valcount = times.size(); + + PoolVector<float>::Read rt = times.read(); + PoolVector<String>::Read rc = clips.read(); + + an->values.resize(valcount); + + for (int i = 0; i < valcount; i++) { + + TKey<StringName> ak; + ak.time = rt[i]; + ak.value = rc[i]; + an->values[i] = ak; + } + } + + return true; + } else { + return false; } } else return false; @@ -232,6 +351,9 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { case TYPE_TRANSFORM: r_ret = "transform"; break; case TYPE_VALUE: r_ret = "value"; break; case TYPE_METHOD: r_ret = "method"; break; + case TYPE_BEZIER: r_ret = "bezier"; break; + case TYPE_AUDIO: r_ret = "audio"; break; + case TYPE_ANIMATION: r_ret = "animation"; break; } return true; @@ -329,7 +451,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { return true; - } else { + } else if (track_get_type(track) == TYPE_METHOD) { Dictionary d; @@ -368,6 +490,119 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { r_ret = d; return true; + } else if (track_get_type(track) == TYPE_BEZIER) { + + const BezierTrack *bt = static_cast<const BezierTrack *>(tracks[track]); + + Dictionary d; + + PoolVector<float> key_times; + PoolVector<float> key_points; + + int kk = bt->values.size(); + + key_times.resize(kk); + key_points.resize(kk * 5); + + PoolVector<float>::Write wti = key_times.write(); + PoolVector<float>::Write wpo = key_points.write(); + + int idx = 0; + + const TKey<BezierKey> *vls = bt->values.ptr(); + + for (int i = 0; i < kk; i++) { + + wti[idx] = vls[i].time; + wpo[idx * 5 + 0] = vls[i].value.value; + wpo[idx * 5 + 1] = vls[i].value.in_handle.x; + wpo[idx * 5 + 2] = vls[i].value.in_handle.y; + wpo[idx * 5 + 3] = vls[i].value.out_handle.x; + wpo[idx * 5 + 4] = vls[i].value.out_handle.y; + idx++; + } + + wti = PoolVector<float>::Write(); + wpo = PoolVector<float>::Write(); + + d["times"] = key_times; + d["points"] = key_points; + + r_ret = d; + + return true; + } else if (track_get_type(track) == TYPE_AUDIO) { + + const AudioTrack *ad = static_cast<const AudioTrack *>(tracks[track]); + + Dictionary d; + + PoolVector<float> key_times; + Array clips; + + int kk = ad->values.size(); + + key_times.resize(kk); + + PoolVector<float>::Write wti = key_times.write(); + + int idx = 0; + + const TKey<AudioKey> *vls = ad->values.ptr(); + + for (int i = 0; i < kk; i++) { + + wti[idx] = vls[i].time; + Dictionary clip; + clip["start_offset"] = vls[i].value.start_offset; + clip["end_offset"] = vls[i].value.end_offset; + clip["stream"] = vls[i].value.stream; + clips.push_back(clip); + idx++; + } + + wti = PoolVector<float>::Write(); + + d["times"] = key_times; + d["clips"] = clips; + + r_ret = d; + + return true; + } else if (track_get_type(track) == TYPE_ANIMATION) { + + const AnimationTrack *an = static_cast<const AnimationTrack *>(tracks[track]); + + Dictionary d; + + PoolVector<float> key_times; + PoolVector<String> clips; + + int kk = an->values.size(); + + key_times.resize(kk); + clips.resize(kk); + + PoolVector<float>::Write wti = key_times.write(); + PoolVector<String>::Write wcl = clips.write(); + + const TKey<StringName> *vls = an->values.ptr(); + + for (int i = 0; i < kk; i++) { + + wti[i] = vls[i].time; + wcl[i] = vls[i].value; + } + + wti = PoolVector<float>::Write(); + wcl = PoolVector<String>::Write(); + + d["times"] = key_times; + d["clips"] = clips; + + r_ret = d; + + return true; } } else return false; @@ -412,6 +647,21 @@ int Animation::add_track(TrackType p_type, int p_at_pos) { tracks.insert(p_at_pos, memnew(MethodTrack)); } break; + case TYPE_BEZIER: { + + tracks.insert(p_at_pos, memnew(BezierTrack)); + + } break; + case TYPE_AUDIO: { + + tracks.insert(p_at_pos, memnew(AudioTrack)); + + } break; + case TYPE_ANIMATION: { + + tracks.insert(p_at_pos, memnew(AnimationTrack)); + + } break; default: { ERR_PRINT("Unknown track type"); @@ -446,6 +696,24 @@ void Animation::remove_track(int p_track) { _clear(mt->methods); } break; + case TYPE_BEZIER: { + + BezierTrack *bz = static_cast<BezierTrack *>(t); + _clear(bz->values); + + } break; + case TYPE_AUDIO: { + + AudioTrack *ad = static_cast<AudioTrack *>(t); + _clear(ad->values); + + } break; + case TYPE_ANIMATION: { + + AnimationTrack *an = static_cast<AnimationTrack *>(t); + _clear(an->values); + + } break; } memdelete(t); @@ -642,6 +910,27 @@ void Animation::track_remove_key(int p_track, int p_idx) { mt->methods.remove(p_idx); } break; + case TYPE_BEZIER: { + + BezierTrack *bz = static_cast<BezierTrack *>(t); + ERR_FAIL_INDEX(p_idx, bz->values.size()); + bz->values.remove(p_idx); + + } break; + case TYPE_AUDIO: { + + AudioTrack *ad = static_cast<AudioTrack *>(t); + ERR_FAIL_INDEX(p_idx, ad->values.size()); + ad->values.remove(p_idx); + + } break; + case TYPE_ANIMATION: { + + AnimationTrack *an = static_cast<AnimationTrack *>(t); + ERR_FAIL_INDEX(p_idx, an->values.size()); + an->values.remove(p_idx); + + } break; } emit_changed(); @@ -686,6 +975,39 @@ int Animation::track_find_key(int p_track, float p_time, bool p_exact) const { return k; } break; + case TYPE_BEZIER: { + + BezierTrack *bt = static_cast<BezierTrack *>(t); + int k = _find(bt->values, p_time); + if (k < 0 || k >= bt->values.size()) + return -1; + if (bt->values[k].time != p_time && p_exact) + return -1; + return k; + + } break; + case TYPE_AUDIO: { + + AudioTrack *at = static_cast<AudioTrack *>(t); + int k = _find(at->values, p_time); + if (k < 0 || k >= at->values.size()) + return -1; + if (at->values[k].time != p_time && p_exact) + return -1; + return k; + + } break; + case TYPE_ANIMATION: { + + AnimationTrack *at = static_cast<AnimationTrack *>(t); + int k = _find(at->values, p_time); + if (k < 0 || k >= at->values.size()) + return -1; + if (at->values[k].time != p_time && p_exact) + return -1; + return k; + + } break; } return -1; @@ -748,6 +1070,51 @@ void Animation::track_insert_key(int p_track, float p_time, const Variant &p_key _insert(p_time, mt->methods, k); } break; + case TYPE_BEZIER: { + + BezierTrack *bt = static_cast<BezierTrack *>(t); + + Array arr = p_key; + ERR_FAIL_COND(arr.size() != 5); + + TKey<BezierKey> k; + k.time = p_time; + k.value.value = arr[0]; + k.value.in_handle.x = arr[1]; + k.value.in_handle.y = arr[2]; + k.value.out_handle.x = arr[3]; + k.value.out_handle.y = arr[4]; + _insert(p_time, bt->values, k); + + } break; + case TYPE_AUDIO: { + + AudioTrack *at = static_cast<AudioTrack *>(t); + + Dictionary k = p_key; + ERR_FAIL_COND(!k.has("start_offset")); + ERR_FAIL_COND(!k.has("end_offset")); + ERR_FAIL_COND(!k.has("stream")); + + TKey<AudioKey> ak; + ak.time = p_time; + ak.value.start_offset = k["start_offset"]; + ak.value.end_offset = k["end_offset"]; + ak.value.stream = k["stream"]; + _insert(p_time, at->values, ak); + + } break; + case TYPE_ANIMATION: { + + AnimationTrack *at = static_cast<AnimationTrack *>(t); + + TKey<StringName> ak; + ak.time = p_time; + ak.value = p_key; + + _insert(p_time, at->values, ak); + + } break; } emit_changed(); @@ -776,6 +1143,21 @@ int Animation::track_get_key_count(int p_track) const { MethodTrack *mt = static_cast<MethodTrack *>(t); return mt->methods.size(); } break; + case TYPE_BEZIER: { + + BezierTrack *bt = static_cast<BezierTrack *>(t); + return bt->values.size(); + } break; + case TYPE_AUDIO: { + + AudioTrack *at = static_cast<AudioTrack *>(t); + return at->values.size(); + } break; + case TYPE_ANIMATION: { + + AnimationTrack *at = static_cast<AnimationTrack *>(t); + return at->values.size(); + } break; } ERR_FAIL_V(-1); @@ -817,6 +1199,41 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const { return d; } break; + case TYPE_BEZIER: { + + BezierTrack *bt = static_cast<BezierTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, bt->values.size(), Variant()); + + Array arr; + arr.resize(5); + arr[0] = bt->values[p_key_idx].value.value; + arr[1] = bt->values[p_key_idx].value.in_handle.x; + arr[2] = bt->values[p_key_idx].value.in_handle.y; + arr[3] = bt->values[p_key_idx].value.out_handle.x; + arr[4] = bt->values[p_key_idx].value.out_handle.y; + return arr; + + } break; + case TYPE_AUDIO: { + + AudioTrack *at = static_cast<AudioTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, at->values.size(), Variant()); + + Dictionary k; + k["start_offset"] = at->values[p_key_idx].value.start_offset; + k["end_offset"] = at->values[p_key_idx].value.end_offset; + k["stream"] = at->values[p_key_idx].value.stream; + return k; + + } break; + case TYPE_ANIMATION: { + + AnimationTrack *at = static_cast<AnimationTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, at->values.size(), Variant()); + + return at->values[p_key_idx].value; + + } break; } ERR_FAIL_V(Variant()); @@ -849,6 +1266,27 @@ float Animation::track_get_key_time(int p_track, int p_key_idx) const { return mt->methods[p_key_idx].time; } break; + case TYPE_BEZIER: { + + BezierTrack *bt = static_cast<BezierTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, bt->values.size(), -1); + return bt->values[p_key_idx].time; + + } break; + case TYPE_AUDIO: { + + AudioTrack *at = static_cast<AudioTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, at->values.size(), -1); + return at->values[p_key_idx].time; + + } break; + case TYPE_ANIMATION: { + + AnimationTrack *at = static_cast<AnimationTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, at->values.size(), -1); + return at->values[p_key_idx].time; + + } break; } ERR_FAIL_V(-1); @@ -881,6 +1319,18 @@ float Animation::track_get_key_transition(int p_track, int p_key_idx) const { return mt->methods[p_key_idx].transition; } break; + case TYPE_BEZIER: { + + return 1; //bezier does not really use transitions + } break; + case TYPE_AUDIO: { + + return 1; //audio does not really use transitions + } break; + case TYPE_ANIMATION: { + + return 1; //animation does not really use transitions + } break; } ERR_FAIL_V(0); @@ -923,6 +1373,42 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p if (d.has("args")) mt->methods[p_key_idx].params = d["args"]; } break; + case TYPE_BEZIER: { + + BezierTrack *bt = static_cast<BezierTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, bt->values.size()); + + Array arr = p_value; + ERR_FAIL_COND(arr.size() != 5); + + bt->values[p_key_idx].value.value = arr[0]; + bt->values[p_key_idx].value.in_handle.x = arr[1]; + bt->values[p_key_idx].value.in_handle.y = arr[2]; + bt->values[p_key_idx].value.out_handle.x = arr[3]; + bt->values[p_key_idx].value.out_handle.y = arr[4]; + + } break; + case TYPE_AUDIO: { + + AudioTrack *at = static_cast<AudioTrack *>(t); + + Dictionary k = p_value; + ERR_FAIL_COND(!k.has("start_offset")); + ERR_FAIL_COND(!k.has("end_offset")); + ERR_FAIL_COND(!k.has("stream")); + + at->values[p_key_idx].value.start_offset = k["start_offset"]; + at->values[p_key_idx].value.end_offset = k["end_offset"]; + at->values[p_key_idx].value.stream = k["stream"]; + + } break; + case TYPE_ANIMATION: { + + AnimationTrack *at = static_cast<AnimationTrack *>(t); + + at->values[p_key_idx].value = p_value; + + } break; } } @@ -953,6 +1439,11 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_tra mt->methods[p_key_idx].transition = p_transition; } break; + case TYPE_BEZIER: + case TYPE_AUDIO: + case TYPE_ANIMATION: { + // they dont use transition + } break; } } @@ -1410,7 +1901,7 @@ void Animation::value_track_set_update_mode(int p_track, UpdateMode p_mode) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; ERR_FAIL_COND(t->type != TYPE_VALUE); - ERR_FAIL_INDEX(p_mode, 3); + ERR_FAIL_INDEX(p_mode, 4); ValueTrack *vt = static_cast<ValueTrack *>(t); vt->update_mode = p_mode; @@ -1426,6 +1917,161 @@ Animation::UpdateMode Animation::value_track_get_update_mode(int p_track) const return vt->update_mode; } +template <class T> +void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, float from_time, float to_time, List<int> *p_indices) const { + + if (from_time != length && to_time == length) + to_time = length * 1.01; //include a little more if at the end + + int to = _find(p_array, to_time); + + // can't really send the events == time, will be sent in the next frame. + // if event>=len then it will probably never be requested by the anim player. + + if (to >= 0 && p_array[to].time >= to_time) + to--; + + if (to < 0) + return; // not bother + + int from = _find(p_array, from_time); + + // position in the right first event.+ + if (from < 0 || p_array[from].time < from_time) + from++; + + int max = p_array.size(); + + for (int i = from; i <= to; i++) { + + ERR_CONTINUE(i < 0 || i >= max); // shouldn't happen + p_indices->push_back(i); + } +} + +void Animation::track_get_key_indices_in_range(int p_track, float p_time, float p_delta, List<int> *p_indices) const { + + ERR_FAIL_INDEX(p_track, tracks.size()); + const Track *t = tracks[p_track]; + + float from_time = p_time - p_delta; + float to_time = p_time; + + if (from_time > to_time) + SWAP(from_time, to_time); + + if (loop) { + + if (from_time > length || from_time < 0) + from_time = Math::fposmod(from_time, length); + + if (to_time > length || to_time < 0) + to_time = Math::fposmod(to_time, length); + + if (from_time > to_time) { + // handle loop by splitting + + switch (t->type) { + + case TYPE_TRANSFORM: { + + const TransformTrack *tt = static_cast<const TransformTrack *>(t); + _track_get_key_indices_in_range(tt->transforms, from_time, length, p_indices); + _track_get_key_indices_in_range(tt->transforms, 0, to_time, p_indices); + + } break; + case TYPE_VALUE: { + + const ValueTrack *vt = static_cast<const ValueTrack *>(t); + _track_get_key_indices_in_range(vt->values, from_time, length, p_indices); + _track_get_key_indices_in_range(vt->values, 0, to_time, p_indices); + + } break; + case TYPE_METHOD: { + + const MethodTrack *mt = static_cast<const MethodTrack *>(t); + _track_get_key_indices_in_range(mt->methods, from_time, length, p_indices); + _track_get_key_indices_in_range(mt->methods, 0, to_time, p_indices); + + } break; + case TYPE_BEZIER: { + + const BezierTrack *bz = static_cast<const BezierTrack *>(t); + _track_get_key_indices_in_range(bz->values, from_time, length, p_indices); + _track_get_key_indices_in_range(bz->values, 0, to_time, p_indices); + + } break; + case TYPE_AUDIO: { + + const AudioTrack *ad = static_cast<const AudioTrack *>(t); + _track_get_key_indices_in_range(ad->values, from_time, length, p_indices); + _track_get_key_indices_in_range(ad->values, 0, to_time, p_indices); + + } break; + case TYPE_ANIMATION: { + + const AnimationTrack *an = static_cast<const AnimationTrack *>(t); + _track_get_key_indices_in_range(an->values, from_time, length, p_indices); + _track_get_key_indices_in_range(an->values, 0, to_time, p_indices); + + } break; + } + return; + } + } else { + + if (from_time < 0) + from_time = 0; + if (from_time > length) + from_time = length; + + if (to_time < 0) + to_time = 0; + if (to_time > length) + to_time = length; + } + + switch (t->type) { + + case TYPE_TRANSFORM: { + + const TransformTrack *tt = static_cast<const TransformTrack *>(t); + _track_get_key_indices_in_range(tt->transforms, from_time, to_time, p_indices); + + } break; + case TYPE_VALUE: { + + const ValueTrack *vt = static_cast<const ValueTrack *>(t); + _track_get_key_indices_in_range(vt->values, from_time, to_time, p_indices); + + } break; + case TYPE_METHOD: { + + const MethodTrack *mt = static_cast<const MethodTrack *>(t); + _track_get_key_indices_in_range(mt->methods, from_time, to_time, p_indices); + + } break; + case TYPE_BEZIER: { + + const BezierTrack *bz = static_cast<const BezierTrack *>(t); + _track_get_key_indices_in_range(bz->values, from_time, to_time, p_indices); + + } break; + case TYPE_AUDIO: { + + const AudioTrack *ad = static_cast<const AudioTrack *>(t); + _track_get_key_indices_in_range(ad->values, from_time, to_time, p_indices); + + } break; + case TYPE_ANIMATION: { + + const AnimationTrack *an = static_cast<const AnimationTrack *>(t); + _track_get_key_indices_in_range(an->values, from_time, to_time, p_indices); + + } break; + } +} + void Animation::_method_track_get_key_indices_in_range(const MethodTrack *mt, float from_time, float to_time, List<int> *p_indices) const { if (from_time != length && to_time == length) @@ -1527,9 +2173,361 @@ StringName Animation::method_track_get_name(int p_track, int p_key_idx) const { return pm->methods[p_key_idx].method; } +int Animation::bezier_track_insert_key(int p_track, float p_time, float p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle) { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_BEZIER, -1); + + BezierTrack *bt = static_cast<BezierTrack *>(t); + + TKey<BezierKey> k; + k.time = p_time; + k.value.value = p_value; + k.value.in_handle = p_in_handle; + if (k.value.in_handle.x > 0) { + k.value.in_handle.x = 0; + } + k.value.out_handle = p_out_handle; + if (k.value.out_handle.x < 0) { + k.value.out_handle.x = 0; + } + + int key = _insert(p_time, bt->values, k); + + emit_changed(); + + return key; +} + +void Animation::bezier_track_set_key_value(int p_track, int p_index, float p_value) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + Track *t = tracks[p_track]; + ERR_FAIL_COND(t->type != TYPE_BEZIER); + + BezierTrack *bt = static_cast<BezierTrack *>(t); + + ERR_FAIL_INDEX(p_index, bt->values.size()); + + bt->values[p_index].value.value = p_value; + emit_changed(); +} + +void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + Track *t = tracks[p_track]; + ERR_FAIL_COND(t->type != TYPE_BEZIER); + + BezierTrack *bt = static_cast<BezierTrack *>(t); + + ERR_FAIL_INDEX(p_index, bt->values.size()); + + bt->values[p_index].value.in_handle = p_handle; + if (bt->values[p_index].value.in_handle.x > 0) { + bt->values[p_index].value.in_handle.x = 0; + } + emit_changed(); +} +void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + Track *t = tracks[p_track]; + ERR_FAIL_COND(t->type != TYPE_BEZIER); + + BezierTrack *bt = static_cast<BezierTrack *>(t); + + ERR_FAIL_INDEX(p_index, bt->values.size()); + + bt->values[p_index].value.out_handle = p_handle; + if (bt->values[p_index].value.out_handle.x < 0) { + bt->values[p_index].value.out_handle.x = 0; + } + emit_changed(); +} +float Animation::bezier_track_get_key_value(int p_track, int p_index) const { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_BEZIER, 0); + + BezierTrack *bt = static_cast<BezierTrack *>(t); + + ERR_FAIL_INDEX_V(p_index, bt->values.size(), 0); + + return bt->values[p_index].value.value; +} +Vector2 Animation::bezier_track_get_key_in_handle(int p_track, int p_index) const { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), Vector2()); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_BEZIER, Vector2()); + + BezierTrack *bt = static_cast<BezierTrack *>(t); + + ERR_FAIL_INDEX_V(p_index, bt->values.size(), Vector2()); + + return bt->values[p_index].value.in_handle; +} +Vector2 Animation::bezier_track_get_key_out_handle(int p_track, int p_index) const { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), Vector2()); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_BEZIER, Vector2()); + + BezierTrack *bt = static_cast<BezierTrack *>(t); + + ERR_FAIL_INDEX_V(p_index, bt->values.size(), Vector2()); + + return bt->values[p_index].value.out_handle; +} + +static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, const Vector2 &start, const Vector2 &control_1, const Vector2 &control_2, const Vector2 &end) { + /* Formula from Wikipedia article on Bezier curves. */ + real_t omt = (1.0 - t); + real_t omt2 = omt * omt; + real_t omt3 = omt2 * omt; + real_t t2 = t * t; + real_t t3 = t2 * t; + + return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; +} + +float Animation::bezier_track_interpolate(int p_track, float p_time) const { + //this uses a different interpolation scheme + ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); + Track *track = tracks[p_track]; + ERR_FAIL_COND_V(track->type != TYPE_BEZIER, 0); + + BezierTrack *bt = static_cast<BezierTrack *>(track); + + int len = _find(bt->values, length) + 1; // try to find last key (there may be more past the end) + + if (len <= 0) { + // (-1 or -2 returned originally) (plus one above) + return 0; + } else if (len == 1) { // one key found (0+1), return it + return bt->values[0].value.value; + } + + int idx = _find(bt->values, p_time); + + ERR_FAIL_COND_V(idx == -2, 0); + + //there really is no looping interpolation on bezier + + if (idx < 0) { + return bt->values[0].value.value; + } + + if (idx >= bt->values.size() - 1) { + return bt->values[bt->values.size() - 1].value.value; + } + + float t = p_time - bt->values[idx].time; + + int iterations = 10; + + float duration = bt->values[idx + 1].time - bt->values[idx].time; // time duration between our two keyframes + float low = 0; // 0% of the current animation segment + float high = 1; // 100% of the current animation segment + float middle = 0; + + Vector2 start(0, bt->values[idx].value.value); + Vector2 start_out = start + bt->values[idx].value.out_handle; + Vector2 end(duration, bt->values[idx + 1].value.value); + Vector2 end_in = end + bt->values[idx + 1].value.in_handle; + + //narrow high and low as much as possible + for (int i = 0; i < iterations; i++) { + + middle = (low + high) / 2; + + Vector2 interp = _bezier_interp(middle, start, start_out, end_in, end); + + if (interp.x < t) { + low = middle; + } else { + high = middle; + } + } + + //interpolate the result: + Vector2 low_pos = _bezier_interp(low, start, start_out, end_in, end); + Vector2 high_pos = _bezier_interp(high, start, start_out, end_in, end); + float c = (t - low_pos.x) / (high_pos.x - low_pos.x); + + return low_pos.linear_interpolate(high_pos, c).y; +} + +int Animation::audio_track_insert_key(int p_track, float p_time, const RES &p_stream, float p_start_offset, float p_end_offset) { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_AUDIO, -1); + + AudioTrack *at = static_cast<AudioTrack *>(t); + + TKey<AudioKey> k; + k.time = p_time; + k.value.stream = p_stream; + k.value.start_offset = p_start_offset; + if (k.value.start_offset < 0) + k.value.start_offset = 0; + k.value.end_offset = p_end_offset; + if (k.value.end_offset < 0) + k.value.end_offset = 0; + + int key = _insert(p_time, at->values, k); + + emit_changed(); + + return key; +} + +void Animation::audio_track_set_key_stream(int p_track, int p_key, const RES &p_stream) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + Track *t = tracks[p_track]; + ERR_FAIL_COND(t->type != TYPE_AUDIO); + + AudioTrack *at = static_cast<AudioTrack *>(t); + + ERR_FAIL_INDEX(p_key, at->values.size()); + + at->values[p_key].value.stream = p_stream; + + emit_changed(); +} + +void Animation::audio_track_set_key_start_offset(int p_track, int p_key, float p_offset) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + Track *t = tracks[p_track]; + ERR_FAIL_COND(t->type != TYPE_AUDIO); + + AudioTrack *at = static_cast<AudioTrack *>(t); + + ERR_FAIL_INDEX(p_key, at->values.size()); + + if (p_offset < 0) + p_offset = 0; + + at->values[p_key].value.start_offset = p_offset; + + emit_changed(); +} + +void Animation::audio_track_set_key_end_offset(int p_track, int p_key, float p_offset) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + Track *t = tracks[p_track]; + ERR_FAIL_COND(t->type != TYPE_AUDIO); + + AudioTrack *at = static_cast<AudioTrack *>(t); + + ERR_FAIL_INDEX(p_key, at->values.size()); + + if (p_offset < 0) + p_offset = 0; + + at->values[p_key].value.end_offset = p_offset; + + emit_changed(); +} + +RES Animation::audio_track_get_key_stream(int p_track, int p_key) const { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), RES()); + const Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_AUDIO, RES()); + + const AudioTrack *at = static_cast<const AudioTrack *>(t); + + ERR_FAIL_INDEX_V(p_key, at->values.size(), RES()); + + return at->values[p_key].value.stream; +} +float Animation::audio_track_get_key_start_offset(int p_track, int p_key) const { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); + const Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_AUDIO, 0); + + const AudioTrack *at = static_cast<const AudioTrack *>(t); + + ERR_FAIL_INDEX_V(p_key, at->values.size(), 0); + + return at->values[p_key].value.start_offset; +} +float Animation::audio_track_get_key_end_offset(int p_track, int p_key) const { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); + const Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_AUDIO, 0); + + const AudioTrack *at = static_cast<const AudioTrack *>(t); + + ERR_FAIL_INDEX_V(p_key, at->values.size(), 0); + + return at->values[p_key].value.end_offset; +} + +// + +int Animation::animation_track_insert_key(int p_track, float p_time, const StringName &p_animation) { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_ANIMATION, -1); + + AnimationTrack *at = static_cast<AnimationTrack *>(t); + + TKey<StringName> k; + k.time = p_time; + k.value = p_animation; + + int key = _insert(p_time, at->values, k); + + emit_changed(); + + return key; +} + +void Animation::animation_track_set_key_animation(int p_track, int p_key, const StringName &p_animation) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + Track *t = tracks[p_track]; + ERR_FAIL_COND(t->type != TYPE_ANIMATION); + + AnimationTrack *at = static_cast<AnimationTrack *>(t); + + ERR_FAIL_INDEX(p_key, at->values.size()); + + at->values[p_key].value = p_animation; + + emit_changed(); +} + +StringName Animation::animation_track_get_key_animation(int p_track, int p_key) const { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), StringName()); + const Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_ANIMATION, StringName()); + + const AnimationTrack *at = static_cast<const AnimationTrack *>(t); + + ERR_FAIL_INDEX_V(p_key, at->values.size(), StringName()); + + return at->values[p_key].value; +} + void Animation::set_length(float p_length) { - ERR_FAIL_COND(length < 0); + if (p_length < ANIM_MIN_LENGTH) { + p_length = ANIM_MIN_LENGTH; + } length = p_length; emit_changed(); } @@ -1592,6 +2590,16 @@ void Animation::track_move_down(int p_track) { emit_changed(); } +void Animation::track_swap(int p_track, int p_with_track) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + ERR_FAIL_INDEX(p_with_track, tracks.size()); + if (p_track == p_with_track) + return; + SWAP(tracks[p_track], tracks[p_with_track]); + emit_changed(); +} + void Animation::set_step(float p_step) { step = p_step; @@ -1631,6 +2639,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_move_up", "idx"), &Animation::track_move_up); ClassDB::bind_method(D_METHOD("track_move_down", "idx"), &Animation::track_move_down); + ClassDB::bind_method(D_METHOD("track_swap", "idx", "with_idx"), &Animation::track_swap); ClassDB::bind_method(D_METHOD("track_set_imported", "idx", "imported"), &Animation::track_set_imported); ClassDB::bind_method(D_METHOD("track_is_imported", "idx"), &Animation::track_is_imported); @@ -1667,6 +2676,30 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("method_track_get_name", "idx", "key_idx"), &Animation::method_track_get_name); ClassDB::bind_method(D_METHOD("method_track_get_params", "idx", "key_idx"), &Animation::method_track_get_params); + ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track", "time", "value", "in_handle", "out_handle"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2())); + + ClassDB::bind_method(D_METHOD("bezier_track_set_key_value", "idx", "key_idx", "value"), &Animation::bezier_track_set_key_value); + ClassDB::bind_method(D_METHOD("bezier_track_set_key_in_handle", "idx", "key_idx", "in_handle"), &Animation::bezier_track_set_key_in_handle); + ClassDB::bind_method(D_METHOD("bezier_track_set_key_out_handle", "idx", "key_idx", "out_handle"), &Animation::bezier_track_set_key_out_handle); + + ClassDB::bind_method(D_METHOD("bezier_track_get_key_value", "idx", "key_idx"), &Animation::bezier_track_get_key_value); + ClassDB::bind_method(D_METHOD("bezier_track_get_key_in_handle", "idx", "key_idx"), &Animation::bezier_track_get_key_in_handle); + ClassDB::bind_method(D_METHOD("bezier_track_get_key_out_handle", "idx", "key_idx"), &Animation::bezier_track_get_key_out_handle); + + ClassDB::bind_method(D_METHOD("bezier_track_interpolate", "track", "time"), &Animation::bezier_track_interpolate); + + ClassDB::bind_method(D_METHOD("audio_track_insert_key", "track", "time", "stream", "start_offset", "end_offset"), &Animation::audio_track_insert_key, DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("audio_track_set_key_stream", "idx", "key_idx", "stream"), &Animation::audio_track_set_key_stream); + ClassDB::bind_method(D_METHOD("audio_track_set_key_start_offset", "idx", "key_idx", "offset"), &Animation::audio_track_set_key_start_offset); + ClassDB::bind_method(D_METHOD("audio_track_set_key_end_offset", "idx", "key_idx", "offset"), &Animation::audio_track_set_key_end_offset); + ClassDB::bind_method(D_METHOD("audio_track_get_key_stream", "idx", "key_idx"), &Animation::audio_track_get_key_stream); + ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "idx", "key_idx"), &Animation::audio_track_get_key_start_offset); + ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "idx", "key_idx"), &Animation::audio_track_get_key_end_offset); + + ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track", "time", "animation"), &Animation::animation_track_insert_key); + ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation); + ClassDB::bind_method(D_METHOD("animation_track_get_key_animation", "idx", "key_idx"), &Animation::animation_track_get_key_animation); + ClassDB::bind_method(D_METHOD("set_length", "time_sec"), &Animation::set_length); ClassDB::bind_method(D_METHOD("get_length"), &Animation::get_length); @@ -1686,6 +2719,9 @@ void Animation::_bind_methods() { BIND_ENUM_CONSTANT(TYPE_VALUE); BIND_ENUM_CONSTANT(TYPE_TRANSFORM); BIND_ENUM_CONSTANT(TYPE_METHOD); + BIND_ENUM_CONSTANT(TYPE_BEZIER); + BIND_ENUM_CONSTANT(TYPE_AUDIO); + BIND_ENUM_CONSTANT(TYPE_ANIMATION); BIND_ENUM_CONSTANT(INTERPOLATION_NEAREST); BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR); @@ -1694,6 +2730,7 @@ void Animation::_bind_methods() { BIND_ENUM_CONSTANT(UPDATE_CONTINUOUS); BIND_ENUM_CONSTANT(UPDATE_DISCRETE); BIND_ENUM_CONSTANT(UPDATE_TRIGGER); + BIND_ENUM_CONSTANT(UPDATE_CAPTURE); } void Animation::clear() { diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 73691a69f2..a41e6ea5d7 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -45,6 +45,9 @@ public: TYPE_VALUE, ///< Set a value in a property, can be interpolated. TYPE_TRANSFORM, ///< Transform a node or a bone. TYPE_METHOD, ///< Call any method on a specific node. + TYPE_BEZIER, ///< Bezier curve + TYPE_AUDIO, + TYPE_ANIMATION, }; enum InterpolationType { @@ -57,6 +60,7 @@ public: UPDATE_CONTINUOUS, UPDATE_DISCRETE, UPDATE_TRIGGER, + UPDATE_CAPTURE, }; @@ -137,6 +141,55 @@ private: MethodTrack() { type = TYPE_METHOD; } }; + /* BEZIER TRACK */ + + struct BezierKey { + Vector2 in_handle; //relative (x always <0) + Vector2 out_handle; //relative (x always >0) + float value; + }; + + struct BezierTrack : public Track { + + Vector<TKey<BezierKey> > values; + + BezierTrack() { + type = TYPE_BEZIER; + } + }; + + /* AUDIO TRACK */ + + struct AudioKey { + RES stream; + float start_offset; //offset from start + float end_offset; //offset from end, if 0 then full length or infinite + AudioKey() { + start_offset = 0; + end_offset = 0; + } + }; + + struct AudioTrack : public Track { + + Vector<TKey<AudioKey> > values; + + AudioTrack() { + type = TYPE_AUDIO; + } + }; + + /* AUDIO TRACK */ + + struct AnimationTrack : public Track { + + Vector<TKey<StringName> > values; + + AnimationTrack() { + type = TYPE_ANIMATION; + } + }; + Vector<Track *> tracks; /* @@ -168,6 +221,9 @@ private: template <class T> _FORCE_INLINE_ T _interpolate(const Vector<TKey<T> > &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const; + template <class T> + _FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, float from_time, float to_time, List<int> *p_indices) const; + _FORCE_INLINE_ void _value_track_get_key_indices_in_range(const ValueTrack *vt, float from_time, float to_time, List<int> *p_indices) const; _FORCE_INLINE_ void _method_track_get_key_indices_in_range(const MethodTrack *mt, float from_time, float to_time, List<int> *p_indices) const; @@ -238,6 +294,7 @@ public: void track_move_up(int p_track); void track_move_down(int p_track); + void track_swap(int p_track, int p_with_track); void track_set_imported(int p_track, bool p_imported); bool track_is_imported(int p_track) const; @@ -245,7 +302,6 @@ public: void track_set_enabled(int p_track, bool p_enabled); bool track_is_enabled(int p_track) const; - int transform_track_insert_key(int p_track, float p_time, const Vector3 p_loc, const Quat &p_rot = Quat(), const Vector3 &p_scale = Vector3()); void track_insert_key(int p_track, float p_time, const Variant &p_key, float p_transition = 1); void track_set_key_transition(int p_track, int p_key_idx, float p_transition); void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value); @@ -257,10 +313,33 @@ public: float track_get_key_time(int p_track, int p_key_idx) const; float track_get_key_transition(int p_track, int p_key_idx) const; + int transform_track_insert_key(int p_track, float p_time, const Vector3 p_loc, const Quat &p_rot = Quat(), const Vector3 &p_scale = Vector3()); Error transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const; void track_set_interpolation_type(int p_track, InterpolationType p_interp); InterpolationType track_get_interpolation_type(int p_track) const; + int bezier_track_insert_key(int p_track, float p_time, float p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle); + void bezier_track_set_key_value(int p_track, int p_index, float p_value); + void bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle); + void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle); + float bezier_track_get_key_value(int p_track, int p_index) const; + Vector2 bezier_track_get_key_in_handle(int p_track, int p_index) const; + Vector2 bezier_track_get_key_out_handle(int p_track, int p_index) const; + + float bezier_track_interpolate(int p_track, float p_time) const; + + int audio_track_insert_key(int p_track, float p_time, const RES &p_stream, float p_start_offset = 0, float p_end_offset = 0); + void audio_track_set_key_stream(int p_track, int p_key, const RES &p_stream); + void audio_track_set_key_start_offset(int p_track, int p_key, float p_offset); + void audio_track_set_key_end_offset(int p_track, int p_key, float p_offset); + RES audio_track_get_key_stream(int p_track, int p_key) const; + float audio_track_get_key_start_offset(int p_track, int p_key) const; + float audio_track_get_key_end_offset(int p_track, int p_key) const; + + int animation_track_insert_key(int p_track, float p_time, const StringName &p_animation); + void animation_track_set_key_animation(int p_track, int p_key, const StringName &p_animation); + StringName animation_track_get_key_animation(int p_track, int p_key) const; + void track_set_interpolation_loop_wrap(int p_track, bool p_enable); bool track_get_interpolation_loop_wrap(int p_track) const; @@ -277,6 +356,8 @@ public: void copy_track(int p_track, Ref<Animation> p_to_animation); + void track_get_key_indices_in_range(int p_track, float p_time, float p_delta, List<int> *p_indices) const; + void set_length(float p_length); float get_length() const; diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 7f902fc982..f2fd919f20 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -479,6 +479,16 @@ real_t Curve::interpolate_baked(real_t offset) { } } +void Curve::ensure_default_setup(float p_min, float p_max) { + if (_points.size() == 0 && _min_value == 0 && _max_value == 1) { + + add_point(Vector2(0, 1)); + add_point(Vector2(1, 1)); + set_min_value(p_min); + set_max_value(p_max); + } +} + void Curve::_bind_methods() { ClassDB::bind_method(D_METHOD("add_point", "position", "left_tangent", "right_tangent", "left_mode", "right_mode"), &Curve::add_point, DEFVAL(0), DEFVAL(0), DEFVAL(TANGENT_FREE), DEFVAL(TANGENT_FREE)); diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 9cb12a4345..058c4f1bc2 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -128,6 +128,8 @@ public: void set_bake_resolution(int p_resolution); real_t interpolate_baked(real_t offset); + void ensure_default_setup(float p_min, float p_max); + protected: static void _bind_methods(); diff --git a/scene/resources/cylinder_shape.cpp b/scene/resources/cylinder_shape.cpp new file mode 100644 index 0000000000..f760462d49 --- /dev/null +++ b/scene/resources/cylinder_shape.cpp @@ -0,0 +1,116 @@ +/*************************************************************************/ +/* cylinder_shape.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "cylinder_shape.h" +#include "servers/physics_server.h" + +Vector<Vector3> CylinderShape::_gen_debug_mesh_lines() { + + float radius = get_radius(); + float height = get_height(); + + Vector<Vector3> points; + + Vector3 d(0, height * 0.5, 0); + for (int i = 0; i < 360; i++) { + + float ra = Math::deg2rad((float)i); + float rb = Math::deg2rad((float)i + 1); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; + + points.push_back(Vector3(a.x, 0, a.y) + d); + points.push_back(Vector3(b.x, 0, b.y) + d); + + points.push_back(Vector3(a.x, 0, a.y) - d); + points.push_back(Vector3(b.x, 0, b.y) - d); + + if (i % 90 == 0) { + + points.push_back(Vector3(a.x, 0, a.y) + d); + points.push_back(Vector3(a.x, 0, a.y) - d); + } + } + + return points; +} + +void CylinderShape::_update_shape() { + + Dictionary d; + d["radius"] = radius; + d["height"] = height; + PhysicsServer::get_singleton()->shape_set_data(get_shape(), d); +} + +void CylinderShape::set_radius(float p_radius) { + + radius = p_radius; + _update_shape(); + notify_change_to_owners(); + _change_notify("radius"); +} + +float CylinderShape::get_radius() const { + + return radius; +} + +void CylinderShape::set_height(float p_height) { + + height = p_height; + _update_shape(); + notify_change_to_owners(); + _change_notify("height"); +} + +float CylinderShape::get_height() const { + + return height; +} + +void CylinderShape::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CylinderShape::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &CylinderShape::get_radius); + ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape::set_height); + ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape::get_height); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_height", "get_height"); +} + +CylinderShape::CylinderShape() : + Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CYLINDER)) { + + radius = 1.0; + height = 2.0; + _update_shape(); +} diff --git a/scene/resources/cylinder_shape.h b/scene/resources/cylinder_shape.h new file mode 100644 index 0000000000..f510758e91 --- /dev/null +++ b/scene/resources/cylinder_shape.h @@ -0,0 +1,57 @@ +/*************************************************************************/ +/* cylinder_shape.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CYLINDER_SHAPE_H +#define CYLINDER_SHAPE_H + +#include "scene/resources/shape.h" + +class CylinderShape : public Shape { + + GDCLASS(CylinderShape, Shape); + float radius; + float height; + +protected: + static void _bind_methods(); + virtual void _update_shape(); + + virtual Vector<Vector3> _gen_debug_mesh_lines(); + +public: + void set_radius(float p_radius); + float get_radius() const; + void set_height(float p_height); + float get_height() const; + + CylinderShape(); +}; + +#endif // CYLINDER_SHAPE_H diff --git a/scene/resources/default_theme/arrow_down.png b/scene/resources/default_theme/arrow_down.png Binary files differindex fc837d120a..bfb87a4761 100644 --- a/scene/resources/default_theme/arrow_down.png +++ b/scene/resources/default_theme/arrow_down.png diff --git a/scene/resources/default_theme/arrow_right.png b/scene/resources/default_theme/arrow_right.png Binary files differindex ebe6e26ace..1e4c8e5529 100644 --- a/scene/resources/default_theme/arrow_right.png +++ b/scene/resources/default_theme/arrow_right.png diff --git a/scene/resources/default_theme/background.png b/scene/resources/default_theme/background.png Binary files differindex 03cfab1de3..6c5f43e3ce 100644 --- a/scene/resources/default_theme/background.png +++ b/scene/resources/default_theme/background.png diff --git a/scene/resources/default_theme/base_green.png b/scene/resources/default_theme/base_green.png Binary files differindex d03d6f08d8..03a5b313d7 100644 --- a/scene/resources/default_theme/base_green.png +++ b/scene/resources/default_theme/base_green.png diff --git a/scene/resources/default_theme/button_disabled.png b/scene/resources/default_theme/button_disabled.png Binary files differindex d75e76989d..708748dfe9 100644 --- a/scene/resources/default_theme/button_disabled.png +++ b/scene/resources/default_theme/button_disabled.png diff --git a/scene/resources/default_theme/button_focus.png b/scene/resources/default_theme/button_focus.png Binary files differindex 44e354be95..70e16b953b 100644 --- a/scene/resources/default_theme/button_focus.png +++ b/scene/resources/default_theme/button_focus.png diff --git a/scene/resources/default_theme/button_hover.png b/scene/resources/default_theme/button_hover.png Binary files differindex 6e609f435f..ef226e3caf 100644 --- a/scene/resources/default_theme/button_hover.png +++ b/scene/resources/default_theme/button_hover.png diff --git a/scene/resources/default_theme/button_normal.png b/scene/resources/default_theme/button_normal.png Binary files differindex 92482aaf28..7d0bd16221 100644 --- a/scene/resources/default_theme/button_normal.png +++ b/scene/resources/default_theme/button_normal.png diff --git a/scene/resources/default_theme/checked.png b/scene/resources/default_theme/checked.png Binary files differindex 93e291a29e..bde031b6a2 100644 --- a/scene/resources/default_theme/checked.png +++ b/scene/resources/default_theme/checked.png diff --git a/scene/resources/default_theme/checker_bg.png b/scene/resources/default_theme/checker_bg.png Binary files differindex f58dfed29c..3eff2f0e08 100644 --- a/scene/resources/default_theme/checker_bg.png +++ b/scene/resources/default_theme/checker_bg.png diff --git a/scene/resources/default_theme/close.png b/scene/resources/default_theme/close.png Binary files differindex 5ac6357dcd..4d4ac4a551 100644 --- a/scene/resources/default_theme/close.png +++ b/scene/resources/default_theme/close.png diff --git a/scene/resources/default_theme/close_hl.png b/scene/resources/default_theme/close_hl.png Binary files differindex 5ac6357dcd..4d4ac4a551 100644 --- a/scene/resources/default_theme/close_hl.png +++ b/scene/resources/default_theme/close_hl.png diff --git a/scene/resources/default_theme/color_picker_sample.png b/scene/resources/default_theme/color_picker_sample.png Binary files differindex b145a3e384..e6ec28d307 100644 --- a/scene/resources/default_theme/color_picker_sample.png +++ b/scene/resources/default_theme/color_picker_sample.png diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 3ea856541e..fe12e2f5f6 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -476,6 +476,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("symbol_color", "TextEdit", control_font_color_hover); theme->set_color("brace_mismatch_color", "TextEdit", Color(1, 0.2, 0.2)); theme->set_color("line_number_color", "TextEdit", Color::html("66aaaaaa")); + theme->set_color("safe_line_number_color", "TextEdit", Color::html("99aac8aa")); theme->set_color("function_color", "TextEdit", Color::html("66a2ce")); theme->set_color("member_variable_color", "TextEdit", Color::html("e64e59")); theme->set_color("number_color", "TextEdit", Color::html("EB9532")); @@ -585,6 +586,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("panel_disabled", "PopupMenu", make_stylebox(popup_bg_disabled_png, 4, 4, 4, 4)); theme->set_stylebox("hover", "PopupMenu", selected); theme->set_stylebox("separator", "PopupMenu", make_stylebox(vseparator_png, 3, 3, 3, 3)); + theme->set_stylebox("labeled_separator_left", "PopupMenu", make_stylebox(vseparator_png, 0, 0, 0, 0)); + theme->set_stylebox("labeled_separator_right", "PopupMenu", make_stylebox(vseparator_png, 0, 0, 0, 0)); theme->set_icon("checked", "PopupMenu", make_icon(checked_png)); theme->set_icon("unchecked", "PopupMenu", make_icon(unchecked_png)); @@ -844,7 +847,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("separation", "HBoxContainer", 4 * scale); theme->set_constant("separation", "VBoxContainer", 4 * scale); - theme->set_constant("margin_left", "MarginContainer", 8 * scale); + theme->set_constant("margin_left", "MarginContainer", 0 * scale); theme->set_constant("margin_top", "MarginContainer", 0 * scale); theme->set_constant("margin_right", "MarginContainer", 0 * scale); theme->set_constant("margin_bottom", "MarginContainer", 0 * scale); @@ -874,6 +877,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("bg", "GraphEdit", make_stylebox(tree_bg_png, 4, 4, 4, 5)); theme->set_color("grid_minor", "GraphEdit", Color(1, 1, 1, 0.05)); theme->set_color("grid_major", "GraphEdit", Color(1, 1, 1, 0.2)); + theme->set_color("activity", "GraphEdit", Color(1, 1, 1)); theme->set_constant("bezier_len_pos", "GraphEdit", 80 * scale); theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale); diff --git a/scene/resources/default_theme/dosfont.png b/scene/resources/default_theme/dosfont.png Binary files differindex 814d2e9060..e2739b94ea 100644 --- a/scene/resources/default_theme/dosfont.png +++ b/scene/resources/default_theme/dosfont.png diff --git a/scene/resources/default_theme/dropdown.png b/scene/resources/default_theme/dropdown.png Binary files differindex 3a6a2ed778..b5d9ffbbb4 100644 --- a/scene/resources/default_theme/dropdown.png +++ b/scene/resources/default_theme/dropdown.png diff --git a/scene/resources/default_theme/error_icon.png b/scene/resources/default_theme/error_icon.png Binary files differindex f291362350..7741d00749 100644 --- a/scene/resources/default_theme/error_icon.png +++ b/scene/resources/default_theme/error_icon.png diff --git a/scene/resources/default_theme/focus.png b/scene/resources/default_theme/focus.png Binary files differindex 5d37028f2d..f51ea89e8f 100644 --- a/scene/resources/default_theme/focus.png +++ b/scene/resources/default_theme/focus.png diff --git a/scene/resources/default_theme/frame_focus.png b/scene/resources/default_theme/frame_focus.png Binary files differindex 9170db38ed..1b24ba47d8 100644 --- a/scene/resources/default_theme/frame_focus.png +++ b/scene/resources/default_theme/frame_focus.png diff --git a/scene/resources/default_theme/full_panel_bg.png b/scene/resources/default_theme/full_panel_bg.png Binary files differindex 7f02dc7259..85f753cc13 100644 --- a/scene/resources/default_theme/full_panel_bg.png +++ b/scene/resources/default_theme/full_panel_bg.png diff --git a/scene/resources/default_theme/graph_node_breakpoint.png b/scene/resources/default_theme/graph_node_breakpoint.png Binary files differindex 0e36f31bd4..e18c6f42e1 100644 --- a/scene/resources/default_theme/graph_node_breakpoint.png +++ b/scene/resources/default_theme/graph_node_breakpoint.png diff --git a/scene/resources/default_theme/graph_node_close.png b/scene/resources/default_theme/graph_node_close.png Binary files differindex 144a8b9c4c..5c962ae1c6 100644 --- a/scene/resources/default_theme/graph_node_close.png +++ b/scene/resources/default_theme/graph_node_close.png diff --git a/scene/resources/default_theme/graph_node_comment.png b/scene/resources/default_theme/graph_node_comment.png Binary files differindex f2d6daa259..cdec1d1eac 100644 --- a/scene/resources/default_theme/graph_node_comment.png +++ b/scene/resources/default_theme/graph_node_comment.png diff --git a/scene/resources/default_theme/graph_node_comment_focus.png b/scene/resources/default_theme/graph_node_comment_focus.png Binary files differindex a4b7b5a618..472a6b6f53 100644 --- a/scene/resources/default_theme/graph_node_comment_focus.png +++ b/scene/resources/default_theme/graph_node_comment_focus.png diff --git a/scene/resources/default_theme/graph_node_default.png b/scene/resources/default_theme/graph_node_default.png Binary files differindex e3a220301f..359bbdc205 100644 --- a/scene/resources/default_theme/graph_node_default.png +++ b/scene/resources/default_theme/graph_node_default.png diff --git a/scene/resources/default_theme/graph_node_default_focus.png b/scene/resources/default_theme/graph_node_default_focus.png Binary files differindex 9972b07593..204dd16ac0 100644 --- a/scene/resources/default_theme/graph_node_default_focus.png +++ b/scene/resources/default_theme/graph_node_default_focus.png diff --git a/scene/resources/default_theme/graph_node_position.png b/scene/resources/default_theme/graph_node_position.png Binary files differindex 7ec15e2ff4..24c2759be6 100644 --- a/scene/resources/default_theme/graph_node_position.png +++ b/scene/resources/default_theme/graph_node_position.png diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png Binary files differindex f76c9703dd..cc4eb7f753 100644 --- a/scene/resources/default_theme/graph_node_selected.png +++ b/scene/resources/default_theme/graph_node_selected.png diff --git a/scene/resources/default_theme/graph_port.png b/scene/resources/default_theme/graph_port.png Binary files differindex 9d5082cfdb..f33ae3baf3 100644 --- a/scene/resources/default_theme/graph_port.png +++ b/scene/resources/default_theme/graph_port.png diff --git a/scene/resources/default_theme/hseparator.png b/scene/resources/default_theme/hseparator.png Binary files differindex 99609ac118..d4fd71ace5 100644 --- a/scene/resources/default_theme/hseparator.png +++ b/scene/resources/default_theme/hseparator.png diff --git a/scene/resources/default_theme/hslider_bg.png b/scene/resources/default_theme/hslider_bg.png Binary files differindex 9c2a2df62a..b402bd370d 100644 --- a/scene/resources/default_theme/hslider_bg.png +++ b/scene/resources/default_theme/hslider_bg.png diff --git a/scene/resources/default_theme/hslider_grabber.png b/scene/resources/default_theme/hslider_grabber.png Binary files differindex 2acd33879a..d273b491ee 100644 --- a/scene/resources/default_theme/hslider_grabber.png +++ b/scene/resources/default_theme/hslider_grabber.png diff --git a/scene/resources/default_theme/hslider_grabber_disabled.png b/scene/resources/default_theme/hslider_grabber_disabled.png Binary files differindex 0d75182b8f..dddd1a468e 100644 --- a/scene/resources/default_theme/hslider_grabber_disabled.png +++ b/scene/resources/default_theme/hslider_grabber_disabled.png diff --git a/scene/resources/default_theme/hslider_grabber_hl.png b/scene/resources/default_theme/hslider_grabber_hl.png Binary files differindex f8a011e64b..e3defb3610 100644 --- a/scene/resources/default_theme/hslider_grabber_hl.png +++ b/scene/resources/default_theme/hslider_grabber_hl.png diff --git a/scene/resources/default_theme/hslider_tick.png b/scene/resources/default_theme/hslider_tick.png Binary files differindex f7afd78529..1ba19c37a1 100644 --- a/scene/resources/default_theme/hslider_tick.png +++ b/scene/resources/default_theme/hslider_tick.png diff --git a/scene/resources/default_theme/hsplit_bg.png b/scene/resources/default_theme/hsplit_bg.png Binary files differindex 7dd1d48b29..a5749f6d5c 100644 --- a/scene/resources/default_theme/hsplit_bg.png +++ b/scene/resources/default_theme/hsplit_bg.png diff --git a/scene/resources/default_theme/hsplitter.png b/scene/resources/default_theme/hsplitter.png Binary files differindex 71a3914d7e..2287753c9d 100644 --- a/scene/resources/default_theme/hsplitter.png +++ b/scene/resources/default_theme/hsplitter.png diff --git a/scene/resources/default_theme/icon_add.png b/scene/resources/default_theme/icon_add.png Binary files differindex fa675045bc..eccb69b363 100644 --- a/scene/resources/default_theme/icon_add.png +++ b/scene/resources/default_theme/icon_add.png diff --git a/scene/resources/default_theme/icon_close.png b/scene/resources/default_theme/icon_close.png Binary files differindex 5ac6357dcd..4d4ac4a551 100644 --- a/scene/resources/default_theme/icon_close.png +++ b/scene/resources/default_theme/icon_close.png diff --git a/scene/resources/default_theme/icon_color_pick.png b/scene/resources/default_theme/icon_color_pick.png Binary files differindex 15679a9558..46953febb8 100644 --- a/scene/resources/default_theme/icon_color_pick.png +++ b/scene/resources/default_theme/icon_color_pick.png diff --git a/scene/resources/default_theme/icon_folder.png b/scene/resources/default_theme/icon_folder.png Binary files differindex cc05e98ebb..d1b308e88d 100644 --- a/scene/resources/default_theme/icon_folder.png +++ b/scene/resources/default_theme/icon_folder.png diff --git a/scene/resources/default_theme/icon_parent_folder.png b/scene/resources/default_theme/icon_parent_folder.png Binary files differindex 47fee1ad81..35d218722e 100644 --- a/scene/resources/default_theme/icon_parent_folder.png +++ b/scene/resources/default_theme/icon_parent_folder.png diff --git a/scene/resources/default_theme/icon_play.png b/scene/resources/default_theme/icon_play.png Binary files differindex 864e4e4fb9..b9ed6e6d5b 100644 --- a/scene/resources/default_theme/icon_play.png +++ b/scene/resources/default_theme/icon_play.png diff --git a/scene/resources/default_theme/icon_reload.png b/scene/resources/default_theme/icon_reload.png Binary files differindex 9303fabb9c..bec5f3f4f9 100644 --- a/scene/resources/default_theme/icon_reload.png +++ b/scene/resources/default_theme/icon_reload.png diff --git a/scene/resources/default_theme/icon_snap_grid.png b/scene/resources/default_theme/icon_snap_grid.png Binary files differindex 44db9bdfdc..0680317d86 100644 --- a/scene/resources/default_theme/icon_snap_grid.png +++ b/scene/resources/default_theme/icon_snap_grid.png diff --git a/scene/resources/default_theme/icon_stop.png b/scene/resources/default_theme/icon_stop.png Binary files differindex 1f194d0e14..0c1371ceb9 100644 --- a/scene/resources/default_theme/icon_stop.png +++ b/scene/resources/default_theme/icon_stop.png diff --git a/scene/resources/default_theme/icon_zoom_less.png b/scene/resources/default_theme/icon_zoom_less.png Binary files differindex 888ddc995d..03119c60ca 100644 --- a/scene/resources/default_theme/icon_zoom_less.png +++ b/scene/resources/default_theme/icon_zoom_less.png diff --git a/scene/resources/default_theme/icon_zoom_more.png b/scene/resources/default_theme/icon_zoom_more.png Binary files differindex fa675045bc..31467ec3de 100644 --- a/scene/resources/default_theme/icon_zoom_more.png +++ b/scene/resources/default_theme/icon_zoom_more.png diff --git a/scene/resources/default_theme/icon_zoom_reset.png b/scene/resources/default_theme/icon_zoom_reset.png Binary files differindex 953ae47d24..cac68c09fa 100644 --- a/scene/resources/default_theme/icon_zoom_reset.png +++ b/scene/resources/default_theme/icon_zoom_reset.png diff --git a/scene/resources/default_theme/line_edit.png b/scene/resources/default_theme/line_edit.png Binary files differindex bf2b91f1be..2b0c506f34 100644 --- a/scene/resources/default_theme/line_edit.png +++ b/scene/resources/default_theme/line_edit.png diff --git a/scene/resources/default_theme/line_edit_disabled.png b/scene/resources/default_theme/line_edit_disabled.png Binary files differindex a0fa505e4c..69d78febd9 100644 --- a/scene/resources/default_theme/line_edit_disabled.png +++ b/scene/resources/default_theme/line_edit_disabled.png diff --git a/scene/resources/default_theme/line_edit_focus.png b/scene/resources/default_theme/line_edit_focus.png Binary files differindex e66d7b60e3..1d74b74068 100644 --- a/scene/resources/default_theme/line_edit_focus.png +++ b/scene/resources/default_theme/line_edit_focus.png diff --git a/scene/resources/default_theme/logo.png b/scene/resources/default_theme/logo.png Binary files differindex 2161402438..d0ef9d8aa7 100644 --- a/scene/resources/default_theme/logo.png +++ b/scene/resources/default_theme/logo.png diff --git a/scene/resources/default_theme/make_header.py b/scene/resources/default_theme/make_header.py index db449f9417..73b1ae0b0b 100755 --- a/scene/resources/default_theme/make_header.py +++ b/scene/resources/default_theme/make_header.py @@ -4,15 +4,16 @@ import os import glob import string +enc = "utf-8" # Generate include files f = open("theme_data.h", "wb") -f.write("// THIS FILE HAS BEEN AUTOGENERATED, DON'T EDIT!!\n") +f.write(b"// THIS FILE HAS BEEN AUTOGENERATED, DON\'T EDIT!!\n") # Generate png image block -f.write("\n// png image block\n"); +f.write(b"\n// png image block\n") pixmaps = glob.glob("*.png") pixmaps.sort() @@ -21,22 +22,23 @@ for x in pixmaps: var_str = x[:-4] + "_png" - f.write("\nstatic const unsigned char " + var_str + "[] = {\n\t") + s = "\nstatic const unsigned char " + var_str + "[] = {\n\t" + f.write(s.encode(enc)) pngf = open(x, "rb") b = pngf.read(1) while(len(b) == 1): - f.write(hex(ord(b))) + f.write(hex(ord(b)).encode(enc)) b = pngf.read(1) if (len(b) == 1): - f.write(", ") + f.write(b", ") - f.write("\n};\n") + f.write(b"\n};\n") pngf.close() # Generate shaders block -f.write("\n// shaders block\n"); +f.write(b"\n// shaders block\n"); shaders = glob.glob("*.gsl") shaders.sort() @@ -45,7 +47,8 @@ for x in shaders: var_str = x[:-4] + "_shader_code" - f.write("\nstatic const char *" + var_str + " = \n") + s = "\nstatic const char *" + var_str + " = \n" + f.write(s.encode(enc)) sf = open(x, "rb") @@ -55,12 +58,13 @@ for x in shaders: b = b[:-2] if (b.endswith("\n")): b = b[:-1] - f.write(" \"" + b) + s = ' \"' + b + f.write(s.encode(enc)) b = sf.readline() if (b != ""): - f.write("\"\n") + f.write(b'"\n') - f.write("\";\n") + f.write(b'";\n') sf.close() f.close() diff --git a/scene/resources/default_theme/mini_checkerboard.png b/scene/resources/default_theme/mini_checkerboard.png Binary files differindex 3e53183847..d8279bda80 100644 --- a/scene/resources/default_theme/mini_checkerboard.png +++ b/scene/resources/default_theme/mini_checkerboard.png diff --git a/scene/resources/default_theme/option_arrow.png b/scene/resources/default_theme/option_arrow.png Binary files differindex 007de16bfa..40590fd60a 100644 --- a/scene/resources/default_theme/option_arrow.png +++ b/scene/resources/default_theme/option_arrow.png diff --git a/scene/resources/default_theme/option_button_disabled.png b/scene/resources/default_theme/option_button_disabled.png Binary files differindex ce727d56e1..1961b673cd 100644 --- a/scene/resources/default_theme/option_button_disabled.png +++ b/scene/resources/default_theme/option_button_disabled.png diff --git a/scene/resources/default_theme/option_button_focus.png b/scene/resources/default_theme/option_button_focus.png Binary files differindex c76d91287e..402670f9a2 100644 --- a/scene/resources/default_theme/option_button_focus.png +++ b/scene/resources/default_theme/option_button_focus.png diff --git a/scene/resources/default_theme/option_button_hover.png b/scene/resources/default_theme/option_button_hover.png Binary files differindex fd1e987ceb..826fe1c9ca 100644 --- a/scene/resources/default_theme/option_button_hover.png +++ b/scene/resources/default_theme/option_button_hover.png diff --git a/scene/resources/default_theme/option_button_normal.png b/scene/resources/default_theme/option_button_normal.png Binary files differindex 9d7fb98d1c..2dadb40338 100644 --- a/scene/resources/default_theme/option_button_normal.png +++ b/scene/resources/default_theme/option_button_normal.png diff --git a/scene/resources/default_theme/option_button_pressed.png b/scene/resources/default_theme/option_button_pressed.png Binary files differindex 28b1d93468..68796f9d85 100644 --- a/scene/resources/default_theme/option_button_pressed.png +++ b/scene/resources/default_theme/option_button_pressed.png diff --git a/scene/resources/default_theme/panel_bg.png b/scene/resources/default_theme/panel_bg.png Binary files differindex 320819ad6d..b496e2177e 100644 --- a/scene/resources/default_theme/panel_bg.png +++ b/scene/resources/default_theme/panel_bg.png diff --git a/scene/resources/default_theme/popup_bg.png b/scene/resources/default_theme/popup_bg.png Binary files differindex 63f5994441..023029f936 100644 --- a/scene/resources/default_theme/popup_bg.png +++ b/scene/resources/default_theme/popup_bg.png diff --git a/scene/resources/default_theme/popup_bg_disabled.png b/scene/resources/default_theme/popup_bg_disabled.png Binary files differindex 611d949380..8eab5f27bc 100644 --- a/scene/resources/default_theme/popup_bg_disabled.png +++ b/scene/resources/default_theme/popup_bg_disabled.png diff --git a/scene/resources/default_theme/popup_checked.png b/scene/resources/default_theme/popup_checked.png Binary files differindex a24e0543c0..b7b05640e1 100644 --- a/scene/resources/default_theme/popup_checked.png +++ b/scene/resources/default_theme/popup_checked.png diff --git a/scene/resources/default_theme/popup_hover.png b/scene/resources/default_theme/popup_hover.png Binary files differindex 85d4e48475..bdb6ae8bd0 100644 --- a/scene/resources/default_theme/popup_hover.png +++ b/scene/resources/default_theme/popup_hover.png diff --git a/scene/resources/default_theme/popup_unchecked.png b/scene/resources/default_theme/popup_unchecked.png Binary files differindex c1137e6fbf..ff922335c3 100644 --- a/scene/resources/default_theme/popup_unchecked.png +++ b/scene/resources/default_theme/popup_unchecked.png diff --git a/scene/resources/default_theme/popup_window.png b/scene/resources/default_theme/popup_window.png Binary files differindex 59362a8ffd..174a29ef45 100644 --- a/scene/resources/default_theme/popup_window.png +++ b/scene/resources/default_theme/popup_window.png diff --git a/scene/resources/default_theme/progress_bar.png b/scene/resources/default_theme/progress_bar.png Binary files differindex bf81e3adea..057557e567 100644 --- a/scene/resources/default_theme/progress_bar.png +++ b/scene/resources/default_theme/progress_bar.png diff --git a/scene/resources/default_theme/progress_fill.png b/scene/resources/default_theme/progress_fill.png Binary files differindex 3a34dfdda6..e39bb2a021 100644 --- a/scene/resources/default_theme/progress_fill.png +++ b/scene/resources/default_theme/progress_fill.png diff --git a/scene/resources/default_theme/radio_checked.png b/scene/resources/default_theme/radio_checked.png Binary files differindex 95d472022f..0ce575c15f 100644 --- a/scene/resources/default_theme/radio_checked.png +++ b/scene/resources/default_theme/radio_checked.png diff --git a/scene/resources/default_theme/radio_unchecked.png b/scene/resources/default_theme/radio_unchecked.png Binary files differindex 7f0535c3a4..fe5bcf6ab1 100644 --- a/scene/resources/default_theme/radio_unchecked.png +++ b/scene/resources/default_theme/radio_unchecked.png diff --git a/scene/resources/default_theme/reference_border.png b/scene/resources/default_theme/reference_border.png Binary files differindex 96219676bf..6a680f393c 100644 --- a/scene/resources/default_theme/reference_border.png +++ b/scene/resources/default_theme/reference_border.png diff --git a/scene/resources/default_theme/scroll_bg.png b/scene/resources/default_theme/scroll_bg.png Binary files differindex cefadb2c08..fb151a48b1 100644 --- a/scene/resources/default_theme/scroll_bg.png +++ b/scene/resources/default_theme/scroll_bg.png diff --git a/scene/resources/default_theme/scroll_button_down.png b/scene/resources/default_theme/scroll_button_down.png Binary files differindex caeac9b286..1df4ef5b6b 100644 --- a/scene/resources/default_theme/scroll_button_down.png +++ b/scene/resources/default_theme/scroll_button_down.png diff --git a/scene/resources/default_theme/scroll_button_down_hl.png b/scene/resources/default_theme/scroll_button_down_hl.png Binary files differindex 48036e0297..ba79087393 100644 --- a/scene/resources/default_theme/scroll_button_down_hl.png +++ b/scene/resources/default_theme/scroll_button_down_hl.png diff --git a/scene/resources/default_theme/scroll_button_left.png b/scene/resources/default_theme/scroll_button_left.png Binary files differindex 3b50938d97..e430cb4673 100644 --- a/scene/resources/default_theme/scroll_button_left.png +++ b/scene/resources/default_theme/scroll_button_left.png diff --git a/scene/resources/default_theme/scroll_button_left_hl.png b/scene/resources/default_theme/scroll_button_left_hl.png Binary files differindex b3d348c24f..2a6ef17a34 100644 --- a/scene/resources/default_theme/scroll_button_left_hl.png +++ b/scene/resources/default_theme/scroll_button_left_hl.png diff --git a/scene/resources/default_theme/scroll_button_right.png b/scene/resources/default_theme/scroll_button_right.png Binary files differindex 1c622a41ad..4f61687aa4 100644 --- a/scene/resources/default_theme/scroll_button_right.png +++ b/scene/resources/default_theme/scroll_button_right.png diff --git a/scene/resources/default_theme/scroll_button_right_hl.png b/scene/resources/default_theme/scroll_button_right_hl.png Binary files differindex 108796ca02..10e2722509 100644 --- a/scene/resources/default_theme/scroll_button_right_hl.png +++ b/scene/resources/default_theme/scroll_button_right_hl.png diff --git a/scene/resources/default_theme/scroll_button_up.png b/scene/resources/default_theme/scroll_button_up.png Binary files differindex 2c8238ae4c..f425412f50 100644 --- a/scene/resources/default_theme/scroll_button_up.png +++ b/scene/resources/default_theme/scroll_button_up.png diff --git a/scene/resources/default_theme/scroll_button_up_hl.png b/scene/resources/default_theme/scroll_button_up_hl.png Binary files differindex 4283bd114a..615a236c52 100644 --- a/scene/resources/default_theme/scroll_button_up_hl.png +++ b/scene/resources/default_theme/scroll_button_up_hl.png diff --git a/scene/resources/default_theme/scroll_grabber.png b/scene/resources/default_theme/scroll_grabber.png Binary files differindex 1d625a9b7b..732725a28f 100644 --- a/scene/resources/default_theme/scroll_grabber.png +++ b/scene/resources/default_theme/scroll_grabber.png diff --git a/scene/resources/default_theme/scroll_grabber_hl.png b/scene/resources/default_theme/scroll_grabber_hl.png Binary files differindex 99eb24b7e7..006cfa3361 100644 --- a/scene/resources/default_theme/scroll_grabber_hl.png +++ b/scene/resources/default_theme/scroll_grabber_hl.png diff --git a/scene/resources/default_theme/scroll_grabber_pressed.png b/scene/resources/default_theme/scroll_grabber_pressed.png Binary files differindex a46d242ddd..f4886158fa 100644 --- a/scene/resources/default_theme/scroll_grabber_pressed.png +++ b/scene/resources/default_theme/scroll_grabber_pressed.png diff --git a/scene/resources/default_theme/selection.png b/scene/resources/default_theme/selection.png Binary files differindex 501877a8b4..7d1c985b35 100644 --- a/scene/resources/default_theme/selection.png +++ b/scene/resources/default_theme/selection.png diff --git a/scene/resources/default_theme/selection_oof.png b/scene/resources/default_theme/selection_oof.png Binary files differindex 9594fe0913..2da0538389 100644 --- a/scene/resources/default_theme/selection_oof.png +++ b/scene/resources/default_theme/selection_oof.png diff --git a/scene/resources/default_theme/spinbox_updown.png b/scene/resources/default_theme/spinbox_updown.png Binary files differindex b40b1e9fd2..74fab19f34 100644 --- a/scene/resources/default_theme/spinbox_updown.png +++ b/scene/resources/default_theme/spinbox_updown.png diff --git a/scene/resources/default_theme/submenu.png b/scene/resources/default_theme/submenu.png Binary files differindex ec727eecf1..8f7de446d4 100644 --- a/scene/resources/default_theme/submenu.png +++ b/scene/resources/default_theme/submenu.png diff --git a/scene/resources/default_theme/tab.png b/scene/resources/default_theme/tab.png Binary files differindex 3e4d792a48..895daa65e2 100644 --- a/scene/resources/default_theme/tab.png +++ b/scene/resources/default_theme/tab.png diff --git a/scene/resources/default_theme/tab_behind.png b/scene/resources/default_theme/tab_behind.png Binary files differindex 12f07c3a91..2803d9db65 100644 --- a/scene/resources/default_theme/tab_behind.png +++ b/scene/resources/default_theme/tab_behind.png diff --git a/scene/resources/default_theme/tab_close.png b/scene/resources/default_theme/tab_close.png Binary files differindex 20d9b5c810..af2775a132 100644 --- a/scene/resources/default_theme/tab_close.png +++ b/scene/resources/default_theme/tab_close.png diff --git a/scene/resources/default_theme/tab_container_bg.png b/scene/resources/default_theme/tab_container_bg.png Binary files differindex 92482aaf28..7d0bd16221 100644 --- a/scene/resources/default_theme/tab_container_bg.png +++ b/scene/resources/default_theme/tab_container_bg.png diff --git a/scene/resources/default_theme/tab_current.png b/scene/resources/default_theme/tab_current.png Binary files differindex 7289e032da..520d147217 100644 --- a/scene/resources/default_theme/tab_current.png +++ b/scene/resources/default_theme/tab_current.png diff --git a/scene/resources/default_theme/tab_menu.png b/scene/resources/default_theme/tab_menu.png Binary files differindex 148b64b8aa..fa4421a28a 100644 --- a/scene/resources/default_theme/tab_menu.png +++ b/scene/resources/default_theme/tab_menu.png diff --git a/scene/resources/default_theme/tab_menu_hl.png b/scene/resources/default_theme/tab_menu_hl.png Binary files differindex 148b64b8aa..fa4421a28a 100644 --- a/scene/resources/default_theme/tab_menu_hl.png +++ b/scene/resources/default_theme/tab_menu_hl.png diff --git a/scene/resources/default_theme/toggle_off.png b/scene/resources/default_theme/toggle_off.png Binary files differindex 71cd64b001..64b51c8c9d 100644 --- a/scene/resources/default_theme/toggle_off.png +++ b/scene/resources/default_theme/toggle_off.png diff --git a/scene/resources/default_theme/toggle_on.png b/scene/resources/default_theme/toggle_on.png Binary files differindex 6ea1b589c7..f0c699c181 100644 --- a/scene/resources/default_theme/toggle_on.png +++ b/scene/resources/default_theme/toggle_on.png diff --git a/scene/resources/default_theme/tool_button_pressed.png b/scene/resources/default_theme/tool_button_pressed.png Binary files differindex bcf70b486d..5494475792 100644 --- a/scene/resources/default_theme/tool_button_pressed.png +++ b/scene/resources/default_theme/tool_button_pressed.png diff --git a/scene/resources/default_theme/tooltip_bg.png b/scene/resources/default_theme/tooltip_bg.png Binary files differindex eca0675a98..07b7d942ca 100644 --- a/scene/resources/default_theme/tooltip_bg.png +++ b/scene/resources/default_theme/tooltip_bg.png diff --git a/scene/resources/default_theme/tree_bg.png b/scene/resources/default_theme/tree_bg.png Binary files differindex 839a6a272a..2b0c506f34 100644 --- a/scene/resources/default_theme/tree_bg.png +++ b/scene/resources/default_theme/tree_bg.png diff --git a/scene/resources/default_theme/tree_bg_disabled.png b/scene/resources/default_theme/tree_bg_disabled.png Binary files differindex a0fa505e4c..69d78febd9 100644 --- a/scene/resources/default_theme/tree_bg_disabled.png +++ b/scene/resources/default_theme/tree_bg_disabled.png diff --git a/scene/resources/default_theme/tree_bg_focus.png b/scene/resources/default_theme/tree_bg_focus.png Binary files differindex 692cf71926..aadc6b0db4 100644 --- a/scene/resources/default_theme/tree_bg_focus.png +++ b/scene/resources/default_theme/tree_bg_focus.png diff --git a/scene/resources/default_theme/tree_cursor.png b/scene/resources/default_theme/tree_cursor.png Binary files differindex 94d2a08818..2b8722d066 100644 --- a/scene/resources/default_theme/tree_cursor.png +++ b/scene/resources/default_theme/tree_cursor.png diff --git a/scene/resources/default_theme/tree_cursor_unfocus.png b/scene/resources/default_theme/tree_cursor_unfocus.png Binary files differindex 3f023bbabe..bfaebbea85 100644 --- a/scene/resources/default_theme/tree_cursor_unfocus.png +++ b/scene/resources/default_theme/tree_cursor_unfocus.png diff --git a/scene/resources/default_theme/tree_title.png b/scene/resources/default_theme/tree_title.png Binary files differindex b0ddcffbbe..e5f3f49695 100644 --- a/scene/resources/default_theme/tree_title.png +++ b/scene/resources/default_theme/tree_title.png diff --git a/scene/resources/default_theme/tree_title_pressed.png b/scene/resources/default_theme/tree_title_pressed.png Binary files differindex 746d10039e..35e2bb3008 100644 --- a/scene/resources/default_theme/tree_title_pressed.png +++ b/scene/resources/default_theme/tree_title_pressed.png diff --git a/scene/resources/default_theme/unchecked.png b/scene/resources/default_theme/unchecked.png Binary files differindex d6f790cbc2..8c818af755 100644 --- a/scene/resources/default_theme/unchecked.png +++ b/scene/resources/default_theme/unchecked.png diff --git a/scene/resources/default_theme/updown.png b/scene/resources/default_theme/updown.png Binary files differindex 916284a3cf..56f81921e8 100644 --- a/scene/resources/default_theme/updown.png +++ b/scene/resources/default_theme/updown.png diff --git a/scene/resources/default_theme/vseparator.png b/scene/resources/default_theme/vseparator.png Binary files differindex 498768c05b..51e79f3ac5 100644 --- a/scene/resources/default_theme/vseparator.png +++ b/scene/resources/default_theme/vseparator.png diff --git a/scene/resources/default_theme/vslider_bg.png b/scene/resources/default_theme/vslider_bg.png Binary files differindex 8d9ead3c5a..ba3244e3e5 100644 --- a/scene/resources/default_theme/vslider_bg.png +++ b/scene/resources/default_theme/vslider_bg.png diff --git a/scene/resources/default_theme/vslider_grabber.png b/scene/resources/default_theme/vslider_grabber.png Binary files differindex afc490be45..6c6bf93e68 100644 --- a/scene/resources/default_theme/vslider_grabber.png +++ b/scene/resources/default_theme/vslider_grabber.png diff --git a/scene/resources/default_theme/vslider_grabber_disabled.png b/scene/resources/default_theme/vslider_grabber_disabled.png Binary files differindex c830359f45..49cced5055 100644 --- a/scene/resources/default_theme/vslider_grabber_disabled.png +++ b/scene/resources/default_theme/vslider_grabber_disabled.png diff --git a/scene/resources/default_theme/vslider_grabber_hl.png b/scene/resources/default_theme/vslider_grabber_hl.png Binary files differindex 548972e115..28774fdbf8 100644 --- a/scene/resources/default_theme/vslider_grabber_hl.png +++ b/scene/resources/default_theme/vslider_grabber_hl.png diff --git a/scene/resources/default_theme/vslider_tick.png b/scene/resources/default_theme/vslider_tick.png Binary files differindex 873ebb00d8..bde788b563 100644 --- a/scene/resources/default_theme/vslider_tick.png +++ b/scene/resources/default_theme/vslider_tick.png diff --git a/scene/resources/default_theme/vsplit_bg.png b/scene/resources/default_theme/vsplit_bg.png Binary files differindex 7dd1d48b29..a5749f6d5c 100644 --- a/scene/resources/default_theme/vsplit_bg.png +++ b/scene/resources/default_theme/vsplit_bg.png diff --git a/scene/resources/default_theme/vsplitter.png b/scene/resources/default_theme/vsplitter.png Binary files differindex ec5542bf69..dde1f390df 100644 --- a/scene/resources/default_theme/vsplitter.png +++ b/scene/resources/default_theme/vsplitter.png diff --git a/scene/resources/default_theme/window_resizer.png b/scene/resources/default_theme/window_resizer.png Binary files differindex ed51968c4e..b06e6f5366 100644 --- a/scene/resources/default_theme/window_resizer.png +++ b/scene/resources/default_theme/window_resizer.png diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index 05493d5777..e5d463d391 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -625,7 +625,7 @@ void DynamicFontAtSize::_update_char(CharType p_char) { break; } - int error = FT_Load_Char(face, p_char, FT_HAS_COLOR(face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); + int error = FT_Load_Char(face, p_char, FT_HAS_COLOR(face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting); if (error) { char_map[p_char] = character; return; diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 3fab4d3cfc..d3da842b79 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -378,7 +378,7 @@ bool Environment::is_ssr_rough() const { void Environment::set_ssao_enabled(bool p_enable) { ssao_enabled = p_enable; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); _change_notify(); } @@ -390,7 +390,7 @@ bool Environment::is_ssao_enabled() const { void Environment::set_ssao_radius(float p_radius) { ssao_radius = p_radius; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); } float Environment::get_ssao_radius() const { @@ -400,7 +400,7 @@ float Environment::get_ssao_radius() const { void Environment::set_ssao_intensity(float p_intensity) { ssao_intensity = p_intensity; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); } float Environment::get_ssao_intensity() const { @@ -411,7 +411,7 @@ float Environment::get_ssao_intensity() const { void Environment::set_ssao_radius2(float p_radius) { ssao_radius2 = p_radius; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); } float Environment::get_ssao_radius2() const { @@ -421,7 +421,7 @@ float Environment::get_ssao_radius2() const { void Environment::set_ssao_intensity2(float p_intensity) { ssao_intensity2 = p_intensity; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); } float Environment::get_ssao_intensity2() const { @@ -431,7 +431,7 @@ float Environment::get_ssao_intensity2() const { void Environment::set_ssao_bias(float p_bias) { ssao_bias = p_bias; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); } float Environment::get_ssao_bias() const { @@ -441,17 +441,27 @@ float Environment::get_ssao_bias() const { void Environment::set_ssao_direct_light_affect(float p_direct_light_affect) { ssao_direct_light_affect = p_direct_light_affect; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); } float Environment::get_ssao_direct_light_affect() const { return ssao_direct_light_affect; } +void Environment::set_ssao_ao_channel_affect(float p_ao_channel_affect) { + + ssao_ao_channel_affect = p_ao_channel_affect; + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); +} +float Environment::get_ssao_ao_channel_affect() const { + + return ssao_ao_channel_affect; +} + void Environment::set_ssao_color(const Color &p_color) { ssao_color = p_color; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); } Color Environment::get_ssao_color() const { @@ -462,7 +472,7 @@ Color Environment::get_ssao_color() const { void Environment::set_ssao_blur(SSAOBlur p_blur) { ssao_blur = p_blur; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); } Environment::SSAOBlur Environment::get_ssao_blur() const { @@ -472,7 +482,7 @@ Environment::SSAOBlur Environment::get_ssao_blur() const { void Environment::set_ssao_quality(SSAOQuality p_quality) { ssao_quality = p_quality; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); } Environment::SSAOQuality Environment::get_ssao_quality() const { @@ -483,7 +493,7 @@ Environment::SSAOQuality Environment::get_ssao_quality() const { void Environment::set_ssao_edge_sharpness(float p_edge_sharpness) { ssao_edge_sharpness = p_edge_sharpness; - VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); } float Environment::get_ssao_edge_sharpness() const { @@ -1008,6 +1018,9 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ssao_direct_light_affect", "amount"), &Environment::set_ssao_direct_light_affect); ClassDB::bind_method(D_METHOD("get_ssao_direct_light_affect"), &Environment::get_ssao_direct_light_affect); + ClassDB::bind_method(D_METHOD("set_ssao_ao_channel_affect", "amount"), &Environment::set_ssao_ao_channel_affect); + ClassDB::bind_method(D_METHOD("get_ssao_ao_channel_affect"), &Environment::get_ssao_ao_channel_affect); + ClassDB::bind_method(D_METHOD("set_ssao_color", "color"), &Environment::set_ssao_color); ClassDB::bind_method(D_METHOD("get_ssao_color"), &Environment::get_ssao_color); @@ -1028,6 +1041,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_intensity2", PROPERTY_HINT_RANGE, "0.0,128,0.1"), "set_ssao_intensity2", "get_ssao_intensity2"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_bias", PROPERTY_HINT_RANGE, "0.001,8,0.001"), "set_ssao_bias", "get_ssao_bias"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_light_affect", PROPERTY_HINT_RANGE, "0.00,1,0.01"), "set_ssao_direct_light_affect", "get_ssao_direct_light_affect"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_ao_channel_affect", PROPERTY_HINT_RANGE, "0.00,1,0.01"), "set_ssao_ao_channel_affect", "get_ssao_ao_channel_affect"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ssao_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ssao_color", "get_ssao_color"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ssao_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_ssao_quality", "get_ssao_quality"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ssao_blur", PROPERTY_HINT_ENUM, "Disabled,1x1,2x2,3x3"), "set_ssao_blur", "get_ssao_blur"); @@ -1220,6 +1234,7 @@ Environment::Environment() { ssao_intensity2 = 1; ssao_bias = 0.01; ssao_direct_light_affect = 0.0; + ssao_ao_channel_affect = 0.0; ssao_blur = SSAO_BLUR_3x3; set_ssao_edge_sharpness(4); set_ssao_quality(SSAO_QUALITY_LOW); diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 27fd57aa09..7d66c7e60b 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -127,6 +127,7 @@ private: float ssao_intensity2; float ssao_bias; float ssao_direct_light_affect; + float ssao_ao_channel_affect; Color ssao_color; SSAOBlur ssao_blur; float ssao_edge_sharpness; @@ -274,6 +275,9 @@ public: void set_ssao_direct_light_affect(float p_direct_light_affect); float get_ssao_direct_light_affect() const; + void set_ssao_ao_channel_affect(float p_ao_channel_affect); + float get_ssao_ao_channel_affect() const; + void set_ssao_color(const Color &p_color); Color get_ssao_color() const; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 5e7569586a..56b3ee70bb 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -145,11 +145,17 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const { void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) { + if (shader.is_valid()) { + shader->disconnect("changed", this, "_shader_changed"); + } + shader = p_shader; RID rid; - if (shader.is_valid()) + if (shader.is_valid()) { rid = shader->get_rid(); + shader->connect("changed", this, "_shader_changed"); + } VS::get_singleton()->material_set_shader(_get_material(), rid); _change_notify(); //properties for shader exposed @@ -171,12 +177,17 @@ Variant ShaderMaterial::get_shader_param(const StringName &p_param) const { return VS::get_singleton()->material_get_param(_get_material(), p_param); } +void ShaderMaterial::_shader_changed() { + _change_notify(); //update all properties +} + void ShaderMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shader", "shader"), &ShaderMaterial::set_shader); ClassDB::bind_method(D_METHOD("get_shader"), &ShaderMaterial::get_shader); ClassDB::bind_method(D_METHOD("set_shader_param", "param", "value"), &ShaderMaterial::set_shader_param); ClassDB::bind_method(D_METHOD("get_shader_param", "param"), &ShaderMaterial::get_shader_param); + ClassDB::bind_method(D_METHOD("_shader_changed"), &ShaderMaterial::_shader_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shader", PROPERTY_HINT_RESOURCE_TYPE, "Shader"), "set_shader", "get_shader"); } @@ -393,6 +404,12 @@ void SpatialMaterial::_update_shader() { if (flags[FLAG_DONT_RECEIVE_SHADOWS]) { code += ",shadows_disabled"; } + if (flags[FLAG_DISABLE_AMBIENT_LIGHT]) { + code += ",ambient_light_disabled"; + } + if (flags[FLAG_ENSURE_CORRECT_NORMALS]) { + code += ",ensure_correct_normals"; + } code += ";\n"; code += "uniform vec4 albedo : hint_color;\n"; @@ -1852,6 +1869,8 @@ void SpatialMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_fixed_size"), "set_flag", "get_flag", FLAG_FIXED_SIZE); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_albedo_tex_force_srgb"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_FORCE_SRGB); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_do_not_receive_shadows"), "set_flag", "get_flag", FLAG_DONT_RECEIVE_SHADOWS); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_disable_ambient_light"), "set_flag", "get_flag", FLAG_DISABLE_AMBIENT_LIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_ensure_correct_normals"), "set_flag", "get_flag", FLAG_ENSURE_CORRECT_NORMALS); ADD_GROUP("Vertex Color", "vertex_color"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "vertex_color_use_as_albedo"), "set_flag", "get_flag", FLAG_ALBEDO_FROM_VERTEX_COLOR); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "vertex_color_is_srgb"), "set_flag", "get_flag", FLAG_SRGB_VERTEX_COLOR); @@ -2042,6 +2061,8 @@ void SpatialMaterial::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_TRIPLANAR_USE_WORLD); BIND_ENUM_CONSTANT(FLAG_ALBEDO_TEXTURE_FORCE_SRGB); BIND_ENUM_CONSTANT(FLAG_DONT_RECEIVE_SHADOWS); + BIND_ENUM_CONSTANT(FLAG_DISABLE_AMBIENT_LIGHT); + BIND_ENUM_CONSTANT(FLAG_ENSURE_CORRECT_NORMALS); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(DIFFUSE_BURLEY); diff --git a/scene/resources/material.h b/scene/resources/material.h index ce733bfb8d..84f1005b03 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -92,6 +92,8 @@ protected: virtual bool _can_do_next_pass() const; + void _shader_changed(); + public: void set_shader(const Ref<Shader> &p_shader); Ref<Shader> get_shader() const; @@ -189,6 +191,8 @@ public: FLAG_USE_ALPHA_SCISSOR, FLAG_ALBEDO_TEXTURE_FORCE_SRGB, FLAG_DONT_RECEIVE_SHADOWS, + FLAG_ENSURE_CORRECT_NORMALS, + FLAG_DISABLE_AMBIENT_LIGHT, FLAG_MAX }; @@ -237,7 +241,7 @@ private: uint64_t blend_mode : 2; uint64_t depth_draw_mode : 2; uint64_t cull_mode : 2; - uint64_t flags : 15; + uint64_t flags : 17; uint64_t detail_blend_mode : 2; uint64_t diffuse_mode : 3; uint64_t specular_mode : 2; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index b0620d3363..fe87dcdd2c 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -40,7 +40,6 @@ void Mesh::_clear_triangle_mesh() const { triangle_mesh.unref(); - ; } Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { @@ -110,6 +109,54 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { return triangle_mesh; } +void Mesh::generate_debug_mesh_lines(Vector<Vector3> &r_lines) { + + Ref<TriangleMesh> tm = generate_triangle_mesh(); + if (tm.is_null()) + return; + + PoolVector<int> triangle_indices; + tm->get_indices(&triangle_indices); + const int triangles_num = tm->get_triangles().size(); + PoolVector<Vector3> vertices = tm->get_vertices(); + + r_lines.resize(tm->get_triangles().size() * 6); // 3 lines x 2 points each line + + PoolVector<int>::Read ind_r = triangle_indices.read(); + PoolVector<Vector3>::Read ver_r = vertices.read(); + for (int j = 0, x = 0, i = 0; i < triangles_num; j += 6, x += 3, ++i) { + // Triangle line 1 + r_lines[j + 0] = ver_r[ind_r[x + 0]]; + r_lines[j + 1] = ver_r[ind_r[x + 1]]; + + // Triangle line 2 + r_lines[j + 2] = ver_r[ind_r[x + 1]]; + r_lines[j + 3] = ver_r[ind_r[x + 2]]; + + // Triangle line 3 + r_lines[j + 4] = ver_r[ind_r[x + 2]]; + r_lines[j + 5] = ver_r[ind_r[x + 0]]; + } +} +void Mesh::generate_debug_mesh_indices(Vector<Vector3> &r_points) { + Ref<TriangleMesh> tm = generate_triangle_mesh(); + if (tm.is_null()) + return; + + PoolVector<Vector3> vertices = tm->get_vertices(); + + int vertices_size = vertices.size(); + r_points.resize(vertices_size); + for (int i = 0; i < vertices_size; ++i) { + r_points[i] = vertices[i]; + } +} + +bool Mesh::surface_is_softbody_friendly(int p_idx) const { + const uint32_t surface_format = surface_get_format(p_idx); + return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE && (!(surface_format & Mesh::ARRAY_COMPRESS_VERTEX)) && (!(surface_format & Mesh::ARRAY_COMPRESS_NORMAL))); +} + PoolVector<Face3> Mesh::get_faces() const { Ref<TriangleMesh> tm = generate_triangle_mesh(); @@ -484,6 +531,10 @@ void Mesh::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_MAX); } +void Mesh::clear_cache() { + _clear_triangle_mesh(); +} + Mesh::Mesh() { } diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index e8b7ecaf9a..2127eaae4c 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -100,7 +100,7 @@ public: ARRAY_FLAG_USE_16_BIT_BONES = ARRAY_COMPRESS_INDEX << 2, ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3, - ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_VERTEX | ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 | ARRAY_COMPRESS_WEIGHTS + ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 | ARRAY_COMPRESS_WEIGHTS }; @@ -123,6 +123,7 @@ public: virtual int get_surface_count() const = 0; virtual int surface_get_array_len(int p_idx) const = 0; virtual int surface_get_array_index_len(int p_idx) const = 0; + virtual bool surface_is_softbody_friendly(int p_idx) const; virtual Array surface_get_arrays(int p_surface) const = 0; virtual Array surface_get_blend_shape_arrays(int p_surface) const = 0; virtual uint32_t surface_get_format(int p_idx) const = 0; @@ -133,6 +134,8 @@ public: PoolVector<Face3> get_faces() const; Ref<TriangleMesh> generate_triangle_mesh() const; + void generate_debug_mesh_lines(Vector<Vector3> &r_lines); + void generate_debug_mesh_indices(Vector<Vector3> &r_points); Ref<Shape> create_trimesh_shape() const; Ref<Shape> create_convex_shape() const; @@ -143,6 +146,7 @@ public: void set_lightmap_size_hint(const Vector2 &p_size); Size2 get_lightmap_size_hint() const; + void clear_cache(); Mesh(); }; diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp new file mode 100644 index 0000000000..de3cfd1371 --- /dev/null +++ b/scene/resources/physics_material.cpp @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* physics_material.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "physics_material.h" + +bool PhysicsMaterial::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "bounce") { + set_bounce(p_value); + } else if (p_name == "bounce_combine_mode") { + set_bounce_combine_mode(static_cast<PhysicsServer::CombineMode>(int(p_value))); + } else if (p_name == "friction") { + set_friction(p_value); + } else if (p_name == "friction_combine_mode") { + set_friction_combine_mode(static_cast<PhysicsServer::CombineMode>(int(p_value))); + } else { + return false; + } + + emit_changed(); + return true; +} + +bool PhysicsMaterial::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == "bounce") { + r_ret = bounce; + } else if (p_name == "bounce_combine_mode") { + r_ret = int(bounce_combine_mode); + } else if (p_name == "friction") { + r_ret = friction; + } else if (p_name == "friction_combine_mode") { + r_ret = int(friction_combine_mode); + } else { + return false; + } + + return true; +} + +void PhysicsMaterial::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::REAL, "bounce")); + p_list->push_back(PropertyInfo(Variant::INT, "bounce_combine_mode", PROPERTY_HINT_ENUM, "Max,Min,Multiply,Average")); + p_list->push_back(PropertyInfo(Variant::REAL, "friction")); + p_list->push_back(PropertyInfo(Variant::INT, "friction_combine_mode", PROPERTY_HINT_ENUM, "Max,Min,Multiply,Average")); +} + +void PhysicsMaterial::_bind_methods() {} + +void PhysicsMaterial::set_bounce(real_t p_val) { + bounce = p_val; +} + +void PhysicsMaterial::set_bounce_combine_mode(PhysicsServer::CombineMode p_val) { + bounce_combine_mode = p_val; +} + +void PhysicsMaterial::set_friction(real_t p_val) { + friction = p_val; +} + +void PhysicsMaterial::set_friction_combine_mode(PhysicsServer::CombineMode p_val) { + friction_combine_mode = p_val; +} + +PhysicsMaterial::PhysicsMaterial() : + bounce(0), + bounce_combine_mode(PhysicsServer::COMBINE_MODE_MAX), + friction(0), + friction_combine_mode(PhysicsServer::COMBINE_MODE_MULTIPLY) {} diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h new file mode 100644 index 0000000000..a6cb8c288e --- /dev/null +++ b/scene/resources/physics_material.h @@ -0,0 +1,70 @@ +/*************************************************************************/ +/* physics_material.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef physics_material_override_H +#define physics_material_override_H + +#include "resource.h" +#include "servers/physics_server.h" + +class PhysicsMaterial : public Resource { + + GDCLASS(PhysicsMaterial, Resource); + OBJ_SAVE_TYPE(PhysicsMaterial); + RES_BASE_EXTENSION("PhyMat"); + + real_t bounce; + PhysicsServer::CombineMode bounce_combine_mode; + real_t friction; + PhysicsServer::CombineMode friction_combine_mode; + +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<PropertyInfo> *p_list) const; + + static void _bind_methods(); + +public: + void set_bounce(real_t p_val); + _FORCE_INLINE_ real_t get_bounce() const { return bounce; } + + void set_bounce_combine_mode(PhysicsServer::CombineMode p_val); + _FORCE_INLINE_ PhysicsServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; } + + void set_friction(real_t p_val); + _FORCE_INLINE_ real_t get_friction() const { return friction; } + + void set_friction_combine_mode(PhysicsServer::CombineMode p_val); + _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; } + + PhysicsMaterial(); +}; + +#endif // physics_material_override_H diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 5b600623b9..28aa6f1aa7 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -419,10 +419,10 @@ void CapsuleMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CapsuleMesh::set_rings); ClassDB::bind_method(D_METHOD("get_rings"), &CapsuleMesh::get_rings); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "mid_height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_mid_height", "get_mid_height"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "mid_height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_mid_height", "get_mid_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings"); } void CapsuleMesh::set_radius(const float p_radius) { @@ -677,9 +677,9 @@ void CubeMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &CubeMesh::get_subdivide_depth); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_width", "get_subdivide_width"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_height", "get_subdivide_height"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_depth", "get_subdivide_depth"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_height", "get_subdivide_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth"); } void CubeMesh::set_size(const Vector3 &p_size) { @@ -881,11 +881,11 @@ void CylinderMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CylinderMesh::set_rings); ClassDB::bind_method(D_METHOD("get_rings"), &CylinderMesh::get_rings); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "top_radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_top_radius", "get_top_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "bottom_radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_bottom_radius", "get_bottom_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_height", "get_height"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "top_radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_top_radius", "get_top_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bottom_radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_bottom_radius", "get_bottom_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings"); } void CylinderMesh::set_top_radius(const float p_radius) { @@ -1017,8 +1017,8 @@ void PlaneMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PlaneMesh::get_subdivide_depth); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_width", "get_subdivide_width"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_depth", "get_subdivide_depth"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth"); } void PlaneMesh::set_size(const Size2 &p_size) { @@ -1283,9 +1283,9 @@ void PrismMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "left_to_right", PROPERTY_HINT_RANGE, "-2.0,2.0,0.1"), "set_left_to_right", "get_left_to_right"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_width", "get_subdivide_width"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_height", "get_subdivide_height"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_depth", "get_subdivide_depth"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_height", "get_subdivide_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth"); } void PrismMesh::set_left_to_right(const float p_left_to_right) { @@ -1352,10 +1352,10 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const { PoolVector<float> tangents; PoolVector<Vector2> uvs; - faces.resize(4); - normals.resize(4); - tangents.resize(4 * 4); - uvs.resize(4); + faces.resize(6); + normals.resize(6); + tangents.resize(6 * 4); + uvs.resize(6); Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f); @@ -1366,9 +1366,15 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const { Vector3(_size.x, -_size.y, 0), }; - for (int i = 0; i < 4; i++) { + static const int indices[6] = { + 0, 1, 2, + 0, 2, 3 + }; + + for (int i = 0; i < 6; i++) { - faces.set(i, quad_faces[i]); + int j = indices[i]; + faces.set(i, quad_faces[j]); normals.set(i, Vector3(0, 0, 1)); tangents.set(i * 4 + 0, 1.0); tangents.set(i * 4 + 1, 0.0); @@ -1382,14 +1388,14 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const { Vector2(1, 1), }; - uvs.set(i, quad_uv[i]); + uvs.set(i, quad_uv[j]); } p_arr[VS::ARRAY_VERTEX] = faces; p_arr[VS::ARRAY_NORMAL] = normals; p_arr[VS::ARRAY_TANGENT] = tangents; p_arr[VS::ARRAY_TEX_UV] = uvs; -}; +} void QuadMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size); @@ -1398,7 +1404,7 @@ void QuadMesh::_bind_methods() { } QuadMesh::QuadMesh() { - primitive_type = PRIMITIVE_TRIANGLE_FAN; + primitive_type = PRIMITIVE_TRIANGLES; size = Size2(1.0, 1.0); } @@ -1499,10 +1505,10 @@ void SphereMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_is_hemisphere", "is_hemisphere"), &SphereMesh::set_is_hemisphere); ClassDB::bind_method(D_METHOD("get_is_hemisphere"), &SphereMesh::get_is_hemisphere); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_height", "get_height"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_hemisphere"), "set_is_hemisphere", "get_is_hemisphere"); } diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp index 597866eb74..9df117d09c 100644 --- a/scene/resources/scene_format_text.cpp +++ b/scene/resources/scene_format_text.cpp @@ -896,7 +896,7 @@ static void bs_save_unicode_string(FileAccess *f, const String &p_string, bool p CharString utf8 = p_string.utf8(); if (p_bit_on_len) { - f->store_32(utf8.length() + 1 | 0x80000000); + f->store_32((utf8.length() + 1) | 0x80000000); } else { f->store_32(utf8.length() + 1); } diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 36740a307b..f53f03c1c8 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -54,16 +54,20 @@ void Shader::set_code(const String &p_code) { VisualServer::get_singleton()->shader_set_code(shader, p_code); params_cache_dirty = true; - emit_signal(SceneStringNames::get_singleton()->changed); + + emit_changed(); } String Shader::get_code() const { + _update_shader(); return VisualServer::get_singleton()->shader_get_code(shader); } void Shader::get_param_list(List<PropertyInfo> *p_params) const { + _update_shader(); + List<PropertyInfo> local; VisualServer::get_singleton()->shader_get_param_list(shader, &local); params_cache.clear(); @@ -72,6 +76,9 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const { for (List<PropertyInfo>::Element *E = local.front(); E; E = E->next()) { PropertyInfo pi = E->get(); + if (default_textures.has(pi.name)) { //do not show default textures + continue; + } pi.name = "shader_param/" + pi.name; params_cache[pi.name] = E->get().name; if (p_params) { @@ -86,6 +93,8 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const { RID Shader::get_rid() const { + _update_shader(); + return shader; } @@ -98,6 +107,8 @@ void Shader::set_default_texture_param(const StringName &p_param, const Ref<Text default_textures.erase(p_param); VS::get_singleton()->shader_set_default_texture_param(shader, p_param, RID()); } + + emit_changed(); } Ref<Texture> Shader::get_default_texture_param(const StringName &p_param) const { @@ -120,6 +131,9 @@ bool Shader::has_param(const StringName &p_param) const { return params_cache.has(p_param); } +void Shader::_update_shader() const { +} + void Shader::_bind_methods() { ClassDB::bind_method(D_METHOD("get_mode"), &Shader::get_mode); @@ -227,5 +241,5 @@ void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, } bool ResourceFormatSaverShader::recognize(const RES &p_resource) const { - return Object::cast_to<Shader>(*p_resource) != NULL; + return p_resource->get_class_name() == "Shader"; //only shader, not inherited } diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 248a6f0125..efc5da7753 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -61,12 +61,13 @@ private: mutable Map<StringName, StringName> params_cache; //map a shader param to a material param.. Map<StringName, Ref<Texture> > default_textures; + virtual void _update_shader() const; //used for visual shader protected: static void _bind_methods(); public: //void set_mode(Mode p_mode); - Mode get_mode() const; + virtual Mode get_mode() const; void set_code(const String &p_code); String get_code() const; diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index ebad00b068..fb81375b0a 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -905,12 +905,20 @@ bool StyleBoxLine::is_vertical() const { return vertical; } -void StyleBoxLine::set_grow(float p_grow) { - grow = p_grow; +void StyleBoxLine::set_grow_end(float p_grow_end) { + grow_end = p_grow_end; emit_changed(); } -float StyleBoxLine::get_grow() const { - return grow; +float StyleBoxLine::get_grow_end() const { + return grow_end; +} + +void StyleBoxLine::set_grow_begin(float p_grow_begin) { + grow_begin = p_grow_begin; + emit_changed(); +} +float StyleBoxLine::get_grow_begin() const { + return grow_begin; } void StyleBoxLine::_bind_methods() { @@ -919,13 +927,16 @@ void StyleBoxLine::_bind_methods() { ClassDB::bind_method(D_METHOD("get_color"), &StyleBoxLine::get_color); ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &StyleBoxLine::set_thickness); ClassDB::bind_method(D_METHOD("get_thickness"), &StyleBoxLine::get_thickness); - ClassDB::bind_method(D_METHOD("set_grow", "grow"), &StyleBoxLine::set_grow); - ClassDB::bind_method(D_METHOD("get_grow"), &StyleBoxLine::get_grow); + ClassDB::bind_method(D_METHOD("set_grow_begin", "offset"), &StyleBoxLine::set_grow_begin); + ClassDB::bind_method(D_METHOD("get_grow_begin"), &StyleBoxLine::get_grow_begin); + ClassDB::bind_method(D_METHOD("set_grow_end", "offset"), &StyleBoxLine::set_grow_end); + ClassDB::bind_method(D_METHOD("get_grow_end"), &StyleBoxLine::get_grow_end); ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &StyleBoxLine::set_vertical); ClassDB::bind_method(D_METHOD("is_vertical"), &StyleBoxLine::is_vertical); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "grow", PROPERTY_HINT_RANGE, "-300,300,1"), "set_grow", "get_grow"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "grow_begin", PROPERTY_HINT_RANGE, "-300,300,1"), "set_grow_begin", "get_grow_begin"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "grow_end", PROPERTY_HINT_RANGE, "-300,300,1"), "set_grow_end", "get_grow_end"); ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,10"), "set_thickness", "get_thickness"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical"); } @@ -941,12 +952,12 @@ void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const { Rect2i r = p_rect; if (vertical) { - r.position.y -= grow; - r.size.y += grow * 2; + r.position.y -= grow_begin; + r.size.y += (grow_begin + grow_end); r.size.x = thickness; } else { - r.position.x -= grow; - r.size.x += grow * 2; + r.position.x -= grow_begin; + r.size.x += (grow_begin + grow_end); r.size.y = thickness; } @@ -954,7 +965,8 @@ void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const { } StyleBoxLine::StyleBoxLine() { - grow = 1.0; + grow_begin = 1.0; + grow_end = 1.0; thickness = 1; color = Color(0.0, 0.0, 0.0); vertical = false; diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index c1d84fe19f..ed193a1ab4 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -236,7 +236,8 @@ class StyleBoxLine : public StyleBox { Color color; int thickness; bool vertical; - float grow; + float grow_begin; + float grow_end; protected: virtual float get_style_margin(Margin p_margin) const; @@ -252,8 +253,11 @@ public: void set_vertical(bool p_vertical); bool is_vertical() const; - void set_grow(float p_grow); - float get_grow() const; + void set_grow_begin(float p_grow); + float get_grow_begin() const; + + void set_grow_end(float p_grow); + float get_grow_end() const; virtual Size2 get_center_size() const; diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 5a42873d79..3df9ab26a4 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -421,6 +421,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_ Array a = commit_to_arrays(); mesh->add_surface_from_arrays(primitive, a, Array(), p_flags); + if (material.is_valid()) mesh->surface_set_material(surface, material); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 54f5aea160..2baad555c0 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -1669,3 +1669,208 @@ ProxyTexture::~ProxyTexture() { VS::get_singleton()->free(proxy); } +////////////////////////////////////////////// + +void AnimatedTexture::_update_proxy() { + + _THREAD_SAFE_METHOD_ + + float delta; + if (prev_ticks == 0) { + delta = 0; + prev_ticks = OS::get_singleton()->get_ticks_usec(); + } else { + uint64_t ticks = OS::get_singleton()->get_ticks_usec(); + delta = float(double(ticks - prev_ticks) / 1000000.0); + prev_ticks = ticks; + } + + time += delta; + + float limit; + + if (fps == 0) { + limit = 0; + } else { + limit = 1.0 / fps; + } + + int iter_max = frame_count; + while (iter_max) { + float frame_limit = limit + frames[current_frame].delay_sec; + + if (time > frame_limit) { + current_frame++; + if (current_frame >= frame_count) { + current_frame = 0; + } + time -= frame_limit; + } else { + break; + } + iter_max--; + } + + if (frames[current_frame].texture.is_valid()) { + VisualServer::get_singleton()->texture_set_proxy(proxy, frames[current_frame].texture->get_rid()); + } +} + +void AnimatedTexture::set_frames(int p_frames) { + ERR_FAIL_COND(p_frames < 1 || p_frames > MAX_FRAMES); + + _THREAD_SAFE_METHOD_ + + frame_count = p_frames; +} +int AnimatedTexture::get_frames() const { + return frame_count; +} + +void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture> &p_texture) { + ERR_FAIL_INDEX(p_frame, MAX_FRAMES); + + _THREAD_SAFE_METHOD_ + + frames[p_frame].texture = p_texture; +} +Ref<Texture> AnimatedTexture::get_frame_texture(int p_frame) const { + ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, Ref<Texture>()); + + _THREAD_SAFE_METHOD_ + + return frames[p_frame].texture; +} + +void AnimatedTexture::set_frame_delay(int p_frame, float p_delay_sec) { + ERR_FAIL_INDEX(p_frame, MAX_FRAMES); + + _THREAD_SAFE_METHOD_ + + frames[p_frame].delay_sec = p_delay_sec; +} +float AnimatedTexture::get_frame_delay(int p_frame) const { + ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, 0); + + _THREAD_SAFE_METHOD_ + + return frames[p_frame].delay_sec; +} + +void AnimatedTexture::set_fps(float p_fps) { + ERR_FAIL_COND(p_fps < 0 || p_fps >= 1000); + + fps = p_fps; +} +float AnimatedTexture::get_fps() const { + return fps; +} + +int AnimatedTexture::get_width() const { + + _THREAD_SAFE_METHOD_ + + if (!frames[current_frame].texture.is_valid()) { + return 1; + } + + return frames[current_frame].texture->get_width(); +} +int AnimatedTexture::get_height() const { + + _THREAD_SAFE_METHOD_ + + if (!frames[current_frame].texture.is_valid()) { + return 1; + } + + return frames[current_frame].texture->get_height(); +} +RID AnimatedTexture::get_rid() const { + return proxy; +} + +bool AnimatedTexture::has_alpha() const { + + _THREAD_SAFE_METHOD_ + + if (!frames[current_frame].texture.is_valid()) { + return false; + } + + return frames[current_frame].texture->has_alpha(); +} + +Ref<Image> AnimatedTexture::get_data() const { + + _THREAD_SAFE_METHOD_ + + if (!frames[current_frame].texture.is_valid()) { + return Ref<Image>(); + } + + return frames[current_frame].texture->get_data(); +} + +void AnimatedTexture::set_flags(uint32_t p_flags) { +} +uint32_t AnimatedTexture::get_flags() const { + + _THREAD_SAFE_METHOD_ + + if (!frames[current_frame].texture.is_valid()) { + return 0; + } + + return frames[current_frame].texture->get_flags(); +} + +void AnimatedTexture::_validate_property(PropertyInfo &property) const { + + String prop = property.name; + if (prop.begins_with("frame_")) { + int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int(); + if (frame >= frame_count) { + property.usage = 0; + } + } +} + +void AnimatedTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_frames", "frames"), &AnimatedTexture::set_frames); + ClassDB::bind_method(D_METHOD("get_frames"), &AnimatedTexture::get_frames); + + ClassDB::bind_method(D_METHOD("set_fps", "fps"), &AnimatedTexture::set_fps); + ClassDB::bind_method(D_METHOD("get_fps"), &AnimatedTexture::get_fps); + + ClassDB::bind_method(D_METHOD("set_frame_texture", "frame", "texture"), &AnimatedTexture::set_frame_texture); + ClassDB::bind_method(D_METHOD("get_frame_texture", "frame"), &AnimatedTexture::get_frame_texture); + + ClassDB::bind_method(D_METHOD("set_frame_delay", "frame", "delay"), &AnimatedTexture::set_frame_delay); + ClassDB::bind_method(D_METHOD("get_frame_delay", "frame"), &AnimatedTexture::get_frame_delay); + + ClassDB::bind_method(D_METHOD("_update_proxy"), &AnimatedTexture::_update_proxy); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "fps", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_fps", "get_fps"); + + for (int i = 0; i < MAX_FRAMES; i++) { + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_frame_texture", "get_frame_texture", i); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01"), "set_frame_delay", "get_frame_delay", i); + } +} + +AnimatedTexture::AnimatedTexture() { + proxy = VS::get_singleton()->texture_create(); + VisualServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true); + time = 0; + frame_count = 1; + fps = 4; + prev_ticks = 0; + current_frame = 0; + VisualServer::get_singleton()->connect("frame_pre_draw", this, "_update_proxy"); +} + +AnimatedTexture::~AnimatedTexture() { + VS::get_singleton()->free(proxy); +} diff --git a/scene/resources/texture.h b/scene/resources/texture.h index d81fd3b19b..c994bdad5f 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -34,10 +34,11 @@ #include "curve.h" #include "io/resource_loader.h" #include "math_2d.h" +#include "os/mutex.h" +#include "os/thread_safe.h" #include "resource.h" #include "scene/resources/color_ramp.h" #include "servers/visual_server.h" - /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -521,4 +522,70 @@ public: ~ProxyTexture(); }; +class AnimatedTexture : public Texture { + GDCLASS(AnimatedTexture, Texture) + + _THREAD_SAFE_CLASS_ + +private: + enum { + MAX_FRAMES = 256 + }; + + RID proxy; + + struct Frame { + + Ref<Texture> texture; + float delay_sec; + + Frame() { + delay_sec = 0; + } + }; + + Frame frames[MAX_FRAMES]; + int frame_count; + int current_frame; + + float fps; + + float time; + + uint64_t prev_ticks; + + void _update_proxy(); + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; + +public: + void set_frames(int p_frames); + int get_frames() const; + + void set_frame_texture(int p_frame, const Ref<Texture> &p_texture); + Ref<Texture> get_frame_texture(int p_frame) const; + + void set_frame_delay(int p_frame, float p_delay_sec); + float get_frame_delay(int p_frame) const; + + void set_fps(float p_fps); + float get_fps() const; + + virtual int get_width() const; + virtual int get_height() const; + virtual RID get_rid() const; + + virtual bool has_alpha() const; + + virtual void set_flags(uint32_t p_flags); + virtual uint32_t get_flags() const; + + virtual Ref<Image> get_data() const; + + AnimatedTexture(); + ~AnimatedTexture(); +}; + #endif diff --git a/scene/resources/theme.h b/scene/resources/theme.h index c23f237c75..e0d4038e7e 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -55,12 +55,12 @@ class Theme : public Resource { void _unref_font(Ref<Font> p_sc); void _emit_theme_changed(); - HashMap<StringName, HashMap<StringName, Ref<Texture>, StringNameHasher>, StringNameHasher> icon_map; - HashMap<StringName, HashMap<StringName, Ref<StyleBox>, StringNameHasher>, StringNameHasher> style_map; - HashMap<StringName, HashMap<StringName, Ref<Font>, StringNameHasher>, StringNameHasher> font_map; - HashMap<StringName, HashMap<StringName, Ref<Shader>, StringNameHasher>, StringNameHasher> shader_map; - HashMap<StringName, HashMap<StringName, Color, StringNameHasher>, StringNameHasher> color_map; - HashMap<StringName, HashMap<StringName, int, StringNameHasher>, StringNameHasher> constant_map; + HashMap<StringName, HashMap<StringName, Ref<Texture> > > icon_map; + HashMap<StringName, HashMap<StringName, Ref<StyleBox> > > style_map; + HashMap<StringName, HashMap<StringName, Ref<Font> > > font_map; + HashMap<StringName, HashMap<StringName, Ref<Shader> > > shader_map; + HashMap<StringName, HashMap<StringName, Color> > color_map; + HashMap<StringName, HashMap<StringName, int> > constant_map; protected: bool _set(const StringName &p_name, const Variant &p_value); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp new file mode 100644 index 0000000000..b7b7802d1b --- /dev/null +++ b/scene/resources/visual_shader.cpp @@ -0,0 +1,1555 @@ +#include "visual_shader.h" +#include "servers/visual/shader_types.h" +#include "vmap.h" + +void VisualShaderNode::set_output_port_for_preview(int p_index) { + + port_preview = p_index; +} + +int VisualShaderNode::get_output_port_for_preview() const { + + return port_preview; +} + +void VisualShaderNode::set_input_port_default_value(int p_port, const Variant &p_value) { + default_input_values[p_port] = p_value; + emit_changed(); +} + +Variant VisualShaderNode::get_input_port_default_value(int p_port) const { + if (default_input_values.has(p_port)) { + return default_input_values[p_port]; + } + + return Variant(); +} + +bool VisualShaderNode::is_port_separator(int p_index) const { + return false; +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + return Vector<VisualShader::DefaultTextureParam>(); +} +String VisualShaderNode::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return String(); +} + +Vector<StringName> VisualShaderNode::get_editable_properties() const { + return Vector<StringName>(); +} + +Array VisualShaderNode::_get_default_input_values() const { + + Array ret; + for (Map<int, Variant>::Element *E = default_input_values.front(); E; E = E->next()) { + ret.push_back(E->key()); + ret.push_back(E->get()); + } + return ret; +} +void VisualShaderNode::_set_default_input_values(const Array &p_values) { + + if (p_values.size() % 2 == 0) { + for (int i = 0; i < p_values.size(); i += 2) { + default_input_values[p_values[i + 0]] = p_values[i + 1]; + } + } + + emit_changed(); +} + +String VisualShaderNode::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { + return String(); +} + +void VisualShaderNode::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_output_port_for_preview", "port"), &VisualShaderNode::set_output_port_for_preview); + ClassDB::bind_method(D_METHOD("get_output_port_for_preview"), &VisualShaderNode::get_output_port_for_preview); + + ClassDB::bind_method(D_METHOD("set_input_port_default_value", "port", "value"), &VisualShaderNode::set_input_port_default_value); + ClassDB::bind_method(D_METHOD("get_input_port_default_value", "port"), &VisualShaderNode::get_input_port_default_value); + + ClassDB::bind_method(D_METHOD("_set_default_input_values", "values"), &VisualShaderNode::_set_default_input_values); + ClassDB::bind_method(D_METHOD("_get_default_input_values"), &VisualShaderNode::_get_default_input_values); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview"); + ADD_PROPERTYNZ(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_default_input_values", "_get_default_input_values"); + ADD_SIGNAL(MethodInfo("editor_refresh_request")); +} + +VisualShaderNode::VisualShaderNode() { + port_preview = -1; +} + +///////////////////////////////////////////////////////// + +void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id) { + ERR_FAIL_COND(p_node.is_null()); + ERR_FAIL_COND(p_id < 2); + ERR_FAIL_INDEX(p_type, TYPE_MAX); + Graph *g = &graph[p_type]; + ERR_FAIL_COND(g->nodes.has(p_id)); + Node n; + n.node = p_node; + n.position = p_position; + + Ref<VisualShaderNodeUniform> uniform = n.node; + if (uniform.is_valid()) { + String valid_name = validate_uniform_name(uniform->get_uniform_name(), uniform); + uniform->set_uniform_name(valid_name); + } + + Ref<VisualShaderNodeInput> input = n.node; + if (input.is_valid()) { + input->shader_mode = shader_mode; + input->shader_type = p_type; + input->connect("input_type_changed", this, "_input_type_changed", varray(p_type, p_id)); + } + + n.node->connect("changed", this, "_queue_update"); + + g->nodes[p_id] = n; + + _queue_update(); +} + +void VisualShader::set_node_position(Type p_type, int p_id, const Vector2 &p_position) { + ERR_FAIL_INDEX(p_type, TYPE_MAX); + Graph *g = &graph[p_type]; + ERR_FAIL_COND(!g->nodes.has(p_id)); + g->nodes[p_id].position = p_position; +} + +Vector2 VisualShader::get_node_position(Type p_type, int p_id) const { + ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Vector2()); + const Graph *g = &graph[p_type]; + ERR_FAIL_COND_V(!g->nodes.has(p_id), Vector2()); + return g->nodes[p_id].position; +} +Ref<VisualShaderNode> VisualShader::get_node(Type p_type, int p_id) const { + ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Ref<VisualShaderNode>()); + const Graph *g = &graph[p_type]; + ERR_FAIL_COND_V(!g->nodes.has(p_id), Ref<VisualShaderNode>()); + return g->nodes[p_id].node; +} + +Vector<int> VisualShader::get_node_list(Type p_type) const { + ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Vector<int>()); + const Graph *g = &graph[p_type]; + + Vector<int> ret; + for (Map<int, Node>::Element *E = g->nodes.front(); E; E = E->next()) { + ret.push_back(E->key()); + } + + return ret; +} +int VisualShader::get_valid_node_id(Type p_type) const { + ERR_FAIL_INDEX_V(p_type, TYPE_MAX, NODE_ID_INVALID); + const Graph *g = &graph[p_type]; + return g->nodes.size() ? MAX(2, g->nodes.back()->key() + 1) : 2; +} + +int VisualShader::find_node_id(Type p_type, const Ref<VisualShaderNode> &p_node) const { + for (const Map<int, Node>::Element *E = graph[p_type].nodes.front(); E; E = E->next()) { + if (E->get().node == p_node) + return E->key(); + } + + return NODE_ID_INVALID; +} + +void VisualShader::remove_node(Type p_type, int p_id) { + ERR_FAIL_INDEX(p_type, TYPE_MAX); + ERR_FAIL_COND(p_id < 2); + Graph *g = &graph[p_type]; + ERR_FAIL_COND(!g->nodes.has(p_id)); + + Ref<VisualShaderNodeInput> input = g->nodes[p_id].node; + if (input.is_valid()) { + input->disconnect("input_type_changed", this, "_input_type_changed"); + } + + g->nodes[p_id].node->disconnect("changed", this, "_queue_update"); + + g->nodes.erase(p_id); + + for (List<Connection>::Element *E = g->connections.front(); E;) { + List<Connection>::Element *N = E->next(); + if (E->get().from_node == p_id || E->get().to_node == p_id) { + g->connections.erase(E); + } + E = N; + } + + _queue_update(); +} + +bool VisualShader::is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const { + ERR_FAIL_INDEX_V(p_type, TYPE_MAX, false); + const Graph *g = &graph[p_type]; + + for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) { + + if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) { + return true; + } + } + + return false; +} + +bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const { + + ERR_FAIL_INDEX_V(p_type, TYPE_MAX, false); + const Graph *g = &graph[p_type]; + + if (!g->nodes.has(p_from_node)) + return false; + + if (p_from_port < 0 || p_from_port >= g->nodes[p_from_node].node->get_output_port_count()) + return false; + + if (!g->nodes.has(p_to_node)) + return false; + + if (p_to_port < 0 || p_to_port >= g->nodes[p_to_node].node->get_input_port_count()) + return false; + + VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port); + VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port); + + if (MAX(0, from_port_type - 1) != (MAX(0, to_port_type - 1))) { + return false; + } + + for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) { + + if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) { + return false; + } + } + + return true; +} + +Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { + ERR_FAIL_INDEX_V(p_type, TYPE_MAX, ERR_CANT_CONNECT); + Graph *g = &graph[p_type]; + + ERR_FAIL_COND_V(!g->nodes.has(p_from_node), ERR_INVALID_PARAMETER); + ERR_FAIL_INDEX_V(p_from_port, g->nodes[p_from_node].node->get_output_port_count(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!g->nodes.has(p_to_node), ERR_INVALID_PARAMETER); + ERR_FAIL_INDEX_V(p_to_port, g->nodes[p_to_node].node->get_input_port_count(), ERR_INVALID_PARAMETER); + + VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port); + VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port); + + if (MAX(0, from_port_type - 1) != (MAX(0, to_port_type - 1))) { + ERR_EXPLAIN("Incompatible port types (scalar/vec with transform"); + ERR_FAIL_V(ERR_INVALID_PARAMETER) + return ERR_INVALID_PARAMETER; + } + + for (List<Connection>::Element *E = g->connections.front(); E; E = E->next()) { + + if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) { + ERR_FAIL_V(ERR_ALREADY_EXISTS); + } + } + + Connection c; + c.from_node = p_from_node; + c.from_port = p_from_port; + c.to_node = p_to_node; + c.to_port = p_to_port; + g->connections.push_back(c); + + _queue_update(); + return OK; +} +void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { + ERR_FAIL_INDEX(p_type, TYPE_MAX); + Graph *g = &graph[p_type]; + + for (List<Connection>::Element *E = g->connections.front(); E; E = E->next()) { + + if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) { + g->connections.erase(E); + _queue_update(); + return; + } + } +} + +Array VisualShader::_get_node_connections(Type p_type) const { + ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Array()); + const Graph *g = &graph[p_type]; + + Array ret; + for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) { + Dictionary d; + d["from_node"] = E->get().from_node; + d["from_port"] = E->get().from_port; + d["to_node"] = E->get().to_node; + d["to_port"] = E->get().to_port; + ret.push_back(d); + } + + return ret; +} +void VisualShader::get_node_connections(Type p_type, List<Connection> *r_connections) const { + ERR_FAIL_INDEX(p_type, TYPE_MAX); + const Graph *g = &graph[p_type]; + + for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) { + r_connections->push_back(E->get()); + } +} + +void VisualShader::set_mode(Mode p_mode) { + if (shader_mode == p_mode) { + return; + } + + //erase input/output connections + modes.clear(); + flags.clear(); + shader_mode = p_mode; + for (int i = 0; i < TYPE_MAX; i++) { + + for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) { + + Ref<VisualShaderNodeInput> input = E->get().node; + if (input.is_valid()) { + input->shader_mode = shader_mode; + //input->input_index = 0; + } + } + + Ref<VisualShaderNodeOutput> output = graph[i].nodes[NODE_ID_OUTPUT].node; + output->shader_mode = shader_mode; + + // clear connections since they are no longer valid + for (List<Connection>::Element *E = graph[i].connections.front(); E;) { + + bool keep = true; + + List<Connection>::Element *N = E->next(); + + int from = E->get().from_node; + int to = E->get().to_node; + + if (!graph[i].nodes.has(from)) { + keep = false; + } else { + Ref<VisualShaderNode> from_node = graph[i].nodes[from].node; + if (from_node->is_class("VisualShaderNodeOutput") || from_node->is_class("VisualShaderNodeInput")) { + keep = false; + } + } + + if (!graph[i].nodes.has(to)) { + keep = false; + } else { + Ref<VisualShaderNode> to_node = graph[i].nodes[to].node; + if (to_node->is_class("VisualShaderNodeOutput") || to_node->is_class("VisualShaderNodeInput")) { + keep = false; + } + } + + if (!keep) { + graph[i].connections.erase(E); + } + E = N; + } + } + + _queue_update(); + _change_notify(); +} + +void VisualShader::set_graph_offset(const Vector2 &p_offset) { + graph_offset = p_offset; +} + +Vector2 VisualShader::get_graph_offset() const { + return graph_offset; +} + +Shader::Mode VisualShader::get_mode() const { + return shader_mode; +} + +String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &default_tex_params) const { + + Ref<VisualShaderNode> node = get_node(p_type, p_node); + ERR_FAIL_COND_V(!node.is_valid(), String()); + ERR_FAIL_COND_V(p_port < 0 || p_port >= node->get_output_port_count(), String()); + ERR_FAIL_COND_V(node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_TRANSFORM, String()); + + StringBuilder global_code; + StringBuilder code; + + global_code += String() + "shader_type canvas_item;\n"; + + //make it faster to go around through shader + VMap<ConnectionKey, const List<Connection>::Element *> input_connections; + VMap<ConnectionKey, const List<Connection>::Element *> output_connections; + + for (const List<Connection>::Element *E = graph[p_type].connections.front(); E; E = E->next()) { + ConnectionKey from_key; + from_key.node = E->get().from_node; + from_key.port = E->get().from_port; + + output_connections.insert(from_key, E); + + ConnectionKey to_key; + to_key.node = E->get().to_node; + to_key.port = E->get().to_port; + + input_connections.insert(to_key, E); + } + + code += "\nvoid fragment() {\n"; + + Set<int> processed; + Error err = _write_node(p_type, global_code, code, default_tex_params, input_connections, output_connections, p_node, processed, true); + ERR_FAIL_COND_V(err != OK, String()); + + if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_SCALAR) { + code += "\tCOLOR.rgb = vec3( n_out" + itos(p_node) + "p" + itos(p_port) + " );\n"; + } else { + code += "\tCOLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n"; + } + code += "}\n"; + + //set code secretly + global_code += "\n\n"; + String final_code = global_code; + final_code += code; + //print_line(final_code); + return final_code; +} + +#define IS_INITIAL_CHAR(m_d) (((m_d) >= 'a' && (m_d) <= 'z') || ((m_d) >= 'A' && (m_d) <= 'Z')) + +#define IS_SYMBOL_CHAR(m_d) (((m_d) >= 'a' && (m_d) <= 'z') || ((m_d) >= 'A' && (m_d) <= 'Z') || ((m_d) >= '0' && (m_d) <= '9') || (m_d) == '_') + +String VisualShader::validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const { + + String name = p_name; //validate name first + while (name.length() && !IS_INITIAL_CHAR(name[0])) { + name = name.substr(1, name.length() - 1); + } + if (name != String()) { + + String valid_name; + + for (int i = 0; i < name.length(); i++) { + if (IS_SYMBOL_CHAR(name[i])) { + valid_name += String::chr(name[i]); + } else if (name[i] == ' ') { + valid_name += "_"; + } + } + + name = valid_name; + } + + if (name == String()) { + name = p_uniform->get_caption(); + } + + int attempt = 1; + + while (true) { + + bool exists = false; + for (int i = 0; i < TYPE_MAX; i++) { + for (const Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) { + Ref<VisualShaderNodeUniform> node = E->get().node; + if (node == p_uniform) { //do not test on self + continue; + } + if (node.is_valid() && node->get_uniform_name() == name) { + exists = true; + break; + } + } + if (exists) { + break; + } + } + + if (exists) { + //remove numbers, put new and try again + attempt++; + while (name.length() && name[name.length() - 1] >= '0' && name[name.length() - 1] <= '9') { + name = name.substr(0, name.length() - 1); + } + ERR_FAIL_COND_V(name == String(), String()); + name += itos(attempt); + } else { + break; + } + } + + return name; +} + +VisualShader::RenderModeEnums VisualShader::render_mode_enums[] = { + { Shader::MODE_SPATIAL, "blend" }, + { Shader::MODE_SPATIAL, "depth_draw" }, + { Shader::MODE_SPATIAL, "cull" }, + { Shader::MODE_SPATIAL, "diffuse" }, + { Shader::MODE_SPATIAL, "specular" }, + { Shader::MODE_CANVAS_ITEM, "blend" }, + { Shader::MODE_CANVAS_ITEM, NULL } +}; + +static const char *type_string[VisualShader::TYPE_MAX] = { + "vertex", + "fragment", + "light" +}; +bool VisualShader::_set(const StringName &p_name, const Variant &p_value) { + + String name = p_name; + if (name == "mode") { + set_mode(Shader::Mode(int(p_value))); + return true; + } else if (name.begins_with("flags/")) { + StringName flag = name.get_slicec('/', 1); + bool enable = p_value; + if (enable) { + flags.insert(flag); + } else { + flags.erase(flag); + } + _queue_update(); + return true; + } else if (name.begins_with("modes/")) { + String mode = name.get_slicec('/', 1); + int value = p_value; + if (value == 0) { + modes.erase(mode); //means its default anyway, so dont store it + } else { + modes[mode] = value; + } + _queue_update(); + return true; + } else if (name.begins_with("nodes/")) { + String typestr = name.get_slicec('/', 1); + Type type = TYPE_VERTEX; + for (int i = 0; i < TYPE_MAX; i++) { + if (typestr == type_string[i]) { + type = Type(i); + break; + } + } + + String index = name.get_slicec('/', 2); + if (index == "connections") { + + Vector<int> conns = p_value; + if (conns.size() % 4 == 0) { + for (int i = 0; i < conns.size(); i += 4) { + connect_nodes(type, conns[i + 0], conns[i + 1], conns[i + 2], conns[i + 3]); + } + } + return true; + } + + int id = index.to_int(); + String what = name.get_slicec('/', 3); + + if (what == "node") { + add_node(type, p_value, Vector2(), id); + return true; + } else if (what == "position") { + set_node_position(type, id, p_value); + return true; + } + } + return false; +} + +bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const { + + String name = p_name; + if (name == "mode") { + r_ret = get_mode(); + return true; + } else if (name.begins_with("flags/")) { + StringName flag = name.get_slicec('/', 1); + r_ret = flags.has(flag); + return true; + } else if (name.begins_with("modes/")) { + String mode = name.get_slicec('/', 1); + if (modes.has(mode)) { + r_ret = modes[mode]; + } else { + r_ret = 0; + } + return true; + } else if (name.begins_with("nodes/")) { + String typestr = name.get_slicec('/', 1); + Type type = TYPE_VERTEX; + for (int i = 0; i < TYPE_MAX; i++) { + if (typestr == type_string[i]) { + type = Type(i); + break; + } + } + + String index = name.get_slicec('/', 2); + if (index == "connections") { + + Vector<int> conns; + for (const List<Connection>::Element *E = graph[type].connections.front(); E; E = E->next()) { + conns.push_back(E->get().from_node); + conns.push_back(E->get().from_port); + conns.push_back(E->get().to_node); + conns.push_back(E->get().to_port); + } + + r_ret = conns; + return true; + } + + int id = index.to_int(); + String what = name.get_slicec('/', 3); + + if (what == "node") { + r_ret = get_node(type, id); + return true; + } else if (what == "position") { + r_ret = get_node_position(type, id); + return true; + } + } + return false; +} +void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const { + + //mode + p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Spatial,CanvasItem,Particles")); + //render modes + + Map<String, String> blend_mode_enums; + Set<String> toggles; + + for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode)).size(); i++) { + + String mode = ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode))[i]; + int idx = 0; + bool in_enum = false; + while (render_mode_enums[idx].string) { + if (mode.begins_with(render_mode_enums[idx].string)) { + String begin = render_mode_enums[idx].string; + String option = mode.replace_first(begin + "_", ""); + if (!blend_mode_enums.has(begin)) { + blend_mode_enums[begin] = option; + } else { + blend_mode_enums[begin] += "," + option; + } + in_enum = true; + break; + } + idx++; + } + + if (!in_enum) { + toggles.insert(mode); + } + } + + for (Map<String, String>::Element *E = blend_mode_enums.front(); E; E = E->next()) { + + p_list->push_back(PropertyInfo(Variant::INT, "modes/" + E->key(), PROPERTY_HINT_ENUM, E->get())); + } + + for (Set<String>::Element *E = toggles.front(); E; E = E->next()) { + p_list->push_back(PropertyInfo(Variant::BOOL, "flags/" + E->get())); + } + + for (int i = 0; i < TYPE_MAX; i++) { + for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) { + + String prop_name = "nodes/"; + prop_name += type_string[i]; + prop_name += "/" + itos(E->key()); + + if (E->key() != NODE_ID_OUTPUT) { + + p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); + } + p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + } + p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "nodes/" + String(type_string[i]) + "/connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + } +} + +Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview) const { + + const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node; + + //check inputs recursively first + int input_count = vsnode->get_input_port_count(); + for (int i = 0; i < input_count; i++) { + ConnectionKey ck; + ck.node = node; + ck.port = i; + + if (input_connections.has(ck)) { + int from_node = input_connections[ck]->get().from_node; + if (processed.has(from_node)) { + continue; + } + + Error err = _write_node(type, global_code, code, def_tex_params, input_connections, output_connections, from_node, processed, for_preview); + if (err) + return err; + } + } + + // then this node + + code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n"; + Vector<String> input_vars; + + input_vars.resize(vsnode->get_input_port_count()); + String *inputs = input_vars.ptrw(); + + for (int i = 0; i < input_count; i++) { + ConnectionKey ck; + ck.node = node; + ck.port = i; + + if (input_connections.has(ck)) { + //connected to something, use that output + int from_node = input_connections[ck]->get().from_node; + int from_port = input_connections[ck]->get().from_port; + + VisualShaderNode::PortType in_type = vsnode->get_input_port_type(i); + VisualShaderNode::PortType out_type = graph[type].nodes[from_node].node->get_output_port_type(from_port); + + String src_var = "n_out" + itos(from_node) + "p" + itos(from_port); + + if (in_type == out_type) { + inputs[i] = src_var; + } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_VECTOR) { + inputs[i] = "dot(" + src_var + ",vec3(0.333333,0.333333,0.333333))"; + } else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_SCALAR) { + inputs[i] = "vec3(" + src_var + ")"; + } + } else { + + Variant defval = vsnode->get_input_port_default_value(i); + if (defval.get_type() == Variant::REAL || defval.get_type() == Variant::INT) { + float val = defval; + inputs[i] = "n_in" + itos(node) + "p" + itos(i); + code += "\tfloat " + inputs[i] + " = " + vformat("%.5f", val) + ";\n"; + } else if (defval.get_type() == Variant::VECTOR3) { + Vector3 val = defval; + inputs[i] = "n_in" + itos(node) + "p" + itos(i); + code += "\tvec3 " + inputs[i] + " = " + vformat("vec3(%.5f,%.5f,%.5f);\n", val.x, val.y, val.z); + } else if (defval.get_type() == Variant::TRANSFORM) { + Transform val = defval; + val.basis.transpose(); + inputs[i] = "n_in" + itos(node) + "p" + itos(i); + Array values; + for (int i = 0; i < 3; i++) { + values.push_back(val.basis[i].x); + values.push_back(val.basis[i].y); + values.push_back(val.basis[i].z); + } + values.push_back(val.origin.x); + values.push_back(val.origin.y); + values.push_back(val.origin.z); + bool err = false; + code += "\tmat4 " + inputs[i] + " = " + String("mat4( vec4(%.5f,%.5f,%.5f,0.0),vec4(%.5f,%.5f,%.5f,0.0),vec4(%.5f,%.5f,%.5f,0.0),vec4(%.5f,%.5f,%.5f,1.0) );\n").sprintf(values, &err); + } else { + //will go empty, node is expected to know what it is doing at this point and handle it + } + } + } + + int output_count = vsnode->get_output_port_count(); + Vector<String> output_vars; + output_vars.resize(vsnode->get_output_port_count()); + String *outputs = output_vars.ptrw(); + + for (int i = 0; i < output_count; i++) { + + outputs[i] = "n_out" + itos(node) + "p" + itos(i); + switch (vsnode->get_output_port_type(i)) { + case VisualShaderNode::PORT_TYPE_SCALAR: code += String() + "\tfloat " + outputs[i] + ";\n"; break; + case VisualShaderNode::PORT_TYPE_VECTOR: code += String() + "\tvec3 " + outputs[i] + ";\n"; break; + case VisualShaderNode::PORT_TYPE_TRANSFORM: code += String() + "\tmat4 " + outputs[i] + ";\n"; break; + default: {} + } + } + + Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node); + for (int i = 0; i < params.size(); i++) { + def_tex_params.push_back(params[i]); + } + + Ref<VisualShaderNodeInput> input = vsnode; + + if (input.is_valid() && for_preview) { + //handle for preview + code += input->generate_code_for_preview(type, node, inputs, outputs); + } else { + //handle normally + global_code += vsnode->generate_global(get_mode(), type, node); + code += vsnode->generate_code(get_mode(), type, node, inputs, outputs); + } + code += "\n"; // + processed.insert(node); + + return OK; +} + +void VisualShader::_update_shader() const { + if (!dirty) + return; + + dirty = false; + + StringBuilder global_code; + StringBuilder code; + Vector<VisualShader::DefaultTextureParam> default_tex_params; + static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles" }; + + global_code += String() + "shader_type " + shader_mode_str[shader_mode] + ";\n"; + + String render_mode; + + { + //fill render mode enums + int idx = 0; + while (render_mode_enums[idx].string) { + + if (shader_mode == render_mode_enums[idx].mode) { + + if (modes.has(render_mode_enums[idx].string)) { + + int which = modes[render_mode_enums[idx].string]; + int count = 0; + for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode)).size(); i++) { + String mode = ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode))[i]; + if (mode.begins_with(render_mode_enums[idx].string)) { + if (count == which) { + if (render_mode != String()) { + render_mode += ", "; + } + render_mode += mode; + break; + } + count++; + } + } + } + } + idx++; + } + + //fill render mode flags + for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode)).size(); i++) { + + String mode = ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode))[i]; + if (flags.has(mode)) { + if (render_mode != String()) { + render_mode += ", "; + } + render_mode += mode; + } + } + } + + if (render_mode != String()) { + + global_code += "render_mode " + render_mode + ";\n\n"; + } + + static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" }; + + for (int i = 0; i < TYPE_MAX; i++) { + + //make it faster to go around through shader + VMap<ConnectionKey, const List<Connection>::Element *> input_connections; + VMap<ConnectionKey, const List<Connection>::Element *> output_connections; + + for (const List<Connection>::Element *E = graph[i].connections.front(); E; E = E->next()) { + ConnectionKey from_key; + from_key.node = E->get().from_node; + from_key.port = E->get().from_port; + + output_connections.insert(from_key, E); + + ConnectionKey to_key; + to_key.node = E->get().to_node; + to_key.port = E->get().to_port; + + input_connections.insert(to_key, E); + } + + code += "\nvoid " + String(func_name[i]) + "() {\n"; + + Set<int> processed; + Error err = _write_node(Type(i), global_code, code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false); + ERR_FAIL_COND(err != OK); + + code += "}\n"; + } + + //set code secretly + global_code += "\n\n"; + String final_code = global_code; + final_code += code; + const_cast<VisualShader *>(this)->set_code(final_code); + //print_line(final_code); + for (int i = 0; i < default_tex_params.size(); i++) { + const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].param); + } +} + +void VisualShader::_queue_update() { + if (dirty) { + return; + } + + dirty = true; + call_deferred("_update_shader"); +} + +void VisualShader::_input_type_changed(Type p_type, int p_id) { + //erase connections using this input, as type changed + Graph *g = &graph[p_type]; + + for (List<Connection>::Element *E = g->connections.front(); E;) { + List<Connection>::Element *N = E->next(); + if (E->get().from_node == p_id) { + g->connections.erase(E); + } + E = N; + } +} + +void VisualShader::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_mode", "mode"), &VisualShader::set_mode); + + ClassDB::bind_method(D_METHOD("add_node", "type", "node", "position", "id"), &VisualShader::add_node); + ClassDB::bind_method(D_METHOD("set_node_position", "type", "id", "position"), &VisualShader::set_node_position); + + ClassDB::bind_method(D_METHOD("get_node_position", "type", "id"), &VisualShader::get_node_position); + ClassDB::bind_method(D_METHOD("get_node", "type"), &VisualShader::get_node); + + ClassDB::bind_method(D_METHOD("get_node_list", "type"), &VisualShader::get_node_list); + ClassDB::bind_method(D_METHOD("get_valid_node_id", "type"), &VisualShader::get_valid_node_id); + + ClassDB::bind_method(D_METHOD("remove_node", "type", "id"), &VisualShader::remove_node); + + ClassDB::bind_method(D_METHOD("is_node_connection", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection); + ClassDB::bind_method(D_METHOD("can_connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection); + + ClassDB::bind_method(D_METHOD("connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes); + ClassDB::bind_method(D_METHOD("disconnect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::disconnect_nodes); + + ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections); + + ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &VisualShader::set_graph_offset); + ClassDB::bind_method(D_METHOD("get_graph_offset"), &VisualShader::get_graph_offset); + + ClassDB::bind_method(D_METHOD("_queue_update"), &VisualShader::_queue_update); + ClassDB::bind_method(D_METHOD("_update_shader"), &VisualShader::_update_shader); + + ClassDB::bind_method(D_METHOD("_input_type_changed"), &VisualShader::_input_type_changed); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset"); + + BIND_ENUM_CONSTANT(TYPE_VERTEX); + BIND_ENUM_CONSTANT(TYPE_FRAGMENT); + BIND_ENUM_CONSTANT(TYPE_LIGHT); + BIND_ENUM_CONSTANT(TYPE_MAX); + + BIND_CONSTANT(NODE_ID_INVALID); + BIND_CONSTANT(NODE_ID_OUTPUT); +} + +VisualShader::VisualShader() { + shader_mode = Shader::MODE_SPATIAL; + + for (int i = 0; i < TYPE_MAX; i++) { + Ref<VisualShaderNodeOutput> output; + output.instance(); + output->shader_type = Type(i); + output->shader_mode = shader_mode; + graph[i].nodes[NODE_ID_OUTPUT].node = output; + graph[i].nodes[NODE_ID_OUTPUT].position = Vector2(400, 150); + } + + dirty = true; +} + +/////////////////////////////////////////////////////////// + +const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { + // Spatial, Vertex + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "TANGENT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "BINORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV2,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(VIEWPORT_SIZE, 0)" }, + + // Spatial, Fragment + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "TANGENT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "BINORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV2,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec2(POINT_COORD,0.0)" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "side", "float(FRONT_FACING ? 1.0 : 0.0)" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(VIEWPORT_SIZE, 0.0)" }, + + // Spatial, Light + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "view", "VIEW" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_color", "LIGHT_COLOR" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "attenuation", "ATTENUATION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "transmission", "TRANSMISSION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(VIEWPORT_SIZE, 0.0)" }, + // Canvas Item, Vertex + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" }, + + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION_MATRIX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "extra", "EXTRA_MATRIX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "light_pass", "float(AT_LIGHT_PASS ? 1.0 : 0.0)" }, + // Canvas Item, Fragment + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec2(POINT_COORD,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light_pass", "float(AT_LIGHT_PASS ? 1.0 : 0.0)" }, + // Canvas Item, Light + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_vec", "vec3(LIGHT_VEC,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_height", "LIGHT_HEIGHT" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_color", "LIGHT_COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_alpha", "LIGHT_COLOR.a" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_uv", "vec3(LIGHT_UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "shadow_color", "SHADOW_COLOR.rgb" }, + + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec2(POINT_COORD,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Particles, Vertex + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "index", "float(INDEX)" }, + + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, NULL, NULL }, +}; + +const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { + + // Spatial, Fragment + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0,0.0,1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "vec3(0.0,1.0,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "vec3(1.0,0.0,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(UV,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "side", "1.0" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(1.0,1.0, 0.0)" }, + + // Spatial, Light + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0,0.0,1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(1.0, 1.0, 0.0)" }, + // Canvas Item, Vertex + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Canvas Item, Fragment + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Canvas Item, Light + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0,0.0,1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, + + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Particles, Vertex + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "vec3(0.0,0.0,1.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, NULL, NULL }, +}; + +int VisualShaderNodeInput::get_input_port_count() const { + + return 0; +} +VisualShaderNodeInput::PortType VisualShaderNodeInput::get_input_port_type(int p_port) const { + + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeInput::get_input_port_name(int p_port) const { + + return ""; +} + +int VisualShaderNodeInput::get_output_port_count() const { + + return 1; +} +VisualShaderNodeInput::PortType VisualShaderNodeInput::get_output_port_type(int p_port) const { + + return get_input_type_by_name(input_name); +} +String VisualShaderNodeInput::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeInput::get_caption() const { + return TTR("Input"); +} + +String VisualShaderNodeInput::generate_code_for_preview(VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + int idx = 0; + + String code; + + while (preview_ports[idx].mode != Shader::MODE_MAX) { + if (preview_ports[idx].mode == shader_mode && preview_ports[idx].shader_type == shader_type && preview_ports[idx].name == input_name) { + code = "\t" + p_output_vars[0] + " = " + preview_ports[idx].string + ";\n"; + break; + } + idx++; + } + + if (code == String()) { + switch (get_output_port_type(0)) { + case PORT_TYPE_SCALAR: { + code = "\t" + p_output_vars[0] + " = 0.0;\n"; + } break; //default (none found) is scalar + case PORT_TYPE_VECTOR: { + code = "\t" + p_output_vars[0] + " = vec3(0.0);\n"; + } break; //default (none found) is scalar + case PORT_TYPE_TRANSFORM: { + code = "\t" + p_output_vars[0] + " = mat4( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), vec4(0.0,0.0,1.0,0.0), vec4(0.0,0.0,0.0,1.0) );\n"; + } break; //default (none found) is scalar + } + } + + return code; +} + +String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + int idx = 0; + + String code; + + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == input_name) { + code = "\t" + p_output_vars[0] + " = " + ports[idx].string + ";\n"; + break; + } + idx++; + } + + if (code == String()) { + code = "\t" + p_output_vars[0] + " = 0.0;\n"; //default (none found) is scalar + } + + return code; +} + +void VisualShaderNodeInput::set_input_name(String p_name) { + PortType prev_type = get_input_type_by_name(input_name); + input_name = p_name; + emit_changed(); + if (get_input_type_by_name(input_name) != prev_type) { + emit_signal("input_type_changed"); + } +} + +String VisualShaderNodeInput::get_input_name() const { + return input_name; +} + +VisualShaderNodeInput::PortType VisualShaderNodeInput::get_input_type_by_name(String p_name) const { + + int idx = 0; + + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == p_name) { + return ports[idx].type; + } + idx++; + } + + return PORT_TYPE_SCALAR; +} + +int VisualShaderNodeInput::get_input_index_count() const { + int idx = 0; + int count = 0; + + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) { + count++; + } + idx++; + } + + return count; +} + +VisualShaderNodeInput::PortType VisualShaderNodeInput::get_input_index_type(int p_index) const { + int idx = 0; + int count = 0; + + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) { + if (count == p_index) { + return ports[idx].type; + } + count++; + } + idx++; + } + + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeInput::get_input_index_name(int p_index) const { + int idx = 0; + int count = 0; + + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) { + if (count == p_index) { + return ports[idx].name; + } + count++; + } + idx++; + } + + return ""; +} + +void VisualShaderNodeInput::_validate_property(PropertyInfo &property) const { + + if (property.name == "input_name") { + String port_list; + + int idx = 0; + + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) { + if (port_list != String()) { + port_list += ","; + } + port_list += ports[idx].name; + } + idx++; + } + + if (port_list == "") { + port_list = TTR("None"); + } + property.hint_string = port_list; + } +} + +Vector<StringName> VisualShaderNodeInput::get_editable_properties() const { + Vector<StringName> props; + props.push_back("input_name"); + return props; +} + +void VisualShaderNodeInput::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_input_name", "name"), &VisualShaderNodeInput::set_input_name); + ClassDB::bind_method(D_METHOD("get_input_name"), &VisualShaderNodeInput::get_input_name); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "input_name", PROPERTY_HINT_ENUM, ""), "set_input_name", "get_input_name"); + ADD_SIGNAL(MethodInfo("input_type_changed")); +} +VisualShaderNodeInput::VisualShaderNodeInput() { + input_name = "[None]"; + // changed when set + shader_type = VisualShader::TYPE_MAX; + shader_mode = Shader::MODE_MAX; +} + +//////////////////////////////////////////// + +const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { + // Spatial, Vertex + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "TANGENT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "BINORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "UV:xy" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "UV2:xy" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, + // Spatial, Fragment + + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular", "SPECULAR" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "emission", "EMISSION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao", "AO" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normalmap", "NORMALMAP" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normalmap_depth", "NORMALMAP_DEPTH" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim", "RIM" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim_tint", "RIM_TINT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat", "CLEARCOAT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat_gloss", "CLEARCOAT_GLOSS" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "anisotropy", "ANISOTROPY" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "anisotropy_flow", "ANISOTROPY_FLOW:xy" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "subsurf_scatter", "SSS_STRENGTH" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "transmission", "TRANSMISSION" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_scissor", "ALPHA_SCISSOR" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao_light_affect", "AO_LIGHT_AFFECT" }, + + // Spatial, Light + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "diffuse", "DIFFUSE_LIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular", "SPECULAR_LIGHT" }, + // Canvas Item, Vertex + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX:xy" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "UV:xy" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + // Canvas Item, Fragment + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normalmap", "NORMALMAP" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normalmap_depth", "NORMALMAP_DEPTH" }, + // Canvas Item, Light + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.rgb" }, + // Particles, Vertex + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, NULL, NULL }, +}; + +int VisualShaderNodeOutput::get_input_port_count() const { + + int idx = 0; + int count = 0; + + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) { + count++; + } + idx++; + } + + return count; +} + +VisualShaderNodeOutput::PortType VisualShaderNodeOutput::get_input_port_type(int p_port) const { + + int idx = 0; + int count = 0; + + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) { + if (count == p_port) { + return ports[idx].type; + } + count++; + } + idx++; + } + + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeOutput::get_input_port_name(int p_port) const { + + int idx = 0; + int count = 0; + + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) { + if (count == p_port) { + return String(ports[idx].name).capitalize(); + } + count++; + } + idx++; + } + + return String(); +} + +Variant VisualShaderNodeOutput::get_input_port_default_value(int p_port) const { + return Variant(); +} + +int VisualShaderNodeOutput::get_output_port_count() const { + + return 0; +} +VisualShaderNodeOutput::PortType VisualShaderNodeOutput::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeOutput::get_output_port_name(int p_port) const { + return String(); +} + +bool VisualShaderNodeOutput::is_port_separator(int p_index) const { + + if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) { + String name = get_input_port_name(p_index); + return (name == "Normal" || name == "Rim" || name == "Alpha Scissor"); + } + return false; +} + +String VisualShaderNodeOutput::get_caption() const { + return TTR("Output"); +} + +String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + int idx = 0; + int count = 0; + + String code; + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) { + + if (p_input_vars[count] != String()) { + String s = ports[idx].string; + if (s.find(":") != -1) { + code += "\t" + s.get_slicec(':', 0) + " = " + p_input_vars[count] + "." + s.get_slicec(':', 1) + ";\n"; + } else { + code += "\t" + s + " = " + p_input_vars[count] + ";\n"; + } + } + count++; + } + idx++; + } + + return code; +} + +VisualShaderNodeOutput::VisualShaderNodeOutput() { +} + +/////////////////////////// + +void VisualShaderNodeUniform::set_uniform_name(const String &p_name) { + uniform_name = p_name; + emit_signal("name_changed"); + emit_changed(); +} + +String VisualShaderNodeUniform::get_uniform_name() const { + return uniform_name; +} + +void VisualShaderNodeUniform::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniform::set_uniform_name); + ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniform::get_uniform_name); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "uniform_name"), "set_uniform_name", "get_uniform_name"); +} + +VisualShaderNodeUniform::VisualShaderNodeUniform() { +} diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h new file mode 100644 index 0000000000..6ff1c9a9fe --- /dev/null +++ b/scene/resources/visual_shader.h @@ -0,0 +1,284 @@ +#ifndef VISUAL_SHADER_H +#define VISUAL_SHADER_H + +#include "scene/resources/shader.h" +#include "string_builder.h" + +class VisualShaderNodeUniform; +class VisualShaderNode; + +class VisualShader : public Shader { + GDCLASS(VisualShader, Shader) +public: + enum Type { + TYPE_VERTEX, + TYPE_FRAGMENT, + TYPE_LIGHT, + TYPE_MAX + }; + + struct Connection { + int from_node; + int from_port; + int to_node; + int to_port; + }; + + struct DefaultTextureParam { + StringName name; + Ref<Texture> param; + }; + +private: + struct Node { + Ref<VisualShaderNode> node; + Vector2 position; + }; + + struct Graph { + Map<int, Node> nodes; + List<Connection> connections; + } graph[TYPE_MAX]; + + Shader::Mode shader_mode; + + Array _get_node_connections(Type p_type) const; + + Vector2 graph_offset; + + struct RenderModeEnums { + Shader::Mode mode; + const char *string; + }; + + HashMap<String, int> modes; + Set<StringName> flags; + + static RenderModeEnums render_mode_enums[]; + + volatile mutable bool dirty; + void _queue_update(); + + union ConnectionKey { + + struct { + uint64_t node : 32; + uint64_t port : 32; + }; + uint64_t key; + bool operator<(const ConnectionKey &p_key) const { + return key < p_key.key; + } + }; + + Error _write_node(Type p_type, StringBuilder &global_code, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview) const; + + void _input_type_changed(Type p_type, int p_id); + +protected: + virtual void _update_shader() const; + static void _bind_methods(); + + 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<PropertyInfo> *p_list) const; + +public: + enum { + NODE_ID_INVALID = -1, + NODE_ID_OUTPUT = 0, + }; + + void add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id); + void set_node_position(Type p_type, int p_id, const Vector2 &p_position); + + Vector2 get_node_position(Type p_type, int p_id) const; + Ref<VisualShaderNode> get_node(Type p_type, int p_id) const; + + Vector<int> get_node_list(Type p_type) const; + int get_valid_node_id(Type p_type) const; + + int find_node_id(Type p_type, const Ref<VisualShaderNode> &p_node) const; + void remove_node(Type p_type, int p_id); + + bool is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const; + bool can_connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const; + Error connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port); + void disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port); + + void get_node_connections(Type p_type, List<Connection> *r_connections) const; + + void set_mode(Mode p_mode); + virtual Mode get_mode() const; + + void set_graph_offset(const Vector2 &p_offset); + Vector2 get_graph_offset() const; + + String generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &r_default_tex_params) const; + + String validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const; + + VisualShader(); +}; + +VARIANT_ENUM_CAST(VisualShader::Type) +/// +/// +/// + +class VisualShaderNode : public Resource { + GDCLASS(VisualShaderNode, Resource) + + int port_preview; + + Map<int, Variant> default_input_values; + + Array _get_default_input_values() const; + void _set_default_input_values(const Array &p_values); + +protected: + static void _bind_methods(); + +public: + enum PortType { + PORT_TYPE_SCALAR, + PORT_TYPE_VECTOR, + PORT_TYPE_TRANSFORM, + }; + + virtual String get_caption() const = 0; + + virtual int get_input_port_count() const = 0; + virtual PortType get_input_port_type(int p_port) const = 0; + virtual String get_input_port_name(int p_port) const = 0; + + void set_input_port_default_value(int p_port, const Variant &p_value); + Variant get_input_port_default_value(int p_port) const; // if NIL (default if node does not set anything) is returned, it means no default value is wanted if disconnected, thus no input var must be supplied (empty string will be supplied) + + virtual int get_output_port_count() const = 0; + virtual PortType get_output_port_type(int p_port) const = 0; + virtual String get_output_port_name(int p_port) const = 0; + + void set_output_port_for_preview(int p_index); + int get_output_port_for_preview() const; + + virtual bool is_port_separator(int p_index) const; + + virtual Vector<StringName> get_editable_properties() const; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const = 0; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const; + + VisualShaderNode(); +}; +///// + +class VisualShaderNodeInput : public VisualShaderNode { + GDCLASS(VisualShaderNodeInput, VisualShaderNode) + + friend class VisualShader; + VisualShader::Type shader_type; + Shader::Mode shader_mode; + + struct Port { + Shader::Mode mode; + VisualShader::Type shader_type; + PortType type; + const char *name; + const char *string; + }; + + static const Port ports[]; + static const Port preview_ports[]; + + String input_name; + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; + +public: + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String get_caption() const; + + virtual String generate_code_for_preview(VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; + + void set_input_name(String p_name); + String get_input_name() const; + + int get_input_index_count() const; + PortType get_input_index_type(int p_index) const; + String get_input_index_name(int p_index) const; + + PortType get_input_type_by_name(String p_name) const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeInput(); +}; + +/// + +class VisualShaderNodeOutput : public VisualShaderNode { + GDCLASS(VisualShaderNodeOutput, VisualShaderNode) +public: + friend class VisualShader; + VisualShader::Type shader_type; + Shader::Mode shader_mode; + + struct Port { + Shader::Mode mode; + VisualShader::Type shader_type; + PortType type; + const char *name; + const char *string; + }; + + static const Port ports[]; + +public: + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + Variant get_input_port_default_value(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual bool is_port_separator(int p_index) const; + + virtual String get_caption() const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; + + VisualShaderNodeOutput(); +}; + +class VisualShaderNodeUniform : public VisualShaderNode { + GDCLASS(VisualShaderNodeUniform, VisualShaderNode) + + String uniform_name; + +protected: + static void _bind_methods(); + +public: + void set_uniform_name(const String &p_name); + String get_uniform_name() const; + + VisualShaderNodeUniform(); +}; + +#endif // VISUAL_SHADER_H diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp new file mode 100644 index 0000000000..98ecdbdf30 --- /dev/null +++ b/scene/resources/visual_shader_nodes.cpp @@ -0,0 +1,1896 @@ +#include "visual_shader_nodes.h" +////////////// Scalar + +String VisualShaderNodeScalarConstant::get_caption() const { + return "Scalar"; +} + +int VisualShaderNodeScalarConstant::get_input_port_count() const { + return 0; +} +VisualShaderNodeScalarConstant::PortType VisualShaderNodeScalarConstant::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeScalarConstant::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeScalarConstant::get_output_port_count() const { + return 1; +} +VisualShaderNodeScalarConstant::PortType VisualShaderNodeScalarConstant::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeScalarConstant::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} + +String VisualShaderNodeScalarConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = " + vformat("%.6f", constant) + ";\n"; +} + +void VisualShaderNodeScalarConstant::set_constant(float p_value) { + + constant = p_value; + emit_changed(); +} + +float VisualShaderNodeScalarConstant::get_constant() const { + + return constant; +} + +Vector<StringName> VisualShaderNodeScalarConstant::get_editable_properties() const { + Vector<StringName> props; + props.push_back("constant"); + return props; +} + +void VisualShaderNodeScalarConstant::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeScalarConstant::set_constant); + ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeScalarConstant::get_constant); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "constant"), "set_constant", "get_constant"); +} + +VisualShaderNodeScalarConstant::VisualShaderNodeScalarConstant() { + constant = 0; +} + +////////////// Color + +String VisualShaderNodeColorConstant::get_caption() const { + return "Color"; +} + +int VisualShaderNodeColorConstant::get_input_port_count() const { + return 0; +} +VisualShaderNodeColorConstant::PortType VisualShaderNodeColorConstant::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeColorConstant::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeColorConstant::get_output_port_count() const { + return 2; +} +VisualShaderNodeColorConstant::PortType VisualShaderNodeColorConstant::get_output_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} +String VisualShaderNodeColorConstant::get_output_port_name(int p_port) const { + return p_port == 0 ? "" : "alpha"; //no output port means the editor will be used as port +} + +String VisualShaderNodeColorConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + String code; + code += "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f,%.6f,%.6f)", constant.r, constant.g, constant.b) + ";\n"; + code += "\t" + p_output_vars[1] + " = " + vformat("%.6f", constant.a) + ";\n"; + + return code; +} + +void VisualShaderNodeColorConstant::set_constant(Color p_value) { + + constant = p_value; + emit_changed(); +} + +Color VisualShaderNodeColorConstant::get_constant() const { + + return constant; +} + +Vector<StringName> VisualShaderNodeColorConstant::get_editable_properties() const { + Vector<StringName> props; + props.push_back("constant"); + return props; +} + +void VisualShaderNodeColorConstant::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeColorConstant::set_constant); + ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeColorConstant::get_constant); + + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "constant"), "set_constant", "get_constant"); +} + +VisualShaderNodeColorConstant::VisualShaderNodeColorConstant() { + constant = Color(1, 1, 1, 1); +} + +////////////// Vector + +String VisualShaderNodeVec3Constant::get_caption() const { + return "Vector"; +} + +int VisualShaderNodeVec3Constant::get_input_port_count() const { + return 0; +} +VisualShaderNodeVec3Constant::PortType VisualShaderNodeVec3Constant::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVec3Constant::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeVec3Constant::get_output_port_count() const { + return 1; +} +VisualShaderNodeVec3Constant::PortType VisualShaderNodeVec3Constant::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVec3Constant::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} + +String VisualShaderNodeVec3Constant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f,%.6f,%.6f)", constant.x, constant.y, constant.z) + ";\n"; +} + +void VisualShaderNodeVec3Constant::set_constant(Vector3 p_value) { + + constant = p_value; + emit_changed(); +} + +Vector3 VisualShaderNodeVec3Constant::get_constant() const { + + return constant; +} + +Vector<StringName> VisualShaderNodeVec3Constant::get_editable_properties() const { + Vector<StringName> props; + props.push_back("constant"); + return props; +} + +void VisualShaderNodeVec3Constant::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeVec3Constant::set_constant); + ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeVec3Constant::get_constant); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant"), "set_constant", "get_constant"); +} + +VisualShaderNodeVec3Constant::VisualShaderNodeVec3Constant() { +} + +////////////// Transform + +String VisualShaderNodeTransformConstant::get_caption() const { + return "Transform"; +} + +int VisualShaderNodeTransformConstant::get_input_port_count() const { + return 0; +} +VisualShaderNodeTransformConstant::PortType VisualShaderNodeTransformConstant::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeTransformConstant::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeTransformConstant::get_output_port_count() const { + return 1; +} +VisualShaderNodeTransformConstant::PortType VisualShaderNodeTransformConstant::get_output_port_type(int p_port) const { + return PORT_TYPE_TRANSFORM; +} +String VisualShaderNodeTransformConstant::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} + +String VisualShaderNodeTransformConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + Transform t = constant; + t.basis.transpose(); + + String code = "\t" + p_output_vars[0] + " = mat4("; + code += vformat("vec4(%.6f,%.6f,%.6f,0.0),", t.basis[0].x, t.basis[0].y, t.basis[0].z); + code += vformat("vec4(%.6f,%.6f,%.6f,0.0),", t.basis[1].x, t.basis[1].y, t.basis[1].z); + code += vformat("vec4(%.6f,%.6f,%.6f,0.0),", t.basis[2].x, t.basis[2].y, t.basis[2].z); + code += vformat("vec4(%.6f,%.6f,%.6f,1.0) );\n", t.origin.x, t.origin.y, t.origin.z); + return code; +} + +void VisualShaderNodeTransformConstant::set_constant(Transform p_value) { + + constant = p_value; + emit_changed(); +} + +Transform VisualShaderNodeTransformConstant::get_constant() const { + + return constant; +} + +Vector<StringName> VisualShaderNodeTransformConstant::get_editable_properties() const { + Vector<StringName> props; + props.push_back("constant"); + return props; +} + +void VisualShaderNodeTransformConstant::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeTransformConstant::set_constant); + ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeTransformConstant::get_constant); + + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "constant"), "set_constant", "get_constant"); +} + +VisualShaderNodeTransformConstant::VisualShaderNodeTransformConstant() { +} + +////////////// Texture + +String VisualShaderNodeTexture::get_caption() const { + return "Texture"; +} + +int VisualShaderNodeTexture::get_input_port_count() const { + return 2; +} +VisualShaderNodeTexture::PortType VisualShaderNodeTexture::get_input_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} +String VisualShaderNodeTexture::get_input_port_name(int p_port) const { + return p_port == 0 ? "uv" : "lod"; +} + +int VisualShaderNodeTexture::get_output_port_count() const { + return 2; +} +VisualShaderNodeTexture::PortType VisualShaderNodeTexture::get_output_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} +String VisualShaderNodeTexture::get_output_port_name(int p_port) const { + return p_port == 0 ? "rgb" : "alpha"; +} + +static String make_unique_id(VisualShader::Type p_type, int p_id, const String &p_name) { + + static const char *typepf[VisualShader::TYPE_MAX] = { "vtx", "frg", "lgt" }; + return p_name + "_" + String(typepf[p_type]) + "_" + itos(p_id); +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNodeTexture::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "tex"); + dtp.param = texture; + Vector<VisualShader::DefaultTextureParam> ret; + ret.push_back(dtp); + return ret; +} + +String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + + if (source == SOURCE_TEXTURE) { + + String u = "uniform sampler2D " + make_unique_id(p_type, p_id, "tex"); + switch (texture_type) { + case TYPE_DATA: break; + case TYPE_COLOR: u += " : hint_color"; break; + case TYPE_NORMALMAP: u += " : hint_normal"; break; + } + return u + ";"; + } + + return String(); +} + +String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + if (source == SOURCE_TEXTURE) { + String id = make_unique_id(p_type, p_id, "tex"); + String code; + if (p_input_vars[0] == String()) { //none bound, do nothing + + code += "\tvec4 " + id + "_read = vec4(0.0);\n"; + + } else if (p_input_vars[1] == String()) { + //no lod + code += "\tvec4 " + id + "_read = texture( " + id + " , " + p_input_vars[0] + ".xy );\n"; + } else { + code += "\tvec4 " + id + "_read = textureLod( " + id + " , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n"; + } + + code += "\t" + p_output_vars[0] + " = " + id + "_read.rgb;\n"; + code += "\t" + p_output_vars[1] + " = " + id + "_read.a;\n"; + return code; + } + + if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) { + + String code = "\t{\n"; + if (p_input_vars[0] == String()) { //none bound, do nothing + + code += "\t\tvec4 _tex_read = vec4(0.0);\n"; + + } else if (p_input_vars[1] == String()) { + //no lod + code += "\t\tvec4 _tex_read = textureLod( SCREEN_TEXTURE , " + p_input_vars[0] + ".xy, 0.0 );\n"; + } else { + code += "\t\tvec4 _tex_read = textureLod( SCREEN_TEXTURE , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n"; + } + + code += "\t\t" + p_output_vars[0] + " = _tex_read.rgb;\n"; + code += "\t\t" + p_output_vars[1] + " = _tex_read.a;\n"; + code += "\t}\n"; + return code; + } + + if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { + + String code = "\t{\n"; + if (p_input_vars[0] == String()) { //none bound, do nothing + + code += "\t\tvec4 _tex_read = vec4(0.0);\n"; + + } else if (p_input_vars[1] == String()) { + //no lod + code += "\t\tvec4 _tex_read = texture( TEXTURE , " + p_input_vars[0] + ".xy );\n"; + } else { + code += "\t\tvec4 _tex_read = textureLod( TEXTURE , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n"; + } + + code += "\t\t" + p_output_vars[0] + " = _tex_read.rgb;\n"; + code += "\t\t" + p_output_vars[1] + " = _tex_read.a;\n"; + code += "\t}\n"; + return code; + } + + if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { + + String code = "\t{\n"; + if (p_input_vars[0] == String()) { //none bound, do nothing + + code += "\t\tvec4 _tex_read = vec4(0.0);\n"; + + } else if (p_input_vars[1] == String()) { + //no lod + code += "\t\tvec4 _tex_read = texture( NORMAL_TEXTURE , " + p_input_vars[0] + ".xy );\n"; + } else { + code += "\t\tvec4 _tex_read = textureLod( NORMAL_TEXTURE , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n"; + } + + code += "\t\t" + p_output_vars[0] + " = _tex_read.rgb;\n"; + code += "\t\t" + p_output_vars[1] + " = _tex_read.a;\n"; + code += "\t}\n"; + return code; + } + + //none + String code; + code += "\t" + p_output_vars[0] + " = vec3(0.0);\n"; + code += "\t" + p_output_vars[1] + " = 1.0;\n"; + return code; +} + +void VisualShaderNodeTexture::set_source(Source p_source) { + source = p_source; + emit_changed(); + emit_signal("editor_refresh_request"); +} + +VisualShaderNodeTexture::Source VisualShaderNodeTexture::get_source() const { + return source; +} + +void VisualShaderNodeTexture::set_texture(Ref<Texture> p_value) { + + texture = p_value; + emit_changed(); +} + +Ref<Texture> VisualShaderNodeTexture::get_texture() const { + + return texture; +} + +void VisualShaderNodeTexture::set_texture_type(TextureType p_type) { + texture_type = p_type; + emit_changed(); +} + +VisualShaderNodeTexture::TextureType VisualShaderNodeTexture::get_texture_type() const { + return texture_type; +} + +Vector<StringName> VisualShaderNodeTexture::get_editable_properties() const { + Vector<StringName> props; + props.push_back("source"); + if (source == SOURCE_TEXTURE) { + props.push_back("texture"); + props.push_back("texture_type"); + } + return props; +} + +String VisualShaderNodeTexture::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { + + if (source == SOURCE_TEXTURE) { + return String(); // all good + } + + if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) { + + return String(); // all good + } + + if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { + + return String(); // all good + } + + if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM) { + + return String(); // all good + } + + return TTR("Invalid source for shader."); +} + +void VisualShaderNodeTexture::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_source", "value"), &VisualShaderNodeTexture::set_source); + ClassDB::bind_method(D_METHOD("get_source"), &VisualShaderNodeTexture::get_source); + + ClassDB::bind_method(D_METHOD("set_texture", "value"), &VisualShaderNodeTexture::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeTexture::get_texture); + + ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeTexture::set_texture_type); + ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTexture::get_texture_type); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D"), "set_source", "get_source"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap"), "set_texture_type", "get_texture_type"); + + BIND_ENUM_CONSTANT(SOURCE_TEXTURE); + BIND_ENUM_CONSTANT(SOURCE_SCREEN); + BIND_ENUM_CONSTANT(SOURCE_2D_TEXTURE); + BIND_ENUM_CONSTANT(SOURCE_2D_NORMAL); + BIND_ENUM_CONSTANT(TYPE_DATA); + BIND_ENUM_CONSTANT(TYPE_COLOR); + BIND_ENUM_CONSTANT(TYPE_NORMALMAP); +} + +VisualShaderNodeTexture::VisualShaderNodeTexture() { + texture_type = TYPE_DATA; + source = SOURCE_TEXTURE; +} + +////////////// CubeMap + +String VisualShaderNodeCubeMap::get_caption() const { + return "CubeMap"; +} + +int VisualShaderNodeCubeMap::get_input_port_count() const { + return 2; +} +VisualShaderNodeCubeMap::PortType VisualShaderNodeCubeMap::get_input_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} +String VisualShaderNodeCubeMap::get_input_port_name(int p_port) const { + return p_port == 0 ? "uv" : "lod"; +} + +int VisualShaderNodeCubeMap::get_output_port_count() const { + return 2; +} +VisualShaderNodeCubeMap::PortType VisualShaderNodeCubeMap::get_output_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} +String VisualShaderNodeCubeMap::get_output_port_name(int p_port) const { + return p_port == 0 ? "rgb" : "alpha"; +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCubeMap::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "cube"); + dtp.param = cube_map; + Vector<VisualShader::DefaultTextureParam> ret; + ret.push_back(dtp); + return ret; +} + +String VisualShaderNodeCubeMap::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + + String u = "uniform sampler2DCube " + make_unique_id(p_type, p_id, "cube"); + switch (texture_type) { + case TYPE_DATA: break; + case TYPE_COLOR: u += " : hint_color"; break; + case TYPE_NORMALMAP: u += " : hint_normal"; break; + } + return u + ";"; +} + +String VisualShaderNodeCubeMap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + String id = make_unique_id(p_type, p_id, "cube"); + String code; + if (p_input_vars[0] == String()) { //none bound, do nothing + + code += "\tvec4 " + id + "_read = vec4(0.0);\n"; + + } else if (p_input_vars[1] == String()) { + //no lod + code += "\tvec4 " + id + "_read = texture( " + id + " , " + p_input_vars[0] + " );\n"; + } else { + code += "\tvec4 " + id + "_read = textureLod( " + id + " , " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; + } + + code += "\t" + p_output_vars[0] + " = " + id + "_read.rgb;\n"; + code += "\t" + p_output_vars[1] + " = " + id + "_read.a;\n"; + return code; +} + +void VisualShaderNodeCubeMap::set_cube_map(Ref<CubeMap> p_value) { + + cube_map = p_value; + emit_changed(); +} + +Ref<CubeMap> VisualShaderNodeCubeMap::get_cube_map() const { + + return cube_map; +} + +void VisualShaderNodeCubeMap::set_texture_type(TextureType p_type) { + texture_type = p_type; + emit_changed(); +} + +VisualShaderNodeCubeMap::TextureType VisualShaderNodeCubeMap::get_texture_type() const { + return texture_type; +} + +Vector<StringName> VisualShaderNodeCubeMap::get_editable_properties() const { + Vector<StringName> props; + props.push_back("cube_map"); + props.push_back("texture_type"); + return props; +} + +void VisualShaderNodeCubeMap::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_cube_map", "value"), &VisualShaderNodeCubeMap::set_cube_map); + ClassDB::bind_method(D_METHOD("get_cube_map"), &VisualShaderNodeCubeMap::get_cube_map); + + ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeCubeMap::set_texture_type); + ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeCubeMap::get_texture_type); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "cube_map", PROPERTY_HINT_RESOURCE_TYPE, "CubeMap"), "set_cube_map", "get_cube_map"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap"), "set_texture_type", "get_texture_type"); + + BIND_ENUM_CONSTANT(TYPE_DATA); + BIND_ENUM_CONSTANT(TYPE_COLOR); + BIND_ENUM_CONSTANT(TYPE_NORMALMAP); +} + +VisualShaderNodeCubeMap::VisualShaderNodeCubeMap() { + texture_type = TYPE_DATA; +} +////////////// Scalar Op + +String VisualShaderNodeScalarOp::get_caption() const { + return "ScalarOp"; +} + +int VisualShaderNodeScalarOp::get_input_port_count() const { + return 2; +} +VisualShaderNodeScalarOp::PortType VisualShaderNodeScalarOp::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeScalarOp::get_input_port_name(int p_port) const { + return p_port == 0 ? "a" : "b"; +} + +int VisualShaderNodeScalarOp::get_output_port_count() const { + return 1; +} +VisualShaderNodeScalarOp::PortType VisualShaderNodeScalarOp::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeScalarOp::get_output_port_name(int p_port) const { + return "op"; //no output port means the editor will be used as port +} + +String VisualShaderNodeScalarOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + String code = "\t" + p_output_vars[0] + " = "; + switch (op) { + + case OP_ADD: code += p_input_vars[0] + " + " + p_input_vars[1] + ";\n"; break; + case OP_SUB: code += p_input_vars[0] + " - " + p_input_vars[1] + ";\n"; break; + case OP_MUL: code += p_input_vars[0] + " * " + p_input_vars[1] + ";\n"; break; + case OP_DIV: code += p_input_vars[0] + " / " + p_input_vars[1] + ";\n"; break; + case OP_MOD: code += "mod( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_POW: code += "pow( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_MAX: code += "max( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_MIN: code += "min( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_ATAN2: code += "atan( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + } + + return code; +} + +void VisualShaderNodeScalarOp::set_operator(Operator p_op) { + + op = p_op; + emit_changed(); +} + +VisualShaderNodeScalarOp::Operator VisualShaderNodeScalarOp::get_operator() const { + + return op; +} + +Vector<StringName> VisualShaderNodeScalarOp::get_editable_properties() const { + Vector<StringName> props; + props.push_back("operator"); + return props; +} + +void VisualShaderNodeScalarOp::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeScalarOp::set_operator); + ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeScalarOp::get_operator); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Atan2"), "set_operator", "get_operator"); + + BIND_ENUM_CONSTANT(OP_ADD); + BIND_ENUM_CONSTANT(OP_SUB); + BIND_ENUM_CONSTANT(OP_MUL); + BIND_ENUM_CONSTANT(OP_DIV); + BIND_ENUM_CONSTANT(OP_MOD); + BIND_ENUM_CONSTANT(OP_POW); + BIND_ENUM_CONSTANT(OP_MAX); + BIND_ENUM_CONSTANT(OP_MIN); + BIND_ENUM_CONSTANT(OP_ATAN2); +} + +VisualShaderNodeScalarOp::VisualShaderNodeScalarOp() { + op = OP_ADD; + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); +} + +////////////// Vector Op + +String VisualShaderNodeVectorOp::get_caption() const { + return "VectorOp"; +} + +int VisualShaderNodeVectorOp::get_input_port_count() const { + return 2; +} +VisualShaderNodeVectorOp::PortType VisualShaderNodeVectorOp::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVectorOp::get_input_port_name(int p_port) const { + return p_port == 0 ? "a" : "b"; +} + +int VisualShaderNodeVectorOp::get_output_port_count() const { + return 1; +} +VisualShaderNodeVectorOp::PortType VisualShaderNodeVectorOp::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVectorOp::get_output_port_name(int p_port) const { + return "op"; //no output port means the editor will be used as port +} + +String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + String code = "\t" + p_output_vars[0] + " = "; + switch (op) { + + case OP_ADD: code += p_input_vars[0] + " + " + p_input_vars[1] + ";\n"; break; + case OP_SUB: code += p_input_vars[0] + " - " + p_input_vars[1] + ";\n"; break; + case OP_MUL: code += p_input_vars[0] + " * " + p_input_vars[1] + ";\n"; break; + case OP_DIV: code += p_input_vars[0] + " / " + p_input_vars[1] + ";\n"; break; + case OP_MOD: code += "mod( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_POW: code += "pow( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_MAX: code += "max( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_MIN: code += "min( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_CROSS: code += "cross( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + } + + return code; +} + +void VisualShaderNodeVectorOp::set_operator(Operator p_op) { + + op = p_op; + emit_changed(); +} + +VisualShaderNodeVectorOp::Operator VisualShaderNodeVectorOp::get_operator() const { + + return op; +} + +Vector<StringName> VisualShaderNodeVectorOp::get_editable_properties() const { + Vector<StringName> props; + props.push_back("operator"); + return props; +} + +void VisualShaderNodeVectorOp::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeVectorOp::set_operator); + ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeVectorOp::get_operator); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Cross"), "set_operator", "get_operator"); + + BIND_ENUM_CONSTANT(OP_ADD); + BIND_ENUM_CONSTANT(OP_SUB); + BIND_ENUM_CONSTANT(OP_MUL); + BIND_ENUM_CONSTANT(OP_DIV); + BIND_ENUM_CONSTANT(OP_MOD); + BIND_ENUM_CONSTANT(OP_POW); + BIND_ENUM_CONSTANT(OP_MAX); + BIND_ENUM_CONSTANT(OP_MIN); + BIND_ENUM_CONSTANT(OP_CROSS); +} + +VisualShaderNodeVectorOp::VisualShaderNodeVectorOp() { + op = OP_ADD; + set_input_port_default_value(0, Vector3()); + set_input_port_default_value(1, Vector3()); +} + +////////////// Color Op + +String VisualShaderNodeColorOp::get_caption() const { + return "ColorOp"; +} + +int VisualShaderNodeColorOp::get_input_port_count() const { + return 2; +} +VisualShaderNodeColorOp::PortType VisualShaderNodeColorOp::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeColorOp::get_input_port_name(int p_port) const { + return p_port == 0 ? "a" : "b"; +} + +int VisualShaderNodeColorOp::get_output_port_count() const { + return 1; +} +VisualShaderNodeColorOp::PortType VisualShaderNodeColorOp::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeColorOp::get_output_port_name(int p_port) const { + return "op"; //no output port means the editor will be used as port +} + +String VisualShaderNodeColorOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + String code; + static const char *axisn[3] = { "x", "y", "z" }; + switch (op) { + case OP_SCREEN: { + + code += "\t" + p_output_vars[0] + "=vec3(1.0)-(vec3(1.0)-" + p_input_vars[0] + ")*(vec3(1.0)-" + p_input_vars[1] + ");\n"; + } break; + case OP_DIFFERENCE: { + + code += "\t" + p_output_vars[0] + "=abs(" + p_input_vars[0] + "-" + p_input_vars[1] + ");\n"; + } break; + case OP_DARKEN: { + + code += "\t" + p_output_vars[0] + "=min(" + p_input_vars[0] + "," + p_input_vars[1] + ");\n"; + } break; + case OP_LIGHTEN: { + + code += "\t" + p_output_vars[0] + "=max(" + p_input_vars[0] + "," + p_input_vars[1] + ");\n"; + + } break; + case OP_OVERLAY: { + + for (int i = 0; i < 3; i++) { + code += "\t{\n"; + code += "\t\tfloat base=" + p_input_vars[0] + "." + axisn[i] + ";\n"; + code += "\t\tfloat blend=" + p_input_vars[1] + "." + axisn[i] + ";\n"; + code += "\t\tif (base < 0.5) {\n"; + code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = 2.0 * base * blend;\n"; + code += "\t\t} else {\n"; + code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n"; + code += "\t\t}\n"; + code += "\t}\n"; + } + + } break; + case OP_DODGE: { + + code += "\t" + p_output_vars[0] + "=(" + p_input_vars[0] + ")/(vec3(1.0)-" + p_input_vars[1] + ");\n"; + + } break; + case OP_BURN: { + + code += "\t" + p_output_vars[0] + "=vec3(1.0)-(vec3(1.0)-" + p_input_vars[0] + ")/(" + p_input_vars[1] + ");\n"; + } break; + case OP_SOFT_LIGHT: { + + for (int i = 0; i < 3; i++) { + code += "\t{\n"; + code += "\t\tfloat base=" + p_input_vars[0] + "." + axisn[i] + ";\n"; + code += "\t\tfloat blend=" + p_input_vars[1] + "." + axisn[i] + ";\n"; + code += "\t\tif (base < 0.5) {\n"; + code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (base * (blend+0.5));\n"; + code += "\t\t} else {\n"; + code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (1.0 - (1.0-base) * (1.0-(blend-0.5)));\n"; + code += "\t\t}\n"; + code += "\t}\n"; + } + + } break; + case OP_HARD_LIGHT: { + + for (int i = 0; i < 3; i++) { + code += "\t{\n"; + code += "\t\tfloat base=" + p_input_vars[0] + "." + axisn[i] + ";\n"; + code += "\t\tfloat blend=" + p_input_vars[1] + "." + axisn[i] + ";\n"; + code += "\t\tif (base < 0.5) {\n"; + code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (base * (2.0*blend));\n"; + code += "\t\t} else {\n"; + code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (1.0 - (1.0-base) * (1.0-2.0*(blend-0.5)));\n"; + code += "\t\t}\n"; + code += "\t}\n"; + } + + } break; + } + + return code; +} + +void VisualShaderNodeColorOp::set_operator(Operator p_op) { + + op = p_op; + emit_changed(); +} + +VisualShaderNodeColorOp::Operator VisualShaderNodeColorOp::get_operator() const { + + return op; +} + +Vector<StringName> VisualShaderNodeColorOp::get_editable_properties() const { + Vector<StringName> props; + props.push_back("operator"); + return props; +} + +void VisualShaderNodeColorOp::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeColorOp::set_operator); + ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeColorOp::get_operator); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Screen,Difference,Darken,Lighten,Overlay,Dodge,Burn,SoftLight,HardLight"), "set_operator", "get_operator"); + + BIND_ENUM_CONSTANT(OP_SCREEN); + BIND_ENUM_CONSTANT(OP_DIFFERENCE); + BIND_ENUM_CONSTANT(OP_DARKEN); + BIND_ENUM_CONSTANT(OP_LIGHTEN); + BIND_ENUM_CONSTANT(OP_OVERLAY); + BIND_ENUM_CONSTANT(OP_DODGE); + BIND_ENUM_CONSTANT(OP_BURN); + BIND_ENUM_CONSTANT(OP_SOFT_LIGHT); + BIND_ENUM_CONSTANT(OP_HARD_LIGHT); +} + +VisualShaderNodeColorOp::VisualShaderNodeColorOp() { + op = OP_SCREEN; + set_input_port_default_value(0, Vector3()); + set_input_port_default_value(1, Vector3()); +} + +////////////// Transform Mult + +String VisualShaderNodeTransformMult::get_caption() const { + return "TransformMult"; +} + +int VisualShaderNodeTransformMult::get_input_port_count() const { + return 2; +} +VisualShaderNodeTransformMult::PortType VisualShaderNodeTransformMult::get_input_port_type(int p_port) const { + return PORT_TYPE_TRANSFORM; +} +String VisualShaderNodeTransformMult::get_input_port_name(int p_port) const { + return p_port == 0 ? "a" : "b"; +} + +int VisualShaderNodeTransformMult::get_output_port_count() const { + return 1; +} +VisualShaderNodeTransformMult::PortType VisualShaderNodeTransformMult::get_output_port_type(int p_port) const { + return PORT_TYPE_TRANSFORM; +} +String VisualShaderNodeTransformMult::get_output_port_name(int p_port) const { + return "mult"; //no output port means the editor will be used as port +} + +String VisualShaderNodeTransformMult::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + if (op == OP_AxB) { + return "\t" + p_output_vars[0] + " = " + p_input_vars[0] + " * " + p_input_vars[1] + ";\n"; + } else { + return "\t" + p_output_vars[0] + " = " + p_input_vars[1] + " * " + p_input_vars[0] + ";\n"; + } +} + +void VisualShaderNodeTransformMult::set_operator(Operator p_op) { + + op = p_op; + emit_changed(); +} + +VisualShaderNodeTransformMult::Operator VisualShaderNodeTransformMult::get_operator() const { + + return op; +} + +Vector<StringName> VisualShaderNodeTransformMult::get_editable_properties() const { + Vector<StringName> props; + props.push_back("operator"); + return props; +} + +void VisualShaderNodeTransformMult::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeTransformMult::set_operator); + ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeTransformMult::get_operator); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "A x B,B x A"), "set_operator", "get_operator"); + + BIND_ENUM_CONSTANT(OP_AxB); + BIND_ENUM_CONSTANT(OP_BxA); +} + +VisualShaderNodeTransformMult::VisualShaderNodeTransformMult() { + op = OP_AxB; + set_input_port_default_value(0, Transform()); + set_input_port_default_value(1, Transform()); +} + +////////////// TransformVec Mult + +String VisualShaderNodeTransformVecMult::get_caption() const { + return "TransformVectorMult"; +} + +int VisualShaderNodeTransformVecMult::get_input_port_count() const { + return 2; +} +VisualShaderNodeTransformVecMult::PortType VisualShaderNodeTransformVecMult::get_input_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_TRANSFORM : PORT_TYPE_VECTOR; +} +String VisualShaderNodeTransformVecMult::get_input_port_name(int p_port) const { + return p_port == 0 ? "a" : "b"; +} + +int VisualShaderNodeTransformVecMult::get_output_port_count() const { + return 1; +} +VisualShaderNodeTransformVecMult::PortType VisualShaderNodeTransformVecMult::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeTransformVecMult::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} + +String VisualShaderNodeTransformVecMult::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + if (op == OP_AxB) { + return "\t" + p_output_vars[0] + " = ( " + p_input_vars[0] + " * vec4(" + p_input_vars[1] + ", 1.0) ).xyz;\n"; + } else if (op == OP_BxA) { + return "\t" + p_output_vars[0] + " = ( vec4(" + p_input_vars[1] + ", 1.0) * " + p_input_vars[0] + " ).xyz;\n"; + } else if (op == OP_3x3_AxB) { + return "\t" + p_output_vars[0] + " = ( " + p_input_vars[0] + " * vec4(" + p_input_vars[1] + ", 0.0) ).xyz;\n"; + } else { + return "\t" + p_output_vars[0] + " = ( vec4(" + p_input_vars[1] + ", 0.0) * " + p_input_vars[0] + " ).xyz;\n"; + } +} + +void VisualShaderNodeTransformVecMult::set_operator(Operator p_op) { + + op = p_op; + emit_changed(); +} + +VisualShaderNodeTransformVecMult::Operator VisualShaderNodeTransformVecMult::get_operator() const { + + return op; +} + +Vector<StringName> VisualShaderNodeTransformVecMult::get_editable_properties() const { + Vector<StringName> props; + props.push_back("operator"); + return props; +} + +void VisualShaderNodeTransformVecMult::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeTransformVecMult::set_operator); + ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeTransformVecMult::get_operator); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "A x B,B x A,A x B (3x3),B x A (3x3)"), "set_operator", "get_operator"); + + BIND_ENUM_CONSTANT(OP_AxB); + BIND_ENUM_CONSTANT(OP_BxA); + BIND_ENUM_CONSTANT(OP_3x3_AxB); + BIND_ENUM_CONSTANT(OP_3x3_BxA); +} + +VisualShaderNodeTransformVecMult::VisualShaderNodeTransformVecMult() { + op = OP_AxB; + set_input_port_default_value(0, Transform()); + set_input_port_default_value(1, Vector3()); +} + +////////////// Scalar Func + +String VisualShaderNodeScalarFunc::get_caption() const { + return "ScalarFunc"; +} + +int VisualShaderNodeScalarFunc::get_input_port_count() const { + return 1; +} +VisualShaderNodeScalarFunc::PortType VisualShaderNodeScalarFunc::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeScalarFunc::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeScalarFunc::get_output_port_count() const { + return 1; +} +VisualShaderNodeScalarFunc::PortType VisualShaderNodeScalarFunc::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeScalarFunc::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} + +String VisualShaderNodeScalarFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + static const char *scalar_func_id[FUNC_NEGATE + 1] = { + "sin($)", + "cos($)", + "tan($)", + "asin($)", + "acos($)", + "atan($)", + "sinh($)", + "cosh($)", + "tanh($)", + "log($)", + "exp($)", + "sqrt($)", + "abs($)", + "sign($)", + "floor($)", + "round($)", + "ceil($)", + "fract($)", + "min(max($,0),1)", + "-($)", + }; + + return "\t" + p_output_vars[0] + " = " + String(scalar_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; +} + +void VisualShaderNodeScalarFunc::set_function(Function p_func) { + + func = p_func; + emit_changed(); +} + +VisualShaderNodeScalarFunc::Function VisualShaderNodeScalarFunc::get_function() const { + + return func; +} + +Vector<StringName> VisualShaderNodeScalarFunc::get_editable_properties() const { + Vector<StringName> props; + props.push_back("function"); + return props; +} + +void VisualShaderNodeScalarFunc::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeScalarFunc::set_function); + ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeScalarFunc::get_function); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate"), "set_function", "get_function"); + + BIND_ENUM_CONSTANT(FUNC_SIN); + BIND_ENUM_CONSTANT(FUNC_COS); + BIND_ENUM_CONSTANT(FUNC_TAN); + BIND_ENUM_CONSTANT(FUNC_ASIN); + BIND_ENUM_CONSTANT(FUNC_ACOS); + BIND_ENUM_CONSTANT(FUNC_ATAN); + BIND_ENUM_CONSTANT(FUNC_SINH); + BIND_ENUM_CONSTANT(FUNC_COSH); + BIND_ENUM_CONSTANT(FUNC_TANH); + BIND_ENUM_CONSTANT(FUNC_LOG); + BIND_ENUM_CONSTANT(FUNC_EXP); + BIND_ENUM_CONSTANT(FUNC_SQRT); + BIND_ENUM_CONSTANT(FUNC_ABS); + BIND_ENUM_CONSTANT(FUNC_SIGN); + BIND_ENUM_CONSTANT(FUNC_FLOOR); + BIND_ENUM_CONSTANT(FUNC_ROUND); + BIND_ENUM_CONSTANT(FUNC_CEIL); + BIND_ENUM_CONSTANT(FUNC_FRAC); + BIND_ENUM_CONSTANT(FUNC_SATURATE); + BIND_ENUM_CONSTANT(FUNC_NEGATE); +} + +VisualShaderNodeScalarFunc::VisualShaderNodeScalarFunc() { + func = FUNC_SIGN; + set_input_port_default_value(0, 0.0); +} + +////////////// Vector Func + +String VisualShaderNodeVectorFunc::get_caption() const { + return "VectorFunc"; +} + +int VisualShaderNodeVectorFunc::get_input_port_count() const { + return 1; +} +VisualShaderNodeVectorFunc::PortType VisualShaderNodeVectorFunc::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVectorFunc::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeVectorFunc::get_output_port_count() const { + return 1; +} +VisualShaderNodeVectorFunc::PortType VisualShaderNodeVectorFunc::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVectorFunc::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} + +String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + static const char *vec_func_id[FUNC_HSV2RGB + 1] = { + "normalize($)", + "max(min($,vec3(1.0)),vec3(0.0))", + "-($)", + "1.0/($)", + "", + "", + }; + + String code; + + if (func == FUNC_RGB2HSV) { + code += "\t{\n"; + code += "\t\tvec3 c = " + p_input_vars[0] + ";\n"; + code += "\t\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n"; + code += "\t\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n"; + code += "\t\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n"; + code += "\t\tfloat d = q.x - min(q.w, q.y);\n"; + code += "\t\tfloat e = 1.0e-10;\n"; + code += "\t\t" + p_output_vars[0] + "=vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n"; + code += "\t}\n"; + } else if (func == FUNC_HSV2RGB) { + code += "\t{\n"; + code += "\t\tvec3 c = " + p_input_vars[0] + ";\n"; + code += "\t\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"; + code += "\t\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n"; + code += "\t\t" + p_output_vars[0] + "=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n"; + code += "\t}\n"; + + } else { + code += "\t" + p_output_vars[0] + "=" + String(vec_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; + } + + return code; +} + +void VisualShaderNodeVectorFunc::set_function(Function p_func) { + + func = p_func; + emit_changed(); +} + +VisualShaderNodeVectorFunc::Function VisualShaderNodeVectorFunc::get_function() const { + + return func; +} + +Vector<StringName> VisualShaderNodeVectorFunc::get_editable_properties() const { + Vector<StringName> props; + props.push_back("function"); + return props; +} + +void VisualShaderNodeVectorFunc::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function); + ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB"), "set_function", "get_function"); + + BIND_ENUM_CONSTANT(FUNC_NORMALIZE); + BIND_ENUM_CONSTANT(FUNC_SATURATE); + BIND_ENUM_CONSTANT(FUNC_NEGATE); + BIND_ENUM_CONSTANT(FUNC_RECIPROCAL); + BIND_ENUM_CONSTANT(FUNC_RGB2HSV); + BIND_ENUM_CONSTANT(FUNC_HSV2RGB); +} + +VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() { + func = FUNC_NORMALIZE; + set_input_port_default_value(0, Vector3()); +} + +////////////// Dot Product + +String VisualShaderNodeDotProduct::get_caption() const { + return "DotProduct"; +} + +int VisualShaderNodeDotProduct::get_input_port_count() const { + return 2; +} +VisualShaderNodeDotProduct::PortType VisualShaderNodeDotProduct::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeDotProduct::get_input_port_name(int p_port) const { + return p_port == 0 ? "a" : "b"; +} + +int VisualShaderNodeDotProduct::get_output_port_count() const { + return 1; +} +VisualShaderNodeDotProduct::PortType VisualShaderNodeDotProduct::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeDotProduct::get_output_port_name(int p_port) const { + return "dot"; +} + +String VisualShaderNodeDotProduct::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = dot( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; +} + +VisualShaderNodeDotProduct::VisualShaderNodeDotProduct() { + set_input_port_default_value(0, Vector3()); + set_input_port_default_value(1, Vector3()); +} + +////////////// Vector Len + +String VisualShaderNodeVectorLen::get_caption() const { + return "VectorLen"; +} + +int VisualShaderNodeVectorLen::get_input_port_count() const { + return 1; +} +VisualShaderNodeVectorLen::PortType VisualShaderNodeVectorLen::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVectorLen::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeVectorLen::get_output_port_count() const { + return 1; +} +VisualShaderNodeVectorLen::PortType VisualShaderNodeVectorLen::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeVectorLen::get_output_port_name(int p_port) const { + return "length"; +} + +String VisualShaderNodeVectorLen::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = length( " + p_input_vars[0] + " );\n"; +} + +VisualShaderNodeVectorLen::VisualShaderNodeVectorLen() { + set_input_port_default_value(0, Vector3()); +} + +////////////// Scalar Interp + +String VisualShaderNodeScalarInterp::get_caption() const { + return "ScalarInterp"; +} + +int VisualShaderNodeScalarInterp::get_input_port_count() const { + return 3; +} +VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeScalarInterp::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "a"; + } else if (p_port == 1) { + return "b"; + } else { + return "c"; + } +} + +int VisualShaderNodeScalarInterp::get_output_port_count() const { + return 1; +} +VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeScalarInterp::get_output_port_name(int p_port) const { + return "mix"; +} + +String VisualShaderNodeScalarInterp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = mix( " + p_input_vars[0] + " , " + p_input_vars[1] + " , " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeScalarInterp::VisualShaderNodeScalarInterp() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 0.0); +} + +////////////// Vector Interp + +String VisualShaderNodeVectorInterp::get_caption() const { + return "VectorInterp"; +} + +int VisualShaderNodeVectorInterp::get_input_port_count() const { + return 3; +} +VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVectorInterp::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "a"; + } else if (p_port == 1) { + return "b"; + } else { + return "c"; + } +} + +int VisualShaderNodeVectorInterp::get_output_port_count() const { + return 1; +} +VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVectorInterp::get_output_port_name(int p_port) const { + return "mix"; +} + +String VisualShaderNodeVectorInterp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = mix( " + p_input_vars[0] + " , " + p_input_vars[1] + " , " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeVectorInterp::VisualShaderNodeVectorInterp() { + set_input_port_default_value(0, Vector3()); + set_input_port_default_value(1, Vector3()); + set_input_port_default_value(2, Vector3()); +} + +////////////// Vector Compose +String VisualShaderNodeVectorCompose::get_caption() const { + return "VectorCompose"; +} + +int VisualShaderNodeVectorCompose::get_input_port_count() const { + return 3; +} +VisualShaderNodeVectorCompose::PortType VisualShaderNodeVectorCompose::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeVectorCompose::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "x"; + } else if (p_port == 1) { + return "y"; + } else { + return "z"; + } +} + +int VisualShaderNodeVectorCompose::get_output_port_count() const { + return 1; +} +VisualShaderNodeVectorCompose::PortType VisualShaderNodeVectorCompose::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVectorCompose::get_output_port_name(int p_port) const { + return "vec"; +} + +String VisualShaderNodeVectorCompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = vec3( " + p_input_vars[0] + " , " + p_input_vars[1] + " , " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeVectorCompose::VisualShaderNodeVectorCompose() { + + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 0.0); +} + +////////////// Transform Compose + +String VisualShaderNodeTransformCompose::get_caption() const { + return "TransformCompose"; +} + +int VisualShaderNodeTransformCompose::get_input_port_count() const { + return 4; +} +VisualShaderNodeTransformCompose::PortType VisualShaderNodeTransformCompose::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeTransformCompose::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "x"; + } else if (p_port == 1) { + return "y"; + } else if (p_port == 2) { + return "z"; + } else { + return "origin"; + } +} + +int VisualShaderNodeTransformCompose::get_output_port_count() const { + return 1; +} +VisualShaderNodeTransformCompose::PortType VisualShaderNodeTransformCompose::get_output_port_type(int p_port) const { + return PORT_TYPE_TRANSFORM; +} +String VisualShaderNodeTransformCompose::get_output_port_name(int p_port) const { + return "xform"; +} + +String VisualShaderNodeTransformCompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = mat4( vec4(" + p_input_vars[0] + ", 0.0) , vec4(" + p_input_vars[1] + ", 0.0) , vec4(" + p_input_vars[2] + ",0.0), vec4(" + p_input_vars[3] + ",1.0) );\n"; +} + +VisualShaderNodeTransformCompose::VisualShaderNodeTransformCompose() { + + set_input_port_default_value(0, Vector3()); + set_input_port_default_value(1, Vector3()); + set_input_port_default_value(2, Vector3()); + set_input_port_default_value(3, Vector3()); +} + +////////////// Vector Decompose +String VisualShaderNodeVectorDecompose::get_caption() const { + return "VectorDecompose"; +} + +int VisualShaderNodeVectorDecompose::get_input_port_count() const { + return 1; +} +VisualShaderNodeVectorDecompose::PortType VisualShaderNodeVectorDecompose::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVectorDecompose::get_input_port_name(int p_port) const { + return "vec"; +} + +int VisualShaderNodeVectorDecompose::get_output_port_count() const { + return 3; +} +VisualShaderNodeVectorDecompose::PortType VisualShaderNodeVectorDecompose::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeVectorDecompose::get_output_port_name(int p_port) const { + if (p_port == 0) { + return "x"; + } else if (p_port == 1) { + return "y"; + } else { + return "z"; + } +} + +String VisualShaderNodeVectorDecompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + String code; + code += "\t" + p_output_vars[0] + " = " + p_input_vars[0] + ".x;\n"; + code += "\t" + p_output_vars[1] + " = " + p_input_vars[0] + ".y;\n"; + code += "\t" + p_output_vars[2] + " = " + p_input_vars[0] + ".z;\n"; + return code; +} + +VisualShaderNodeVectorDecompose::VisualShaderNodeVectorDecompose() { + set_input_port_default_value(0, Vector3()); +} + +////////////// Transform Decompose + +String VisualShaderNodeTransformDecompose::get_caption() const { + return "TransformDecompose"; +} + +int VisualShaderNodeTransformDecompose::get_input_port_count() const { + return 1; +} +VisualShaderNodeTransformDecompose::PortType VisualShaderNodeTransformDecompose::get_input_port_type(int p_port) const { + return PORT_TYPE_TRANSFORM; +} +String VisualShaderNodeTransformDecompose::get_input_port_name(int p_port) const { + return "xform"; +} + +int VisualShaderNodeTransformDecompose::get_output_port_count() const { + return 4; +} +VisualShaderNodeTransformDecompose::PortType VisualShaderNodeTransformDecompose::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeTransformDecompose::get_output_port_name(int p_port) const { + if (p_port == 0) { + return "x"; + } else if (p_port == 1) { + return "y"; + } else if (p_port == 2) { + return "z"; + } else { + return "origin"; + } +} + +String VisualShaderNodeTransformDecompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + String code; + code += "\t" + p_output_vars[0] + " = " + p_input_vars[0] + "[0].xyz;\n"; + code += "\t" + p_output_vars[1] + " = " + p_input_vars[0] + "[1].xyz;\n"; + code += "\t" + p_output_vars[2] + " = " + p_input_vars[0] + "[2].xyz;\n"; + code += "\t" + p_output_vars[3] + " = " + p_input_vars[0] + "[3].xyz;\n"; + return code; +} + +VisualShaderNodeTransformDecompose::VisualShaderNodeTransformDecompose() { + set_input_port_default_value(0, Transform()); +} + +////////////// Scalar Uniform + +String VisualShaderNodeScalarUniform::get_caption() const { + return "ScalarUniform"; +} + +int VisualShaderNodeScalarUniform::get_input_port_count() const { + return 0; +} +VisualShaderNodeScalarUniform::PortType VisualShaderNodeScalarUniform::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeScalarUniform::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeScalarUniform::get_output_port_count() const { + return 1; +} +VisualShaderNodeScalarUniform::PortType VisualShaderNodeScalarUniform::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} +String VisualShaderNodeScalarUniform::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} + +String VisualShaderNodeScalarUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform float " + get_uniform_name() + ";\n"; +} +String VisualShaderNodeScalarUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +} + +VisualShaderNodeScalarUniform::VisualShaderNodeScalarUniform() { +} + +////////////// Color Uniform + +String VisualShaderNodeColorUniform::get_caption() const { + return "ColorUniform"; +} + +int VisualShaderNodeColorUniform::get_input_port_count() const { + return 0; +} +VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeColorUniform::get_output_port_count() const { + return 2; +} +VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_output_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} +String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const { + return p_port == 0 ? "color" : "alpha"; //no output port means the editor will be used as port +} + +String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + + return "uniform vec4 " + get_uniform_name() + " : hint_color;\n"; +} + +String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + String code = "\t" + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n"; + code += "\t" + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n"; + return code; +} + +VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() { +} + +////////////// Vector Uniform + +String VisualShaderNodeVec3Uniform::get_caption() const { + return "VectorUniform"; +} + +int VisualShaderNodeVec3Uniform::get_input_port_count() const { + return 0; +} +VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVec3Uniform::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeVec3Uniform::get_output_port_count() const { + return 1; +} +VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeVec3Uniform::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} +String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform vec3 " + get_uniform_name() + ";\n"; +} + +String VisualShaderNodeVec3Uniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +} + +VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() { +} + +////////////// Transform Uniform + +String VisualShaderNodeTransformUniform::get_caption() const { + return "TransformUniform"; +} + +int VisualShaderNodeTransformUniform::get_input_port_count() const { + return 0; +} +VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} +String VisualShaderNodeTransformUniform::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeTransformUniform::get_output_port_count() const { + return 1; +} +VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_output_port_type(int p_port) const { + return PORT_TYPE_TRANSFORM; +} +String VisualShaderNodeTransformUniform::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} +String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform mat4 " + get_uniform_name() + ";\n"; +} + +String VisualShaderNodeTransformUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +} + +VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() { +} + +////////////// Texture Uniform + +String VisualShaderNodeTextureUniform::get_caption() const { + return "TextureUniform"; +} + +int VisualShaderNodeTextureUniform::get_input_port_count() const { + return 2; +} +VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} +String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const { + return p_port == 0 ? "uv" : "lod"; +} + +int VisualShaderNodeTextureUniform::get_output_port_count() const { + return 2; +} +VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} +String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const { + return p_port == 0 ? "rgb" : "alpha"; +} + +String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = "uniform sampler2D " + get_uniform_name(); + + switch (texture_type) { + case TYPE_DATA: + if (color_default == COLOR_DEFAULT_BLACK) + code += " : hint_black;\n"; + else + code += ";\n"; + break; + case TYPE_COLOR: + if (color_default == COLOR_DEFAULT_BLACK) + code += " : hint_black_albedo;\n"; + else + code += " : hint_albedo;\n"; + break; + case TYPE_NORMALMAP: code += " : hint_normal;\n"; break; + case TYPE_ANISO: code += " : hint_aniso;\n"; break; + } + + return code; +} + +String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + + String id = get_uniform_name(); + String code = "\t{\n"; + if (p_input_vars[0] == String()) { //none bound, do nothing + + code += "\t\tvec4 n_tex_read = vec4(0.0);\n"; + } else if (p_input_vars[1] == String()) { + //no lod + code += "\t\tvec4 n_tex_read = texture( " + id + " , " + p_input_vars[0] + ".xy );\n"; + } else { + code += "\t\tvec4 n_tex_read = textureLod( " + id + " , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n"; + } + + code += "\t\t" + p_output_vars[0] + " = n_tex_read.rgb;\n"; + code += "\t\t" + p_output_vars[1] + " = n_tex_read.a;\n"; + code += "\t}\n"; + return code; +} + +void VisualShaderNodeTextureUniform::set_texture_type(TextureType p_type) { + + texture_type = p_type; + emit_changed(); +} + +VisualShaderNodeTextureUniform::TextureType VisualShaderNodeTextureUniform::get_texture_type() const { + return texture_type; +} + +void VisualShaderNodeTextureUniform::set_color_default(ColorDefault p_default) { + color_default = p_default; + emit_changed(); +} +VisualShaderNodeTextureUniform::ColorDefault VisualShaderNodeTextureUniform::get_color_default() const { + return color_default; +} + +Vector<StringName> VisualShaderNodeTextureUniform::get_editable_properties() const { + Vector<StringName> props; + props.push_back("texture_type"); + props.push_back("color_default"); + return props; +} + +void VisualShaderNodeTextureUniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureUniform::set_texture_type); + ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureUniform::get_texture_type); + + ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureUniform::set_color_default); + ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureUniform::get_color_default); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap,Aniso"), "set_texture_type", "get_texture_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White Default,Black Default"), "set_color_default", "get_color_default"); + + BIND_ENUM_CONSTANT(TYPE_DATA); + BIND_ENUM_CONSTANT(TYPE_COLOR); + BIND_ENUM_CONSTANT(TYPE_NORMALMAP); + BIND_ENUM_CONSTANT(TYPE_ANISO); + + BIND_ENUM_CONSTANT(COLOR_DEFAULT_WHITE); + BIND_ENUM_CONSTANT(COLOR_DEFAULT_BLACK); +} + +VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() { + texture_type = TYPE_DATA; + color_default = COLOR_DEFAULT_WHITE; +} + +////////////// CubeMap Uniform + +String VisualShaderNodeCubeMapUniform::get_caption() const { + return "CubeMapUniform"; +} + +int VisualShaderNodeCubeMapUniform::get_input_port_count() const { + return 2; +} +VisualShaderNodeCubeMapUniform::PortType VisualShaderNodeCubeMapUniform::get_input_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} +String VisualShaderNodeCubeMapUniform::get_input_port_name(int p_port) const { + return p_port == 0 ? "normal" : "lod"; +} + +int VisualShaderNodeCubeMapUniform::get_output_port_count() const { + return 2; +} +VisualShaderNodeCubeMapUniform::PortType VisualShaderNodeCubeMapUniform::get_output_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} +String VisualShaderNodeCubeMapUniform::get_output_port_name(int p_port) const { + return p_port == 0 ? "rgb" : "alpha"; +} + +String VisualShaderNodeCubeMapUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + return String(); +} + +VisualShaderNodeCubeMapUniform::VisualShaderNodeCubeMapUniform() { +} diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h new file mode 100644 index 0000000000..2ede36fbc8 --- /dev/null +++ b/scene/resources/visual_shader_nodes.h @@ -0,0 +1,861 @@ +#ifndef VISUAL_SHADER_NODES_H +#define VISUAL_SHADER_NODES_H + +#include "scene/resources/visual_shader.h" + +/// CONSTANTS /// + +class VisualShaderNodeScalarConstant : public VisualShaderNode { + GDCLASS(VisualShaderNodeScalarConstant, VisualShaderNode) + float constant; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_constant(float p_value); + float get_constant() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeScalarConstant(); +}; + +class VisualShaderNodeColorConstant : public VisualShaderNode { + GDCLASS(VisualShaderNodeColorConstant, VisualShaderNode) + Color constant; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_constant(Color p_value); + Color get_constant() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeColorConstant(); +}; + +class VisualShaderNodeVec3Constant : public VisualShaderNode { + GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNode) + Vector3 constant; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_constant(Vector3 p_value); + Vector3 get_constant() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeVec3Constant(); +}; + +class VisualShaderNodeTransformConstant : public VisualShaderNode { + GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNode) + Transform constant; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_constant(Transform p_value); + Transform get_constant() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeTransformConstant(); +}; + +////////////////////////////////// + +class VisualShaderNodeTexture : public VisualShaderNode { + GDCLASS(VisualShaderNodeTexture, VisualShaderNode) + Ref<Texture> texture; + +public: + enum Source { + SOURCE_TEXTURE, + SOURCE_SCREEN, + SOURCE_2D_TEXTURE, + SOURCE_2D_NORMAL + }; + + enum TextureType { + TYPE_DATA, + TYPE_COLOR, + TYPE_NORMALMAP + }; + +private: + Source source; + TextureType texture_type; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_source(Source p_source); + Source get_source() const; + + void set_texture(Ref<Texture> p_value); + Ref<Texture> get_texture() const; + + void set_texture_type(TextureType p_type); + TextureType get_texture_type() const; + + virtual Vector<StringName> get_editable_properties() const; + + virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const; + + VisualShaderNodeTexture(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeTexture::TextureType) +VARIANT_ENUM_CAST(VisualShaderNodeTexture::Source) + +////////////////////////////////// + +class VisualShaderNodeCubeMap : public VisualShaderNode { + GDCLASS(VisualShaderNodeCubeMap, VisualShaderNode) + Ref<CubeMap> cube_map; + +public: + enum TextureType { + TYPE_DATA, + TYPE_COLOR, + TYPE_NORMALMAP + }; + +private: + TextureType texture_type; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_cube_map(Ref<CubeMap> p_value); + Ref<CubeMap> get_cube_map() const; + + void set_texture_type(TextureType p_type); + TextureType get_texture_type() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeCubeMap(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeCubeMap::TextureType) +/////////////////////////////////////// + +class VisualShaderNodeScalarOp : public VisualShaderNode { + GDCLASS(VisualShaderNodeScalarOp, VisualShaderNode) + +public: + enum Operator { + OP_ADD, + OP_SUB, + OP_MUL, + OP_DIV, + OP_MOD, + OP_POW, + OP_MAX, + OP_MIN, + OP_ATAN2 + }; + +protected: + Operator op; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_operator(Operator p_op); + Operator get_operator() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeScalarOp(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeScalarOp::Operator) + +class VisualShaderNodeVectorOp : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorOp, VisualShaderNode) + +public: + enum Operator { + OP_ADD, + OP_SUB, + OP_MUL, + OP_DIV, + OP_MOD, + OP_POW, + OP_MAX, + OP_MIN, + OP_CROSS + + }; + +protected: + Operator op; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_operator(Operator p_op); + Operator get_operator() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeVectorOp(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeVectorOp::Operator) + +class VisualShaderNodeColorOp : public VisualShaderNode { + GDCLASS(VisualShaderNodeColorOp, VisualShaderNode) + +public: + enum Operator { + OP_SCREEN, + OP_DIFFERENCE, + OP_DARKEN, + OP_LIGHTEN, + OP_OVERLAY, + OP_DODGE, + OP_BURN, + OP_SOFT_LIGHT, + OP_HARD_LIGHT, + }; + +protected: + Operator op; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_operator(Operator p_op); + Operator get_operator() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeColorOp(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeColorOp::Operator) + +class VisualShaderNodeTransformMult : public VisualShaderNode { + GDCLASS(VisualShaderNodeTransformMult, VisualShaderNode) + +public: + enum Operator { + OP_AxB, + OP_BxA, + }; + +protected: + Operator op; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_operator(Operator p_op); + Operator get_operator() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeTransformMult(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeTransformMult::Operator) + +class VisualShaderNodeTransformVecMult : public VisualShaderNode { + GDCLASS(VisualShaderNodeTransformVecMult, VisualShaderNode) + +public: + enum Operator { + OP_AxB, + OP_BxA, + OP_3x3_AxB, + OP_3x3_BxA, + }; + +protected: + Operator op; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_operator(Operator p_op); + Operator get_operator() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeTransformVecMult(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeTransformVecMult::Operator) + +/////////////////////////////////////// + +class VisualShaderNodeScalarFunc : public VisualShaderNode { + GDCLASS(VisualShaderNodeScalarFunc, VisualShaderNode) + +public: + enum Function { + FUNC_SIN, + FUNC_COS, + FUNC_TAN, + FUNC_ASIN, + FUNC_ACOS, + FUNC_ATAN, + FUNC_SINH, + FUNC_COSH, + FUNC_TANH, + FUNC_LOG, + FUNC_EXP, + FUNC_SQRT, + FUNC_ABS, + FUNC_SIGN, + FUNC_FLOOR, + FUNC_ROUND, + FUNC_CEIL, + FUNC_FRAC, + FUNC_SATURATE, + FUNC_NEGATE, + }; + +protected: + Function func; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_function(Function p_func); + Function get_function() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeScalarFunc(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeScalarFunc::Function) + +/////////////////////////////////////// + +class VisualShaderNodeVectorFunc : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorFunc, VisualShaderNode) + +public: + enum Function { + FUNC_NORMALIZE, + FUNC_SATURATE, + FUNC_NEGATE, + FUNC_RECIPROCAL, + FUNC_RGB2HSV, + FUNC_HSV2RGB, + }; + +protected: + Function func; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_function(Function p_func); + Function get_function() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeVectorFunc(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeVectorFunc::Function) + +/////////////////////////////////////// + +class VisualShaderNodeDotProduct : public VisualShaderNode { + GDCLASS(VisualShaderNodeDotProduct, VisualShaderNode) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeDotProduct(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeVectorLen : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorLen, VisualShaderNode) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeVectorLen(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeScalarInterp : public VisualShaderNode { + GDCLASS(VisualShaderNodeScalarInterp, VisualShaderNode) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeScalarInterp(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeVectorInterp : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorInterp, VisualShaderNode) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeVectorInterp(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeVectorCompose : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorCompose, VisualShaderNode) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeVectorCompose(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeTransformCompose : public VisualShaderNode { + GDCLASS(VisualShaderNodeTransformCompose, VisualShaderNode) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeTransformCompose(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeVectorDecompose : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorDecompose, VisualShaderNode) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeVectorDecompose(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeTransformDecompose : public VisualShaderNode { + GDCLASS(VisualShaderNodeTransformDecompose, VisualShaderNode) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeTransformDecompose(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeScalarUniform : public VisualShaderNodeUniform { + GDCLASS(VisualShaderNodeScalarUniform, VisualShaderNodeUniform) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeScalarUniform(); +}; + +class VisualShaderNodeColorUniform : public VisualShaderNodeUniform { + GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeColorUniform(); +}; + +class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform { + GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeVec3Uniform(); +}; + +class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform { + GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeTransformUniform(); +}; + +////////////////////////////////// + +class VisualShaderNodeTextureUniform : public VisualShaderNodeUniform { + GDCLASS(VisualShaderNodeTextureUniform, VisualShaderNodeUniform) +public: + enum TextureType { + TYPE_DATA, + TYPE_COLOR, + TYPE_NORMALMAP, + TYPE_ANISO, + }; + + enum ColorDefault { + COLOR_DEFAULT_WHITE, + COLOR_DEFAULT_BLACK + }; + +private: + TextureType texture_type; + ColorDefault color_default; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + Vector<StringName> get_editable_properties() const; + + void set_texture_type(TextureType p_type); + TextureType get_texture_type() const; + + void set_color_default(ColorDefault p_default); + ColorDefault get_color_default() const; + + VisualShaderNodeTextureUniform(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureType) +VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::ColorDefault) + +////////////////////////////////// + +class VisualShaderNodeCubeMapUniform : public VisualShaderNode { + GDCLASS(VisualShaderNodeCubeMapUniform, VisualShaderNode) + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeCubeMapUniform(); +}; + +#endif // VISUAL_SHADER_NODES_H |