summaryrefslogtreecommitdiff
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/SCsub1
-rw-r--r--scene/resources/animation.cpp287
-rw-r--r--scene/resources/animation.h5
-rw-r--r--scene/resources/audio_stream_resampled.cpp30
-rw-r--r--scene/resources/audio_stream_resampled.h4
-rw-r--r--scene/resources/baked_light.cpp94
-rw-r--r--scene/resources/baked_light.h25
-rw-r--r--scene/resources/circle_shape_2d.cpp4
-rw-r--r--scene/resources/curve.cpp6
-rw-r--r--scene/resources/default_theme/default_theme.cpp19
-rw-r--r--scene/resources/default_theme/graph_node.pngbin0 -> 770 bytes
-rw-r--r--scene/resources/default_theme/graph_node_close.pngbin0 -> 243 bytes
-rw-r--r--scene/resources/default_theme/graph_port.pngbin0 -> 509 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h15
-rw-r--r--scene/resources/image_path_finder.cpp427
-rw-r--r--scene/resources/image_path_finder.h84
-rw-r--r--scene/resources/material.cpp177
-rw-r--r--scene/resources/material.h70
-rw-r--r--scene/resources/mesh.cpp246
-rw-r--r--scene/resources/mesh.h3
-rw-r--r--scene/resources/mikktspace.c1890
-rw-r--r--scene/resources/mikktspace.h145
-rw-r--r--scene/resources/packed_scene.cpp50
-rw-r--r--scene/resources/polygon_path_finder.cpp4
-rw-r--r--scene/resources/scene_preloader.cpp853
-rw-r--r--scene/resources/shader.cpp61
-rw-r--r--scene/resources/shader.h44
-rw-r--r--scene/resources/shader_graph.cpp2532
-rw-r--r--scene/resources/shader_graph.h413
-rw-r--r--scene/resources/shape_2d.cpp2
-rw-r--r--scene/resources/surface_tool.cpp206
-rw-r--r--scene/resources/surface_tool.h10
-rw-r--r--scene/resources/texture.cpp4
-rw-r--r--scene/resources/texture.h2
-rw-r--r--scene/resources/video_stream.cpp1
-rw-r--r--scene/resources/video_stream.h6
-rw-r--r--scene/resources/world_2d.cpp4
37 files changed, 5436 insertions, 2288 deletions
diff --git a/scene/resources/SCsub b/scene/resources/SCsub
index 87bd33e00e..eaa282ae1a 100644
--- a/scene/resources/SCsub
+++ b/scene/resources/SCsub
@@ -1,6 +1,7 @@
Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
+env.add_source_files(env.scene_sources,"*.c")
Export('env')
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 67f45ced2b..80993c7eaf 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1266,7 +1266,7 @@ T Animation::_interpolate( const Vector< TKey<T> >& p_keys, float p_time, Inter
}
} else { // no loop
-
+
if (idx>=0) {
if ((idx+1) < len) {
@@ -1716,185 +1716,222 @@ void Animation::clear() {
}
-void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,float p_alowed_angular_err) {
- ERR_FAIL_INDEX(p_idx,tracks.size());
- ERR_FAIL_COND(tracks[p_idx]->type!=TYPE_TRANSFORM);
- TransformTrack *tt= static_cast<TransformTrack*>(tracks[p_idx]);
- for(int i=1;i<tt->transforms.size()-1;i++) {
- TKey<TransformKey> &t0 = tt->transforms[i-1];
- TKey<TransformKey> &t1 = tt->transforms[i];
- TKey<TransformKey> &t2 = tt->transforms[i+1];
+bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) {
- real_t c = (t1.time-t0.time)/(t2.time-t0.time);
- real_t t[3]={-1,-1,-1};
- { //translation
+ real_t c = (t1.time-t0.time)/(t2.time-t0.time);
+ real_t t[3]={-1,-1,-1};
- const Vector3 &v0=t0.value.loc;
- const Vector3 &v1=t1.value.loc;
- const Vector3 &v2=t2.value.loc;
+ { //translation
- if (v0.distance_to(v2)<CMP_EPSILON) {
- //0 and 2 are close, let's see if 1 is close
- if (v0.distance_to(v1)>CMP_EPSILON) {
- //not close, not optimizable
- continue;
- }
+ const Vector3 &v0=t0.value.loc;
+ const Vector3 &v1=t1.value.loc;
+ const Vector3 &v2=t2.value.loc;
- } else {
+ if (v0.distance_to(v2)<CMP_EPSILON) {
+ //0 and 2 are close, let's see if 1 is close
+ if (v0.distance_to(v1)>CMP_EPSILON) {
+ //not close, not optimizable
+ return false;
+ }
- Vector3 pd = (v2-v0);
- float d0 = pd.dot(v0);
- float d1 = pd.dot(v1);
- float d2 = pd.dot(v2);
- if (d1<d0 || d1>d2) {
- continue; //beyond segment range
- }
+ } else {
- Vector3 s[2]={ v0, v2 };
- real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
+ Vector3 pd = (v2-v0);
+ float d0 = pd.dot(v0);
+ float d1 = pd.dot(v1);
+ float d2 = pd.dot(v2);
+ if (d1<d0 || d1>d2) {
+ return false;
+ }
- if (d>pd.length()*p_alowed_linear_err) {
- continue; //beyond allowed error for colinearity
- }
+ Vector3 s[2]={ v0, v2 };
+ real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
- t[0] = (d1-d0)/(d2-d0);
+ if (d>pd.length()*p_alowed_linear_err) {
+ return false; //beyond allowed error for colinearity
}
- }
- { //rotation
+ t[0] = (d1-d0)/(d2-d0);
+ }
+ }
- const Quat &q0=t0.value.rot;
- const Quat &q1=t1.value.rot;
- const Quat &q2=t2.value.rot;
+ { //rotation
- //localize both to rotation from q0
+ const Quat &q0=t0.value.rot;
+ const Quat &q1=t1.value.rot;
+ const Quat &q2=t2.value.rot;
- if ((q0-q2).length() < CMP_EPSILON) {
+ //localize both to rotation from q0
- if ((q0-q1).length() > CMP_EPSILON)
- continue;
+ if ((q0-q2).length() < CMP_EPSILON) {
- } else {
+ if ((q0-q1).length() > CMP_EPSILON)
+ return false;
- Quat r02 = (q0.inverse() * q2).normalized();
- Quat r01 = (q0.inverse() * q1).normalized();
+ } else {
- Vector3 v02,v01;
- real_t a02,a01;
- r02.get_axis_and_angle(v02,a02);
- r01.get_axis_and_angle(v01,a01);
+ Quat r02 = (q0.inverse() * q2).normalized();
+ Quat r01 = (q0.inverse() * q1).normalized();
- if (v01.dot(v02)<0) {
- //make sure both rotations go the same way to compare
- v02=-v02;
- a02=-a02;
- }
+ Vector3 v02,v01;
+ real_t a02,a01;
- real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized()))/Math_PI;
- if (err_01>p_alowed_angular_err) {
- //not rotating in the same axis
- continue;
- }
+ r02.get_axis_and_angle(v02,a02);
+ r01.get_axis_and_angle(v01,a01);
- if (a01*a02 < 0 ) {
- //not rotating in the same direction
- continue;
- }
+ if (Math::abs(a02)>p_max_optimizable_angle)
+ return false;
- real_t tr = a01/a02;
- if (tr<0 || tr>1)
- continue; //rotating too much or too less
+ if (v01.dot(v02)<0) {
+ //make sure both rotations go the same way to compare
+ v02=-v02;
+ a02=-a02;
+ }
- t[1]=tr;
+ real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized()))/Math_PI;
+ if (err_01>p_alowed_angular_err) {
+ //not rotating in the same axis
+ return false;
+ }
+ if (a01*a02 < 0 ) {
+ //not rotating in the same direction
+ return false;
}
+ real_t tr = a01/a02;
+ if (tr<0 || tr>1)
+ return false; //rotating too much or too less
+
+ t[1]=tr;
+
}
- { //scale
+ }
- const Vector3 &v0=t0.value.scale;
- const Vector3 &v1=t1.value.scale;
- const Vector3 &v2=t2.value.scale;
+ { //scale
- if (v0.distance_to(v2)<CMP_EPSILON) {
- //0 and 2 are close, let's see if 1 is close
- if (v0.distance_to(v1)>CMP_EPSILON) {
- //not close, not optimizable
- continue;
- }
+ const Vector3 &v0=t0.value.scale;
+ const Vector3 &v1=t1.value.scale;
+ const Vector3 &v2=t2.value.scale;
- } else {
+ if (v0.distance_to(v2)<CMP_EPSILON) {
+ //0 and 2 are close, let's see if 1 is close
+ if (v0.distance_to(v1)>CMP_EPSILON) {
+ //not close, not optimizable
+ return false;
+ }
- Vector3 pd = (v2-v0);
- float d0 = pd.dot(v0);
- float d1 = pd.dot(v1);
- float d2 = pd.dot(v2);
- if (d1<d0 || d1>d2) {
- continue; //beyond segment range
- }
+ } else {
- Vector3 s[2]={ v0, v2 };
- real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
+ Vector3 pd = (v2-v0);
+ float d0 = pd.dot(v0);
+ float d1 = pd.dot(v1);
+ float d2 = pd.dot(v2);
+ if (d1<d0 || d1>d2) {
+ return false; //beyond segment range
+ }
- if (d>pd.length()*p_alowed_linear_err) {
- continue; //beyond allowed error for colinearity
- }
+ Vector3 s[2]={ v0, v2 };
+ real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
- t[2] = (d1-d0)/(d2-d0);
+ if (d>pd.length()*p_alowed_linear_err) {
+ return false; //beyond allowed error for colinearity
}
+
+ t[2] = (d1-d0)/(d2-d0);
}
+ }
- bool erase=false;
- if (t[0]==-1 && t[1]==-1 && t[2]==-1) {
+ bool erase=false;
+ if (t[0]==-1 && t[1]==-1 && t[2]==-1) {
- erase=true;
- } else {
+ erase=true;
+ } else {
- erase=true;
- real_t lt=-1;
- for(int j=0;j<3;j++) {
- //search for t on first, one must be it
- if (t[j]!=-1) {
- lt=t[j]; //official t
- //validate rest
- for(int k=j+1;k<3;k++) {
- if (t[k]==-1)
- continue;
-
- if (Math::abs(lt-t[k])>p_alowed_linear_err) {
- erase=false;
- break;
- }
+ erase=true;
+ real_t lt=-1;
+ for(int j=0;j<3;j++) {
+ //search for t on first, one must be it
+ if (t[j]!=-1) {
+ lt=t[j]; //official t
+ //validate rest
+ for(int k=j+1;k<3;k++) {
+ if (t[k]==-1)
+ continue;
+
+ if (Math::abs(lt-t[k])>p_alowed_linear_err) {
+ erase=false;
+ break;
}
- break;
}
+ break;
}
+ }
- ERR_CONTINUE( lt==-1 );
+ ERR_FAIL_COND_V( lt==-1,false );
- if (erase) {
+ if (erase) {
- if (Math::abs(lt-c)>p_alowed_linear_err) {
- //todo, evaluate changing the transition if this fails?
- //this could be done as a second pass and would be
- //able to optimize more
- erase=false;
- } else {
+ if (Math::abs(lt-c)>p_alowed_linear_err) {
+ //todo, evaluate changing the transition if this fails?
+ //this could be done as a second pass and would be
+ //able to optimize more
+ erase=false;
+ } else {
- //print_line(itos(i)+"because of interp");
- }
+ //print_line(itos(i)+"because of interp");
}
+ }
+
+ }
+
+
+ return erase;
+
+
+}
+
+void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) {
+
+ ERR_FAIL_INDEX(p_idx,tracks.size());
+ ERR_FAIL_COND(tracks[p_idx]->type!=TYPE_TRANSFORM);
+ TransformTrack *tt= static_cast<TransformTrack*>(tracks[p_idx]);
+ bool prev_erased=false;
+ TKey<TransformKey> first_erased;
+
+ for(int i=1;i<tt->transforms.size()-1;i++) {
+
+ TKey<TransformKey> &t0 = tt->transforms[i-1];
+ TKey<TransformKey> &t1 = tt->transforms[i];
+ TKey<TransformKey> &t2 = tt->transforms[i+1];
+
+ bool erase = _transform_track_optimize_key(t0,t1,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle);
+
+
+ if (prev_erased && !_transform_track_optimize_key(t0,first_erased,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle)) {
+ //avoid error to go beyond first erased key
+ erase=false;
}
+
if (erase) {
+
+ if (!prev_erased) {
+ first_erased=t1;
+ prev_erased=true;
+ }
+
tt->transforms.remove(i);
i--;
+
+ } else {
+ prev_erased=false;
}
@@ -1905,7 +1942,7 @@ void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,fl
}
-void Animation::optimize(float p_allowed_linear_err,float p_allowed_angular_err) {
+void Animation::optimize(float p_allowed_linear_err,float p_allowed_angular_err,float p_angle_max) {
int total_tt=0;
@@ -1913,7 +1950,7 @@ void Animation::optimize(float p_allowed_linear_err,float p_allowed_angular_err)
for(int i=0;i<tracks.size();i++) {
if (tracks[i]->type==TYPE_TRANSFORM)
- _transform_track_optimize(i,p_allowed_linear_err,p_allowed_angular_err);
+ _transform_track_optimize(i,p_allowed_linear_err,p_allowed_angular_err,p_angle_max);
}
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 4c4e2f0275..bf87789e39 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -204,7 +204,8 @@ private:
return idxr;
}
- void _transform_track_optimize(int p_idx, float p_allowed_err=0.05, float p_alowed_angular_err=0.01);
+ bool _transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle);
+ void _transform_track_optimize(int p_idx, float p_allowed_err=0.05, float p_alowed_angular_err=0.01,float p_max_optimizable_angle=Math_PI*0.125);
protected:
@@ -271,7 +272,7 @@ public:
void clear();
- void optimize(float p_allowed_linear_err=0.05,float p_allowed_angular_err=0.01);
+ void optimize(float p_allowed_linear_err=0.05,float p_allowed_angular_err=0.01,float p_max_optimizable_angle=Math_PI*0.125);
Animation();
~Animation();
diff --git a/scene/resources/audio_stream_resampled.cpp b/scene/resources/audio_stream_resampled.cpp
index 8e694a6110..bc7bffa9d2 100644
--- a/scene/resources/audio_stream_resampled.cpp
+++ b/scene/resources/audio_stream_resampled.cpp
@@ -38,15 +38,18 @@ int AudioStreamResampled::get_channel_count() const {
template<int C>
-void AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increment) {
+uint32_t AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increment) {
+
+ uint32_t read=offset&MIX_FRAC_MASK;
for (int i=0;i<p_todo;i++) {
offset = (offset + p_increment)&(((1<<(rb_bits+MIX_FRAC_BITS))-1));
+ read+=p_increment;
uint32_t pos = offset >> MIX_FRAC_BITS;
uint32_t frac = offset & MIX_FRAC_MASK;
#ifndef FAST_AUDIO
- ERR_FAIL_COND(pos>=rb_len);
+ ERR_FAIL_COND_V(pos>=rb_len,0);
#endif
uint32_t pos_next = (pos+1)&rb_mask;
//printf("rb pos %i\n",pos);
@@ -151,7 +154,7 @@ void AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increm
}
- rb_read_pos=offset>>MIX_FRAC_BITS;
+ return read>>MIX_FRAC_BITS;//rb_read_pos=offset>>MIX_FRAC_BITS;
}
@@ -173,10 +176,10 @@ bool AudioStreamResampled::mix(int32_t *p_dest, int p_frames) {
} else if (rb_read_pos<write_pos_cache) {
- rb_todo=write_pos_cache-rb_read_pos-1;
+ rb_todo=write_pos_cache-rb_read_pos; //-1?
} else {
- rb_todo=(rb_len-rb_read_pos)+write_pos_cache-1;
+ rb_todo=(rb_len-rb_read_pos)+write_pos_cache; //-1?
}
int todo = MIN( ((int64_t(rb_todo)<<MIX_FRAC_BITS)/increment)+1, p_frames );
@@ -220,13 +223,22 @@ bool AudioStreamResampled::mix(int32_t *p_dest, int p_frames) {
#endif
{
+ uint32_t read=0;
switch(channels) {
- case 1: _resample<1>(p_dest,todo,increment); break;
- case 2: _resample<2>(p_dest,todo,increment); break;
- case 4: _resample<4>(p_dest,todo,increment); break;
- case 6: _resample<6>(p_dest,todo,increment); break;
+ case 1: read=_resample<1>(p_dest,todo,increment); break;
+ case 2: read=_resample<2>(p_dest,todo,increment); break;
+ case 4: read=_resample<4>(p_dest,todo,increment); break;
+ case 6: read=_resample<6>(p_dest,todo,increment); break;
}
+ if (read>rb_todo)
+ read=rb_todo;
+
+ rb_read_pos = (rb_read_pos+read)&rb_mask;
+
+
+
+
}
return true;
diff --git a/scene/resources/audio_stream_resampled.h b/scene/resources/audio_stream_resampled.h
index f1e3629ac7..a1b95e81d5 100644
--- a/scene/resources/audio_stream_resampled.h
+++ b/scene/resources/audio_stream_resampled.h
@@ -57,7 +57,7 @@ class AudioStreamResampled : public AudioStream {
template<int C>
- void _resample(int32_t *p_dest,int p_todo,int32_t p_increment);
+ uint32_t _resample(int32_t *p_dest,int p_todo,int32_t p_increment);
protected:
@@ -97,7 +97,7 @@ protected:
_FORCE_INLINE_ int16_t *get_write_buffer() { return read_buf; }
_FORCE_INLINE_ void write(uint32_t p_frames) {
- ERR_FAIL_COND(p_frames > rb_len);
+ ERR_FAIL_COND(p_frames >= rb_len);
switch(channels) {
case 1: {
diff --git a/scene/resources/baked_light.cpp b/scene/resources/baked_light.cpp
index 647c8df5d4..226edec9ae 100644
--- a/scene/resources/baked_light.cpp
+++ b/scene/resources/baked_light.cpp
@@ -23,6 +23,27 @@ DVector<uint8_t> BakedLight::get_octree() const {
return VS::get_singleton()->baked_light_get_octree(baked_light);
}
+void BakedLight::set_light(const DVector<uint8_t>& p_light) {
+
+ VS::get_singleton()->baked_light_set_light(baked_light,p_light);
+}
+
+DVector<uint8_t> BakedLight::get_light() const {
+
+ return VS::get_singleton()->baked_light_get_light(baked_light);
+}
+
+
+void BakedLight::set_sampler_octree(const DVector<int>& p_sampler_octree) {
+
+ VS::get_singleton()->baked_light_set_sampler_octree(baked_light,p_sampler_octree);
+}
+
+DVector<int> BakedLight::get_sampler_octree() const {
+
+ return VS::get_singleton()->baked_light_get_sampler_octree(baked_light);
+}
+
@@ -199,6 +220,43 @@ float BakedLight::get_normal_damp() const {
return normal_damp;
}
+void BakedLight::set_tint(float p_margin) {
+ tint=p_margin;
+}
+
+float BakedLight::get_tint() const {
+
+ return tint;
+}
+
+void BakedLight::set_saturation(float p_margin) {
+ saturation=p_margin;
+}
+
+float BakedLight::get_saturation() const {
+
+ return saturation;
+}
+
+void BakedLight::set_ao_radius(float p_ao_radius) {
+ ao_radius=p_ao_radius;
+}
+
+float BakedLight::get_ao_radius() const {
+ return ao_radius;
+}
+
+void BakedLight::set_ao_strength(float p_ao_strength) {
+
+ ao_strength=p_ao_strength;
+}
+
+float BakedLight::get_ao_strength() const {
+
+ return ao_strength;
+}
+
+
void BakedLight::set_energy_multiplier(float p_multiplier){
energy_multiply=p_multiplier;
@@ -329,6 +387,13 @@ void BakedLight::_bind_methods(){
ObjectTypeDB::bind_method(_MD("set_octree","octree"),&BakedLight::set_octree);
ObjectTypeDB::bind_method(_MD("get_octree"),&BakedLight::get_octree);
+ ObjectTypeDB::bind_method(_MD("set_light","light"),&BakedLight::set_light);
+ ObjectTypeDB::bind_method(_MD("get_light"),&BakedLight::get_light);
+
+ ObjectTypeDB::bind_method(_MD("set_sampler_octree","sampler_octree"),&BakedLight::set_sampler_octree);
+ ObjectTypeDB::bind_method(_MD("get_sampler_octree"),&BakedLight::get_sampler_octree);
+
+
ObjectTypeDB::bind_method(_MD("add_lightmap","texture:Texture","gen_size"),&BakedLight::add_lightmap);
ObjectTypeDB::bind_method(_MD("erase_lightmap","id"),&BakedLight::erase_lightmap);
ObjectTypeDB::bind_method(_MD("clear_lightmaps"),&BakedLight::clear_lightmaps);
@@ -357,6 +422,18 @@ void BakedLight::_bind_methods(){
ObjectTypeDB::bind_method(_MD("set_normal_damp","normal_damp"),&BakedLight::set_normal_damp);
ObjectTypeDB::bind_method(_MD("get_normal_damp"),&BakedLight::get_normal_damp);
+ ObjectTypeDB::bind_method(_MD("set_tint","tint"),&BakedLight::set_tint);
+ ObjectTypeDB::bind_method(_MD("get_tint"),&BakedLight::get_tint);
+
+ ObjectTypeDB::bind_method(_MD("set_saturation","saturation"),&BakedLight::set_saturation);
+ ObjectTypeDB::bind_method(_MD("get_saturation"),&BakedLight::get_saturation);
+
+ ObjectTypeDB::bind_method(_MD("set_ao_radius","ao_radius"),&BakedLight::set_ao_radius);
+ ObjectTypeDB::bind_method(_MD("get_ao_radius"),&BakedLight::get_ao_radius);
+
+ ObjectTypeDB::bind_method(_MD("set_ao_strength","ao_strength"),&BakedLight::set_ao_strength);
+ ObjectTypeDB::bind_method(_MD("get_ao_strength"),&BakedLight::get_ao_strength);
+
ObjectTypeDB::bind_method(_MD("set_format","format"),&BakedLight::set_format);
ObjectTypeDB::bind_method(_MD("get_format"),&BakedLight::get_format);
@@ -384,17 +461,24 @@ void BakedLight::_bind_methods(){
ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/plot_size",PROPERTY_HINT_RANGE,"1.0,16.0,0.01"),_SCS("set_plot_size"),_SCS("get_plot_size"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/energy_mult",PROPERTY_HINT_RANGE,"0.01,4096.0,0.01"),_SCS("set_energy_multiplier"),_SCS("get_energy_multiplier"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/gamma_adjust",PROPERTY_HINT_EXP_EASING),_SCS("set_gamma_adjust"),_SCS("get_gamma_adjust"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/saturation",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("set_saturation"),_SCS("get_saturation"));
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/diffuse"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_DIFFUSE);
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/specular"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_SPECULAR);
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/translucent"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_TRANSLUCENT);
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/conserve_energy"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_CONSERVE_ENERGY);
+ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/linear_color"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_LINEAR_COLOR);
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"lightmap/use_only_uv2"),_SCS("set_transfer_lightmaps_only_to_uv2"),_SCS("get_transfer_lightmaps_only_to_uv2"));
ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_octree"),_SCS("get_octree"));
+ ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"light",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_light"),_SCS("get_light"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT_ARRAY,"sampler_octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_sampler_octree"),_SCS("get_sampler_octree"));
ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"lightmaps",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_lightmap_data"),_SCS("_get_lightmap_data"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/cell_margin",PROPERTY_HINT_RANGE,"0.01,0.8,0.01"),_SCS("set_cell_extra_margin"),_SCS("get_cell_extra_margin"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/edge_damp",PROPERTY_HINT_RANGE,"0.0,8.0,0.1"),_SCS("set_edge_damp"),_SCS("get_edge_damp"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/normal_damp",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_normal_damp"),_SCS("get_normal_damp"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/light_tint",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_tint"),_SCS("get_tint"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_radius",PROPERTY_HINT_RANGE,"0.0,16.0,0.01"),_SCS("set_ao_radius"),_SCS("get_ao_radius"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_strength",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_ao_strength"),_SCS("get_ao_strength"));
BIND_CONSTANT( MODE_OCTREE );
BIND_CONSTANT( MODE_LIGHTMAPS );
@@ -415,18 +499,24 @@ BakedLight::BakedLight() {
lattice_subdiv=4;
plot_size=2.5;
bounces=1;
- energy_multiply=1.0;
- gamma_adjust=1.0;
+ energy_multiply=2.0;
+ gamma_adjust=0.7;
cell_extra_margin=0.05;
edge_damp=0.0;
normal_damp=0.0;
+ saturation=1;
+ tint=0.0;
+ ao_radius=2.5;
+ ao_strength=0.7;
format=FORMAT_RGB;
transfer_only_uv2=false;
+
flags[BAKE_DIFFUSE]=true;
flags[BAKE_SPECULAR]=false;
flags[BAKE_TRANSLUCENT]=true;
flags[BAKE_CONSERVE_ENERGY]=false;
+ flags[BAKE_LINEAR_COLOR]=false;
mode=MODE_OCTREE;
baked_light=VS::get_singleton()->baked_light_create();
diff --git a/scene/resources/baked_light.h b/scene/resources/baked_light.h
index 57ed7d7aee..41e1e5f9e0 100644
--- a/scene/resources/baked_light.h
+++ b/scene/resources/baked_light.h
@@ -26,6 +26,7 @@ public:
BAKE_SPECULAR,
BAKE_TRANSLUCENT,
BAKE_CONSERVE_ENERGY,
+ BAKE_LINEAR_COLOR,
BAKE_MAX
};
@@ -50,6 +51,10 @@ private:
float cell_extra_margin;
float edge_damp;
float normal_damp;
+ float tint;
+ float ao_radius;
+ float ao_strength;
+ float saturation;
int bounces;
bool transfer_only_uv2;
Format format;
@@ -99,6 +104,18 @@ public:
void set_normal_damp(float p_margin);
float get_normal_damp() const;
+ void set_tint(float p_margin);
+ float get_tint() const;
+
+ void set_saturation(float p_saturation);
+ float get_saturation() const;
+
+ void set_ao_radius(float p_ao_radius);
+ float get_ao_radius() const;
+
+ void set_ao_strength(float p_ao_strength);
+ float get_ao_strength() const;
+
void set_bake_flag(BakeFlags p_flags,bool p_enable);
bool get_bake_flag(BakeFlags p_flags) const;
@@ -114,6 +131,14 @@ public:
void set_octree(const DVector<uint8_t>& p_octree);
DVector<uint8_t> get_octree() const;
+ void set_light(const DVector<uint8_t>& p_light);
+ DVector<uint8_t> get_light() const;
+
+ void set_sampler_octree(const DVector<int>& p_sampler_octree);
+ DVector<int> get_sampler_octree() const;
+
+
+
void add_lightmap(const Ref<Texture> &p_texture,Size2 p_gen_size=Size2(256,256));
void set_lightmap_gen_size(int p_idx,const Size2& p_size);
Size2 get_lightmap_gen_size(int p_idx) const;
diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp
index 056be87e72..d6a9db690b 100644
--- a/scene/resources/circle_shape_2d.cpp
+++ b/scene/resources/circle_shape_2d.cpp
@@ -54,9 +54,7 @@ void CircleShape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_radius","radius"),&CircleShape2D::set_radius);
ObjectTypeDB::bind_method(_MD("get_radius"),&CircleShape2D::get_radius);
-
-
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"radius"),_SCS("set_radius"),_SCS("get_radius") );
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"radius",PROPERTY_HINT_RANGE,"0.01,16384,0.5"),_SCS("set_radius"),_SCS("get_radius") );
}
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index ae2c07ff56..6c27ffc6d9 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -134,7 +134,7 @@ Vector2 Curve2D::interpolate(int p_index, float p_offset) const {
Vector2 Curve2D::interpolatef(real_t p_findex) const {
- if (p_findex>0)
+ if (p_findex<0)
p_findex=0;
else if (p_findex>=points.size())
p_findex=points.size();
@@ -485,7 +485,7 @@ Vector2 Curve2D::interpolate(int p_index, float p_offset) const {
Vector2 Curve2D::interpolatef(real_t p_findex) const {
- if (p_findex>0)
+ if (p_findex<0)
p_findex=0;
else if (p_findex>=points.size())
p_findex=points.size();
@@ -956,7 +956,7 @@ Vector3 Curve3D::interpolate(int p_index, float p_offset) const {
Vector3 Curve3D::interpolatef(real_t p_findex) const {
- if (p_findex>0)
+ if (p_findex<0)
p_findex=0;
else if (p_findex>=points.size())
p_findex=points.size();
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index d10bb37f60..e7f0d9b1f5 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -65,7 +65,7 @@ static Ref<Texture> make_icon(T p_src) {
Ref<ImageTexture> texture( memnew( ImageTexture ) );
- texture->create_from_image( Image(p_src) );
+ texture->create_from_image( Image(p_src),ImageTexture::FLAG_FILTER );
return texture;
}
@@ -331,6 +331,7 @@ void make_default_theme() {
t->set_color("current_line_color","TextEdit", Color(0.3,0.5,0.8,0.15) );
t->set_color("cursor_color","TextEdit", control_font_color );
t->set_color("symbol_color","TextEdit", control_font_color_hover );
+ t->set_color("brace_mismatch_color","TextEdit", Color(1,0.2,0.2) );
t->set_constant("line_spacing","TextEdit",1 );
t->set_stylebox("scroll","HScrollBar", make_stylebox( hscroll_bg_png,3,3,3,3,0,0,0,0) );
@@ -415,7 +416,21 @@ void make_default_theme() {
t->set_color("font_color_hover","PopupMenu", control_font_color );
t->set_constant("hseparation","PopupMenu",2);
t->set_constant("vseparation","PopupMenu",1);
-
+
+ Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5);
+ //graphsb->set_expand_margin_size(MARGIN_LEFT,10);
+ //graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
+ t->set_stylebox("frame","GraphNode", graphsb );
+ t->set_constant("separation","GraphNode", 1 );
+ t->set_icon("port","GraphNode", make_icon( graph_port_png ) );
+ t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) );
+ t->set_font("title_font","GraphNode", default_font );
+ t->set_color("title_color","GraphNode", Color(0,0,0,1));
+ t->set_constant("title_offset","GraphNode", 18);
+ t->set_constant("close_offset","GraphNode", 18);
+ t->set_constant("port_offset","GraphNode", 3);
+
+
t->set_stylebox("bg","Tree", make_stylebox( tree_bg_png,4,4,4,5,3,3,3,3) );
t->set_stylebox("bg_focus","Tree", focus );
Ref<StyleBoxTexture> tree_selected = make_stylebox( selection_png,4,4,4,4);
diff --git a/scene/resources/default_theme/graph_node.png b/scene/resources/default_theme/graph_node.png
new file mode 100644
index 0000000000..3adccf2c3b
--- /dev/null
+++ b/scene/resources/default_theme/graph_node.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_close.png b/scene/resources/default_theme/graph_node_close.png
new file mode 100644
index 0000000000..ea5b510418
--- /dev/null
+++ b/scene/resources/default_theme/graph_node_close.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_port.png b/scene/resources/default_theme/graph_port.png
new file mode 100644
index 0000000000..92f425f977
--- /dev/null
+++ b/scene/resources/default_theme/graph_port.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index 9cef0265ee..a0f3dcd988 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -99,6 +99,21 @@ static const unsigned char full_panel_bg_png[]={
};
+static const unsigned char graph_node_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0xc,0x14,0x10,0x3,0x2e,0x15,0xb6,0x7,0x4a,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x2,0x6a,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0xbb,0x6e,0x13,0x51,0x10,0x86,0xbf,0xf1,0x2e,0xb1,0x83,0x85,0x63,0x5,0x10,0xe2,0x22,0xa5,0x0,0x1a,0x24,0x90,0x22,0x9e,0x81,0x2,0xd1,0x53,0xf1,0x2,0x20,0xa,0x1a,0xa,0xa0,0x44,0xd0,0xd0,0x20,0x81,0xe0,0x5,0xa8,0xe8,0x11,0x5,0xcf,0x80,0x22,0x81,0x42,0x3,0x14,0x91,0xb8,0x4,0x85,0x58,0x8e,0x21,0x78,0xd7,0xd9,0x73,0x86,0xe2,0x9c,0xdd,0xec,0xae,0xd7,0xce,0x85,0xe,0xed,0x34,0xbb,0x3a,0x3e,0xf3,0xcd,0xcc,0x3f,0x63,0x69,0x47,0xd8,0x36,0x1,0x1a,0x40,0xe0,0x9f,0x42,0xd1,0x14,0xb0,0x80,0xf1,0x4f,0x25,0x77,0xa9,0x1,0x1c,0x4,0xe6,0x81,0xa3,0x40,0x7,0x38,0x50,0x2,0x6c,0x1,0x3,0x60,0xd,0xe8,0x1,0x7f,0x0,0x9b,0x46,0x6d,0x3,0x67,0xe6,0xe,0x75,0xaf,0xb7,0x9a,0xad,0xcb,0x33,0x33,0xcd,0x53,0x54,0xd8,0x68,0x14,0x7f,0x89,0xe2,0xe8,0xf5,0xc6,0xaf,0xfe,0x73,0xe0,0x13,0xb0,0x29,0x3e,0xd2,0xc2,0x7c,0xf7,0xf0,0xe3,0xd3,0xb,0x67,0xaf,0x3c,0xb8,0xfb,0x88,0xd9,0x4e,0xab,0xca,0x9f,0xe1,0x20,0xe2,0xde,0xc3,0xdb,0x7c,0x5e,0xf9,0xf8,0xaa,0xd7,0x5f,0xbf,0x5,0xac,0x8,0xd0,0x2,0x16,0x8f,0x1f,0x3b,0xf9,0xe6,0xc5,0xb3,0x97,0xed,0x24,0xb1,0x24,0xa3,0xa4,0x12,0x10,0xce,0x84,0x84,0x61,0x83,0x6b,0x37,0xae,0x6e,0x7e,0xff,0xf1,0xf5,0x12,0xb0,0x14,0x7a,0x1d,0xda,0x61,0x10,0xb6,0x87,0xbf,0x63,0x10,0x75,0x47,0xa,0x2a,0x79,0x85,0x95,0x51,0xbc,0xc5,0x28,0x86,0x30,0x8,0xdb,0xbe,0x6c,0x49,0x1,0x1,0x80,0x51,0xeb,0xfc,0x9d,0xc0,0x4e,0x6b,0xf,0xd1,0xfc,0xb9,0xb3,0x20,0x5,0x68,0xfa,0x8b,0x5a,0x8b,0xaa,0x80,0x28,0x82,0xa0,0x28,0xa2,0x92,0x73,0xd3,0xb1,0xde,0x86,0x85,0x46,0x5b,0x45,0x51,0x50,0x45,0xc4,0x95,0x61,0x53,0x27,0x71,0x61,0x74,0x1a,0xc0,0xaa,0xcd,0x6e,0xa8,0x64,0x2f,0xee,0x5d,0x29,0x8a,0x32,0x39,0x3,0x5f,0xb6,0x2f,0x4c,0x45,0x73,0x5a,0xd8,0x31,0x48,0x1,0x60,0xac,0x2d,0xf1,0x5,0x51,0x75,0x45,0x68,0x5a,0xbf,0x4e,0xcf,0x60,0xfb,0x82,0x2b,0x5a,0x73,0x4e,0xb6,0xe2,0xf,0x52,0x2,0xd8,0x82,0xe2,0x14,0x50,0x54,0xc4,0x2f,0x8b,0x68,0xad,0x1f,0x99,0x54,0x79,0x41,0xdd,0x0,0xf8,0xb6,0x82,0x88,0x4e,0xeb,0x82,0x66,0x89,0xaa,0x3b,0xc8,0x52,0x48,0x41,0x56,0x76,0xcc,0x60,0x7b,0x74,0x75,0xac,0x1a,0x49,0x47,0x72,0x72,0x6,0xe2,0xe7,0x56,0x45,0xfd,0x5d,0xc9,0x44,0x28,0x40,0x2b,0x45,0x34,0xea,0x7,0xa8,0x14,0xc9,0x92,0x75,0x64,0x7,0x11,0x8d,0x8f,0x98,0x9b,0x87,0xf2,0xf4,0x4d,0xd5,0x40,0xd5,0xc9,0x97,0xf,0xa3,0x5a,0x74,0x9c,0x36,0x89,0xf7,0x9f,0xdc,0x61,0xaf,0x96,0x1,0x92,0x2d,0xc3,0xe2,0xf9,0x8b,0xbb,0x72,0x5a,0x7a,0xff,0xb6,0x3a,0x83,0x8d,0x41,0x7f,0xcf,0x19,0x34,0xf8,0x47,0xab,0x1,0x35,0xa0,0x6,0xd4,0x80,0x1a,0x50,0x3,0x6a,0xc0,0x7f,0x9,0x90,0x8a,0x4f,0xe0,0x3d,0x67,0x60,0xf7,0xe1,0x6b,0x53,0x80,0x5,0x22,0x63,0x4c,0x6c,0x93,0x5d,0x78,0x25,0x60,0x8c,0x89,0x81,0x8,0xb0,0xd,0xbf,0xca,0xae,0x47,0xf1,0x70,0x79,0xad,0xb7,0xca,0x34,0x88,0x4d,0x60,0xad,0xb7,0x4a,0x14,0xf,0x97,0x81,0x75,0xc0,0xa4,0x9b,0xeb,0x1c,0x70,0xa1,0xd3,0xee,0x3e,0x6d,0x35,0x67,0xcf,0x5,0x41,0x50,0x29,0xae,0x31,0xc6,0x46,0xf1,0xf0,0xc3,0x60,0xb3,0x7f,0x13,0x78,0x7,0x6c,0x48,0x6e,0x85,0xeb,0x0,0x27,0x80,0x23,0x40,0x73,0xc2,0xf2,0x1d,0x3,0x3f,0x81,0x6f,0x7e,0x8f,0x36,0x52,0x12,0x34,0x4c,0xf7,0xc1,0x9,0x55,0xa8,0x2f,0x39,0xd9,0xa7,0xf0,0xe3,0xf6,0x17,0x4c,0x97,0x1d,0x24,0x5b,0x8,0x8b,0x95,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char graph_node_close_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0xc,0x15,0x14,0x15,0x39,0x35,0x48,0xf8,0xe3,0x0,0x0,0x0,0x80,0x49,0x44,0x41,0x54,0x28,0xcf,0xa5,0xd1,0xb1,0xa,0xc2,0x40,0x10,0x84,0xe1,0x4f,0xe5,0x30,0xad,0x9d,0xb5,0x60,0xeb,0x3,0x88,0x2f,0x6d,0xfa,0xb4,0x29,0x83,0xbd,0xb5,0xb5,0x9d,0x68,0x15,0x9b,0x3d,0xb9,0x4,0x11,0xe,0x7,0xb6,0xd9,0xfd,0x67,0xb9,0xb9,0xa5,0x52,0xab,0xa8,0x13,0xb6,0x78,0xe0,0x39,0x63,0x36,0x38,0x60,0x87,0x1b,0x34,0xb8,0x60,0xc4,0x19,0xa9,0x80,0x53,0xf4,0xc6,0x60,0x9a,0x72,0xd0,0xc6,0xa0,0x2b,0xc,0x5d,0xf4,0xda,0xd9,0xa2,0x8f,0x29,0x3,0x43,0x54,0x5e,0x90,0x7e,0xe5,0xca,0x60,0x36,0x4e,0xb4,0xf4,0x87,0xaa,0x9e,0x54,0x15,0xba,0xea,0x5b,0x17,0x71,0xb8,0x23,0x5e,0xb8,0xe2,0xfe,0xe5,0x70,0x7b,0xac,0xd1,0x57,0x7,0x7d,0x3,0x51,0x8f,0x29,0x6b,0x3c,0x49,0x28,0x81,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char graph_port_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0xa,0x8,0x6,0x0,0x0,0x0,0x8d,0x32,0xcf,0xbd,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0xf9,0x43,0xbb,0x7f,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0xc,0x14,0x17,0x20,0x3,0xeb,0x8f,0x3a,0xdb,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x65,0x49,0x44,0x41,0x54,0x18,0xd3,0x4d,0xd0,0x4f,0x6b,0xda,0x70,0x1c,0x7,0xe0,0xcf,0x37,0x7f,0x7e,0x49,0x66,0xd2,0x64,0x61,0x5,0x61,0x76,0x47,0xf1,0xa4,0x2d,0xdb,0x75,0x5,0x11,0x84,0xb0,0x5e,0xeb,0xd9,0xeb,0xf4,0x6d,0xec,0x2d,0xf8,0x26,0xb6,0x77,0xe0,0x45,0xba,0xa3,0x6c,0xa0,0x3b,0xad,0x39,0xb6,0x36,0x8,0x1b,0x4b,0x32,0xd2,0xc6,0x6c,0x9a,0x4f,0x4f,0x85,0x3e,0x2f,0xe1,0x11,0x0,0x20,0x29,0xd3,0xe9,0xd4,0xda,0x6e,0xb7,0x23,0xdf,0xf7,0xbb,0x0,0x90,0xe7,0xf9,0x8f,0x66,0xb3,0xf9,0x79,0x36,0x9b,0x55,0x22,0x42,0x83,0xa4,0x44,0x51,0xf4,0xea,0xe2,0xe2,0xc3,0xf7,0xf1,0x78,0xdc,0xa,0x82,0x40,0x8,0x20,0xcf,0x32,0x2e,0x97,0xcb,0x4f,0x51,0x14,0xbd,0x25,0xf9,0x5b,0x26,0x93,0x89,0xdd,0xe9,0x74,0xe2,0xf7,0xe7,0xe7,0x27,0x59,0xfa,0x87,0x65,0xb9,0x13,0x0,0xb0,0x1d,0x9b,0xe1,0xcb,0x50,0xbe,0x5e,0x5d,0xdd,0xfe,0xbc,0xbe,0x6e,0x6b,0x49,0x92,0x8c,0x4e,0x7b,0xa7,0xad,0xbf,0x79,0x4e,0xd3,0x54,0x12,0x86,0x21,0xc2,0x30,0x84,0x32,0x95,0xe4,0x79,0xc6,0xde,0xd9,0x59,0x2b,0x49,0xee,0x46,0x86,0xeb,0xba,0x5d,0xfb,0x85,0x23,0x87,0xfd,0x1e,0xb6,0xed,0x40,0xd7,0x35,0x0,0x40,0x7d,0x38,0xa0,0xdc,0xed,0x44,0x37,0x74,0xb8,0xae,0xd7,0x35,0x48,0x62,0xff,0xff,0x1f,0xfc,0x20,0x80,0xae,0xe9,0x78,0x42,0x0,0xca,0xb2,0x90,0x65,0x19,0x58,0xd7,0xd0,0x8a,0xa2,0x58,0xa7,0x69,0x56,0x6b,0xa2,0x51,0x29,0x5,0xcb,0x52,0xb0,0x94,0x5,0x4b,0x29,0x88,0x8,0xd3,0x34,0xad,0x8b,0xfb,0x62,0xad,0xf,0x6,0x83,0xb8,0xaa,0xaa,0xb1,0xe7,0x79,0xbe,0x77,0x74,0x44,0xb7,0xe1,0x89,0x69,0x1a,0x28,0xcb,0x92,0x9b,0xcd,0x46,0x56,0xab,0xd5,0x86,0xe4,0x47,0x21,0x29,0xc3,0xe1,0xf0,0xb8,0xdf,0xef,0x7f,0x6b,0xb7,0xdb,0xaf,0x1b,0x8d,0x86,0x46,0x10,0xf,0xf7,0xf,0x75,0x1c,0xc7,0x77,0x8b,0xc5,0xe2,0xdd,0x7c,0x3e,0xff,0x25,0xcf,0xc3,0x6f,0x6e,0x6f,0x2e,0x1d,0xdb,0xe9,0x9,0x80,0xb2,0x2a,0xd7,0x27,0xad,0x37,0x5f,0x9e,0xc2,0x1f,0x1,0x3a,0xe6,0xa5,0x7b,0xef,0xf2,0xf3,0xcd,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
static const unsigned char hscroll_bg_png[]={
0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0xc4,0xf,0xbe,0x8b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdd,0x9,0x1b,0x12,0x30,0x1c,0x3c,0x99,0xa,0x1c,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x53,0x49,0x44,0x41,0x54,0x18,0xd3,0x7d,0x8f,0xc9,0xd,0x80,0x20,0x0,0xc0,0xca,0x21,0xe8,0x5f,0x12,0x89,0x84,0xfd,0x5c,0x48,0x26,0x34,0x3e,0x74,0x2,0xa2,0xe8,0x2,0x40,0xbf,0xed,0xa7,0xc2,0xbb,0xb0,0x3,0x1b,0x75,0x92,0xf0,0x2e,0x7c,0x46,0x9b,0xaa,0xcd,0x4f,0x46,0x3,0x8c,0x76,0xea,0x7,0x4a,0x29,0x5a,0x68,0x0,0x29,0x65,0x3f,0x30,0x83,0xed,0x6,0xe9,0xbc,0x8e,0xf6,0x45,0x79,0xb,0xc0,0x5c,0xb3,0xeb,0x12,0xef,0x1f,0xc6,0x6f,0x12,0x2,0xa,0xbd,0xc9,0x5d,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
diff --git a/scene/resources/image_path_finder.cpp b/scene/resources/image_path_finder.cpp
deleted file mode 100644
index 1a7758789c..0000000000
--- a/scene/resources/image_path_finder.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/*************************************************************************/
-/* image_path_finder.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-#include "image_path_finder.h"
-
-
-void ImagePathFinder::_unlock() {
-
- lock=DVector<Cell>::Write();
- cells=NULL;
-
-}
-
-void ImagePathFinder::_lock() {
-
- lock = cell_data.write();
- cells=lock.ptr();
-
-}
-
-
-bool ImagePathFinder::_can_go_straigth(const Point2& p_from, const Point2& p_to) const {
-
- int x1=p_from.x;
- int y1=p_from.y;
- int x2=p_to.x;
- int y2=p_to.y;
-
-#define _TEST_VALID \
- {\
- uint32_t ofs=drawy*width+drawx;\
- if (cells[ofs].solid) {\
- if (!((drawx>0 && cells[ofs-1].visited) ||\
- (drawx<width-1 && cells[ofs+1].visited) ||\
- (drawy>0 && cells[ofs-width].visited) ||\
- (drawy<height-1 && cells[ofs+width].visited))) {\
- return false;\
- }\
- }\
- }\
-
-
- int n, deltax, deltay, sgndeltax, sgndeltay, deltaxabs, deltayabs, x, y, drawx, drawy;
- deltax = x2 - x1;
- deltay = y2 - y1;
- deltaxabs = ABS(deltax);
- deltayabs = ABS(deltay);
- sgndeltax = SGN(deltax);
- sgndeltay = SGN(deltay);
- x = deltayabs >> 1;
- y = deltaxabs >> 1;
- drawx = x1;
- drawy = y1;
- int pc=0;
-
- _TEST_VALID
-
- if(deltaxabs >= deltayabs) {
- for(n = 0; n < deltaxabs; n++) {
- y += deltayabs;
- if(y >= deltaxabs){
- y -= deltaxabs;
- drawy += sgndeltay;
- }
- drawx += sgndeltax;
- _TEST_VALID
- }
- } else {
- for(n = 0; n < deltayabs; n++) {
- x += deltaxabs;
- if(x >= deltayabs) {
- x -= deltayabs;
- drawx += sgndeltax;
- }
- drawy += sgndeltay;
- _TEST_VALID
- }
- }
- return true;
-
-
-}
-
-bool ImagePathFinder::_is_linear_path(const Point2& p_from, const Point2& p_to) {
-
- int x1=p_from.x;
- int y1=p_from.y;
- int x2=p_to.x;
- int y2=p_to.y;
-
-#define _TEST_CELL \
- if (cells[drawy*width+drawx].solid)\
- return false;
-
-
- int n, deltax, deltay, sgndeltax, sgndeltay, deltaxabs, deltayabs, x, y, drawx, drawy;
- deltax = x2 - x1;
- deltay = y2 - y1;
- deltaxabs = ABS(deltax);
- deltayabs = ABS(deltay);
- sgndeltax = SGN(deltax);
- sgndeltay = SGN(deltay);
- x = deltayabs >> 1;
- y = deltaxabs >> 1;
- drawx = x1;
- drawy = y1;
- int pc=0;
-
- _TEST_CELL
-
- if(deltaxabs >= deltayabs) {
- for(n = 0; n < deltaxabs; n++) {
- y += deltayabs;
- if(y >= deltaxabs){
- y -= deltaxabs;
- drawy += sgndeltay;
- }
- drawx += sgndeltax;
- _TEST_CELL
- }
- } else {
- for(n = 0; n < deltayabs; n++) {
- x += deltaxabs;
- if(x >= deltayabs) {
- x -= deltayabs;
- drawx += sgndeltax;
- }
- drawy += sgndeltay;
- _TEST_CELL
- }
- }
- return true;
-}
-
-
-DVector<Point2> ImagePathFinder::find_path(const Point2& p_from, const Point2& p_to,bool p_optimize) {
-
-
- Point2i from=p_from;
- Point2i to=p_to;
-
- ERR_FAIL_COND_V(from.x < 0,DVector<Point2>());
- ERR_FAIL_COND_V(from.y < 0,DVector<Point2>());
- ERR_FAIL_COND_V(from.x >=width,DVector<Point2>());
- ERR_FAIL_COND_V(from.y >=height,DVector<Point2>());
- ERR_FAIL_COND_V(to.x < 0,DVector<Point2>());
- ERR_FAIL_COND_V(to.y < 0,DVector<Point2>());
- ERR_FAIL_COND_V(to.x >=width,DVector<Point2>());
- ERR_FAIL_COND_V(to.y >=height,DVector<Point2>());
-
- if (from==to) {
- DVector<Point2> p;
- p.push_back(from);
- return p;
- }
-
- _lock();
-
-
- if (p_optimize) { //try a line first
-
- if (_is_linear_path(p_from,p_to)) {
- _unlock();
- DVector<Point2> p;
- p.push_back(from);
- p.push_back(to);
- return p;
- }
- }
-
-
- //clear all
- for(int i=0;i<width*height;i++) {
-
- bool s = cells[i].solid;
- cells[i].data=0;
- cells[i].solid=s;
- }
-
-#define CELL_INDEX(m_p) (m_p.y*width+m_p.x)
-#define CELL_COST(m_p) (cells[CELL_INDEX(m_p)].cost+( ABS(m_p.x-to.x)+ABS(m_p.y-to.y))*10)
-
-
- Set<Point2i> pending;
- pending.insert(from);
-
- //helper constants
- static const Point2i neighbour_rel[8]={
- Point2i(-1,-1), //0
- Point2i(-1, 0), //1
- Point2i(-1,+1), //2
- Point2i( 0,-1), //3
- Point2i( 0,+1), //4
- Point2i(+1,-1), //5
- Point2i(+1, 0), //6
- Point2i(+1,+1) }; //7
-
- static const int neighbour_cost[8]={
- 14,
- 10,
- 14,
- 10,
- 10,
- 14,
- 10,
- 14
- };
-
- static const int neighbour_parent[8]={
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- };
-
- while(true) {
-
- if (pending.size() == 0) {
- _unlock();
- return DVector<Point2>(); // points don't connect
- }
- Point2i current;
- int lc=0x7FFFFFFF;
- { //find the one with the least cost
-
- Set<Point2i>::Element *Efound=NULL;
- for (Set<Point2i>::Element *E=pending.front();E;E=E->next()) {
-
- int cc =CELL_COST(E->get());
- if (cc<lc) {
- lc=cc;
- current=E->get();
- Efound=E;
-
- }
-
- }
- pending.erase(Efound);
- }
-
- Cell &c = cells[CELL_INDEX(current)];
-
- //search around other cells
-
-
- int accum_cost = (from==current) ? 0 : cells[CELL_INDEX((current + neighbour_rel[c.parent]))].cost;
-
- bool done=false;
-
- for(int i=0;i<8;i++) {
-
- Point2i neighbour=current+neighbour_rel[i];
- if (neighbour.x<0 || neighbour.y<0 || neighbour.x>=width || neighbour.y>=height)
- continue;
-
- Cell &n = cells[CELL_INDEX(neighbour)];
- if (n.solid)
- continue; //no good
-
- int cost = neighbour_cost[i]+accum_cost;
-
- if (n.visited && n.cost < cost)
- continue;
-
- n.cost=cost;
- n.parent=neighbour_parent[i];
- n.visited=true;
- pending.insert(neighbour);
- if (neighbour==to)
- done=true;
-
- }
-
- if (done)
- break;
- }
-
-
- // go througuh poins twice, first compute amount, then add them
-
- Point2i current=to;
- int pcount=0;
-
- while(true) {
-
- Cell &c = cells[CELL_INDEX(current)];
- c.visited=true;
- pcount++;
- if (current==from)
- break;
- current+=neighbour_rel[ c.parent ];
- }
-
- //now place them in an array
- DVector<Vector2> result;
- result.resize(pcount);
-
- DVector<Vector2>::Write res=result.write();
-
- current=to;
- int pidx=pcount-1;
-
- while(true) {
-
- Cell &c = cells[CELL_INDEX(current)];
- res[pidx]=current;
- pidx--;
- if (current==from)
- break;
- current+=neighbour_rel[ c.parent ];
- }
-
-
- //simplify..
-
-
- if (p_optimize) {
-
- int p=pcount-1;
- while(p>0) {
-
-
- int limit=p;
- while(limit>0) {
-
- limit--;
- if (!_can_go_straigth(res[p],res[limit]))
- break;
- }
-
-
- if (limit<p-1) {
- int diff = p-limit-1;
- pcount-=diff;
- for(int i=limit+1;i<pcount;i++) {
-
- res[i]=res[i+diff];
- }
- }
- p=limit;
- }
- }
-
- res=DVector<Vector2>::Write();
- result.resize(pcount);
- return result;
-}
-
-Size2 ImagePathFinder::get_size() const {
-
- return Size2(width,height);
-}
-bool ImagePathFinder::is_solid(const Point2& p_pos) {
-
-
- Point2i pos = p_pos;
-
- ERR_FAIL_COND_V(pos.x<0,true);
- ERR_FAIL_COND_V(pos.y<0,true);
- ERR_FAIL_COND_V(pos.x>=width,true);
- ERR_FAIL_COND_V(pos.y>=height,true);
-
- return cell_data[pos.y*width+pos.x].solid;
-}
-
-void ImagePathFinder::create_from_image_alpha(const Image& p_image) {
-
- ERR_FAIL_COND(p_image.get_format() != Image::FORMAT_RGBA);
- width = p_image.get_width();
- height = p_image.get_height();
- DVector<uint8_t> data = p_image.get_data();
- cell_data.resize(width * height);
- DVector<uint8_t>::Read read = data.read();
- DVector<Cell>::Write write = cell_data.write();
- for (int i=0; i<width * height; i++) {
- Cell cell;
- cell.data = 0;
- cell.solid = read[i*4+3] < 128;
- write[i] = cell;
- };
-};
-
-
-void ImagePathFinder::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("find_path","from","to","optimize"),&ImagePathFinder::find_path,DEFVAL(false));
- ObjectTypeDB::bind_method(_MD("get_size"),&ImagePathFinder::get_size);
- ObjectTypeDB::bind_method(_MD("is_solid","pos"),&ImagePathFinder::is_solid);
- ObjectTypeDB::bind_method(_MD("create_from_image_alpha"),&ImagePathFinder::create_from_image_alpha);
-}
-
-ImagePathFinder::ImagePathFinder()
-{
-
- cells=NULL;
- width=0;
- height=0;
-}
diff --git a/scene/resources/image_path_finder.h b/scene/resources/image_path_finder.h
deleted file mode 100644
index e975ea5ed9..0000000000
--- a/scene/resources/image_path_finder.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*************************************************************************/
-/* image_path_finder.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-#ifndef IMAGE_PATH_FINDER_H
-#define IMAGE_PATH_FINDER_H
-
-#include "resource.h"
-
-class ImagePathFinder : public Resource{
-
-
- OBJ_TYPE(ImagePathFinder,Resource);
- union Cell {
-
- struct {
- bool solid:1;
- bool visited:1;
- bool final:1;
- uint8_t parent:3;
- uint32_t cost:26;
- };
-
- uint32_t data;
- };
-
-
-
-
-
- DVector<Cell>::Write lock;
- DVector<Cell> cell_data;
-
- uint32_t width;
- uint32_t height;
- Cell* cells; //when unlocked
-
- void _unlock();
- void _lock();
-
-
- _FORCE_INLINE_ bool _can_go_straigth(const Point2& p_from, const Point2& p_to) const;
- _FORCE_INLINE_ bool _is_linear_path(const Point2& p_from, const Point2& p_to);
-
-protected:
-
- static void _bind_methods();
-public:
-
- DVector<Point2> find_path(const Point2& p_from, const Point2& p_to,bool p_optimize=false);
- Size2 get_size() const;
- bool is_solid(const Point2& p_pos);
- void create_from_image_alpha(const Image& p_image);
-
-
-
- ImagePathFinder();
-};
-
-#endif // IMAGE_PATH_FINDER_H
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 2314926b2b..355cc8884c 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -36,7 +36,8 @@ static const char*_flag_names[Material::FLAG_MAX]={
"invert_faces",
"unshaded",
"on_top",
- "lightmap_on_uv2"
+ "lightmap_on_uv2",
+ "colarray_is_srgb"
};
@@ -46,7 +47,8 @@ static const Material::Flag _flag_indices[Material::FLAG_MAX]={
Material::FLAG_INVERT_FACES,
Material::FLAG_UNSHADED,
Material::FLAG_ONTOP,
- Material::FLAG_LIGHTMAP_ON_UV2
+ Material::FLAG_LIGHTMAP_ON_UV2,
+ Material::FLAG_COLOR_ARRAY_SRGB,
};
@@ -132,6 +134,8 @@ void Material::_bind_methods() {
BIND_CONSTANT( FLAG_INVERT_FACES );
BIND_CONSTANT( FLAG_UNSHADED );
BIND_CONSTANT( FLAG_ONTOP );
+ BIND_CONSTANT( FLAG_LIGHTMAP_ON_UV2 );
+ BIND_CONSTANT( FLAG_COLOR_ARRAY_SRGB );
BIND_CONSTANT( FLAG_MAX );
BIND_CONSTANT( DEPTH_DRAW_ALWAYS );
@@ -156,6 +160,8 @@ Material::Material(const RID& p_material) {
flags[FLAG_INVERT_FACES]=false;
flags[FLAG_UNSHADED]=false;
flags[FLAG_ONTOP]=false;
+ flags[FLAG_LIGHTMAP_ON_UV2]=true;
+ flags[FLAG_COLOR_ARRAY_SRGB]=false;
depth_draw_mode=DEPTH_DRAW_OPAQUE_ONLY;
@@ -316,14 +322,14 @@ Transform FixedMaterial::get_uv_transform() const {
void FixedMaterial::set_fixed_flag(FixedFlag p_flag, bool p_value) {
- ERR_FAIL_INDEX(p_flag,4);
+ ERR_FAIL_INDEX(p_flag,5);
fixed_flags[p_flag]=p_value;
VisualServer::get_singleton()->fixed_material_set_flag(material,(VS::FixedMaterialFlags)p_flag,p_value);
}
bool FixedMaterial::get_fixed_flag(FixedFlag p_flag) const {
- ERR_FAIL_INDEX_V(p_flag,4,false);
+ ERR_FAIL_INDEX_V(p_flag,5,false);
return fixed_flags[p_flag];
}
@@ -371,6 +377,7 @@ void FixedMaterial::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_color_array" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_COLOR_ARRAY);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_point_size" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_POINT_SIZE);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/discard_alpha" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_DISCARD_ALPHA);
+ ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_xy_normalmap" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_XY_NORMALMAP);
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/diffuse" ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_DIFFUSE);
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/specular", PROPERTY_HINT_COLOR_NO_ALPHA ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPECULAR );
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/emission", PROPERTY_HINT_COLOR_NO_ALPHA ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_EMISSION );
@@ -426,11 +433,14 @@ FixedMaterial::FixedMaterial() : Material(VS::get_singleton()->fixed_material_cr
param[PARAM_SHADE_PARAM]=0.5;
param[PARAM_DETAIL]=1.0;
-
+ set_flag(FLAG_COLOR_ARRAY_SRGB,true);
fixed_flags[FLAG_USE_ALPHA]=false;
fixed_flags[FLAG_USE_COLOR_ARRAY]=false;
fixed_flags[FLAG_USE_POINT_SIZE]=false;
+ fixed_flags[FLAG_USE_XY_NORMALMAP]=false;
+ fixed_flags[FLAG_DISCARD_ALPHA]=false;
+
for(int i=0;i<PARAM_MAX;i++) {
@@ -448,6 +458,8 @@ FixedMaterial::~FixedMaterial() {
}
+
+
bool ShaderMaterial::_set(const StringName& p_name, const Variant& p_value) {
if (p_name==SceneStringNames::get_singleton()->shader_shader) {
@@ -455,10 +467,20 @@ bool ShaderMaterial::_set(const StringName& p_name, const Variant& p_value) {
return true;
} else {
- String n = p_name;
- if (n.begins_with("param/")) {
- VisualServer::get_singleton()->material_set_param(material,String(n.ptr()+6),p_value);
- return true;
+ if (shader.is_valid()) {
+
+
+ StringName pr = shader->remap_param(p_name);
+ if (!pr) {
+ String n = p_name;
+ if (n.find("param/")==0) { //backwards compatibility
+ pr = n.substr(6,n.length());
+ }
+ }
+ if (pr) {
+ VisualServer::get_singleton()->material_set_param(material,pr,p_value);
+ return true;
+ }
}
}
@@ -474,10 +496,13 @@ bool ShaderMaterial::_get(const StringName& p_name,Variant &r_ret) const {
return true;
} else {
- String n = p_name;
- if (n.begins_with("param/")) {
- r_ret=VisualServer::get_singleton()->material_get_param(material,String(n.ptr()+6));
- return true;
+ if (shader.is_valid()) {
+
+ StringName pr = shader->remap_param(p_name);
+ if (pr) {
+ r_ret=VisualServer::get_singleton()->material_get_param(material,pr);
+ return true;
+ }
}
}
@@ -489,7 +514,7 @@ bool ShaderMaterial::_get(const StringName& p_name,Variant &r_ret) const {
void ShaderMaterial::_get_property_list( List<PropertyInfo> *p_list) const {
- p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"Shader" ) );
+ p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"MaterialShader,MaterialShaderGraph" ) );
if (!shader.is_null()) {
@@ -540,124 +565,34 @@ void ShaderMaterial::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_shader","shader:Shader"), &ShaderMaterial::set_shader );
ObjectTypeDB::bind_method(_MD("get_shader:Shader"), &ShaderMaterial::get_shader );
- ObjectTypeDB::bind_method(_MD("_shader_changed"), &ShaderMaterial::_shader_changed );
-}
-
-
-
-
-ShaderMaterial::ShaderMaterial() :Material(VisualServer::get_singleton()->material_create()){
-
-
-}
-
-
-/////////////////////////////////
-
-void ParticleSystemMaterial::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_texture","texture"),&ParticleSystemMaterial::set_texture);
- ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&ParticleSystemMaterial::get_texture);
-
- ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture" ), _SCS("set_texture"), _SCS("get_texture"));
-
-}
-
-void ParticleSystemMaterial::set_texture(const Ref<Texture>& p_texture) {
- texture=p_texture;
- RID rid;
- if (texture.is_valid())
- rid=texture->get_rid();
-
- VS::get_singleton()->fixed_material_set_texture(material,VS::FIXED_MATERIAL_PARAM_DIFFUSE,rid);
-}
-
-Ref<Texture> ParticleSystemMaterial::get_texture() const {
-
- return texture;
-}
-
-
-ParticleSystemMaterial::ParticleSystemMaterial() :Material(VisualServer::get_singleton()->fixed_material_create()){
- set_flag(FLAG_DOUBLE_SIDED,true);
- set_flag(FLAG_UNSHADED,true);
- set_depth_draw_mode(DEPTH_DRAW_NEVER);
- VisualServer::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_ALPHA,true);
- VisualServer::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);
-}
-
-ParticleSystemMaterial::~ParticleSystemMaterial() {
-
-
-}
-
-//////////////////////////////
-
-
-
-void UnshadedMaterial::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_texture","texture"),&UnshadedMaterial::set_texture);
- ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&UnshadedMaterial::get_texture);
-
- ObjectTypeDB::bind_method(_MD("set_use_alpha","enable"),&UnshadedMaterial::set_use_alpha);
- ObjectTypeDB::bind_method(_MD("is_using_alpha"),&UnshadedMaterial::is_using_alpha);
-
- ObjectTypeDB::bind_method(_MD("set_use_color_array","enable"),&UnshadedMaterial::set_use_color_array);
- ObjectTypeDB::bind_method(_MD("is_using_color_array"),&UnshadedMaterial::is_using_color_array);
-
- ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture" ), _SCS("set_texture"), _SCS("get_texture"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "alpha" ), _SCS("set_use_alpha"), _SCS("is_using_alpha"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "color_array" ), _SCS("set_use_color_array"), _SCS("is_using_color_array"));
-
-}
-
-void UnshadedMaterial::set_texture(const Ref<Texture>& p_texture) {
- RID rid;
- if (texture.is_valid())
- rid=texture->get_rid();
-
- VS::get_singleton()->fixed_material_set_texture(material,VS::FIXED_MATERIAL_PARAM_DIFFUSE,rid);
-}
-Ref<Texture> UnshadedMaterial::get_texture() const {
-
- return texture;
-}
-
-void UnshadedMaterial::set_use_alpha(bool p_use_alpha) {
-
- alpha=p_use_alpha;
- VS::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_ALPHA,p_use_alpha);
- //set_depth_draw_mode();
- //set_hint(HINT,p_use_alpha);
+ ObjectTypeDB::bind_method(_MD("set_shader_param","param","value:var"), &ShaderMaterial::set_shader_param);
+ ObjectTypeDB::bind_method(_MD("get_shader_param:var","param"), &ShaderMaterial::get_shader_param);
+ ObjectTypeDB::bind_method(_MD("_shader_changed"), &ShaderMaterial::_shader_changed );
}
-bool UnshadedMaterial::is_using_alpha() const{
-
- return alpha;
-}
-void UnshadedMaterial::set_use_color_array(bool p_use_color_array){
+void ShaderMaterial::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
- color_array=p_use_color_array;
- VS::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,p_use_color_array);
+ String f = p_function.operator String();
+ if ((f=="get_shader_param" || f=="set_shader_param") && p_idx==0) {
+ if (shader.is_valid()) {
+ List<PropertyInfo> pl;
+ shader->get_param_list(&pl);
+ for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
+ r_options->push_back(E->get().name);
+ }
+ }
+ }
+ Material::get_argument_options(p_function,p_idx,r_options);
}
-bool UnshadedMaterial::is_using_color_array() const{
-
- return color_array;
-}
+ShaderMaterial::ShaderMaterial() :Material(VisualServer::get_singleton()->material_create()){
-UnshadedMaterial::UnshadedMaterial() :Material(VisualServer::get_singleton()->fixed_material_create()){
- set_flag(FLAG_UNSHADED,true);
- set_use_alpha(true);
}
-UnshadedMaterial::~UnshadedMaterial() {
-
-}
+/////////////////////////////////
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 23ecb18fac..73d1a4e188 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -54,6 +54,7 @@ public:
FLAG_UNSHADED = VS::MATERIAL_FLAG_UNSHADED,
FLAG_ONTOP = VS::MATERIAL_FLAG_ONTOP,
FLAG_LIGHTMAP_ON_UV2 = VS::MATERIAL_FLAG_LIGHTMAP_ON_UV2,
+ FLAG_COLOR_ARRAY_SRGB = VS::MATERIAL_FLAG_COLOR_ARRAY_SRGB,
FLAG_MAX = VS::MATERIAL_FLAG_MAX
};
@@ -141,7 +142,9 @@ public:
FLAG_USE_ALPHA=VS::FIXED_MATERIAL_FLAG_USE_ALPHA,
FLAG_USE_COLOR_ARRAY=VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,
FLAG_USE_POINT_SIZE=VS::FIXED_MATERIAL_FLAG_USE_POINT_SIZE,
- FLAG_DISCARD_ALPHA=VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA
+ FLAG_DISCARD_ALPHA=VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA,
+ FLAG_USE_XY_NORMALMAP=VS::FIXED_MATERIAL_FLAG_USE_XY_NORMALMAP,
+ FLAG_MAX=VS::FIXED_MATERIAL_FLAG_MAX
};
enum LightShader {
@@ -166,7 +169,7 @@ private:
Ref<Texture> texture_param[PARAM_MAX];
TexCoordMode texture_texcoord[PARAM_MAX];
LightShader light_shader;
- bool fixed_flags[3];
+ bool fixed_flags[FLAG_MAX];
float point_size;
@@ -240,6 +243,7 @@ public:
void set_shader_param(const StringName& p_param,const Variant& p_value);
Variant get_shader_param(const StringName& p_param) const;
+ void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
ShaderMaterial();
};
@@ -249,68 +253,6 @@ public:
-class ParticleSystemMaterial : public Material {
-
- OBJ_TYPE( ParticleSystemMaterial, Material );
- REVERSE_GET_PROPERTY_LIST
-
-private:
-
-
-
- Ref<Texture> texture;
-
-protected:
-
-
- static void _bind_methods();
-
-public:
-
- void set_texture(const Ref<Texture>& p_texture);
- Ref<Texture> get_texture() const;
-
-
- ParticleSystemMaterial();
- ~ParticleSystemMaterial();
-
-};
-
-///////////////////////////////////////////
-
-
-class UnshadedMaterial : public Material {
-
- OBJ_TYPE( UnshadedMaterial, Material );
- REVERSE_GET_PROPERTY_LIST
-
-private:
-
-
- bool alpha;
- bool color_array;
- Ref<Texture> texture;
-
-protected:
-
-
- static void _bind_methods();
-
-public:
-
- void set_texture(const Ref<Texture>& p_texture);
- Ref<Texture> get_texture() const;
-
- void set_use_alpha(bool p_use_alpha);
- bool is_using_alpha() const;
-
- void set_use_color_array(bool p_use_color_array);
- bool is_using_color_array() const;
-
- UnshadedMaterial();
- ~UnshadedMaterial();
-
-};
#endif
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index c6e492fcb3..f4bb3088c3 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -29,6 +29,7 @@
#include "mesh.h"
#include "scene/resources/concave_polygon_shape.h"
#include "scene/resources/convex_polygon_shape.h"
+#include "surface_tool.h"
static const char*_array_name[]={
"vertex_array",
@@ -648,6 +649,30 @@ void Mesh::center_geometry() {
}
+void Mesh::regen_normalmaps() {
+
+
+ Vector< Ref<SurfaceTool> > surfs;
+ for(int i=0;i<get_surface_count();i++) {
+
+ Ref<SurfaceTool> st = memnew( SurfaceTool );
+ st->create_from(Ref<Mesh>(this),i);
+ surfs.push_back(st);
+ }
+
+ while (get_surface_count()) {
+ surface_remove(0);
+ }
+
+ for(int i=0;i<surfs.size();i++) {
+
+ surfs[i]->generate_tangents();
+ surfs[i]->commit(Ref<Mesh>(this));
+ }
+}
+
+
+
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
if (triangle_mesh.is_valid())
@@ -718,6 +743,225 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
}
+Ref<Mesh> Mesh::create_outline(float p_margin) const {
+
+
+ Array arrays;
+ int index_accum=0;
+ for(int i=0;i<get_surface_count();i++) {
+
+ if (surface_get_primitive_type(i)!=PRIMITIVE_TRIANGLES)
+ continue;
+
+ Array a = surface_get_arrays(i);
+ int vcount=0;
+
+ if (i==0) {
+ arrays=a;
+ DVector<Vector3> v=a[ARRAY_VERTEX];
+ index_accum+=v.size();
+ } else {
+
+ for(int j=0;j<arrays.size();j++) {
+
+ if (arrays[j].get_type()==Variant::NIL || a[j].get_type()==Variant::NIL) {
+ //mismatch, do not use
+ arrays[j]=Variant();
+ continue;
+ }
+
+ switch(j) {
+
+ case ARRAY_VERTEX:
+ case ARRAY_NORMAL: {
+
+ DVector<Vector3> dst = arrays[j];
+ DVector<Vector3> src = a[j];
+ if (j==ARRAY_VERTEX)
+ vcount=src.size();
+ if (dst.size()==0 || src.size()==0) {
+ arrays[j]=Variant();
+ continue;
+ }
+ dst.append_array(src);
+ arrays[j]=dst;
+ } break;
+ case ARRAY_TANGENT:
+ case ARRAY_BONES:
+ case ARRAY_WEIGHTS: {
+
+ DVector<real_t> dst = arrays[j];
+ DVector<real_t> src = a[j];
+ if (dst.size()==0 || src.size()==0) {
+ arrays[j]=Variant();
+ continue;
+ }
+ dst.append_array(src);
+ arrays[j]=dst;
+
+ } break;
+ case ARRAY_COLOR: {
+ DVector<Color> dst = arrays[j];
+ DVector<Color> src = a[j];
+ if (dst.size()==0 || src.size()==0) {
+ arrays[j]=Variant();
+ continue;
+ }
+ dst.append_array(src);
+ arrays[j]=dst;
+
+ } break;
+ case ARRAY_TEX_UV:
+ case ARRAY_TEX_UV2: {
+ DVector<Vector2> dst = arrays[j];
+ DVector<Vector2> src = a[j];
+ if (dst.size()==0 || src.size()==0) {
+ arrays[j]=Variant();
+ continue;
+ }
+ dst.append_array(src);
+ arrays[j]=dst;
+
+ } break;
+ case ARRAY_INDEX: {
+ DVector<int> dst = arrays[j];
+ DVector<int> src = a[j];
+ if (dst.size()==0 || src.size()==0) {
+ arrays[j]=Variant();
+ continue;
+ }
+ {
+ int ss = src.size();
+ DVector<int>::Write w = src.write();
+ for(int k=0;k<ss;k++) {
+ w[k]+=index_accum;
+ }
+
+ }
+ dst.append_array(src);
+ arrays[j]=dst;
+ index_accum+=vcount;
+
+ } break;
+
+ }
+ }
+ }
+ }
+
+ {
+ int tc=0;
+ DVector<int>::Write ir;
+ DVector<int> indices =arrays[ARRAY_INDEX];
+ bool has_indices=false;
+ DVector<Vector3> vertices =arrays[ARRAY_VERTEX];
+ int vc = vertices.size();
+ ERR_FAIL_COND_V(!vc,Ref<Mesh>());
+ DVector<Vector3>::Write r=vertices.write();
+
+
+ if (indices.size()) {
+ vc=indices.size();
+ ir=indices.write();
+ has_indices=true;
+ }
+
+ Map<Vector3,Vector3> normal_accum;
+
+ //fill normals with triangle normals
+ for(int i=0;i<vc;i+=3) {
+
+
+ Vector3 t[3];
+
+ if (has_indices) {
+ t[0]=r[ir[i+0]];
+ t[1]=r[ir[i+1]];
+ t[2]=r[ir[i+2]];
+ } else {
+ t[0]=r[i+0];
+ t[1]=r[i+1];
+ t[2]=r[i+2];
+ }
+
+ Vector3 n = Plane(t[0],t[1],t[2]).normal;
+
+ for(int j=0;j<3;j++) {
+
+ Map<Vector3,Vector3>::Element *E=normal_accum.find(t[j]);
+ if (!E) {
+ normal_accum[t[j]]=n;
+ } else {
+ float d = n.dot(E->get());
+ if (d<1.0)
+ E->get()+=n*(1.0-d);
+ //E->get()+=n;
+ }
+ }
+ }
+
+ //normalize
+
+ for (Map<Vector3,Vector3>::Element *E=normal_accum.front();E;E=E->next()) {
+ E->get().normalize();
+ }
+
+
+ //displace normals
+ int vc2 = vertices.size();
+
+ for(int i=0;i<vc2;i++) {
+
+
+ Vector3 t=r[i];
+
+ Map<Vector3,Vector3>::Element *E=normal_accum.find(t);
+ ERR_CONTINUE(!E);
+
+ t+=E->get()*p_margin;
+ r[i]=t;
+ }
+
+ r = DVector<Vector3>::Write();
+ arrays[ARRAY_VERTEX]=vertices;
+
+ if (!has_indices) {
+
+ DVector<int> new_indices;
+ new_indices.resize(vertices.size());
+ DVector<int>::Write iw = new_indices.write();
+
+ for(int j=0;j<vc2;j+=3) {
+
+ iw[j]=j;
+ iw[j+1]=j+2;
+ iw[j+2]=j+1;
+ }
+
+ iw=DVector<int>::Write();
+ arrays[ARRAY_INDEX]=new_indices;
+
+ } else {
+
+ for(int j=0;j<vc;j+=3) {
+
+ SWAP(ir[j+1],ir[j+2]);
+ }
+ ir=DVector<int>::Write();
+ arrays[ARRAY_INDEX]=indices;
+
+ }
+ }
+
+
+
+
+ Ref<Mesh> newmesh = memnew( Mesh );
+ newmesh->add_surface(PRIMITIVE_TRIANGLES,arrays);
+ return newmesh;
+}
+
+
void Mesh::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_morph_target","name"),&Mesh::add_morph_target);
@@ -740,6 +984,8 @@ void Mesh::_bind_methods() {
ObjectTypeDB::bind_method(_MD("surface_get_name","surf_idx"),&Mesh::surface_get_name);
ObjectTypeDB::bind_method(_MD("center_geometry"),&Mesh::center_geometry);
ObjectTypeDB::set_method_flags(get_type_static(),_SCS("center_geometry"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+ ObjectTypeDB::bind_method(_MD("regen_normalmaps"),&Mesh::regen_normalmaps);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("regen_normalmaps"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
ObjectTypeDB::bind_method(_MD("set_custom_aabb","aabb"),&Mesh::set_custom_aabb);
ObjectTypeDB::bind_method(_MD("get_custom_aabb"),&Mesh::get_custom_aabb);
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 5243163a4d..5aacc8be57 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -166,7 +166,10 @@ public:
Ref<Shape> create_trimesh_shape() const;
Ref<Shape> create_convex_shape() const;
+ Ref<Mesh> create_outline(float p_margin) const;
+
void center_geometry();
+ void regen_normalmaps();
DVector<Face3> get_faces() const;
Ref<TriangleMesh> generate_triangle_mesh() const;
diff --git a/scene/resources/mikktspace.c b/scene/resources/mikktspace.c
new file mode 100644
index 0000000000..62aa2da251
--- /dev/null
+++ b/scene/resources/mikktspace.c
@@ -0,0 +1,1890 @@
+/** \file mikktspace/mikktspace.c
+ * \ingroup mikktspace
+ */
+/**
+ * Copyright (C) 2011 by Morten S. Mikkelsen
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <float.h>
+#include <stdlib.h>
+
+#include "mikktspace.h"
+
+#define TFALSE 0
+#define TTRUE 1
+
+#ifndef M_PI
+#define M_PI 3.1415926535897932384626433832795
+#endif
+
+#define INTERNAL_RND_SORT_SEED 39871946
+
+// internal structure
+typedef struct {
+ float x, y, z;
+} SVec3;
+
+static tbool veq( const SVec3 v1, const SVec3 v2 )
+{
+ return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z);
+}
+
+static SVec3 vadd( const SVec3 v1, const SVec3 v2 )
+{
+ SVec3 vRes;
+
+ vRes.x = v1.x + v2.x;
+ vRes.y = v1.y + v2.y;
+ vRes.z = v1.z + v2.z;
+
+ return vRes;
+}
+
+
+static SVec3 vsub( const SVec3 v1, const SVec3 v2 )
+{
+ SVec3 vRes;
+
+ vRes.x = v1.x - v2.x;
+ vRes.y = v1.y - v2.y;
+ vRes.z = v1.z - v2.z;
+
+ return vRes;
+}
+
+static SVec3 vscale(const float fS, const SVec3 v)
+{
+ SVec3 vRes;
+
+ vRes.x = fS * v.x;
+ vRes.y = fS * v.y;
+ vRes.z = fS * v.z;
+
+ return vRes;
+}
+
+static float LengthSquared( const SVec3 v )
+{
+ return v.x*v.x + v.y*v.y + v.z*v.z;
+}
+
+static float Length( const SVec3 v )
+{
+ return sqrtf(LengthSquared(v));
+}
+
+static SVec3 Normalize( const SVec3 v )
+{
+ return vscale(1 / Length(v), v);
+}
+
+static float vdot( const SVec3 v1, const SVec3 v2)
+{
+ return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
+}
+
+
+static tbool NotZero(const float fX)
+{
+ // could possibly use FLT_EPSILON instead
+ return fabsf(fX) > FLT_MIN;
+}
+
+static tbool VNotZero(const SVec3 v)
+{
+ // might change this to an epsilon based test
+ return NotZero(v.x) || NotZero(v.y) || NotZero(v.z);
+}
+
+
+
+typedef struct {
+ int iNrFaces;
+ int * pTriMembers;
+} SSubGroup;
+
+typedef struct {
+ int iNrFaces;
+ int * pFaceIndices;
+ int iVertexRepresentitive;
+ tbool bOrientPreservering;
+} SGroup;
+
+//
+#define MARK_DEGENERATE 1
+#define QUAD_ONE_DEGEN_TRI 2
+#define GROUP_WITH_ANY 4
+#define ORIENT_PRESERVING 8
+
+
+
+typedef struct {
+ int FaceNeighbors[3];
+ SGroup * AssignedGroup[3];
+
+ // normalized first order face derivatives
+ SVec3 vOs, vOt;
+ float fMagS, fMagT; // original magnitudes
+
+ // determines if the current and the next triangle are a quad.
+ int iOrgFaceNumber;
+ int iFlag, iTSpacesOffs;
+ unsigned char vert_num[4];
+} STriInfo;
+
+typedef struct {
+ SVec3 vOs;
+ float fMagS;
+ SVec3 vOt;
+ float fMagT;
+ int iCounter; // this is to average back into quads.
+ tbool bOrient;
+} STSpace;
+
+static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
+static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
+static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
+static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn);
+static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[],
+ const int iNrActiveGroups, const int piTriListIn[], const float fThresCos,
+ const SMikkTSpaceContext * pContext);
+
+static int MakeIndex(const int iFace, const int iVert)
+{
+ assert(iVert>=0 && iVert<4 && iFace>=0);
+ return (iFace<<2) | (iVert&0x3);
+}
+
+static void IndexToData(int * piFace, int * piVert, const int iIndexIn)
+{
+ piVert[0] = iIndexIn&0x3;
+ piFace[0] = iIndexIn>>2;
+}
+
+static STSpace AvgTSpace(const STSpace * pTS0, const STSpace * pTS1)
+{
+ STSpace ts_res;
+
+ // this if is important. Due to floating point precision
+ // averaging when ts0==ts1 will cause a slight difference
+ // which results in tangent space splits later on
+ if (pTS0->fMagS==pTS1->fMagS && pTS0->fMagT==pTS1->fMagT &&
+ veq(pTS0->vOs,pTS1->vOs) && veq(pTS0->vOt, pTS1->vOt))
+ {
+ ts_res.fMagS = pTS0->fMagS;
+ ts_res.fMagT = pTS0->fMagT;
+ ts_res.vOs = pTS0->vOs;
+ ts_res.vOt = pTS0->vOt;
+ }
+ else
+ {
+ ts_res.fMagS = 0.5f*(pTS0->fMagS+pTS1->fMagS);
+ ts_res.fMagT = 0.5f*(pTS0->fMagT+pTS1->fMagT);
+ ts_res.vOs = vadd(pTS0->vOs,pTS1->vOs);
+ ts_res.vOt = vadd(pTS0->vOt,pTS1->vOt);
+ if ( VNotZero(ts_res.vOs) ) ts_res.vOs = Normalize(ts_res.vOs);
+ if ( VNotZero(ts_res.vOt) ) ts_res.vOt = Normalize(ts_res.vOt);
+ }
+
+ return ts_res;
+}
+
+
+
+static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index);
+static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index);
+static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index);
+
+
+// degen triangles
+static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris);
+static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris);
+
+
+tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext)
+{
+ return genTangSpace(pContext, 180.0f);
+}
+
+tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold)
+{
+ // count nr_triangles
+ int * piTriListIn = NULL, * piGroupTrianglesBuffer = NULL;
+ STriInfo * pTriInfos = NULL;
+ SGroup * pGroups = NULL;
+ STSpace * psTspace = NULL;
+ int iNrTrianglesIn = 0, f=0, t=0, i=0;
+ int iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0;
+ int iNrActiveGroups = 0, index = 0;
+ const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext);
+ tbool bRes = TFALSE;
+ const float fThresCos = (float) cos((fAngularThreshold*(float)M_PI)/180.0f);
+
+ // verify all call-backs have been set
+ if ( pContext->m_pInterface->m_getNumFaces==NULL ||
+ pContext->m_pInterface->m_getNumVerticesOfFace==NULL ||
+ pContext->m_pInterface->m_getPosition==NULL ||
+ pContext->m_pInterface->m_getNormal==NULL ||
+ pContext->m_pInterface->m_getTexCoord==NULL )
+ return TFALSE;
+
+ // count triangles on supported faces
+ for (f=0; f<iNrFaces; f++)
+ {
+ const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
+ if (verts==3) ++iNrTrianglesIn;
+ else if (verts==4) iNrTrianglesIn += 2;
+ }
+ if (iNrTrianglesIn<=0) return TFALSE;
+
+ // allocate memory for an index list
+ piTriListIn = (int *) malloc(sizeof(int)*3*iNrTrianglesIn);
+ pTriInfos = (STriInfo *) malloc(sizeof(STriInfo)*iNrTrianglesIn);
+ if (piTriListIn==NULL || pTriInfos==NULL)
+ {
+ if (piTriListIn!=NULL) free(piTriListIn);
+ if (pTriInfos!=NULL) free(pTriInfos);
+ return TFALSE;
+ }
+
+ // make an initial triangle --> face index list
+ iNrTSPaces = GenerateInitialVerticesIndexList(pTriInfos, piTriListIn, pContext, iNrTrianglesIn);
+
+ // make a welded index list of identical positions and attributes (pos, norm, texc)
+ //printf("gen welded index list begin\n");
+ GenerateSharedVerticesIndexList(piTriListIn, pContext, iNrTrianglesIn);
+ //printf("gen welded index list end\n");
+
+ // Mark all degenerate triangles
+ iTotTris = iNrTrianglesIn;
+ iDegenTriangles = 0;
+ for (t=0; t<iTotTris; t++)
+ {
+ const int i0 = piTriListIn[t*3+0];
+ const int i1 = piTriListIn[t*3+1];
+ const int i2 = piTriListIn[t*3+2];
+ const SVec3 p0 = GetPosition(pContext, i0);
+ const SVec3 p1 = GetPosition(pContext, i1);
+ const SVec3 p2 = GetPosition(pContext, i2);
+ if (veq(p0,p1) || veq(p0,p2) || veq(p1,p2)) // degenerate
+ {
+ pTriInfos[t].iFlag |= MARK_DEGENERATE;
+ ++iDegenTriangles;
+ }
+ }
+ iNrTrianglesIn = iTotTris - iDegenTriangles;
+
+ // mark all triangle pairs that belong to a quad with only one
+ // good triangle. These need special treatment in DegenEpilogue().
+ // Additionally, move all good triangles to the start of
+ // pTriInfos[] and piTriListIn[] without changing order and
+ // put the degenerate triangles last.
+ DegenPrologue(pTriInfos, piTriListIn, iNrTrianglesIn, iTotTris);
+
+
+ // evaluate triangle level attributes and neighbor list
+ //printf("gen neighbors list begin\n");
+ InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn);
+ //printf("gen neighbors list end\n");
+
+
+ // based on the 4 rules, identify groups based on connectivity
+ iNrMaxGroups = iNrTrianglesIn*3;
+ pGroups = (SGroup *) malloc(sizeof(SGroup)*iNrMaxGroups);
+ piGroupTrianglesBuffer = (int *) malloc(sizeof(int)*iNrTrianglesIn*3);
+ if (pGroups==NULL || piGroupTrianglesBuffer==NULL)
+ {
+ if (pGroups!=NULL) free(pGroups);
+ if (piGroupTrianglesBuffer!=NULL) free(piGroupTrianglesBuffer);
+ free(piTriListIn);
+ free(pTriInfos);
+ return TFALSE;
+ }
+ //printf("gen 4rule groups begin\n");
+ iNrActiveGroups =
+ Build4RuleGroups(pTriInfos, pGroups, piGroupTrianglesBuffer, piTriListIn, iNrTrianglesIn);
+ //printf("gen 4rule groups end\n");
+
+ //
+
+ psTspace = (STSpace *) malloc(sizeof(STSpace)*iNrTSPaces);
+ if (psTspace==NULL)
+ {
+ free(piTriListIn);
+ free(pTriInfos);
+ free(pGroups);
+ free(piGroupTrianglesBuffer);
+ return TFALSE;
+ }
+ memset(psTspace, 0, sizeof(STSpace)*iNrTSPaces);
+ for (t=0; t<iNrTSPaces; t++)
+ {
+ psTspace[t].vOs.x=1.0f; psTspace[t].vOs.y=0.0f; psTspace[t].vOs.z=0.0f; psTspace[t].fMagS = 1.0f;
+ psTspace[t].vOt.x=0.0f; psTspace[t].vOt.y=1.0f; psTspace[t].vOt.z=0.0f; psTspace[t].fMagT = 1.0f;
+ }
+
+ // make tspaces, each group is split up into subgroups if necessary
+ // based on fAngularThreshold. Finally a tangent space is made for
+ // every resulting subgroup
+ //printf("gen tspaces begin\n");
+ bRes = GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriListIn, fThresCos, pContext);
+ //printf("gen tspaces end\n");
+
+ // clean up
+ free(pGroups);
+ free(piGroupTrianglesBuffer);
+
+ if (!bRes) // if an allocation in GenerateTSpaces() failed
+ {
+ // clean up and return false
+ free(pTriInfos); free(piTriListIn); free(psTspace);
+ return TFALSE;
+ }
+
+
+ // degenerate quads with one good triangle will be fixed by copying a space from
+ // the good triangle to the coinciding vertex.
+ // all other degenerate triangles will just copy a space from any good triangle
+ // with the same welded index in piTriListIn[].
+ DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesIn, iTotTris);
+
+ free(pTriInfos); free(piTriListIn);
+
+ index = 0;
+ for (f=0; f<iNrFaces; f++)
+ {
+ const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
+ if (verts!=3 && verts!=4) continue;
+
+
+ // I've decided to let degenerate triangles and group-with-anythings
+ // vary between left/right hand coordinate systems at the vertices.
+ // All healthy triangles on the other hand are built to always be either or.
+
+ /*// force the coordinate system orientation to be uniform for every face.
+ // (this is already the case for good triangles but not for
+ // degenerate ones and those with bGroupWithAnything==true)
+ bool bOrient = psTspace[index].bOrient;
+ if (psTspace[index].iCounter == 0) // tspace was not derived from a group
+ {
+ // look for a space created in GenerateTSpaces() by iCounter>0
+ bool bNotFound = true;
+ int i=1;
+ while (i<verts && bNotFound)
+ {
+ if (psTspace[index+i].iCounter > 0) bNotFound=false;
+ else ++i;
+ }
+ if (!bNotFound) bOrient = psTspace[index+i].bOrient;
+ }*/
+
+ // set data
+ for (i=0; i<verts; i++)
+ {
+ const STSpace * pTSpace = &psTspace[index];
+ float tang[] = {pTSpace->vOs.x, pTSpace->vOs.y, pTSpace->vOs.z};
+ float bitang[] = {pTSpace->vOt.x, pTSpace->vOt.y, pTSpace->vOt.z};
+ if (pContext->m_pInterface->m_setTSpace!=NULL)
+ pContext->m_pInterface->m_setTSpace(pContext, tang, bitang, pTSpace->fMagS, pTSpace->fMagT, pTSpace->bOrient, f, i);
+ if (pContext->m_pInterface->m_setTSpaceBasic!=NULL)
+ pContext->m_pInterface->m_setTSpaceBasic(pContext, tang, pTSpace->bOrient==TTRUE ? 1.0f : (-1.0f), f, i);
+
+ ++index;
+ }
+ }
+
+ free(psTspace);
+
+
+ return TTRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct {
+ float vert[3];
+ int index;
+} STmpVert;
+
+static const int g_iCells = 2048;
+
+#ifdef _MSC_VER
+ #define NOINLINE __declspec(noinline)
+#else
+ #define NOINLINE __attribute__ ((noinline))
+#endif
+
+// it is IMPORTANT that this function is called to evaluate the hash since
+// inlining could potentially reorder instructions and generate different
+// results for the same effective input value fVal.
+static NOINLINE int FindGridCell(const float fMin, const float fMax, const float fVal)
+{
+ const float fIndex = g_iCells * ((fVal-fMin)/(fMax-fMin));
+ const int iIndex = (int)fIndex;
+ return iIndex < g_iCells ? (iIndex >= 0 ? iIndex : 0) : (g_iCells - 1);
+}
+
+static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in);
+static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries);
+static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
+
+static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn)
+{
+
+ // Generate bounding box
+ int * piHashTable=NULL, * piHashCount=NULL, * piHashOffsets=NULL, * piHashCount2=NULL;
+ STmpVert * pTmpVert = NULL;
+ int i=0, iChannel=0, k=0, e=0;
+ int iMaxCount=0;
+ SVec3 vMin = GetPosition(pContext, 0), vMax = vMin, vDim;
+ float fMin, fMax;
+ for (i=1; i<(iNrTrianglesIn*3); i++)
+ {
+ const int index = piTriList_in_and_out[i];
+
+ const SVec3 vP = GetPosition(pContext, index);
+ if (vMin.x > vP.x) vMin.x = vP.x;
+ else if (vMax.x < vP.x) vMax.x = vP.x;
+ if (vMin.y > vP.y) vMin.y = vP.y;
+ else if (vMax.y < vP.y) vMax.y = vP.y;
+ if (vMin.z > vP.z) vMin.z = vP.z;
+ else if (vMax.z < vP.z) vMax.z = vP.z;
+ }
+
+ vDim = vsub(vMax,vMin);
+ iChannel = 0;
+ fMin = vMin.x; fMax=vMax.x;
+ if (vDim.y>vDim.x && vDim.y>vDim.z)
+ {
+ iChannel=1;
+ fMin = vMin.y, fMax=vMax.y;
+ }
+ else if (vDim.z>vDim.x)
+ {
+ iChannel=2;
+ fMin = vMin.z, fMax=vMax.z;
+ }
+
+ // make allocations
+ piHashTable = (int *) malloc(sizeof(int)*iNrTrianglesIn*3);
+ piHashCount = (int *) malloc(sizeof(int)*g_iCells);
+ piHashOffsets = (int *) malloc(sizeof(int)*g_iCells);
+ piHashCount2 = (int *) malloc(sizeof(int)*g_iCells);
+
+ if (piHashTable==NULL || piHashCount==NULL || piHashOffsets==NULL || piHashCount2==NULL)
+ {
+ if (piHashTable!=NULL) free(piHashTable);
+ if (piHashCount!=NULL) free(piHashCount);
+ if (piHashOffsets!=NULL) free(piHashOffsets);
+ if (piHashCount2!=NULL) free(piHashCount2);
+ GenerateSharedVerticesIndexListSlow(piTriList_in_and_out, pContext, iNrTrianglesIn);
+ return;
+ }
+ memset(piHashCount, 0, sizeof(int)*g_iCells);
+ memset(piHashCount2, 0, sizeof(int)*g_iCells);
+
+ // count amount of elements in each cell unit
+ for (i=0; i<(iNrTrianglesIn*3); i++)
+ {
+ const int index = piTriList_in_and_out[i];
+ const SVec3 vP = GetPosition(pContext, index);
+ const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z);
+ const int iCell = FindGridCell(fMin, fMax, fVal);
+ ++piHashCount[iCell];
+ }
+
+ // evaluate start index of each cell.
+ piHashOffsets[0]=0;
+ for (k=1; k<g_iCells; k++)
+ piHashOffsets[k]=piHashOffsets[k-1]+piHashCount[k-1];
+
+ // insert vertices
+ for (i=0; i<(iNrTrianglesIn*3); i++)
+ {
+ const int index = piTriList_in_and_out[i];
+ const SVec3 vP = GetPosition(pContext, index);
+ const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z);
+ const int iCell = FindGridCell(fMin, fMax, fVal);
+ int * pTable = NULL;
+
+ assert(piHashCount2[iCell]<piHashCount[iCell]);
+ pTable = &piHashTable[piHashOffsets[iCell]];
+ pTable[piHashCount2[iCell]] = i; // vertex i has been inserted.
+ ++piHashCount2[iCell];
+ }
+ for (k=0; k<g_iCells; k++)
+ assert(piHashCount2[k] == piHashCount[k]); // verify the count
+ free(piHashCount2);
+
+ // find maximum amount of entries in any hash entry
+ iMaxCount = piHashCount[0];
+ for (k=1; k<g_iCells; k++)
+ if (iMaxCount<piHashCount[k])
+ iMaxCount=piHashCount[k];
+ pTmpVert = (STmpVert *) malloc(sizeof(STmpVert)*iMaxCount);
+
+
+ // complete the merge
+ for (k=0; k<g_iCells; k++)
+ {
+ // extract table of cell k and amount of entries in it
+ int * pTable = &piHashTable[piHashOffsets[k]];
+ const int iEntries = piHashCount[k];
+ if (iEntries < 2) continue;
+
+ if (pTmpVert!=NULL)
+ {
+ for (e=0; e<iEntries; e++)
+ {
+ int i = pTable[e];
+ const SVec3 vP = GetPosition(pContext, piTriList_in_and_out[i]);
+ pTmpVert[e].vert[0] = vP.x; pTmpVert[e].vert[1] = vP.y;
+ pTmpVert[e].vert[2] = vP.z; pTmpVert[e].index = i;
+ }
+ MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, 0, iEntries-1);
+ }
+ else
+ MergeVertsSlow(piTriList_in_and_out, pContext, pTable, iEntries);
+ }
+
+ if (pTmpVert!=NULL) { free(pTmpVert); }
+ free(piHashTable);
+ free(piHashCount);
+ free(piHashOffsets);
+}
+
+static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in)
+{
+ // make bbox
+ int c=0, l=0, channel=0;
+ float fvMin[3], fvMax[3];
+ float dx=0, dy=0, dz=0, fSep=0;
+ for (c=0; c<3; c++)
+ { fvMin[c]=pTmpVert[iL_in].vert[c]; fvMax[c]=fvMin[c]; }
+ for (l=(iL_in+1); l<=iR_in; l++)
+ for (c=0; c<3; c++)
+ if (fvMin[c]>pTmpVert[l].vert[c]) fvMin[c]=pTmpVert[l].vert[c];
+ else if (fvMax[c]<pTmpVert[l].vert[c]) fvMax[c]=pTmpVert[l].vert[c];
+
+ dx = fvMax[0]-fvMin[0];
+ dy = fvMax[1]-fvMin[1];
+ dz = fvMax[2]-fvMin[2];
+
+ channel = 0;
+ if (dy>dx && dy>dz) channel=1;
+ else if (dz>dx) channel=2;
+
+ fSep = 0.5f*(fvMax[channel]+fvMin[channel]);
+
+ // terminate recursion when the separation/average value
+ // is no longer strictly between fMin and fMax values.
+ if (fSep>=fvMax[channel] || fSep<=fvMin[channel])
+ {
+ // complete the weld
+ for (l=iL_in; l<=iR_in; l++)
+ {
+ int i = pTmpVert[l].index;
+ const int index = piTriList_in_and_out[i];
+ const SVec3 vP = GetPosition(pContext, index);
+ const SVec3 vN = GetNormal(pContext, index);
+ const SVec3 vT = GetTexCoord(pContext, index);
+
+ tbool bNotFound = TTRUE;
+ int l2=iL_in, i2rec=-1;
+ while (l2<l && bNotFound)
+ {
+ const int i2 = pTmpVert[l2].index;
+ const int index2 = piTriList_in_and_out[i2];
+ const SVec3 vP2 = GetPosition(pContext, index2);
+ const SVec3 vN2 = GetNormal(pContext, index2);
+ const SVec3 vT2 = GetTexCoord(pContext, index2);
+ i2rec=i2;
+
+ //if (vP==vP2 && vN==vN2 && vT==vT2)
+ if (vP.x==vP2.x && vP.y==vP2.y && vP.z==vP2.z &&
+ vN.x==vN2.x && vN.y==vN2.y && vN.z==vN2.z &&
+ vT.x==vT2.x && vT.y==vT2.y && vT.z==vT2.z)
+ bNotFound = TFALSE;
+ else
+ ++l2;
+ }
+
+ // merge if previously found
+ if (!bNotFound)
+ piTriList_in_and_out[i] = piTriList_in_and_out[i2rec];
+ }
+ }
+ else
+ {
+ int iL=iL_in, iR=iR_in;
+ assert((iR_in-iL_in)>0); // at least 2 entries
+
+ // separate (by fSep) all points between iL_in and iR_in in pTmpVert[]
+ while (iL < iR)
+ {
+ tbool bReadyLeftSwap = TFALSE, bReadyRightSwap = TFALSE;
+ while ((!bReadyLeftSwap) && iL<iR)
+ {
+ assert(iL>=iL_in && iL<=iR_in);
+ bReadyLeftSwap = !(pTmpVert[iL].vert[channel]<fSep);
+ if (!bReadyLeftSwap) ++iL;
+ }
+ while ((!bReadyRightSwap) && iL<iR)
+ {
+ assert(iR>=iL_in && iR<=iR_in);
+ bReadyRightSwap = pTmpVert[iR].vert[channel]<fSep;
+ if (!bReadyRightSwap) --iR;
+ }
+ assert( (iL<iR) || !(bReadyLeftSwap && bReadyRightSwap) );
+
+ if (bReadyLeftSwap && bReadyRightSwap)
+ {
+ const STmpVert sTmp = pTmpVert[iL];
+ assert(iL<iR);
+ pTmpVert[iL] = pTmpVert[iR];
+ pTmpVert[iR] = sTmp;
+ ++iL; --iR;
+ }
+ }
+
+ assert(iL==(iR+1) || (iL==iR));
+ if (iL==iR)
+ {
+ const tbool bReadyRightSwap = pTmpVert[iR].vert[channel]<fSep;
+ if (bReadyRightSwap) ++iL;
+ else --iR;
+ }
+
+ // only need to weld when there is more than 1 instance of the (x,y,z)
+ if (iL_in < iR)
+ MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR); // weld all left of fSep
+ if (iL < iR_in)
+ MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL, iR_in); // weld all right of (or equal to) fSep
+ }
+}
+
+static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries)
+{
+ // this can be optimized further using a tree structure or more hashing.
+ int e=0;
+ for (e=0; e<iEntries; e++)
+ {
+ int i = pTable[e];
+ const int index = piTriList_in_and_out[i];
+ const SVec3 vP = GetPosition(pContext, index);
+ const SVec3 vN = GetNormal(pContext, index);
+ const SVec3 vT = GetTexCoord(pContext, index);
+
+ tbool bNotFound = TTRUE;
+ int e2=0, i2rec=-1;
+ while (e2<e && bNotFound)
+ {
+ const int i2 = pTable[e2];
+ const int index2 = piTriList_in_and_out[i2];
+ const SVec3 vP2 = GetPosition(pContext, index2);
+ const SVec3 vN2 = GetNormal(pContext, index2);
+ const SVec3 vT2 = GetTexCoord(pContext, index2);
+ i2rec = i2;
+
+ if (veq(vP,vP2) && veq(vN,vN2) && veq(vT,vT2))
+ bNotFound = TFALSE;
+ else
+ ++e2;
+ }
+
+ // merge if previously found
+ if (!bNotFound)
+ piTriList_in_and_out[i] = piTriList_in_and_out[i2rec];
+ }
+}
+
+static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn)
+{
+ int iNumUniqueVerts = 0, t=0, i=0;
+ for (t=0; t<iNrTrianglesIn; t++)
+ {
+ for (i=0; i<3; i++)
+ {
+ const int offs = t*3 + i;
+ const int index = piTriList_in_and_out[offs];
+
+ const SVec3 vP = GetPosition(pContext, index);
+ const SVec3 vN = GetNormal(pContext, index);
+ const SVec3 vT = GetTexCoord(pContext, index);
+
+ tbool bFound = TFALSE;
+ int t2=0, index2rec=-1;
+ while (!bFound && t2<=t)
+ {
+ int j=0;
+ while (!bFound && j<3)
+ {
+ const int index2 = piTriList_in_and_out[t2*3 + j];
+ const SVec3 vP2 = GetPosition(pContext, index2);
+ const SVec3 vN2 = GetNormal(pContext, index2);
+ const SVec3 vT2 = GetTexCoord(pContext, index2);
+
+ if (veq(vP,vP2) && veq(vN,vN2) && veq(vT,vT2))
+ bFound = TTRUE;
+ else
+ ++j;
+ }
+ if (!bFound) ++t2;
+ }
+
+ assert(bFound);
+ // if we found our own
+ if (index2rec == index) { ++iNumUniqueVerts; }
+
+ piTriList_in_and_out[offs] = index2rec;
+ }
+ }
+}
+
+static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn)
+{
+ int iTSpacesOffs = 0, f=0, t=0;
+ int iDstTriIndex = 0;
+ for (f=0; f<pContext->m_pInterface->m_getNumFaces(pContext); f++)
+ {
+ const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
+ if (verts!=3 && verts!=4) continue;
+
+ pTriInfos[iDstTriIndex].iOrgFaceNumber = f;
+ pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs;
+
+ if (verts==3)
+ {
+ unsigned char * pVerts = pTriInfos[iDstTriIndex].vert_num;
+ pVerts[0]=0; pVerts[1]=1; pVerts[2]=2;
+ piTriList_out[iDstTriIndex*3+0] = MakeIndex(f, 0);
+ piTriList_out[iDstTriIndex*3+1] = MakeIndex(f, 1);
+ piTriList_out[iDstTriIndex*3+2] = MakeIndex(f, 2);
+ ++iDstTriIndex; // next
+ }
+ else
+ {
+ {
+ pTriInfos[iDstTriIndex+1].iOrgFaceNumber = f;
+ pTriInfos[iDstTriIndex+1].iTSpacesOffs = iTSpacesOffs;
+ }
+
+ {
+ // need an order independent way to evaluate
+ // tspace on quads. This is done by splitting
+ // along the shortest diagonal.
+ const int i0 = MakeIndex(f, 0);
+ const int i1 = MakeIndex(f, 1);
+ const int i2 = MakeIndex(f, 2);
+ const int i3 = MakeIndex(f, 3);
+ const SVec3 T0 = GetTexCoord(pContext, i0);
+ const SVec3 T1 = GetTexCoord(pContext, i1);
+ const SVec3 T2 = GetTexCoord(pContext, i2);
+ const SVec3 T3 = GetTexCoord(pContext, i3);
+ const float distSQ_02 = LengthSquared(vsub(T2,T0));
+ const float distSQ_13 = LengthSquared(vsub(T3,T1));
+ tbool bQuadDiagIs_02;
+ if (distSQ_02<distSQ_13)
+ bQuadDiagIs_02 = TTRUE;
+ else if (distSQ_13<distSQ_02)
+ bQuadDiagIs_02 = TFALSE;
+ else
+ {
+ const SVec3 P0 = GetPosition(pContext, i0);
+ const SVec3 P1 = GetPosition(pContext, i1);
+ const SVec3 P2 = GetPosition(pContext, i2);
+ const SVec3 P3 = GetPosition(pContext, i3);
+ const float distSQ_02 = LengthSquared(vsub(P2,P0));
+ const float distSQ_13 = LengthSquared(vsub(P3,P1));
+
+ bQuadDiagIs_02 = distSQ_13<distSQ_02 ? TFALSE : TTRUE;
+ }
+
+ if (bQuadDiagIs_02)
+ {
+ {
+ unsigned char * pVerts_A = pTriInfos[iDstTriIndex].vert_num;
+ pVerts_A[0]=0; pVerts_A[1]=1; pVerts_A[2]=2;
+ }
+ piTriList_out[iDstTriIndex*3+0] = i0;
+ piTriList_out[iDstTriIndex*3+1] = i1;
+ piTriList_out[iDstTriIndex*3+2] = i2;
+ ++iDstTriIndex; // next
+ {
+ unsigned char * pVerts_B = pTriInfos[iDstTriIndex].vert_num;
+ pVerts_B[0]=0; pVerts_B[1]=2; pVerts_B[2]=3;
+ }
+ piTriList_out[iDstTriIndex*3+0] = i0;
+ piTriList_out[iDstTriIndex*3+1] = i2;
+ piTriList_out[iDstTriIndex*3+2] = i3;
+ ++iDstTriIndex; // next
+ }
+ else
+ {
+ {
+ unsigned char * pVerts_A = pTriInfos[iDstTriIndex].vert_num;
+ pVerts_A[0]=0; pVerts_A[1]=1; pVerts_A[2]=3;
+ }
+ piTriList_out[iDstTriIndex*3+0] = i0;
+ piTriList_out[iDstTriIndex*3+1] = i1;
+ piTriList_out[iDstTriIndex*3+2] = i3;
+ ++iDstTriIndex; // next
+ {
+ unsigned char * pVerts_B = pTriInfos[iDstTriIndex].vert_num;
+ pVerts_B[0]=1; pVerts_B[1]=2; pVerts_B[2]=3;
+ }
+ piTriList_out[iDstTriIndex*3+0] = i1;
+ piTriList_out[iDstTriIndex*3+1] = i2;
+ piTriList_out[iDstTriIndex*3+2] = i3;
+ ++iDstTriIndex; // next
+ }
+ }
+ }
+
+ iTSpacesOffs += verts;
+ assert(iDstTriIndex<=iNrTrianglesIn);
+ }
+
+ for (t=0; t<iNrTrianglesIn; t++)
+ pTriInfos[t].iFlag = 0;
+
+ // return total amount of tspaces
+ return iTSpacesOffs;
+}
+
+static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index)
+{
+ int iF, iI;
+ SVec3 res; float pos[3];
+ IndexToData(&iF, &iI, index);
+ pContext->m_pInterface->m_getPosition(pContext, pos, iF, iI);
+ res.x=pos[0]; res.y=pos[1]; res.z=pos[2];
+ return res;
+}
+
+static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index)
+{
+ int iF, iI;
+ SVec3 res; float norm[3];
+ IndexToData(&iF, &iI, index);
+ pContext->m_pInterface->m_getNormal(pContext, norm, iF, iI);
+ res.x=norm[0]; res.y=norm[1]; res.z=norm[2];
+ return res;
+}
+
+static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index)
+{
+ int iF, iI;
+ SVec3 res; float texc[2];
+ IndexToData(&iF, &iI, index);
+ pContext->m_pInterface->m_getTexCoord(pContext, texc, iF, iI);
+ res.x=texc[0]; res.y=texc[1]; res.z=1.0f;
+ return res;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+typedef union {
+ struct
+ {
+ int i0, i1, f;
+ };
+ int array[3];
+} SEdge;
+
+static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn);
+static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn);
+
+// returns the texture area times 2
+static float CalcTexArea(const SMikkTSpaceContext * pContext, const int indices[])
+{
+ const SVec3 t1 = GetTexCoord(pContext, indices[0]);
+ const SVec3 t2 = GetTexCoord(pContext, indices[1]);
+ const SVec3 t3 = GetTexCoord(pContext, indices[2]);
+
+ const float t21x = t2.x-t1.x;
+ const float t21y = t2.y-t1.y;
+ const float t31x = t3.x-t1.x;
+ const float t31y = t3.y-t1.y;
+
+ const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x;
+
+ return fSignedAreaSTx2<0 ? (-fSignedAreaSTx2) : fSignedAreaSTx2;
+}
+
+static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn)
+{
+ int f=0, i=0, t=0;
+ // pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList() which is called before this function.
+
+ // generate neighbor info list
+ for (f=0; f<iNrTrianglesIn; f++)
+ for (i=0; i<3; i++)
+ {
+ pTriInfos[f].FaceNeighbors[i] = -1;
+ pTriInfos[f].AssignedGroup[i] = NULL;
+
+ pTriInfos[f].vOs.x=0.0f; pTriInfos[f].vOs.y=0.0f; pTriInfos[f].vOs.z=0.0f;
+ pTriInfos[f].vOt.x=0.0f; pTriInfos[f].vOt.y=0.0f; pTriInfos[f].vOt.z=0.0f;
+ pTriInfos[f].fMagS = 0;
+ pTriInfos[f].fMagT = 0;
+
+ // assumed bad
+ pTriInfos[f].iFlag |= GROUP_WITH_ANY;
+ }
+
+ // evaluate first order derivatives
+ for (f=0; f<iNrTrianglesIn; f++)
+ {
+ // initial values
+ const SVec3 v1 = GetPosition(pContext, piTriListIn[f*3+0]);
+ const SVec3 v2 = GetPosition(pContext, piTriListIn[f*3+1]);
+ const SVec3 v3 = GetPosition(pContext, piTriListIn[f*3+2]);
+ const SVec3 t1 = GetTexCoord(pContext, piTriListIn[f*3+0]);
+ const SVec3 t2 = GetTexCoord(pContext, piTriListIn[f*3+1]);
+ const SVec3 t3 = GetTexCoord(pContext, piTriListIn[f*3+2]);
+
+ const float t21x = t2.x-t1.x;
+ const float t21y = t2.y-t1.y;
+ const float t31x = t3.x-t1.x;
+ const float t31y = t3.y-t1.y;
+ const SVec3 d1 = vsub(v2,v1);
+ const SVec3 d2 = vsub(v3,v1);
+
+ const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x;
+ //assert(fSignedAreaSTx2!=0);
+ SVec3 vOs = vsub(vscale(t31y,d1), vscale(t21y,d2)); // eq 18
+ SVec3 vOt = vadd(vscale(-t31x,d1), vscale(t21x,d2)); // eq 19
+
+ pTriInfos[f].iFlag |= (fSignedAreaSTx2>0 ? ORIENT_PRESERVING : 0);
+
+ if ( NotZero(fSignedAreaSTx2) )
+ {
+ const float fAbsArea = fabsf(fSignedAreaSTx2);
+ const float fLenOs = Length(vOs);
+ const float fLenOt = Length(vOt);
+ const float fS = (pTriInfos[f].iFlag&ORIENT_PRESERVING)==0 ? (-1.0f) : 1.0f;
+ if ( NotZero(fLenOs) ) pTriInfos[f].vOs = vscale(fS/fLenOs, vOs);
+ if ( NotZero(fLenOt) ) pTriInfos[f].vOt = vscale(fS/fLenOt, vOt);
+
+ // evaluate magnitudes prior to normalization of vOs and vOt
+ pTriInfos[f].fMagS = fLenOs / fAbsArea;
+ pTriInfos[f].fMagT = fLenOt / fAbsArea;
+
+ // if this is a good triangle
+ if ( NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT))
+ pTriInfos[f].iFlag &= (~GROUP_WITH_ANY);
+ }
+ }
+
+ // force otherwise healthy quads to a fixed orientation
+ while (t<(iNrTrianglesIn-1))
+ {
+ const int iFO_a = pTriInfos[t].iOrgFaceNumber;
+ const int iFO_b = pTriInfos[t+1].iOrgFaceNumber;
+ if (iFO_a==iFO_b) // this is a quad
+ {
+ const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE;
+ const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE;
+
+ // bad triangles should already have been removed by
+ // DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false
+ if ((bIsDeg_a||bIsDeg_b)==TFALSE)
+ {
+ const tbool bOrientA = (pTriInfos[t].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ const tbool bOrientB = (pTriInfos[t+1].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ // if this happens the quad has extremely bad mapping!!
+ if (bOrientA!=bOrientB)
+ {
+ //printf("found quad with bad mapping\n");
+ tbool bChooseOrientFirstTri = TFALSE;
+ if ((pTriInfos[t+1].iFlag&GROUP_WITH_ANY)!=0) bChooseOrientFirstTri = TTRUE;
+ else if ( CalcTexArea(pContext, &piTriListIn[t*3+0]) >= CalcTexArea(pContext, &piTriListIn[(t+1)*3+0]) )
+ bChooseOrientFirstTri = TTRUE;
+
+ // force match
+ {
+ const int t0 = bChooseOrientFirstTri ? t : (t+1);
+ const int t1 = bChooseOrientFirstTri ? (t+1) : t;
+ pTriInfos[t1].iFlag &= (~ORIENT_PRESERVING); // clear first
+ pTriInfos[t1].iFlag |= (pTriInfos[t0].iFlag&ORIENT_PRESERVING); // copy bit
+ }
+ }
+ }
+ t += 2;
+ }
+ else
+ ++t;
+ }
+
+ // match up edge pairs
+ {
+ SEdge * pEdges = (SEdge *) malloc(sizeof(SEdge)*iNrTrianglesIn*3);
+ if (pEdges==NULL)
+ BuildNeighborsSlow(pTriInfos, piTriListIn, iNrTrianglesIn);
+ else
+ {
+ BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn);
+
+ free(pEdges);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], const int iMyTriIndex, SGroup * pGroup);
+static void AddTriToGroup(SGroup * pGroup, const int iTriIndex);
+
+static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn)
+{
+ const int iNrMaxGroups = iNrTrianglesIn*3;
+ int iNrActiveGroups = 0;
+ int iOffset = 0, f=0, i=0;
+ (void)iNrMaxGroups; /* quiet warnings in non debug mode */
+ for (f=0; f<iNrTrianglesIn; f++)
+ {
+ for (i=0; i<3; i++)
+ {
+ // if not assigned to a group
+ if ((pTriInfos[f].iFlag&GROUP_WITH_ANY)==0 && pTriInfos[f].AssignedGroup[i]==NULL)
+ {
+ tbool bOrPre;
+ int neigh_indexL, neigh_indexR;
+ const int vert_index = piTriListIn[f*3+i];
+ assert(iNrActiveGroups<iNrMaxGroups);
+ pTriInfos[f].AssignedGroup[i] = &pGroups[iNrActiveGroups];
+ pTriInfos[f].AssignedGroup[i]->iVertexRepresentitive = vert_index;
+ pTriInfos[f].AssignedGroup[i]->bOrientPreservering = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0;
+ pTriInfos[f].AssignedGroup[i]->iNrFaces = 0;
+ pTriInfos[f].AssignedGroup[i]->pFaceIndices = &piGroupTrianglesBuffer[iOffset];
+ ++iNrActiveGroups;
+
+ AddTriToGroup(pTriInfos[f].AssignedGroup[i], f);
+ bOrPre = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ neigh_indexL = pTriInfos[f].FaceNeighbors[i];
+ neigh_indexR = pTriInfos[f].FaceNeighbors[i>0?(i-1):2];
+ if (neigh_indexL>=0) // neighbor
+ {
+ const tbool bAnswer =
+ AssignRecur(piTriListIn, pTriInfos, neigh_indexL,
+ pTriInfos[f].AssignedGroup[i] );
+
+ const tbool bOrPre2 = (pTriInfos[neigh_indexL].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE;
+ assert(bAnswer || bDiff);
+ (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */
+ }
+ if (neigh_indexR>=0) // neighbor
+ {
+ const tbool bAnswer =
+ AssignRecur(piTriListIn, pTriInfos, neigh_indexR,
+ pTriInfos[f].AssignedGroup[i] );
+
+ const tbool bOrPre2 = (pTriInfos[neigh_indexR].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE;
+ assert(bAnswer || bDiff);
+ (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */
+ }
+
+ // update offset
+ iOffset += pTriInfos[f].AssignedGroup[i]->iNrFaces;
+ // since the groups are disjoint a triangle can never
+ // belong to more than 3 groups. Subsequently something
+ // is completely screwed if this assertion ever hits.
+ assert(iOffset <= iNrMaxGroups);
+ }
+ }
+ }
+
+ return iNrActiveGroups;
+}
+
+static void AddTriToGroup(SGroup * pGroup, const int iTriIndex)
+{
+ pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex;
+ ++pGroup->iNrFaces;
+}
+
+static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[],
+ const int iMyTriIndex, SGroup * pGroup)
+{
+ STriInfo * pMyTriInfo = &psTriInfos[iMyTriIndex];
+
+ // track down vertex
+ const int iVertRep = pGroup->iVertexRepresentitive;
+ const int * pVerts = &piTriListIn[3*iMyTriIndex+0];
+ int i=-1;
+ if (pVerts[0]==iVertRep) i=0;
+ else if (pVerts[1]==iVertRep) i=1;
+ else if (pVerts[2]==iVertRep) i=2;
+ assert(i>=0 && i<3);
+
+ // early out
+ if (pMyTriInfo->AssignedGroup[i] == pGroup) return TTRUE;
+ else if (pMyTriInfo->AssignedGroup[i]!=NULL) return TFALSE;
+ if ((pMyTriInfo->iFlag&GROUP_WITH_ANY)!=0)
+ {
+ // first to group with a group-with-anything triangle
+ // determines it's orientation.
+ // This is the only existing order dependency in the code!!
+ if ( pMyTriInfo->AssignedGroup[0] == NULL &&
+ pMyTriInfo->AssignedGroup[1] == NULL &&
+ pMyTriInfo->AssignedGroup[2] == NULL )
+ {
+ pMyTriInfo->iFlag &= (~ORIENT_PRESERVING);
+ pMyTriInfo->iFlag |= (pGroup->bOrientPreservering ? ORIENT_PRESERVING : 0);
+ }
+ }
+ {
+ const tbool bOrient = (pMyTriInfo->iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE;
+ if (bOrient != pGroup->bOrientPreservering) return TFALSE;
+ }
+
+ AddTriToGroup(pGroup, iMyTriIndex);
+ pMyTriInfo->AssignedGroup[i] = pGroup;
+
+ {
+ const int neigh_indexL = pMyTriInfo->FaceNeighbors[i];
+ const int neigh_indexR = pMyTriInfo->FaceNeighbors[i>0?(i-1):2];
+ if (neigh_indexL>=0)
+ AssignRecur(piTriListIn, psTriInfos, neigh_indexL, pGroup);
+ if (neigh_indexR>=0)
+ AssignRecur(piTriListIn, psTriInfos, neigh_indexR, pGroup);
+ }
+
+
+
+ return TTRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2);
+static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed);
+static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], const SMikkTSpaceContext * pContext, const int iVertexRepresentitive);
+
+static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[],
+ const int iNrActiveGroups, const int piTriListIn[], const float fThresCos,
+ const SMikkTSpaceContext * pContext)
+{
+ STSpace * pSubGroupTspace = NULL;
+ SSubGroup * pUniSubGroups = NULL;
+ int * pTmpMembers = NULL;
+ int iMaxNrFaces=0, iUniqueTspaces=0, g=0, i=0;
+ for (g=0; g<iNrActiveGroups; g++)
+ if (iMaxNrFaces < pGroups[g].iNrFaces)
+ iMaxNrFaces = pGroups[g].iNrFaces;
+
+ if (iMaxNrFaces == 0) return TTRUE;
+
+ // make initial allocations
+ pSubGroupTspace = (STSpace *) malloc(sizeof(STSpace)*iMaxNrFaces);
+ pUniSubGroups = (SSubGroup *) malloc(sizeof(SSubGroup)*iMaxNrFaces);
+ pTmpMembers = (int *) malloc(sizeof(int)*iMaxNrFaces);
+ if (pSubGroupTspace==NULL || pUniSubGroups==NULL || pTmpMembers==NULL)
+ {
+ if (pSubGroupTspace!=NULL) free(pSubGroupTspace);
+ if (pUniSubGroups!=NULL) free(pUniSubGroups);
+ if (pTmpMembers!=NULL) free(pTmpMembers);
+ return TFALSE;
+ }
+
+
+ iUniqueTspaces = 0;
+ for (g=0; g<iNrActiveGroups; g++)
+ {
+ const SGroup * pGroup = &pGroups[g];
+ int iUniqueSubGroups = 0, s=0;
+
+ for (i=0; i<pGroup->iNrFaces; i++) // triangles
+ {
+ const int f = pGroup->pFaceIndices[i]; // triangle number
+ int index=-1, iVertIndex=-1, iOF_1=-1, iMembers=0, j=0, l=0;
+ SSubGroup tmp_group;
+ tbool bFound;
+ SVec3 n, vOs, vOt;
+ if (pTriInfos[f].AssignedGroup[0]==pGroup) index=0;
+ else if (pTriInfos[f].AssignedGroup[1]==pGroup) index=1;
+ else if (pTriInfos[f].AssignedGroup[2]==pGroup) index=2;
+ assert(index>=0 && index<3);
+
+ iVertIndex = piTriListIn[f*3+index];
+ assert(iVertIndex==pGroup->iVertexRepresentitive);
+
+ // is normalized already
+ n = GetNormal(pContext, iVertIndex);
+
+ // project
+ vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n));
+ vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n));
+ if ( VNotZero(vOs) ) vOs = Normalize(vOs);
+ if ( VNotZero(vOt) ) vOt = Normalize(vOt);
+
+ // original face number
+ iOF_1 = pTriInfos[f].iOrgFaceNumber;
+
+ iMembers = 0;
+ for (j=0; j<pGroup->iNrFaces; j++)
+ {
+ const int t = pGroup->pFaceIndices[j]; // triangle number
+ const int iOF_2 = pTriInfos[t].iOrgFaceNumber;
+
+ // project
+ SVec3 vOs2 = vsub(pTriInfos[t].vOs, vscale(vdot(n,pTriInfos[t].vOs), n));
+ SVec3 vOt2 = vsub(pTriInfos[t].vOt, vscale(vdot(n,pTriInfos[t].vOt), n));
+ if ( VNotZero(vOs2) ) vOs2 = Normalize(vOs2);
+ if ( VNotZero(vOt2) ) vOt2 = Normalize(vOt2);
+
+ {
+ const tbool bAny = ( (pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY )!=0 ? TTRUE : TFALSE;
+ // make sure triangles which belong to the same quad are joined.
+ const tbool bSameOrgFace = iOF_1==iOF_2 ? TTRUE : TFALSE;
+
+ const float fCosS = vdot(vOs,vOs2);
+ const float fCosT = vdot(vOt,vOt2);
+
+ assert(f!=t || bSameOrgFace); // sanity check
+ if (bAny || bSameOrgFace || (fCosS>fThresCos && fCosT>fThresCos))
+ pTmpMembers[iMembers++] = t;
+ }
+ }
+
+ // sort pTmpMembers
+ tmp_group.iNrFaces = iMembers;
+ tmp_group.pTriMembers = pTmpMembers;
+ if (iMembers>1)
+ {
+ unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
+ QuickSort(pTmpMembers, 0, iMembers-1, uSeed);
+ }
+
+ // look for an existing match
+ bFound = TFALSE;
+ l=0;
+ while (l<iUniqueSubGroups && !bFound)
+ {
+ bFound = CompareSubGroups(&tmp_group, &pUniSubGroups[l]);
+ if (!bFound) ++l;
+ }
+
+ // assign tangent space index
+ assert(bFound || l==iUniqueSubGroups);
+ //piTempTangIndices[f*3+index] = iUniqueTspaces+l;
+
+ // if no match was found we allocate a new subgroup
+ if (!bFound)
+ {
+ // insert new subgroup
+ int * pIndices = (int *) malloc(sizeof(int)*iMembers);
+ if (pIndices==NULL)
+ {
+ // clean up and return false
+ int s=0;
+ for (s=0; s<iUniqueSubGroups; s++)
+ free(pUniSubGroups[s].pTriMembers);
+ free(pUniSubGroups);
+ free(pTmpMembers);
+ free(pSubGroupTspace);
+ return TFALSE;
+ }
+ pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers;
+ pUniSubGroups[iUniqueSubGroups].pTriMembers = pIndices;
+ memcpy(pIndices, tmp_group.pTriMembers, iMembers*sizeof(int));
+ pSubGroupTspace[iUniqueSubGroups] =
+ EvalTspace(tmp_group.pTriMembers, iMembers, piTriListIn, pTriInfos, pContext, pGroup->iVertexRepresentitive);
+ ++iUniqueSubGroups;
+ }
+
+ // output tspace
+ {
+ const int iOffs = pTriInfos[f].iTSpacesOffs;
+ const int iVert = pTriInfos[f].vert_num[index];
+ STSpace * pTS_out = &psTspace[iOffs+iVert];
+ assert(pTS_out->iCounter<2);
+ assert(((pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0) == pGroup->bOrientPreservering);
+ if (pTS_out->iCounter==1)
+ {
+ *pTS_out = AvgTSpace(pTS_out, &pSubGroupTspace[l]);
+ pTS_out->iCounter = 2; // update counter
+ pTS_out->bOrient = pGroup->bOrientPreservering;
+ }
+ else
+ {
+ assert(pTS_out->iCounter==0);
+ *pTS_out = pSubGroupTspace[l];
+ pTS_out->iCounter = 1; // update counter
+ pTS_out->bOrient = pGroup->bOrientPreservering;
+ }
+ }
+ }
+
+ // clean up and offset iUniqueTspaces
+ for (s=0; s<iUniqueSubGroups; s++)
+ free(pUniSubGroups[s].pTriMembers);
+ iUniqueTspaces += iUniqueSubGroups;
+ }
+
+ // clean up
+ free(pUniSubGroups);
+ free(pTmpMembers);
+ free(pSubGroupTspace);
+
+ return TTRUE;
+}
+
+static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[],
+ const SMikkTSpaceContext * pContext, const int iVertexRepresentitive)
+{
+ STSpace res;
+ float fAngleSum = 0;
+ int face=0;
+ res.vOs.x=0.0f; res.vOs.y=0.0f; res.vOs.z=0.0f;
+ res.vOt.x=0.0f; res.vOt.y=0.0f; res.vOt.z=0.0f;
+ res.fMagS = 0; res.fMagT = 0;
+
+ for (face=0; face<iFaces; face++)
+ {
+ const int f = face_indices[face];
+
+ // only valid triangles get to add their contribution
+ if ( (pTriInfos[f].iFlag&GROUP_WITH_ANY)==0 )
+ {
+ SVec3 n, vOs, vOt, p0, p1, p2, v1, v2;
+ float fCos, fAngle, fMagS, fMagT;
+ int i=-1, index=-1, i0=-1, i1=-1, i2=-1;
+ if (piTriListIn[3*f+0]==iVertexRepresentitive) i=0;
+ else if (piTriListIn[3*f+1]==iVertexRepresentitive) i=1;
+ else if (piTriListIn[3*f+2]==iVertexRepresentitive) i=2;
+ assert(i>=0 && i<3);
+
+ // project
+ index = piTriListIn[3*f+i];
+ n = GetNormal(pContext, index);
+ vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n));
+ vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n));
+ if ( VNotZero(vOs) ) vOs = Normalize(vOs);
+ if ( VNotZero(vOt) ) vOt = Normalize(vOt);
+
+ i2 = piTriListIn[3*f + (i<2?(i+1):0)];
+ i1 = piTriListIn[3*f + i];
+ i0 = piTriListIn[3*f + (i>0?(i-1):2)];
+
+ p0 = GetPosition(pContext, i0);
+ p1 = GetPosition(pContext, i1);
+ p2 = GetPosition(pContext, i2);
+ v1 = vsub(p0,p1);
+ v2 = vsub(p2,p1);
+
+ // project
+ v1 = vsub(v1, vscale(vdot(n,v1),n)); if ( VNotZero(v1) ) v1 = Normalize(v1);
+ v2 = vsub(v2, vscale(vdot(n,v2),n)); if ( VNotZero(v2) ) v2 = Normalize(v2);
+
+ // weight contribution by the angle
+ // between the two edge vectors
+ fCos = vdot(v1,v2); fCos=fCos>1?1:(fCos<(-1) ? (-1) : fCos);
+ fAngle = (float) acos(fCos);
+ fMagS = pTriInfos[f].fMagS;
+ fMagT = pTriInfos[f].fMagT;
+
+ res.vOs=vadd(res.vOs, vscale(fAngle,vOs));
+ res.vOt=vadd(res.vOt,vscale(fAngle,vOt));
+ res.fMagS+=(fAngle*fMagS);
+ res.fMagT+=(fAngle*fMagT);
+ fAngleSum += fAngle;
+ }
+ }
+
+ // normalize
+ if ( VNotZero(res.vOs) ) res.vOs = Normalize(res.vOs);
+ if ( VNotZero(res.vOt) ) res.vOt = Normalize(res.vOt);
+ if (fAngleSum>0)
+ {
+ res.fMagS /= fAngleSum;
+ res.fMagT /= fAngleSum;
+ }
+
+ return res;
+}
+
+static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2)
+{
+ tbool bStillSame=TTRUE;
+ int i=0;
+ if (pg1->iNrFaces!=pg2->iNrFaces) return TFALSE;
+ while (i<pg1->iNrFaces && bStillSame)
+ {
+ bStillSame = pg1->pTriMembers[i]==pg2->pTriMembers[i] ? TTRUE : TFALSE;
+ if (bStillSame) ++i;
+ }
+ return bStillSame;
+}
+
+static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed)
+{
+ int iL, iR, n, index, iMid, iTmp;
+
+ // Random
+ unsigned int t=uSeed&31;
+ t=(uSeed<<t)|(uSeed>>(32-t));
+ uSeed=uSeed+t+3;
+ // Random end
+
+ iL=iLeft; iR=iRight;
+ n = (iR-iL)+1;
+ assert(n>=0);
+ index = (int) (uSeed%n);
+
+ iMid=pSortBuffer[index + iL];
+
+
+ do
+ {
+ while (pSortBuffer[iL] < iMid)
+ ++iL;
+ while (pSortBuffer[iR] > iMid)
+ --iR;
+
+ if (iL <= iR)
+ {
+ iTmp = pSortBuffer[iL];
+ pSortBuffer[iL] = pSortBuffer[iR];
+ pSortBuffer[iR] = iTmp;
+ ++iL; --iR;
+ }
+ }
+ while (iL <= iR);
+
+ if (iLeft < iR)
+ QuickSort(pSortBuffer, iLeft, iR, uSeed);
+ if (iL < iRight)
+ QuickSort(pSortBuffer, iL, iRight, uSeed);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed);
+static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in);
+
+static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn)
+{
+ // build array of edges
+ unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
+ int iEntries=0, iCurStartIndex=-1, f=0, i=0;
+ for (f=0; f<iNrTrianglesIn; f++)
+ for (i=0; i<3; i++)
+ {
+ const int i0 = piTriListIn[f*3+i];
+ const int i1 = piTriListIn[f*3+(i<2?(i+1):0)];
+ pEdges[f*3+i].i0 = i0 < i1 ? i0 : i1; // put minimum index in i0
+ pEdges[f*3+i].i1 = !(i0 < i1) ? i0 : i1; // put maximum index in i1
+ pEdges[f*3+i].f = f; // record face number
+ }
+
+ // sort over all edges by i0, this is the pricy one.
+ QuickSortEdges(pEdges, 0, iNrTrianglesIn*3-1, 0, uSeed); // sort channel 0 which is i0
+
+ // sub sort over i1, should be fast.
+ // could replace this with a 64 bit int sort over (i0,i1)
+ // with i0 as msb in the quicksort call above.
+ iEntries = iNrTrianglesIn*3;
+ iCurStartIndex = 0;
+ for (i=1; i<iEntries; i++)
+ {
+ if (pEdges[iCurStartIndex].i0 != pEdges[i].i0)
+ {
+ const int iL = iCurStartIndex;
+ const int iR = i-1;
+ //const int iElems = i-iL;
+ iCurStartIndex = i;
+ QuickSortEdges(pEdges, iL, iR, 1, uSeed); // sort channel 1 which is i1
+ }
+ }
+
+ // sub sort over f, which should be fast.
+ // this step is to remain compliant with BuildNeighborsSlow() when
+ // more than 2 triangles use the same edge (such as a butterfly topology).
+ iCurStartIndex = 0;
+ for (i=1; i<iEntries; i++)
+ {
+ if (pEdges[iCurStartIndex].i0 != pEdges[i].i0 || pEdges[iCurStartIndex].i1 != pEdges[i].i1)
+ {
+ const int iL = iCurStartIndex;
+ const int iR = i-1;
+ //const int iElems = i-iL;
+ iCurStartIndex = i;
+ QuickSortEdges(pEdges, iL, iR, 2, uSeed); // sort channel 2 which is f
+ }
+ }
+
+ // pair up, adjacent triangles
+ for (i=0; i<iEntries; i++)
+ {
+ const int i0=pEdges[i].i0;
+ const int i1=pEdges[i].i1;
+ const int f = pEdges[i].f;
+ tbool bUnassigned_A;
+
+ int i0_A, i1_A;
+ int edgenum_A, edgenum_B=0; // 0,1 or 2
+ GetEdge(&i0_A, &i1_A, &edgenum_A, &piTriListIn[f*3], i0, i1); // resolve index ordering and edge_num
+ bUnassigned_A = pTriInfos[f].FaceNeighbors[edgenum_A] == -1 ? TTRUE : TFALSE;
+
+ if (bUnassigned_A)
+ {
+ // get true index ordering
+ int j=i+1, t;
+ tbool bNotFound = TTRUE;
+ while (j<iEntries && i0==pEdges[j].i0 && i1==pEdges[j].i1 && bNotFound)
+ {
+ tbool bUnassigned_B;
+ int i0_B, i1_B;
+ t = pEdges[j].f;
+ // flip i0_B and i1_B
+ GetEdge(&i1_B, &i0_B, &edgenum_B, &piTriListIn[t*3], pEdges[j].i0, pEdges[j].i1); // resolve index ordering and edge_num
+ //assert(!(i0_A==i1_B && i1_A==i0_B));
+ bUnassigned_B = pTriInfos[t].FaceNeighbors[edgenum_B]==-1 ? TTRUE : TFALSE;
+ if (i0_A==i0_B && i1_A==i1_B && bUnassigned_B)
+ bNotFound = TFALSE;
+ else
+ ++j;
+ }
+
+ if (!bNotFound)
+ {
+ int t = pEdges[j].f;
+ pTriInfos[f].FaceNeighbors[edgenum_A] = t;
+ //assert(pTriInfos[t].FaceNeighbors[edgenum_B]==-1);
+ pTriInfos[t].FaceNeighbors[edgenum_B] = f;
+ }
+ }
+ }
+}
+
+static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn)
+{
+ int f=0, i=0;
+ for (f=0; f<iNrTrianglesIn; f++)
+ {
+ for (i=0; i<3; i++)
+ {
+ // if unassigned
+ if (pTriInfos[f].FaceNeighbors[i] == -1)
+ {
+ const int i0_A = piTriListIn[f*3+i];
+ const int i1_A = piTriListIn[f*3+(i<2?(i+1):0)];
+
+ // search for a neighbor
+ tbool bFound = TFALSE;
+ int t=0, j=0;
+ while (!bFound && t<iNrTrianglesIn)
+ {
+ if (t!=f)
+ {
+ j=0;
+ while (!bFound && j<3)
+ {
+ // in rev order
+ const int i1_B = piTriListIn[t*3+j];
+ const int i0_B = piTriListIn[t*3+(j<2?(j+1):0)];
+ //assert(!(i0_A==i1_B && i1_A==i0_B));
+ if (i0_A==i0_B && i1_A==i1_B)
+ bFound = TTRUE;
+ else
+ ++j;
+ }
+ }
+
+ if (!bFound) ++t;
+ }
+
+ // assign neighbors
+ if (bFound)
+ {
+ pTriInfos[f].FaceNeighbors[i] = t;
+ //assert(pTriInfos[t].FaceNeighbors[j]==-1);
+ pTriInfos[t].FaceNeighbors[j] = f;
+ }
+ }
+ }
+ }
+}
+
+static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed)
+{
+ unsigned int t;
+ int iL, iR, n, index, iMid;
+
+ // early out
+ SEdge sTmp;
+ const int iElems = iRight-iLeft+1;
+ if (iElems<2) return;
+ else if (iElems==2)
+ {
+ if (pSortBuffer[iLeft].array[channel] > pSortBuffer[iRight].array[channel])
+ {
+ sTmp = pSortBuffer[iLeft];
+ pSortBuffer[iLeft] = pSortBuffer[iRight];
+ pSortBuffer[iRight] = sTmp;
+ }
+ return;
+ }
+
+ // Random
+ t=uSeed&31;
+ t=(uSeed<<t)|(uSeed>>(32-t));
+ uSeed=uSeed+t+3;
+ // Random end
+
+ iL=iLeft, iR=iRight;
+ n = (iR-iL)+1;
+ assert(n>=0);
+ index = (int) (uSeed%n);
+
+ iMid=pSortBuffer[index + iL].array[channel];
+
+ do
+ {
+ while (pSortBuffer[iL].array[channel] < iMid)
+ ++iL;
+ while (pSortBuffer[iR].array[channel] > iMid)
+ --iR;
+
+ if (iL <= iR)
+ {
+ sTmp = pSortBuffer[iL];
+ pSortBuffer[iL] = pSortBuffer[iR];
+ pSortBuffer[iR] = sTmp;
+ ++iL; --iR;
+ }
+ }
+ while (iL <= iR);
+
+ if (iLeft < iR)
+ QuickSortEdges(pSortBuffer, iLeft, iR, channel, uSeed);
+ if (iL < iRight)
+ QuickSortEdges(pSortBuffer, iL, iRight, channel, uSeed);
+}
+
+// resolve ordering and edge number
+static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in)
+{
+ *edgenum_out = -1;
+
+ // test if first index is on the edge
+ if (indices[0]==i0_in || indices[0]==i1_in)
+ {
+ // test if second index is on the edge
+ if (indices[1]==i0_in || indices[1]==i1_in)
+ {
+ edgenum_out[0]=0; // first edge
+ i0_out[0]=indices[0];
+ i1_out[0]=indices[1];
+ }
+ else
+ {
+ edgenum_out[0]=2; // third edge
+ i0_out[0]=indices[2];
+ i1_out[0]=indices[0];
+ }
+ }
+ else
+ {
+ // only second and third index is on the edge
+ edgenum_out[0]=1; // second edge
+ i0_out[0]=indices[1];
+ i1_out[0]=indices[2];
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// Degenerate triangles ////////////////////////////////////
+
+static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris)
+{
+ int iNextGoodTriangleSearchIndex=-1;
+ tbool bStillFindingGoodOnes;
+
+ // locate quads with only one good triangle
+ int t=0;
+ while (t<(iTotTris-1))
+ {
+ const int iFO_a = pTriInfos[t].iOrgFaceNumber;
+ const int iFO_b = pTriInfos[t+1].iOrgFaceNumber;
+ if (iFO_a==iFO_b) // this is a quad
+ {
+ const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE;
+ const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE;
+ if ((bIsDeg_a^bIsDeg_b)!=0)
+ {
+ pTriInfos[t].iFlag |= QUAD_ONE_DEGEN_TRI;
+ pTriInfos[t+1].iFlag |= QUAD_ONE_DEGEN_TRI;
+ }
+ t += 2;
+ }
+ else
+ ++t;
+ }
+
+ // reorder list so all degen triangles are moved to the back
+ // without reordering the good triangles
+ iNextGoodTriangleSearchIndex = 1;
+ t=0;
+ bStillFindingGoodOnes = TTRUE;
+ while (t<iNrTrianglesIn && bStillFindingGoodOnes)
+ {
+ const tbool bIsGood = (pTriInfos[t].iFlag&MARK_DEGENERATE)==0 ? TTRUE : TFALSE;
+ if (bIsGood)
+ {
+ if (iNextGoodTriangleSearchIndex < (t+2))
+ iNextGoodTriangleSearchIndex = t+2;
+ }
+ else
+ {
+ int t0, t1;
+ // search for the first good triangle.
+ tbool bJustADegenerate = TTRUE;
+ while (bJustADegenerate && iNextGoodTriangleSearchIndex<iTotTris)
+ {
+ const tbool bIsGood = (pTriInfos[iNextGoodTriangleSearchIndex].iFlag&MARK_DEGENERATE)==0 ? TTRUE : TFALSE;
+ if (bIsGood) bJustADegenerate=TFALSE;
+ else ++iNextGoodTriangleSearchIndex;
+ }
+
+ t0 = t;
+ t1 = iNextGoodTriangleSearchIndex;
+ ++iNextGoodTriangleSearchIndex;
+ assert(iNextGoodTriangleSearchIndex > (t+1));
+
+ // swap triangle t0 and t1
+ if (!bJustADegenerate)
+ {
+ int i=0;
+ for (i=0; i<3; i++)
+ {
+ const int index = piTriList_out[t0*3+i];
+ piTriList_out[t0*3+i] = piTriList_out[t1*3+i];
+ piTriList_out[t1*3+i] = index;
+ }
+ {
+ const STriInfo tri_info = pTriInfos[t0];
+ pTriInfos[t0] = pTriInfos[t1];
+ pTriInfos[t1] = tri_info;
+ }
+ }
+ else
+ bStillFindingGoodOnes = TFALSE; // this is not supposed to happen
+ }
+
+ if (bStillFindingGoodOnes) ++t;
+ }
+
+ assert(bStillFindingGoodOnes); // code will still work.
+ assert(iNrTrianglesIn == t);
+}
+
+static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris)
+{
+ int t=0, i=0;
+ // deal with degenerate triangles
+ // punishment for degenerate triangles is O(N^2)
+ for (t=iNrTrianglesIn; t<iTotTris; t++)
+ {
+ // degenerate triangles on a quad with one good triangle are skipped
+ // here but processed in the next loop
+ const tbool bSkip = (pTriInfos[t].iFlag&QUAD_ONE_DEGEN_TRI)!=0 ? TTRUE : TFALSE;
+
+ if (!bSkip)
+ {
+ for (i=0; i<3; i++)
+ {
+ const int index1 = piTriListIn[t*3+i];
+ // search through the good triangles
+ tbool bNotFound = TTRUE;
+ int j=0;
+ while (bNotFound && j<(3*iNrTrianglesIn))
+ {
+ const int index2 = piTriListIn[j];
+ if (index1==index2) bNotFound=TFALSE;
+ else ++j;
+ }
+
+ if (!bNotFound)
+ {
+ const int iTri = j/3;
+ const int iVert = j%3;
+ const int iSrcVert=pTriInfos[iTri].vert_num[iVert];
+ const int iSrcOffs=pTriInfos[iTri].iTSpacesOffs;
+ const int iDstVert=pTriInfos[t].vert_num[i];
+ const int iDstOffs=pTriInfos[t].iTSpacesOffs;
+
+ // copy tspace
+ psTspace[iDstOffs+iDstVert] = psTspace[iSrcOffs+iSrcVert];
+ }
+ }
+ }
+ }
+
+ // deal with degenerate quads with one good triangle
+ for (t=0; t<iNrTrianglesIn; t++)
+ {
+ // this triangle belongs to a quad where the
+ // other triangle is degenerate
+ if ( (pTriInfos[t].iFlag&QUAD_ONE_DEGEN_TRI)!=0 )
+ {
+ SVec3 vDstP;
+ int iOrgF=-1, i=0;
+ tbool bNotFound;
+ unsigned char * pV = pTriInfos[t].vert_num;
+ int iFlag = (1<<pV[0]) | (1<<pV[1]) | (1<<pV[2]);
+ int iMissingIndex = 0;
+ if ((iFlag&2)==0) iMissingIndex=1;
+ else if ((iFlag&4)==0) iMissingIndex=2;
+ else if ((iFlag&8)==0) iMissingIndex=3;
+
+ iOrgF = pTriInfos[t].iOrgFaceNumber;
+ vDstP = GetPosition(pContext, MakeIndex(iOrgF, iMissingIndex));
+ bNotFound = TTRUE;
+ i=0;
+ while (bNotFound && i<3)
+ {
+ const int iVert = pV[i];
+ const SVec3 vSrcP = GetPosition(pContext, MakeIndex(iOrgF, iVert));
+ if (veq(vSrcP, vDstP)==TTRUE)
+ {
+ const int iOffs = pTriInfos[t].iTSpacesOffs;
+ psTspace[iOffs+iMissingIndex] = psTspace[iOffs+iVert];
+ bNotFound=TFALSE;
+ }
+ else
+ ++i;
+ }
+ assert(!bNotFound);
+ }
+ }
+}
diff --git a/scene/resources/mikktspace.h b/scene/resources/mikktspace.h
new file mode 100644
index 0000000000..52c44a713c
--- /dev/null
+++ b/scene/resources/mikktspace.h
@@ -0,0 +1,145 @@
+/** \file mikktspace/mikktspace.h
+ * \ingroup mikktspace
+ */
+/**
+ * Copyright (C) 2011 by Morten S. Mikkelsen
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#ifndef __MIKKTSPACE_H__
+#define __MIKKTSPACE_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Author: Morten S. Mikkelsen
+ * Version: 1.0
+ *
+ * The files mikktspace.h and mikktspace.c are designed to be
+ * stand-alone files and it is important that they are kept this way.
+ * Not having dependencies on structures/classes/libraries specific
+ * to the program, in which they are used, allows them to be copied
+ * and used as is into any tool, program or plugin.
+ * The code is designed to consistently generate the same
+ * tangent spaces, for a given mesh, in any tool in which it is used.
+ * This is done by performing an internal welding step and subsequently an order-independent evaluation
+ * of tangent space for meshes consisting of triangles and quads.
+ * This means faces can be received in any order and the same is true for
+ * the order of vertices of each face. The generated result will not be affected
+ * by such reordering. Additionally, whether degenerate (vertices or texture coordinates)
+ * primitives are present or not will not affect the generated results either.
+ * Once tangent space calculation is done the vertices of degenerate primitives will simply
+ * inherit tangent space from neighboring non degenerate primitives.
+ * The analysis behind this implementation can be found in my master's thesis
+ * which is available for download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf
+ * Note that though the tangent spaces at the vertices are generated in an order-independent way,
+ * by this implementation, the interpolated tangent space is still affected by which diagonal is
+ * chosen to split each quad. A sensible solution is to have your tools pipeline always
+ * split quads by the shortest diagonal. This choice is order-independent and works with mirroring.
+ * If these have the same length then compare the diagonals defined by the texture coordinates.
+ * XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin
+ * and also quad triangulator plugin.
+ */
+
+
+typedef int tbool;
+typedef struct SMikkTSpaceContext SMikkTSpaceContext;
+
+typedef struct {
+ // Returns the number of faces (triangles/quads) on the mesh to be processed.
+ int (*m_getNumFaces)(const SMikkTSpaceContext * pContext);
+
+ // Returns the number of vertices on face number iFace
+ // iFace is a number in the range {0, 1, ..., getNumFaces()-1}
+ int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace);
+
+ // returns the position/normal/texcoord of the referenced face of vertex number iVert.
+ // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
+ void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert);
+ void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert);
+ void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert);
+
+ // either (or both) of the two setTSpace callbacks can be set.
+ // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
+
+ // This function is used to return the tangent and fSign to the application.
+ // fvTangent is a unit length vector.
+ // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
+ // bitangent = fSign * cross(vN, tangent);
+ // Note that the results are returned unindexed. It is possible to generate a new index list
+ // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
+ // DO NOT! use an already existing index list.
+ void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert);
+
+ // This function is used to return tangent space results to the application.
+ // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their
+ // true magnitudes which can be used for relief mapping effects.
+ // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent.
+ // However, both are perpendicular to the vertex normal.
+ // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
+ // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
+ // bitangent = fSign * cross(vN, tangent);
+ // Note that the results are returned unindexed. It is possible to generate a new index list
+ // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
+ // DO NOT! use an already existing index list.
+ void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
+ const tbool bIsOrientationPreserving, const int iFace, const int iVert);
+} SMikkTSpaceInterface;
+
+struct SMikkTSpaceContext
+{
+ SMikkTSpaceInterface * m_pInterface; // initialized with callback functions
+ void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call)
+};
+
+// these are both thread safe!
+tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled)
+tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold);
+
+
+// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the
+// normal map sampler must use the exact inverse of the pixel shader transformation.
+// The most efficient transformation we can possibly do in the pixel shader is
+// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN.
+// pixel shader (fast transform out)
+// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
+// where vNt is the tangent space normal. The normal map sampler must likewise use the
+// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader.
+// sampler does (exact inverse of pixel shader):
+// float3 row0 = cross(vB, vN);
+// float3 row1 = cross(vN, vT);
+// float3 row2 = cross(vT, vB);
+// float fSign = dot(vT, row0)<0 ? -1 : 1;
+// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) );
+// where vNout is the sampled normal in some chosen 3D space.
+//
+// Should you choose to reconstruct the bitangent in the pixel shader instead
+// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also.
+// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of
+// quads as your renderer then problems will occur since the interpolated tangent spaces will differ
+// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before
+// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier.
+// However, this must be used both by the sampler and your tools/rendering pipeline.
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 3bd7314778..5883686f20 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -29,6 +29,9 @@
#include "packed_scene.h"
#include "globals.h"
#include "io/resource_loader.h"
+#include "scene/3d/spatial.h"
+#include "scene/gui/control.h"
+#include "scene/2d/node_2d.h"
bool PackedScene::can_instance() const {
@@ -80,9 +83,28 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
} else {
//create anew
Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
- ERR_FAIL_COND_V(!obj,NULL);
+ if (!obj || !obj->cast_to<Node>()) {
+ if (obj) {
+ memdelete(obj);
+ obj=NULL;
+ }
+ WARN_PRINT(String("Warning node of type "+snames[n.type].operator String()+" does not exist.").ascii().get_data());
+ if (n.parent>=0 && n.parent<nc && ret_nodes[n.parent]) {
+ if (ret_nodes[n.parent]->cast_to<Spatial>()) {
+ obj = memnew( Spatial );
+ } else if (ret_nodes[n.parent]->cast_to<Control>()) {
+ obj = memnew( Control );
+ } else if (ret_nodes[n.parent]->cast_to<Node2D>()) {
+ obj = memnew( Node2D );
+ }
+
+ }
+ if (!obj) {
+ obj = memnew( Node );
+ }
+ }
+
node = obj->cast_to<Node>();
- ERR_FAIL_COND_V(!node,NULL);
}
@@ -225,22 +247,38 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<
p_node->get_property_list(&plist);
for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
+
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
continue;
+ }
String name = E->get().name;
Variant value = p_node->get( E->get().name );
- if (E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())
+ if (E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero()) {
continue;
+ }
if (nd.instance>=0) {
//only save changed properties in instance
- if (!instance_state.has(name))
+ /*
+ // this was commented because it would not save properties created from within script
+ // done with _get_property_list, that are not in the original node.
+ // if some property is not saved, check again
+
+ if (!instance_state.has(name)) {
+ print_line("skip not in instance");
+ continue;
+ }*/
+
+ if (E->get().usage & PROPERTY_USAGE_NO_INSTANCE_STATE) {
continue;
- if (instance_state[name]==value)
+ }
+
+ if (instance_state[name]==value) {
continue;
+ }
}
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index afb0ae1815..9f691d6ad3 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -142,6 +142,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector
if (d<closest_dist) {
ignore_from_edge=E->get();
closest_dist=d;
+ closest_point=closest;
}
}
@@ -168,6 +169,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector
if (d<closest_dist) {
ignore_to_edge=E->get();
closest_dist=d;
+ closest_point=closest;
}
}
@@ -529,7 +531,7 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2& p_point) const {
float d = p_point.distance_squared_to(points[i].pos);
if (d<closest_dist) {
- d=closest_dist;
+ closest_dist=d;
closest_idx=i;
}
diff --git a/scene/resources/scene_preloader.cpp b/scene/resources/scene_preloader.cpp
index 59d8cae970..e37a2c4967 100644
--- a/scene/resources/scene_preloader.cpp
+++ b/scene/resources/scene_preloader.cpp
@@ -26,430 +26,429 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "scene_preloader.h"
-#include "scene/io/scene_loader.h"
-#include "globals.h"
-
-bool ScenePreloader::can_instance() const {
-
- return nodes.size()>0;
-}
-
-Node *ScenePreloader::instance() const {
-
- int nc = nodes.size();
- ERR_FAIL_COND_V(nc==0,NULL);
-
- const StringName*snames=NULL;
- int sname_count=names.size();
- if (sname_count)
- snames=&names[0];
-
- const Variant*props=NULL;
- int prop_count=variants.size();
- if (prop_count)
- props=&variants[0];
-
- Vector<Variant> properties;
-
- const NodeData *nd = &nodes[0];
-
- Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc );
-
- for(int i=0;i<nc;i++) {
-
- const NodeData &n=nd[i];
-
-
- if (!ObjectTypeDB::is_type_enabled(snames[n.type])) {
- ret_nodes[i]=NULL;
- continue;
- }
-
- Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
- ERR_FAIL_COND_V(!obj,NULL);
- Node *node = obj->cast_to<Node>();
- ERR_FAIL_COND_V(!node,NULL);
-
- int nprop_count=n.properties.size();
- if (nprop_count) {
-
- const NodeData::Property* nprops=&n.properties[0];
-
- for(int j=0;j<nprop_count;j++) {
-
- bool valid;
- node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
- }
-
-
- }
-
- node->set_name( snames[ n.name ] );
- ret_nodes[i]=node;
- if (i>0) {
- ERR_FAIL_INDEX_V(n.parent,i,NULL);
- ERR_FAIL_COND_V(!ret_nodes[n.parent],NULL);
- ret_nodes[n.parent]->add_child(node);
- }
- }
-
-
- //do connections
-
- int cc = connections.size();
- const ConnectionData *cdata = connections.ptr();
-
- for(int i=0;i<cc;i++) {
-
- const ConnectionData &c=cdata[i];
- ERR_FAIL_INDEX_V( c.from, nc, NULL );
- ERR_FAIL_INDEX_V( c.to, nc, NULL );
-
- Vector<Variant> binds;
- if (c.binds.size()) {
- binds.resize(c.binds.size());
- for(int j=0;j<c.binds.size();j++)
- binds[j]=props[ c.binds[j] ];
- }
-
- if (!ret_nodes[c.from] || !ret_nodes[c.to])
- continue;
- ret_nodes[c.from]->connect( snames[ c.signal], ret_nodes[ c.to ], snames[ c.method], binds,CONNECT_PERSIST );
- }
-
- return ret_nodes[0];
-
-}
-
-
-static int _nm_get_string(const String& p_string, Map<StringName,int> &name_map) {
-
- if (name_map.has(p_string))
- return name_map[p_string];
-
- int idx = name_map.size();
- name_map[p_string]=idx;
- return idx;
-}
-
-static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,VariantHasher> &variant_map) {
-
- if (variant_map.has(p_variant))
- return variant_map[p_variant];
-
- int idx = variant_map.size();
- variant_map[p_variant]=idx;
- return idx;
-}
-
-void ScenePreloader::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) {
-
- if (p_node!=p_owner && !p_node->get_owner())
- return;
-
- NodeData nd;
- nd.name=_nm_get_string(p_node->get_name(),name_map);
- nd.type=_nm_get_string(p_node->get_type(),name_map);
- nd.parent=p_parent_idx;
-
- List<PropertyInfo> plist;
- p_node->get_property_list(&plist);
- for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
-
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
- continue;
-
- NodeData::Property prop;
- prop.name=_nm_get_string(E->get().name,name_map);
- prop.value=_vm_get_variant( p_node->get( E->get().name ), variant_map);
- nd.properties.push_back(prop);
- }
-
- int idx = nodes.size();
- node_map[p_node]=idx;
- nodes.push_back(nd);
-
- for(int i=0;i<p_node->get_child_count();i++) {
-
- Node *c=p_node->get_child(i);
- _parse_node(p_owner,c,idx,name_map,variant_map,node_map);
- }
-
-
-
-}
-
-void ScenePreloader::_parse_connections(Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,bool p_instance) {
-
-
- List<MethodInfo> signals;
- p_node->get_signal_list(&signals);
-
- for(List<MethodInfo>::Element *E=signals.front();E;E=E->next()) {
-
- List<Node::Connection> conns;
- p_node->get_signal_connection_list(E->get().name,&conns);
- for(List<Node::Connection>::Element *F=conns.front();F;F=F->next()) {
-
- const Node::Connection &c = F->get();
- if (!(c.flags&CONNECT_PERSIST))
- continue;
- Node *n=c.target->cast_to<Node>();
- if (!n)
- continue;
-
- if (!node_map.has(n))
- continue;
-
- ConnectionData cd;
- cd.from=node_map[p_node];
- cd.to=node_map[n];
- cd.method=_nm_get_string(c.method,name_map);
- cd.signal=_nm_get_string(c.signal,name_map);
- for(int i=0;i<c.binds.size();i++) {
-
- cd.binds.push_back( _vm_get_variant(c.binds[i],variant_map));
- }
- connections.push_back(cd);
- }
- }
-
-}
-
-
-Error ScenePreloader::load_scene(const String& p_path) {
-
- return ERR_CANT_OPEN;
-#if 0
- if (path==p_path)
- return OK;
-
- String p=Globals::get_singleton()->localize_path(p_path);
- clear();
-
- Node *scene = SceneLoader::load(p);
-
- ERR_FAIL_COND_V(!scene,ERR_CANT_OPEN);
-
- path=p;
-
- Map<StringName,int> name_map;
- HashMap<Variant,int,VariantHasher> variant_map;
- Map<Node*,int> node_map;
-
- _parse_node(scene,scene,-1,name_map,variant_map,node_map);
-
-
- names.resize(name_map.size());
-
- for(Map<StringName,int>::Element *E=name_map.front();E;E=E->next()) {
-
- names[E->get()]=E->key();
- }
-
- variants.resize(variant_map.size());
- const Variant *K=NULL;
- while((K=variant_map.next(K))) {
-
- int idx = variant_map[*K];
- variants[idx]=*K;
- }
-
-
- memdelete(scene); // <- me falto esto :(
- return OK;
-#endif
-}
-
-String ScenePreloader::get_scene_path() const {
-
- return path;
-}
-
-void ScenePreloader::clear() {
-
- names.clear();
- variants.clear();
- nodes.clear();
- connections.clear();
-
-}
-
-void ScenePreloader::_set_bundled_scene(const Dictionary& d) {
-
-
- ERR_FAIL_COND( !d.has("names"));
- ERR_FAIL_COND( !d.has("variants"));
- ERR_FAIL_COND( !d.has("node_count"));
- ERR_FAIL_COND( !d.has("nodes"));
- ERR_FAIL_COND( !d.has("conn_count"));
- ERR_FAIL_COND( !d.has("conns"));
- ERR_FAIL_COND( !d.has("path"));
-
- DVector<String> snames = d["names"];
- if (snames.size()) {
-
- int namecount = snames.size();
- names.resize(namecount);
- DVector<String>::Read r =snames.read();
- for(int i=0;i<names.size();i++)
- names[i]=r[i];
- }
-
- Array svariants = d["variants"];
-
- if (svariants.size()) {
- int varcount=svariants.size();
- variants.resize(varcount);
- for(int i=0;i<varcount;i++) {
-
- variants[i]=svariants[i];
- }
-
- } else {
- variants.clear();
- }
-
- nodes.resize(d["node_count"]);
- int nc=nodes.size();
- if (nc) {
- DVector<int> snodes = d["nodes"];
- DVector<int>::Read r = snodes.read();
- int idx=0;
- for(int i=0;i<nc;i++) {
- NodeData &nd = nodes[i];
- nd.parent=r[idx++];
- nd.type=r[idx++];
- nd.name=r[idx++];
- nd.properties.resize(r[idx++]);
- for(int j=0;j<nd.properties.size();j++) {
-
- nd.properties[j].name=r[idx++];
- nd.properties[j].value=r[idx++];
- }
- }
-
- }
-
- connections.resize(d["conn_count"]);
- int cc=connections.size();
-
- if (cc) {
-
- DVector<int> sconns = d["conns"];
- DVector<int>::Read r = sconns.read();
- int idx=0;
- for(int i=0;i<nc;i++) {
- ConnectionData &cd = connections[nc];
- cd.from=r[idx++];
- cd.to=r[idx++];
- cd.signal=r[idx++];
- cd.method=r[idx++];
- cd.binds.resize(r[idx++]);
- for(int j=0;j<cd.binds.size();j++) {
-
- cd.binds[j]=r[idx++];
- }
- }
-
- }
-
-
-
- path=d["path"];
-
-}
-
-Dictionary ScenePreloader::_get_bundled_scene() const {
-
- DVector<String> rnames;
- rnames.resize(names.size());
-
- if (names.size()) {
-
- DVector<String>::Write r=rnames.write();
-
- for(int i=0;i<names.size();i++)
- r[i]=names[i];
- }
-
- Dictionary d;
- d["names"]=rnames;
- d["variants"]=variants;
-
- Vector<int> rnodes;
- d["node_count"]=nodes.size();
-
- for(int i=0;i<nodes.size();i++) {
-
- const NodeData &nd=nodes[i];
- rnodes.push_back(nd.parent);
- rnodes.push_back(nd.type);
- rnodes.push_back(nd.name);
- rnodes.push_back(nd.properties.size());
- for(int j=0;j<nd.properties.size();j++) {
-
- rnodes.push_back(nd.properties[j].name);
- rnodes.push_back(nd.properties[j].value);
- }
- }
-
- d["nodes"]=rnodes;
-
- Vector<int> rconns;
- d["conn_count"]=connections.size();
-
- for(int i=0;i<connections.size();i++) {
-
- const ConnectionData &cd=connections[i];
- rconns.push_back(cd.from);
- rconns.push_back(cd.to);
- rconns.push_back(cd.signal);
- rconns.push_back(cd.method);
- rconns.push_back(cd.binds.size());
- for(int j=0;j<cd.binds.size();i++)
- rconns.push_back(cd.binds[j]);
-
- }
-
- d["conns"]=rconns;
-
- d["path"]=path;
-
- return d;
-
-
-}
-
-void ScenePreloader::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("load_scene","path"),&ScenePreloader::load_scene);
- ObjectTypeDB::bind_method(_MD("get_scene_path"),&ScenePreloader::get_scene_path);
- ObjectTypeDB::bind_method(_MD("instance:Node"),&ScenePreloader::instance);
- ObjectTypeDB::bind_method(_MD("can_instance"),&ScenePreloader::can_instance);
- ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&ScenePreloader::_set_bundled_scene);
- ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&ScenePreloader::_get_bundled_scene);
-
- ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_BUNDLE),_SCS("_set_bundled_scene"),_SCS("_get_bundled_scene"));
-#if 0
- List<String> extensions;
- SceneLoader::get_recognized_extensions(&extensions);
- String exthint;
- for (List<String>::Element*E=extensions.front();E;E=E->next()) {
-
- if (exthint!="")
- exthint+=",";
- exthint+="*."+E->get();
- }
-
- exthint+="; Scenes";
-
- ADD_PROPERTY( PropertyInfo(Variant::STRING,"scene",PROPERTY_HINT_FILE,exthint),_SCS("load_scene"),_SCS("get_scene_path"));
-#endif
-}
-
-ScenePreloader::ScenePreloader() {
-
-
-}
+#include "scene_preloader.h"
+#include "globals.h"
+
+bool ScenePreloader::can_instance() const {
+
+ return nodes.size()>0;
+}
+
+Node *ScenePreloader::instance() const {
+
+ int nc = nodes.size();
+ ERR_FAIL_COND_V(nc==0,NULL);
+
+ const StringName*snames=NULL;
+ int sname_count=names.size();
+ if (sname_count)
+ snames=&names[0];
+
+ const Variant*props=NULL;
+ int prop_count=variants.size();
+ if (prop_count)
+ props=&variants[0];
+
+ Vector<Variant> properties;
+
+ const NodeData *nd = &nodes[0];
+
+ Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc );
+
+ for(int i=0;i<nc;i++) {
+
+ const NodeData &n=nd[i];
+
+
+ if (!ObjectTypeDB::is_type_enabled(snames[n.type])) {
+ ret_nodes[i]=NULL;
+ continue;
+ }
+
+ Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
+ ERR_FAIL_COND_V(!obj,NULL);
+ Node *node = obj->cast_to<Node>();
+ ERR_FAIL_COND_V(!node,NULL);
+
+ int nprop_count=n.properties.size();
+ if (nprop_count) {
+
+ const NodeData::Property* nprops=&n.properties[0];
+
+ for(int j=0;j<nprop_count;j++) {
+
+ bool valid;
+ node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
+ }
+
+
+ }
+
+ node->set_name( snames[ n.name ] );
+ ret_nodes[i]=node;
+ if (i>0) {
+ ERR_FAIL_INDEX_V(n.parent,i,NULL);
+ ERR_FAIL_COND_V(!ret_nodes[n.parent],NULL);
+ ret_nodes[n.parent]->add_child(node);
+ }
+ }
+
+
+ //do connections
+
+ int cc = connections.size();
+ const ConnectionData *cdata = connections.ptr();
+
+ for(int i=0;i<cc;i++) {
+
+ const ConnectionData &c=cdata[i];
+ ERR_FAIL_INDEX_V( c.from, nc, NULL );
+ ERR_FAIL_INDEX_V( c.to, nc, NULL );
+
+ Vector<Variant> binds;
+ if (c.binds.size()) {
+ binds.resize(c.binds.size());
+ for(int j=0;j<c.binds.size();j++)
+ binds[j]=props[ c.binds[j] ];
+ }
+
+ if (!ret_nodes[c.from] || !ret_nodes[c.to])
+ continue;
+ ret_nodes[c.from]->connect( snames[ c.signal], ret_nodes[ c.to ], snames[ c.method], binds,CONNECT_PERSIST );
+ }
+
+ return ret_nodes[0];
+
+}
+
+
+static int _nm_get_string(const String& p_string, Map<StringName,int> &name_map) {
+
+ if (name_map.has(p_string))
+ return name_map[p_string];
+
+ int idx = name_map.size();
+ name_map[p_string]=idx;
+ return idx;
+}
+
+static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,VariantHasher> &variant_map) {
+
+ if (variant_map.has(p_variant))
+ return variant_map[p_variant];
+
+ int idx = variant_map.size();
+ variant_map[p_variant]=idx;
+ return idx;
+}
+
+void ScenePreloader::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) {
+
+ if (p_node!=p_owner && !p_node->get_owner())
+ return;
+
+ NodeData nd;
+ nd.name=_nm_get_string(p_node->get_name(),name_map);
+ nd.type=_nm_get_string(p_node->get_type(),name_map);
+ nd.parent=p_parent_idx;
+
+ List<PropertyInfo> plist;
+ p_node->get_property_list(&plist);
+ for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
+
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
+ continue;
+
+ NodeData::Property prop;
+ prop.name=_nm_get_string(E->get().name,name_map);
+ prop.value=_vm_get_variant( p_node->get( E->get().name ), variant_map);
+ nd.properties.push_back(prop);
+ }
+
+ int idx = nodes.size();
+ node_map[p_node]=idx;
+ nodes.push_back(nd);
+
+ for(int i=0;i<p_node->get_child_count();i++) {
+
+ Node *c=p_node->get_child(i);
+ _parse_node(p_owner,c,idx,name_map,variant_map,node_map);
+ }
+
+
+
+}
+
+void ScenePreloader::_parse_connections(Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,bool p_instance) {
+
+
+ List<MethodInfo> signals;
+ p_node->get_signal_list(&signals);
+
+ for(List<MethodInfo>::Element *E=signals.front();E;E=E->next()) {
+
+ List<Node::Connection> conns;
+ p_node->get_signal_connection_list(E->get().name,&conns);
+ for(List<Node::Connection>::Element *F=conns.front();F;F=F->next()) {
+
+ const Node::Connection &c = F->get();
+ if (!(c.flags&CONNECT_PERSIST))
+ continue;
+ Node *n=c.target->cast_to<Node>();
+ if (!n)
+ continue;
+
+ if (!node_map.has(n))
+ continue;
+
+ ConnectionData cd;
+ cd.from=node_map[p_node];
+ cd.to=node_map[n];
+ cd.method=_nm_get_string(c.method,name_map);
+ cd.signal=_nm_get_string(c.signal,name_map);
+ for(int i=0;i<c.binds.size();i++) {
+
+ cd.binds.push_back( _vm_get_variant(c.binds[i],variant_map));
+ }
+ connections.push_back(cd);
+ }
+ }
+
+}
+
+
+Error ScenePreloader::load_scene(const String& p_path) {
+
+ return ERR_CANT_OPEN;
+#if 0
+ if (path==p_path)
+ return OK;
+
+ String p=Globals::get_singleton()->localize_path(p_path);
+ clear();
+
+ Node *scene = SceneLoader::load(p);
+
+ ERR_FAIL_COND_V(!scene,ERR_CANT_OPEN);
+
+ path=p;
+
+ Map<StringName,int> name_map;
+ HashMap<Variant,int,VariantHasher> variant_map;
+ Map<Node*,int> node_map;
+
+ _parse_node(scene,scene,-1,name_map,variant_map,node_map);
+
+
+ names.resize(name_map.size());
+
+ for(Map<StringName,int>::Element *E=name_map.front();E;E=E->next()) {
+
+ names[E->get()]=E->key();
+ }
+
+ variants.resize(variant_map.size());
+ const Variant *K=NULL;
+ while((K=variant_map.next(K))) {
+
+ int idx = variant_map[*K];
+ variants[idx]=*K;
+ }
+
+
+ memdelete(scene); // <- me falto esto :(
+ return OK;
+#endif
+}
+
+String ScenePreloader::get_scene_path() const {
+
+ return path;
+}
+
+void ScenePreloader::clear() {
+
+ names.clear();
+ variants.clear();
+ nodes.clear();
+ connections.clear();
+
+}
+
+void ScenePreloader::_set_bundled_scene(const Dictionary& d) {
+
+
+ ERR_FAIL_COND( !d.has("names"));
+ ERR_FAIL_COND( !d.has("variants"));
+ ERR_FAIL_COND( !d.has("node_count"));
+ ERR_FAIL_COND( !d.has("nodes"));
+ ERR_FAIL_COND( !d.has("conn_count"));
+ ERR_FAIL_COND( !d.has("conns"));
+ ERR_FAIL_COND( !d.has("path"));
+
+ DVector<String> snames = d["names"];
+ if (snames.size()) {
+
+ int namecount = snames.size();
+ names.resize(namecount);
+ DVector<String>::Read r =snames.read();
+ for(int i=0;i<names.size();i++)
+ names[i]=r[i];
+ }
+
+ Array svariants = d["variants"];
+
+ if (svariants.size()) {
+ int varcount=svariants.size();
+ variants.resize(varcount);
+ for(int i=0;i<varcount;i++) {
+
+ variants[i]=svariants[i];
+ }
+
+ } else {
+ variants.clear();
+ }
+
+ nodes.resize(d["node_count"]);
+ int nc=nodes.size();
+ if (nc) {
+ DVector<int> snodes = d["nodes"];
+ DVector<int>::Read r = snodes.read();
+ int idx=0;
+ for(int i=0;i<nc;i++) {
+ NodeData &nd = nodes[i];
+ nd.parent=r[idx++];
+ nd.type=r[idx++];
+ nd.name=r[idx++];
+ nd.properties.resize(r[idx++]);
+ for(int j=0;j<nd.properties.size();j++) {
+
+ nd.properties[j].name=r[idx++];
+ nd.properties[j].value=r[idx++];
+ }
+ }
+
+ }
+
+ connections.resize(d["conn_count"]);
+ int cc=connections.size();
+
+ if (cc) {
+
+ DVector<int> sconns = d["conns"];
+ DVector<int>::Read r = sconns.read();
+ int idx=0;
+ for(int i=0;i<nc;i++) {
+ ConnectionData &cd = connections[nc];
+ cd.from=r[idx++];
+ cd.to=r[idx++];
+ cd.signal=r[idx++];
+ cd.method=r[idx++];
+ cd.binds.resize(r[idx++]);
+ for(int j=0;j<cd.binds.size();j++) {
+
+ cd.binds[j]=r[idx++];
+ }
+ }
+
+ }
+
+
+
+ path=d["path"];
+
+}
+
+Dictionary ScenePreloader::_get_bundled_scene() const {
+
+ DVector<String> rnames;
+ rnames.resize(names.size());
+
+ if (names.size()) {
+
+ DVector<String>::Write r=rnames.write();
+
+ for(int i=0;i<names.size();i++)
+ r[i]=names[i];
+ }
+
+ Dictionary d;
+ d["names"]=rnames;
+ d["variants"]=variants;
+
+ Vector<int> rnodes;
+ d["node_count"]=nodes.size();
+
+ for(int i=0;i<nodes.size();i++) {
+
+ const NodeData &nd=nodes[i];
+ rnodes.push_back(nd.parent);
+ rnodes.push_back(nd.type);
+ rnodes.push_back(nd.name);
+ rnodes.push_back(nd.properties.size());
+ for(int j=0;j<nd.properties.size();j++) {
+
+ rnodes.push_back(nd.properties[j].name);
+ rnodes.push_back(nd.properties[j].value);
+ }
+ }
+
+ d["nodes"]=rnodes;
+
+ Vector<int> rconns;
+ d["conn_count"]=connections.size();
+
+ for(int i=0;i<connections.size();i++) {
+
+ const ConnectionData &cd=connections[i];
+ rconns.push_back(cd.from);
+ rconns.push_back(cd.to);
+ rconns.push_back(cd.signal);
+ rconns.push_back(cd.method);
+ rconns.push_back(cd.binds.size());
+ for(int j=0;j<cd.binds.size();i++)
+ rconns.push_back(cd.binds[j]);
+
+ }
+
+ d["conns"]=rconns;
+
+ d["path"]=path;
+
+ return d;
+
+
+}
+
+void ScenePreloader::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("load_scene","path"),&ScenePreloader::load_scene);
+ ObjectTypeDB::bind_method(_MD("get_scene_path"),&ScenePreloader::get_scene_path);
+ ObjectTypeDB::bind_method(_MD("instance:Node"),&ScenePreloader::instance);
+ ObjectTypeDB::bind_method(_MD("can_instance"),&ScenePreloader::can_instance);
+ ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&ScenePreloader::_set_bundled_scene);
+ ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&ScenePreloader::_get_bundled_scene);
+
+ ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_BUNDLE),_SCS("_set_bundled_scene"),_SCS("_get_bundled_scene"));
+#if 0
+ List<String> extensions;
+ SceneLoader::get_recognized_extensions(&extensions);
+ String exthint;
+ for (List<String>::Element*E=extensions.front();E;E=E->next()) {
+
+ if (exthint!="")
+ exthint+=",";
+ exthint+="*."+E->get();
+ }
+
+ exthint+="; Scenes";
+
+ ADD_PROPERTY( PropertyInfo(Variant::STRING,"scene",PROPERTY_HINT_FILE,exthint),_SCS("load_scene"),_SCS("get_scene_path"));
+#endif
+}
+
+ScenePreloader::ScenePreloader() {
+
+
+}
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 6d65da3782..42251124bd 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -33,12 +33,6 @@
#include "scene/scene_string_names.h"
-void Shader::set_mode(Mode p_mode) {
-
- ERR_FAIL_INDEX(p_mode,2);
- VisualServer::get_singleton()->shader_set_mode(shader,VisualServer::ShaderMode(p_mode));
- emit_signal(SceneStringNames::get_singleton()->changed);
-}
Shader::Mode Shader::get_mode() const {
@@ -90,7 +84,7 @@ 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();
- pi.name="param/"+pi.name;
+ pi.name="shader_param/"+pi.name;
params_cache[pi.name]=E->get().name;
if (p_params) {
@@ -120,6 +114,13 @@ Dictionary Shader::_get_code() {
c["vertex_ofs"]=0;
c["light"]=ls;
c["light_ofs"]=0;
+ Array arr;
+ for(const Map<StringName,Ref<Texture> >::Element *E=default_textures.front();E;E=E->next()) {
+ arr.push_back(E->key());
+ arr.push_back(E->get());
+ }
+ if (arr.size())
+ c["default_tex"]=arr;
return c;
}
@@ -132,11 +133,46 @@ void Shader::_set_code(const Dictionary& p_string) {
light=p_string["light"];
set_code(p_string["vertex"],p_string["fragment"],light);
+ if (p_string.has("default_tex")) {
+ Array arr=p_string["default_tex"];
+ if ((arr.size()&1)==0) {
+ for(int i=0;i<arr.size();i+=2)
+ set_default_texture_param(arr[i],arr[i+1]);
+ }
+ }
}
+void Shader::set_default_texture_param(const StringName& p_param,const Ref<Texture>& p_texture) {
+
+ if (p_texture.is_valid()) {
+ default_textures[p_param]=p_texture;
+ VS::get_singleton()->shader_set_default_texture_param(shader,p_param,p_texture->get_rid());
+ } else {
+ default_textures.erase(p_param);
+ VS::get_singleton()->shader_set_default_texture_param(shader,p_param,RID());
+ }
+}
+
+Ref<Texture> Shader::get_default_texture_param(const StringName& p_param) const{
+
+ if (default_textures.has(p_param))
+ return default_textures[p_param];
+ else
+ return Ref<Texture>();
+}
+
+void Shader::get_default_texture_param_list(List<StringName>* r_textures) const{
+
+ for(const Map<StringName,Ref<Texture> >::Element *E=default_textures.front();E;E=E->next()) {
+
+ r_textures->push_back(E->key());
+ }
+
+}
+
+
void Shader::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("set_mode","mode"),&Shader::set_mode);
ObjectTypeDB::bind_method(_MD("get_mode"),&Shader::get_mode);
ObjectTypeDB::bind_method(_MD("set_code","vcode","fcode","lcode","fofs","lofs"),&Shader::set_code,DEFVAL(0),DEFVAL(0));
@@ -144,6 +180,9 @@ void Shader::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_fragment_code"),&Shader::get_fragment_code);
ObjectTypeDB::bind_method(_MD("get_light_code"),&Shader::get_light_code);
+ ObjectTypeDB::bind_method(_MD("set_default_texture_param","param","texture:Texture"),&Shader::set_default_texture_param);
+ ObjectTypeDB::bind_method(_MD("get_default_texture_param:Texture","param"),&Shader::get_default_texture_param);
+
ObjectTypeDB::bind_method(_MD("has_param","name"),&Shader::has_param);
ObjectTypeDB::bind_method(_MD("_set_code","code"),&Shader::_set_code);
@@ -160,9 +199,9 @@ void Shader::_bind_methods() {
}
-Shader::Shader() {
+Shader::Shader(Mode p_mode) {
- shader = VisualServer::get_singleton()->shader_create();
+ shader = VisualServer::get_singleton()->shader_create(VS::ShaderMode(p_mode));
params_cache_dirty=true;
}
@@ -194,7 +233,7 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin
String base_path = p_path.get_base_dir();
- Ref<Shader> shader( memnew( Shader ) );
+ Ref<Shader> shader;//( memnew( Shader ) );
int line=0;
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index fff6f1d28a..4a380d455b 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -31,7 +31,7 @@
#include "resource.h"
#include "io/resource_loader.h"
-
+#include "scene/resources/texture.h"
class Shader : public Resource {
OBJ_TYPE(Shader,Resource);
@@ -48,6 +48,9 @@ class Shader : public Resource {
// convertion fast and save memory.
mutable bool params_cache_dirty;
mutable Map<StringName,StringName> params_cache; //map a shader param to a material param..
+ Map<StringName,Ref<Texture> > default_textures;
+
+
protected:
@@ -58,10 +61,11 @@ public:
MODE_MATERIAL,
MODE_CANVAS_ITEM,
- MODE_POST_PROCESS
+ MODE_POST_PROCESS,
+ MODE_MAX
};
- void set_mode(Mode p_mode);
+ //void set_mode(Mode p_mode);
Mode get_mode() const;
void set_code( const String& p_vertex, const String& p_fragment, const String& p_light,int p_fragment_ofs=0,int p_light_ofs=0);
@@ -72,15 +76,47 @@ public:
void get_param_list(List<PropertyInfo> *p_params) const;
bool has_param(const StringName& p_param) const;
+ void set_default_texture_param(const StringName& p_param, const Ref<Texture> &p_texture);
+ Ref<Texture> get_default_texture_param(const StringName& p_param) const;
+ void get_default_texture_param_list(List<StringName>* r_textures) const;
+
+ _FORCE_INLINE_ StringName remap_param(const StringName& p_param) const {
+ if (params_cache_dirty)
+ get_param_list(NULL);
+
+ const Map<StringName,StringName>::Element *E=params_cache.find(p_param);
+ if (E)
+ return E->get();
+ return StringName();
+ }
+
virtual RID get_rid() const;
- Shader();
+ Shader(Mode p_mode);
~Shader();
};
VARIANT_ENUM_CAST( Shader::Mode );
+class MaterialShader : public Shader {
+
+ OBJ_TYPE(MaterialShader,Shader);
+
+public:
+
+ MaterialShader() : Shader(MODE_MATERIAL) {};
+};
+
+class CanvasItemShader : public Shader {
+
+ OBJ_TYPE(CanvasItemShader,Shader);
+
+public:
+
+ CanvasItemShader() : Shader(MODE_CANVAS_ITEM) {};
+};
+
class ResourceFormatLoaderShader : public ResourceFormatLoader {
diff --git a/scene/resources/shader_graph.cpp b/scene/resources/shader_graph.cpp
index df5fee81a8..9703799a48 100644
--- a/scene/resources/shader_graph.cpp
+++ b/scene/resources/shader_graph.cpp
@@ -27,129 +27,351 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "shader_graph.h"
+#include "scene/scene_string_names.h"
+Array ShaderGraph::_get_node_list(ShaderType p_type) const {
+ List<int> nodes;
+ get_node_list(p_type,&nodes);
+ Array arr(true);
+ for (List<int>::Element *E=nodes.front();E;E=E->next())
+ arr.push_back(E->get());
+ return arr;
+}
+Array ShaderGraph::_get_connections(ShaderType p_type) const {
+
+ List<Connection> connections;
+ get_node_connections(p_type,&connections);
+ Array arr(true);
+ for (List<Connection>::Element *E=connections.front();E;E=E->next()) {
+
+ Dictionary d(true);
+ d["src_id"]=E->get().src_id;
+ d["src_slot"]=E->get().src_slot;
+ d["dst_id"]=E->get().dst_id;
+ d["dst_slot"]=E->get().dst_slot;
+ arr.push_back(d);
-# if 0
-void ShaderGraph::_set(const String& p_name, const Variant& p_value) {
+ }
+ return arr;
+}
- if (p_name.begins_with("nodes/")) {
- int idx=p_name.get_slice("/",1).to_int();
- Dictionary data=p_value;
+void ShaderGraph::_set_data(const Dictionary &p_data) {
- ERR_FAIL_COND(!data.has("type"));
- String type=data["type"];
+ Dictionary d=p_data;
+ ERR_FAIL_COND(!d.has("shaders"));
+ Array sh=d["shaders"];
+ ERR_FAIL_COND(sh.size()!=3);
- VS::NodeType node_type=VS::NODE_TYPE_MAX;
- for(int i=0;i<NODE_TYPE_MAX;i++) {
+ for(int t=0;t<3;t++) {
+ Array data=sh[t];
+ ERR_FAIL_COND((data.size()%6)!=0);
+ shader[t].node_map.clear();
+ for(int i=0;i<data.size();i+=6) {
- if (type==VisualServer::shader_node_get_type_info((VS::NodeType)i).name)
- node_type=(VS::NodeType)i;
- }
+ Node n;
+ n.id=data[i+0];
+ n.type=NodeType(int(data[i+1]));
+ n.pos=data[i+2];
+ n.param1=data[i+3];
+ n.param2=data[i+4];
- ERR_FAIL_COND(node_type==VS::NODE_TYPE_MAX);
+ Array conns=data[i+5];
+ ERR_FAIL_COND((conns.size()%3)!=0);
- node_add( (NodeType)node_type, idx );
- if (data.has("param"))
- node_set_param(idx,data["param"]);
- if (data.has("pos"))
- node_set_pos(idx,data["pos"]);
- }
+ for(int j=0;j<conns.size();j+=3) {
- if (p_name.begins_with("conns/")) {
- Dictionary data=p_value;
- ERR_FAIL_COND( !data.has("src_id") );
- ERR_FAIL_COND( !data.has("src_slot") );
- ERR_FAIL_COND( !data.has("dst_id") );
- ERR_FAIL_COND( !data.has("dst_slot") );
+ SourceSlot ss;
+ int ls=conns[j+0];
+ ss.id=conns[j+1];
+ ss.slot=conns[j+2];
+ n.connections[ls]=ss;
+ }
+ shader[t].node_map[n.id]=n;
- connect(data["src_id"],data["src_slot"],data["dst_id"],data["dst_slot"]);
+ }
}
- return false;
+ _update_shader();
+
}
-Variant ShaderGraph::_get(const String& p_name) const {
- if (p_name.begins_with("nodes/")) {
- int idx=p_name.get_slice("/",1).to_int();
- Dictionary data;
- data["type"]=VisualServer::shader_node_get_type_info((VS::NodeType)node_get_type(idx)).name;
- data["pos"]=node_get_pos(idx);
- data["param"]=node_get_param(idx);
- return data;
- }
- if (p_name.begins_with("conns/")) {
- int idx=p_name.get_slice("/",1).to_int();
- Dictionary data;
-
- List<Connection> connections;
- get_connections(&connections);
- ERR_FAIL_INDEX_V( idx,connections.size(), Variant() );
- Connection c = connections[idx];
-
- data["src_id"]=c.src_id;
- data["src_slot"]=c.src_slot;
- data["dst_id"]=c.dst_id;
- data["dst_slot"]=c.dst_slot;
- return data;
+Dictionary ShaderGraph::_get_data() const {
+
+ Array sh;
+ for(int i=0;i<3;i++) {
+ Array data;
+ int ec = shader[i].node_map.size();
+ data.resize(ec*6);
+ int idx=0;
+ for (Map<int,Node>::Element*E=shader[i].node_map.front();E;E=E->next()) {
+
+ data[idx+0]=E->key();
+ data[idx+1]=E->get().type;
+ data[idx+2]=E->get().pos;
+ data[idx+3]=E->get().param1;
+ data[idx+4]=E->get().param2;
+
+ Array conns;
+ conns.resize(E->get().connections.size()*3);
+ int idx2=0;
+ for(Map<int,SourceSlot>::Element*F=E->get().connections.front();F;F=F->next()) {
+
+ conns[idx2+0]=F->key();
+ conns[idx2+1]=F->get().id;
+ conns[idx2+2]=F->get().slot;
+ idx2+=3;
+ }
+ data[idx+5]=conns;
+ idx+=6;
+ }
+ sh.push_back(data);
}
- return Variant();
+ Dictionary data;
+ data["shaders"]=sh;
+ return data;
}
-void ShaderGraph::_get_property_list( List<PropertyInfo> *p_list) const {
- List<int> nodes;
- get_node_list(&nodes);
- for(List<int>::Element *E=nodes.front();E;E=E->next()) {
- int idx=E->get();
- p_list->push_back(PropertyInfo( Variant::DICTIONARY , "nodes/"+itos(idx),PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_STORAGE ) );
- }
-
- List<Connection> connections;
- get_connections(&connections);
- int idx=0;
- for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
- p_list->push_back(PropertyInfo( Variant::DICTIONARY , "conns/"+itos(idx++),PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_STORAGE ) );
- }
+ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const {
+ ERR_FAIL_INDEX_V(p_type,3,GRAPH_OK);
+ return shader[p_type].error;
}
-#endif
-#if 0
-Array ShaderGraph::_get_connections_helper() const {
+void ShaderGraph::_bind_methods() {
- Array connections_ret;
- List<Connection> connections;
- get_connections(&connections);
- connections_ret.resize(connections.size());
-
- int idx=0;
- for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
-
- Connection c = E->get();
- Dictionary data;
- data["src_id"]=c.src_id;
- data["src_slot"]=c.src_slot;
- data["dst_id"]=c.dst_id;
- data["dst_slot"]=c.dst_slot;
- connections_ret.set(idx++,data);
- }
+ ObjectTypeDB::bind_method(_MD("_update_shader"),&ShaderGraph::_update_shader);
- return connections_ret;
-}
+ ObjectTypeDB::bind_method(_MD("node_add","shader_type","node_type","id"),&ShaderGraph::node_add);
+ ObjectTypeDB::bind_method(_MD("node_remove","shader_type","id"),&ShaderGraph::node_remove);
+ ObjectTypeDB::bind_method(_MD("node_set_pos","shader_type","id","pos"),&ShaderGraph::node_set_pos);
+ ObjectTypeDB::bind_method(_MD("node_get_pos","shader_type","id"),&ShaderGraph::node_get_pos);
-void ShaderGraph::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("node_get_type","shader_type","id"),&ShaderGraph::node_get_type);
+
+ ObjectTypeDB::bind_method(_MD("get_node_list","shader_type"),&ShaderGraph::_get_node_list);
+
+ ObjectTypeDB::bind_method(_MD("scalar_const_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_const_node_set_value);
+ ObjectTypeDB::bind_method(_MD("scalar_const_node_get_value","shader_type","id"),&ShaderGraph::scalar_const_node_set_value);
+
+ ObjectTypeDB::bind_method(_MD("vec_const_node_set_value","shader_type","id","value"),&ShaderGraph::vec_const_node_set_value);
+ ObjectTypeDB::bind_method(_MD("vec_const_node_get_value","shader_type","id"),&ShaderGraph::vec_const_node_set_value);
+
+ ObjectTypeDB::bind_method(_MD("rgb_const_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_const_node_set_value);
+ ObjectTypeDB::bind_method(_MD("rgb_const_node_get_value","shader_type","id"),&ShaderGraph::rgb_const_node_set_value);
+
+ ObjectTypeDB::bind_method(_MD("xform_const_node_set_value","shader_type","id","value"),&ShaderGraph::xform_const_node_set_value);
+ ObjectTypeDB::bind_method(_MD("xform_const_node_get_value","shader_type","id"),&ShaderGraph::xform_const_node_set_value);
+
+
+// void get_node_list(ShaderType p_which,List<int> *p_node_list) const;
+
+ ObjectTypeDB::bind_method(_MD("texture_node_set_filter_size","shader_type","id","filter_size"),&ShaderGraph::texture_node_set_filter_size);
+ ObjectTypeDB::bind_method(_MD("texture_node_get_filter_size","shader_type","id"),&ShaderGraph::texture_node_set_filter_size);
+
+ ObjectTypeDB::bind_method(_MD("texture_node_set_filter_strength","shader_type","id","filter_strength"),&ShaderGraph::texture_node_set_filter_strength);
+ ObjectTypeDB::bind_method(_MD("texture_node_get_filter_strength","shader_type","id"),&ShaderGraph::texture_node_set_filter_strength);
+
+ ObjectTypeDB::bind_method(_MD("scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::scalar_op_node_set_op);
+ ObjectTypeDB::bind_method(_MD("scalar_op_node_get_op","shader_type","id"),&ShaderGraph::scalar_op_node_get_op);
+
+ ObjectTypeDB::bind_method(_MD("vec_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_op_node_set_op);
+ ObjectTypeDB::bind_method(_MD("vec_op_node_get_op","shader_type","id"),&ShaderGraph::vec_op_node_get_op);
+
+ ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_scalar_op_node_set_op);
+ ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_get_op","shader_type","id"),&ShaderGraph::vec_scalar_op_node_get_op);
+
+ ObjectTypeDB::bind_method(_MD("rgb_op_node_set_op","shader_type","id","op"),&ShaderGraph::rgb_op_node_set_op);
+ ObjectTypeDB::bind_method(_MD("rgb_op_node_get_op","shader_type","id"),&ShaderGraph::rgb_op_node_get_op);
+
+ ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_set_no_translation","shader_type","id","disable"),&ShaderGraph::xform_vec_mult_node_set_no_translation);
+ ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_get_no_translation","shader_type","id"),&ShaderGraph::xform_vec_mult_node_get_no_translation);
+
+ ObjectTypeDB::bind_method(_MD("scalar_func_node_set_function","shader_type","id","func"),&ShaderGraph::scalar_func_node_set_function);
+ ObjectTypeDB::bind_method(_MD("scalar_func_node_get_function","shader_type","id"),&ShaderGraph::scalar_func_node_get_function);
+
+ ObjectTypeDB::bind_method(_MD("vec_func_node_set_function","shader_type","id","func"),&ShaderGraph::vec_func_node_set_function);
+ ObjectTypeDB::bind_method(_MD("vec_func_node_get_function","shader_type","id"),&ShaderGraph::vec_func_node_get_function);
+
+ ObjectTypeDB::bind_method(_MD("input_node_set_name","shader_type","id","name"),&ShaderGraph::input_node_set_name);
+ ObjectTypeDB::bind_method(_MD("input_node_get_name","shader_type","id"),&ShaderGraph::input_node_get_name);
+
+ ObjectTypeDB::bind_method(_MD("scalar_input_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("scalar_input_node_get_value","shader_type","id"),&ShaderGraph::scalar_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("vec_input_node_set_value","shader_type","id","value"),&ShaderGraph::vec_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("vec_input_node_get_value","shader_type","id"),&ShaderGraph::vec_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("rgb_input_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("rgb_input_node_get_value","shader_type","id"),&ShaderGraph::rgb_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("xform_input_node_set_value","shader_type","id","value"),&ShaderGraph::xform_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("xform_input_node_get_value","shader_type","id"),&ShaderGraph::xform_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("texture_input_node_set_value","shader_type","id","value:Texture"),&ShaderGraph::texture_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("texture_input_node_get_value:Texture","shader_type","id"),&ShaderGraph::texture_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("cubemap_input_node_set_value","shader_type","id","value:CubeMap"),&ShaderGraph::cubemap_input_node_set_value);
+ ObjectTypeDB::bind_method(_MD("cubemap_input_node_get_value:CubeMap","shader_type","id"),&ShaderGraph::cubemap_input_node_get_value);
+
+ ObjectTypeDB::bind_method(_MD("comment_node_set_text","shader_type","id","text"),&ShaderGraph::comment_node_set_text);
+ ObjectTypeDB::bind_method(_MD("comment_node_get_text","shader_type","id"),&ShaderGraph::comment_node_get_text);
+
+ ObjectTypeDB::bind_method(_MD("connect_node:Error","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::connect_node);
+ ObjectTypeDB::bind_method(_MD("is_node_connected","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::is_node_connected);
+ ObjectTypeDB::bind_method(_MD("disconnect_node","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::disconnect_node);
+ ObjectTypeDB::bind_method(_MD("get_node_connections","shader_type"),&ShaderGraph::_get_connections);
+
+ ObjectTypeDB::bind_method(_MD("clear","shader_type"),&ShaderGraph::clear);
+
+ ObjectTypeDB::bind_method(_MD("node_set_state","shader_type","id","state"),&ShaderGraph::node_set_state);
+ ObjectTypeDB::bind_method(_MD("node_get_state:var","shader_type","id"),&ShaderGraph::node_get_state);
+
+ ObjectTypeDB::bind_method(_MD("_set_data"),&ShaderGraph::_set_data);
+ ObjectTypeDB::bind_method(_MD("_get_data"),&ShaderGraph::_get_data);
+
+ ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR), _SCS("_set_data"),_SCS("_get_data"));
+
+ //void get_connections(ShaderType p_which,List<Connection> *p_connections) const;
+
+
+ BIND_CONSTANT( NODE_INPUT ); // all inputs (shader type dependent)
+ BIND_CONSTANT( NODE_SCALAR_CONST ); //scalar constant
+ BIND_CONSTANT( NODE_VEC_CONST ); //vec3 constant
+ BIND_CONSTANT( NODE_RGB_CONST ); //rgb constant (shows a color picker instead)
+ BIND_CONSTANT( NODE_XFORM_CONST ); // 4x4 matrix constant
+ BIND_CONSTANT( NODE_TIME ); // time in seconds
+ BIND_CONSTANT( NODE_SCREEN_TEX ); // screen texture sampler (takes UV) (only usable in fragment shader)
+ BIND_CONSTANT( NODE_SCALAR_OP ); // scalar vs scalar op (mul ); add ); div ); etc)
+ BIND_CONSTANT( NODE_VEC_OP ); // vec3 vs vec3 op (mul );ad );div );crossprod );etc)
+ BIND_CONSTANT( NODE_VEC_SCALAR_OP ); // vec3 vs scalar op (mul ); add ); div ); etc)
+ BIND_CONSTANT( NODE_RGB_OP ); // vec3 vs vec3 rgb op (with scalar amount) ); like brighten ); darken ); burn ); dodge ); multiply ); etc.
+ BIND_CONSTANT( NODE_XFORM_MULT ); // mat4 x mat4
+ BIND_CONSTANT( NODE_XFORM_VEC_MULT ); // mat4 x vec3 mult (with no-translation option)
+ BIND_CONSTANT( NODE_XFORM_VEC_INV_MULT ); // mat4 x vec3 inverse mult (with no-translation option)
+ BIND_CONSTANT( NODE_SCALAR_FUNC ); // scalar function (sin ); cos ); etc)
+ BIND_CONSTANT( NODE_VEC_FUNC ); // vector function (normalize ); negate ); reciprocal ); rgb2hsv ); hsv2rgb ); etc ); etc)
+ BIND_CONSTANT( NODE_VEC_LEN ); // vec3 length
+ BIND_CONSTANT( NODE_DOT_PROD ); // vec3 . vec3 (dot product -> scalar output)
+ BIND_CONSTANT( NODE_VEC_TO_SCALAR ); // 1 vec3 input ); 3 scalar outputs
+ BIND_CONSTANT( NODE_SCALAR_TO_VEC ); // 3 scalar input ); 1 vec3 output
+ BIND_CONSTANT( NODE_VEC_TO_XFORM ); // 3 vec input ); 1 xform output
+ BIND_CONSTANT( NODE_XFORM_TO_VEC ); // 3 vec input ); 1 xform output
+ BIND_CONSTANT( NODE_SCALAR_INTERP ); // scalar interpolation (with optional curve)
+ BIND_CONSTANT( NODE_VEC_INTERP ); // vec3 interpolation (with optional curve)
+ BIND_CONSTANT( NODE_SCALAR_INPUT ); // scalar uniform (assignable in material)
+ BIND_CONSTANT( NODE_VEC_INPUT ); // vec3 uniform (assignable in material)
+ BIND_CONSTANT( NODE_RGB_INPUT ); // color uniform (assignable in material)
+ BIND_CONSTANT( NODE_XFORM_INPUT ); // mat4 uniform (assignable in material)
+ BIND_CONSTANT( NODE_TEXTURE_INPUT ); // texture input (assignable in material)
+ BIND_CONSTANT( NODE_CUBEMAP_INPUT ); // cubemap input (assignable in material)
+ BIND_CONSTANT( NODE_OUTPUT ); // output (shader type dependent)
+ BIND_CONSTANT( NODE_COMMENT ); // comment
+ BIND_CONSTANT( NODE_TYPE_MAX );
+
+ BIND_CONSTANT( SLOT_TYPE_SCALAR );
+ BIND_CONSTANT( SLOT_TYPE_VEC );
+ BIND_CONSTANT( SLOT_TYPE_XFORM );
+ BIND_CONSTANT( SLOT_TYPE_TEXTURE );
+ BIND_CONSTANT( SLOT_MAX );
+
+ BIND_CONSTANT( SHADER_TYPE_VERTEX );
+ BIND_CONSTANT( SHADER_TYPE_FRAGMENT );
+ BIND_CONSTANT( SHADER_TYPE_LIGHT );
+ BIND_CONSTANT( SHADER_TYPE_MAX );
+
+
+ BIND_CONSTANT( SLOT_IN );
+ BIND_CONSTANT( SLOT_OUT );
+
+ BIND_CONSTANT( GRAPH_OK );
+ BIND_CONSTANT( GRAPH_ERROR_CYCLIC );
+ BIND_CONSTANT( GRAPH_ERROR_MISSING_CONNECTIONS );
+
+ BIND_CONSTANT( SCALAR_OP_ADD );
+ BIND_CONSTANT( SCALAR_OP_SUB );
+ BIND_CONSTANT( SCALAR_OP_MUL );
+ BIND_CONSTANT( SCALAR_OP_DIV );
+ BIND_CONSTANT( SCALAR_OP_MOD );
+ BIND_CONSTANT( SCALAR_OP_POW );
+ BIND_CONSTANT( SCALAR_OP_MAX );
+ BIND_CONSTANT( SCALAR_OP_MIN );
+ BIND_CONSTANT( SCALAR_OP_ATAN2 );
+ BIND_CONSTANT( SCALAR_MAX_OP );
+
+ BIND_CONSTANT( VEC_OP_ADD );
+ BIND_CONSTANT( VEC_OP_SUB );
+ BIND_CONSTANT( VEC_OP_MUL );
+ BIND_CONSTANT( VEC_OP_DIV );
+ BIND_CONSTANT( VEC_OP_MOD );
+ BIND_CONSTANT( VEC_OP_POW );
+ BIND_CONSTANT( VEC_OP_MAX );
+ BIND_CONSTANT( VEC_OP_MIN );
+ BIND_CONSTANT( VEC_OP_CROSS );
+ BIND_CONSTANT( VEC_MAX_OP );
+
+ BIND_CONSTANT( VEC_SCALAR_OP_MUL );
+ BIND_CONSTANT( VEC_SCALAR_OP_DIV );
+ BIND_CONSTANT( VEC_SCALAR_OP_POW );
+ BIND_CONSTANT( VEC_SCALAR_MAX_OP );
+
+ BIND_CONSTANT( RGB_OP_SCREEN );
+ BIND_CONSTANT( RGB_OP_DIFFERENCE );
+ BIND_CONSTANT( RGB_OP_DARKEN );
+ BIND_CONSTANT( RGB_OP_LIGHTEN );
+ BIND_CONSTANT( RGB_OP_OVERLAY );
+ BIND_CONSTANT( RGB_OP_DODGE );
+ BIND_CONSTANT( RGB_OP_BURN );
+ BIND_CONSTANT( RGB_OP_SOFT_LIGHT );
+ BIND_CONSTANT( RGB_OP_HARD_LIGHT );
+ BIND_CONSTANT( RGB_MAX_OP );
+
+ BIND_CONSTANT( SCALAR_FUNC_SIN );
+ BIND_CONSTANT( SCALAR_FUNC_COS );
+ BIND_CONSTANT( SCALAR_FUNC_TAN );
+ BIND_CONSTANT( SCALAR_FUNC_ASIN );
+ BIND_CONSTANT( SCALAR_FUNC_ACOS );
+ BIND_CONSTANT( SCALAR_FUNC_ATAN );
+ BIND_CONSTANT( SCALAR_FUNC_SINH );
+ BIND_CONSTANT( SCALAR_FUNC_COSH );
+ BIND_CONSTANT( SCALAR_FUNC_TANH );
+ BIND_CONSTANT( SCALAR_FUNC_LOG );
+ BIND_CONSTANT( SCALAR_FUNC_EXP );
+ BIND_CONSTANT( SCALAR_FUNC_SQRT );
+ BIND_CONSTANT( SCALAR_FUNC_ABS );
+ BIND_CONSTANT( SCALAR_FUNC_SIGN );
+ BIND_CONSTANT( SCALAR_FUNC_FLOOR );
+ BIND_CONSTANT( SCALAR_FUNC_ROUND );
+ BIND_CONSTANT( SCALAR_FUNC_CEIL );
+ BIND_CONSTANT( SCALAR_FUNC_FRAC );
+ BIND_CONSTANT( SCALAR_FUNC_SATURATE );
+ BIND_CONSTANT( SCALAR_FUNC_NEGATE );
+ BIND_CONSTANT( SCALAR_MAX_FUNC );
+
+ BIND_CONSTANT( VEC_FUNC_NORMALIZE );
+ BIND_CONSTANT( VEC_FUNC_SATURATE );
+ BIND_CONSTANT( VEC_FUNC_NEGATE );
+ BIND_CONSTANT( VEC_FUNC_RECIPROCAL );
+ BIND_CONSTANT( VEC_FUNC_RGB2HSV );
+ BIND_CONSTANT( VEC_FUNC_HSV2RGB );
+ BIND_CONSTANT( VEC_MAX_FUNC );
+
+ ADD_SIGNAL(MethodInfo("updated"));
+
+
+#if 0
ObjectTypeDB::bind_method(_MD("node_add"),&ShaderGraph::node_add );
ObjectTypeDB::bind_method(_MD("node_remove"),&ShaderGraph::node_remove );
ObjectTypeDB::bind_method(_MD("node_set_param"),&ShaderGraph::node_set_param );
ObjectTypeDB::bind_method(_MD("node_set_pos"),&ShaderGraph::node_set_pos );
ObjectTypeDB::bind_method(_MD("node_get_pos"),&ShaderGraph::node_get_pos );
- ObjectTypeDB::bind_method(_MD("node_get_param"),&ShaderGraph::node_get_type);
- ObjectTypeDB::bind_method(_MD("node_get_type"),&ShaderGraph::node_get_param);
+ ObjectTypeDB::bind_method(_MD("node_get_param"),&ShaderGraph::node_get_param);
+ ObjectTypeDB::bind_method(_MD("node_get_type"),&ShaderGraph::node_get_type);
ObjectTypeDB::bind_method(_MD("connect"),&ShaderGraph::connect );
ObjectTypeDB::bind_method(_MD("disconnect"),&ShaderGraph::disconnect );
@@ -212,73 +434,158 @@ void ShaderGraph::_bind_methods() {
BIND_CONSTANT( NODE_TEXTURE_2D_PARAMETER );
BIND_CONSTANT( NODE_TEXTURE_CUBE_PARAMETER );
BIND_CONSTANT( NODE_TYPE_MAX );
+#endif
}
-void ShaderGraph::node_add(NodeType p_type,int p_id) {
+
+String ShaderGraph::_find_unique_name(const String& p_base) {
+
- ERR_FAIL_COND( node_map.has(p_id ) );
- ERR_FAIL_INDEX( p_type, NODE_TYPE_MAX );
+ int idx=1;
+ while(true) {
+ String tocmp=p_base;
+ if (idx>1) {
+ tocmp+="_"+itos(idx);
+ }
+ bool valid=true;
+ for(int i=0;i<3;i++) {
+ if (!valid)
+ break;
+ for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+ if (E->get().type!=NODE_SCALAR_INPUT && E->get().type!=NODE_VEC_INPUT && E->get().type==NODE_RGB_INPUT && E->get().type==NODE_XFORM_INPUT && E->get().type==NODE_TEXTURE_INPUT && E->get().type==NODE_CUBEMAP_INPUT)
+ continue;
+ String name = E->get().param1;
+ if (name==tocmp) {
+ valid=false;
+ break;
+ }
+
+ }
+ }
+
+ if (!valid) {
+ idx++;
+ continue;
+ }
+ return tocmp;
+ }
+ return String();
+}
+
+void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) {
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(p_id==0);
+ ERR_FAIL_COND(p_node_type==NODE_OUTPUT); //can't create output
+ ERR_FAIL_COND( shader[p_type].node_map.has(p_id ) );
+ ERR_FAIL_INDEX( p_node_type, NODE_TYPE_MAX );
Node node;
- node.type=p_type;
+ if (p_node_type==NODE_INPUT) {
+ //see if it already exists
+ for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+ if (E->get().type==NODE_INPUT) {
+ ERR_EXPLAIN("Only one input node can be added to the graph.");
+ ERR_FAIL_COND(E->get().type==NODE_INPUT);
+ }
+ }
+ }
+ node.type=p_node_type;
node.id=p_id;
- node.x=0;
- node.y=0;
- node_map[p_id]=node;
+ switch(p_node_type) {
+ case NODE_INPUT: {} break; // all inputs (shader type dependent)
+ case NODE_SCALAR_CONST: { node.param1=0;} break; //scalar constant
+ case NODE_VEC_CONST: {node.param1=Vector3();} break; //vec3 constant
+ case NODE_RGB_CONST: {node.param1=Color();} break; //rgb constant (shows a color picker instead)
+ case NODE_XFORM_CONST: {node.param1=Transform();} break; // 4x4 matrix constant
+ case NODE_TIME: {} break; // time in seconds
+ case NODE_SCREEN_TEX: {Array arr; arr.push_back(0); arr.push_back(0); node.param2=arr;} break; // screen texture sampler (takes UV) (only usable in fragment shader)
+ case NODE_SCALAR_OP: {node.param1=SCALAR_OP_ADD;} break; // scalar vs scalar op (mul: {} break; add: {} break; div: {} break; etc)
+ case NODE_VEC_OP: {node.param1=VEC_OP_ADD;} break; // vec3 vs vec3 op (mul: {} break;ad: {} break;div: {} break;crossprod: {} break;etc)
+ case NODE_VEC_SCALAR_OP: {node.param1=VEC_SCALAR_OP_MUL;} break; // vec3 vs scalar op (mul: {} break; add: {} break; div: {} break; etc)
+ case NODE_RGB_OP: {node.param1=RGB_OP_SCREEN;} break; // vec3 vs vec3 rgb op (with scalar amount): {} break; like brighten: {} break; darken: {} break; burn: {} break; dodge: {} break; multiply: {} break; etc.
+ case NODE_XFORM_MULT: {} break; // mat4 x mat4
+ case NODE_XFORM_VEC_MULT: {} break; // mat4 x vec3 mult (with no-translation option)
+ case NODE_XFORM_VEC_INV_MULT: {} break; // mat4 x vec3 inverse mult (with no-translation option)
+ case NODE_SCALAR_FUNC: {node.param1=SCALAR_FUNC_SIN;} break; // scalar function (sin: {} break; cos: {} break; etc)
+ case NODE_VEC_FUNC: {node.param1=VEC_FUNC_NORMALIZE;} break; // vector function (normalize: {} break; negate: {} break; reciprocal: {} break; rgb2hsv: {} break; hsv2rgb: {} break; etc: {} break; etc)
+ case NODE_VEC_LEN: {} break; // vec3 length
+ case NODE_DOT_PROD: {} break; // vec3 . vec3 (dot product -> scalar output)
+ case NODE_VEC_TO_SCALAR: {} break; // 1 vec3 input: {} break; 3 scalar outputs
+ case NODE_SCALAR_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
+ case NODE_VEC_TO_XFORM: {} break; // 3 scalar input: {} break; 1 vec3 output
+ case NODE_XFORM_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
+ case NODE_SCALAR_INTERP: {} break; // scalar interpolation (with optional curve)
+ case NODE_VEC_INTERP: {} break; // vec3 interpolation (with optional curve)
+ case NODE_SCALAR_INPUT: {node.param1=_find_unique_name("Scalar"); node.param2=0;} break; // scalar uniform (assignable in material)
+ case NODE_VEC_INPUT: {node.param1=_find_unique_name("Vec3");node.param2=Vector3();} break; // vec3 uniform (assignable in material)
+ case NODE_RGB_INPUT: {node.param1=_find_unique_name("Color");node.param2=Color();} break; // color uniform (assignable in material)
+ case NODE_XFORM_INPUT: {node.param1=_find_unique_name("XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material)
+ case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name("Tex"); } break; // texture input (assignable in material)
+ case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
+ case NODE_OUTPUT: {} break; // output (shader type dependent)
+ case NODE_COMMENT: {} break; // comment
+ case NODE_TYPE_MAX: {};
+ }
+ shader[p_type].node_map[p_id]=node;
+ _request_update();
}
-void ShaderGraph::node_set_pos(int p_id, const Vector2& p_pos) {
+void ShaderGraph::node_set_pos(ShaderType p_type,int p_id, const Vector2& p_pos) {
+ ERR_FAIL_INDEX(p_type,3);
+
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ shader[p_type].node_map[p_id].pos=p_pos;
+ _request_update();
- ERR_FAIL_COND(!node_map.has(p_id));
- node_map[p_id].x=p_pos.x;
- node_map[p_id].y=p_pos.y;
}
-Vector2 ShaderGraph::node_get_pos(int p_id) const {
+Vector2 ShaderGraph::node_get_pos(ShaderType p_type,int p_id) const {
+ ERR_FAIL_INDEX_V(p_type,3,Vector2());
- ERR_FAIL_COND_V(!node_map.has(p_id),Vector2());
- return Vector2(node_map[p_id].x,node_map[p_id].y);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector2());
+ return shader[p_type].node_map[p_id].pos;
}
-void ShaderGraph::node_remove(int p_id) {
+void ShaderGraph::node_remove(ShaderType p_type,int p_id) {
+
+ ERR_FAIL_COND(p_id==0);
+ ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!node_map.has(p_id));
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
//erase connections associated with node
- List<Connection>::Element *N,*E=connections.front();
- while(E) {
- N=E->next();
- const Connection &c = E->get();
- if (c.src_id==p_id || c.dst_id==p_id) {
+ for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+ if (E->key()==p_id)
+ continue; //no self
+
+ for (Map<int,SourceSlot>::Element *F=E->get().connections.front();F;) {
+ Map<int,SourceSlot>::Element *N=F->next();
+
+ if (F->get().id==p_id) {
+ E->get().connections.erase(F);
+ }
- connections.erase(E);
+ F=N;
}
- E=N;
}
- node_map.erase(p_id);
-}
-
-void ShaderGraph::node_change_type(int p_id, NodeType p_type) {
+ shader[p_type].node_map.erase(p_id);
- ERR_FAIL_COND(!node_map.has(p_id));
- node_map[p_id].type=p_type;
- node_map[p_id].param=Variant();
+ _request_update();
}
-void ShaderGraph::node_set_param(int p_id, const Variant& p_value) {
- ERR_FAIL_COND(!node_map.has(p_id));
- node_map[p_id].param=p_value;
-}
-void ShaderGraph::get_node_list(List<int> *p_node_list) const {
+void ShaderGraph::get_node_list(ShaderType p_type,List<int> *p_node_list) const {
- Map<int,Node>::Element *E = node_map.front();
+ ERR_FAIL_INDEX(p_type,3);
+
+ Map<int,Node>::Element *E = shader[p_type].node_map.front();
while(E) {
@@ -288,740 +595,1463 @@ void ShaderGraph::get_node_list(List<int> *p_node_list) const {
}
-ShaderGraph::NodeType ShaderGraph::node_get_type(int p_id) const {
+ShaderGraph::NodeType ShaderGraph::node_get_type(ShaderType p_type,int p_id) const {
- ERR_FAIL_COND_V(!node_map.has(p_id),NODE_TYPE_MAX);
- return node_map[p_id].type;
-}
+ ERR_FAIL_INDEX_V(p_type,3,NODE_TYPE_MAX);
-Variant ShaderGraph::node_get_param(int p_id) const {
-
- ERR_FAIL_COND_V(!node_map.has(p_id),Variant());
- return node_map[p_id].param;
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),NODE_TYPE_MAX);
+ return shader[p_type].node_map[p_id].type;
}
-Error ShaderGraph::connect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+Error ShaderGraph::connect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+ ERR_FAIL_INDEX_V(p_type,3,ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_src_id==p_dst_id, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!node_map.has(p_src_id), ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!node_map.has(p_dst_id), ERR_INVALID_PARAMETER);
- NodeType type_src=node_map[p_src_id].type;
- NodeType type_dst=node_map[p_dst_id].type;
- //ERR_FAIL_INDEX_V( p_src_slot, VisualServer::shader_get_output_count(type_src), ERR_INVALID_PARAMETER );
- //ERR_FAIL_INDEX_V( p_dst_slot, VisualServer::shader_get_input_count(type_dst), ERR_INVALID_PARAMETER );
- //ERR_FAIL_COND_V(VisualServer::shader_is_output_vector(type_src,p_src_slot) != VisualServer::shader_is_input_vector(type_dst,p_dst_slot), ERR_INVALID_PARAMETER );
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_src_id), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_dst_id), ERR_INVALID_PARAMETER);
+ NodeType type_src=shader[p_type].node_map[p_src_id].type;
+ NodeType type_dst=shader[p_type].node_map[p_dst_id].type;
+ ERR_FAIL_INDEX_V( p_src_slot, get_node_output_slot_count(get_mode(),p_type,type_src), ERR_INVALID_PARAMETER );
+ ERR_FAIL_INDEX_V( p_dst_slot, get_node_input_slot_count(get_mode(),p_type,type_dst), ERR_INVALID_PARAMETER );
+ ERR_FAIL_COND_V(get_node_output_slot_type(get_mode(),p_type,type_src,p_src_slot) != get_node_input_slot_type(get_mode(),p_type,type_dst,p_dst_slot), ERR_INVALID_PARAMETER );
- List<Connection>::Element *E=connections.front();
- while(E) {
- const Connection &c = E->get();
- ERR_FAIL_COND_V(c.dst_slot==p_dst_slot && c.dst_id == p_dst_id, ERR_ALREADY_EXISTS);
+ SourceSlot ts;
+ ts.id=p_src_id;
+ ts.slot=p_src_slot;
+ shader[p_type].node_map[p_dst_id].connections[p_dst_slot]=ts;
+ _request_update();
- E=E->next();
- }
+ return OK;
+}
- Connection c;
- c.src_slot=p_src_slot;
- c.src_id=p_src_id;
- c.dst_slot=p_dst_slot;
- c.dst_id=p_dst_id;
+bool ShaderGraph::is_node_connected(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const {
- connections.push_back(c);
+ ERR_FAIL_INDEX_V(p_type,3,false);
- return OK;
+ SourceSlot ts;
+ ts.id=p_src_id;
+ ts.slot=p_src_slot;
+ return shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) &&
+ shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts;
}
-bool ShaderGraph::is_connected(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const {
+void ShaderGraph::disconnect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+ ERR_FAIL_INDEX(p_type,3);
- const List<Connection>::Element *E=connections.front();
- while(E) {
- const Connection &c = E->get();
- if (c.dst_slot==p_dst_slot && c.dst_id == p_dst_id && c.src_slot==p_src_slot && c.src_id == p_src_id)
- return true;
+ SourceSlot ts;
+ ts.id=p_src_id;
+ ts.slot=p_src_slot;
+ if (shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) &&
+ shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts) {
+ shader[p_type].node_map[p_dst_id].connections.erase(p_dst_slot);
- E=E->next();
}
+ _request_update();
- return false;
}
-void ShaderGraph::disconnect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+void ShaderGraph::get_node_connections(ShaderType p_type,List<Connection> *p_connections) const {
- List<Connection>::Element *N,*E=connections.front();
- while(E) {
- N=E->next();
- const Connection &c = E->get();
- if (c.src_slot==p_src_slot && c.src_id==p_src_id && c.dst_slot==p_dst_slot && c.dst_id == p_dst_id) {
+ ERR_FAIL_INDEX(p_type,3);
+
+ for(const Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+ for (const Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
- connections.erase(E);
+ Connection c;
+ c.dst_id=E->key();
+ c.dst_slot=F->key();
+ c.src_id=F->get().id;
+ c.src_slot=F->get().slot;
+ p_connections->push_back(c);
}
- E=N;
}
+}
+
+
+void ShaderGraph::clear(ShaderType p_type) {
+ ERR_FAIL_INDEX(p_type,3);
+ shader[p_type].node_map.clear();
+ Node out;
+ out.pos=Vector2(300,300);
+ out.type=NODE_OUTPUT;
+ shader[p_type].node_map.insert(0,out);
+
+ _request_update();
}
-void ShaderGraph::get_connections(List<Connection> *p_connections) const {
- const List<Connection>::Element*E=connections.front();
- while(E) {
- p_connections->push_back(E->get());
- E=E->next();
- }
+void ShaderGraph::scalar_const_node_set_value(ShaderType p_type,int p_id,float p_value) {
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_SCALAR_CONST);
+ n.param1=p_value;
+ _request_update();
}
+float ShaderGraph::scalar_const_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,0);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_SCALAR_CONST,0);
+ return n.param1;
+}
+
+void ShaderGraph::vec_const_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_VEC_CONST);
+ n.param1=p_value;
+ _request_update();
-void ShaderGraph::clear() {
- connections.clear();
- node_map.clear();
}
+Vector3 ShaderGraph::vec_const_node_get_value(ShaderType p_type,int p_id) const{
+ ERR_FAIL_INDEX_V(p_type,3,Vector3());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_VEC_CONST,Vector3());
+ return n.param1;
-#if 0
-void ShaderGraph::node_add(NodeType p_type,int p_id) {
+}
+
+void ShaderGraph::rgb_const_node_set_value(ShaderType p_type,int p_id,const Color& p_value){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_RGB_CONST);
+ n.param1=p_value;
+ _request_update();
- ShaderNode sn;
- sn.type=p_type;
- nodes[p_id]=sn;
- version++;
}
-void ShaderGraph::node_remove(int p_id) {
+Color ShaderGraph::rgb_const_node_get_value(ShaderType p_type,int p_id) const{
- nodes.erase(p_id);
+ ERR_FAIL_INDEX_V(p_type,3,Color());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_RGB_CONST,Color());
+ return n.param1;
}
-void ShaderGraph::node_set_param( int p_id, const Variant& p_value) {
- VisualServer::get_singleton()->shader_node_set_param(shader,p_id,p_value);
- version++;
+void ShaderGraph::xform_const_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_XFORM_CONST);
+ n.param1=p_value;
+ _request_update();
+
}
+Transform ShaderGraph::xform_const_node_get_value(ShaderType p_type,int p_id) const{
-void ShaderGraph::get_node_list(List<int> *p_node_list) const {
+ ERR_FAIL_INDEX_V(p_type,3,Transform());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_XFORM_CONST,Transform());
+ return n.param1;
- VisualServer::get_singleton()->shader_get_node_list(shader,p_node_list);
}
-ShaderGraph::NodeType ShaderGraph::node_get_type(int p_id) const {
- return (NodeType)VisualServer::get_singleton()->shader_node_get_type(shader,p_id);
+void ShaderGraph::texture_node_set_filter_size(ShaderType p_type,int p_id,int p_size){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX);
+ Array arr = n.param2;
+ arr[0]=p_size;
+ n.param2=arr;
+ _request_update();
+
}
-Variant ShaderGraph::node_get_param(int p_id) const {
+int ShaderGraph::texture_node_get_filter_size(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,0);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0);
+ Array arr = n.param2;
+ return arr[0];
- return VisualServer::get_singleton()->shader_node_get_param(shader,p_id);
}
-void ShaderGraph::connect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+void ShaderGraph::texture_node_set_filter_strength(ShaderType p_type,float p_id,float p_strength){
- VisualServer::get_singleton()->shader_connect(shader,p_src_id,p_src_slot,p_dst_id,p_dst_slot);
- version++;
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX);
+ Array arr = n.param2;
+ arr[1]=p_strength;
+ n.param2=arr;
+ _request_update();
+
+}
+float ShaderGraph::texture_node_get_filter_strength(ShaderType p_type,float p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,0);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0);
+ Array arr = n.param2;
+ return arr[1];
}
-void ShaderGraph::disconnect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
- VisualServer::get_singleton()->shader_disconnect(shader,p_src_id,p_src_slot,p_dst_id,p_dst_slot);
- version++;
+
+void ShaderGraph::scalar_op_node_set_op(ShaderType p_type,float p_id,ScalarOp p_op){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_SCALAR_OP);
+ n.param1=p_op;
+ _request_update();
+
}
+ShaderGraph::ScalarOp ShaderGraph::scalar_op_node_get_op(ShaderType p_type,float p_id) const{
-void ShaderGraph::get_connections(List<Connection> *p_connections) const {
+ ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_OP);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_OP);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_SCALAR_OP,SCALAR_MAX_OP);
+ int op = n.param1;
+ return ScalarOp(op);
- List<VS::ShaderGraphConnection> connections;
- VisualServer::get_singleton()->shader_get_connections(shader,&connections);
- for( List<VS::ShaderGraphConnection>::Element *E=connections.front();E;E=E->next()) {
+}
+
+
+void ShaderGraph::vec_op_node_set_op(ShaderType p_type,float p_id,VecOp p_op){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_VEC_OP);
+ n.param1=p_op;
+ _request_update();
- Connection c;
- c.src_id=E->get().src_id;
- c.src_slot=E->get().src_slot;
- c.dst_id=E->get().dst_id;
- c.dst_slot=E->get().dst_slot;
- p_connections->push_back(c);
- }
}
+ShaderGraph::VecOp ShaderGraph::vec_op_node_get_op(ShaderType p_type,float p_id) const{
-void ShaderGraph::node_set_pos(int p_id,const Point2& p_pos) {
+ ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_OP);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_OP);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_VEC_OP,VEC_MAX_OP);
+ int op = n.param1;
+ return VecOp(op);
-#ifdef TOOLS_ENABLED
- ERR_FAIL_COND(!positions.has(p_id));
- positions[p_id]=p_pos;
-#endif
}
-Point2 ShaderGraph::node_get_pos(int p_id) const {
-#ifdef TOOLS_ENABLED
- ERR_FAIL_COND_V(!positions.has(p_id),Point2());
- return positions[p_id];
-#endif
+
+void ShaderGraph::vec_scalar_op_node_set_op(ShaderType p_type,float p_id,VecScalarOp p_op){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_VEC_SCALAR_OP);
+ n.param1=p_op;
+ _request_update();
+
}
+ShaderGraph::VecScalarOp ShaderGraph::vec_scalar_op_node_get_op(ShaderType p_type,float p_id) const{
-void ShaderGraph::clear() {
+ ERR_FAIL_INDEX_V(p_type,3,VEC_SCALAR_MAX_OP);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_SCALAR_MAX_OP);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_VEC_SCALAR_OP,VEC_SCALAR_MAX_OP);
+ int op = n.param1;
+ return VecScalarOp(op);
- VisualServer::get_singleton()->shader_clear(shader);
- version++;
}
-#endif
-ShaderGraph::ShaderGraph() {
+void ShaderGraph::rgb_op_node_set_op(ShaderType p_type,float p_id,RGBOp p_op){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_RGB_OP);
+ n.param1=p_op;
+
+ _request_update();
- //shader = VisualServer::get_singleton()->shader_create();
- version = 1;
}
+ShaderGraph::RGBOp ShaderGraph::rgb_op_node_get_op(ShaderType p_type,float p_id) const{
-ShaderGraph::~ShaderGraph() {
+ ERR_FAIL_INDEX_V(p_type,3,RGB_MAX_OP);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),RGB_MAX_OP);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_RGB_OP,RGB_MAX_OP);
+ int op = n.param1;
+ return RGBOp(op);
- //VisualServer::get_singleton()->free(shader);
}
-#if 0
-void ShaderGraph::shader_get_default_input_nodes(Mode p_type,List<PropertyInfo> *p_inputs) {
- switch(p_type) {
+void ShaderGraph::xform_vec_mult_node_set_no_translation(ShaderType p_type,int p_id,bool p_no_translation){
- case SHADER_VERTEX: {
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT);
+ n.param1=p_no_translation;
+ _request_update();
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"vertex") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
- p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
- } break;
- case SHADER_FRAGMENT: {
+}
+bool ShaderGraph::xform_vec_mult_node_get_no_translation(ShaderType p_type,int p_id) const{
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"position") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") );
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
- p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
+ ERR_FAIL_INDEX_V(p_type,3,false);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),false);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT,false);
+ return n.param1;
- } break;
- case SHADER_POST_PROCESS: {
- p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
- p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
- } break;
+}
- }
+void ShaderGraph::scalar_func_node_set_function(ShaderType p_type,int p_id,ScalarFunc p_func){
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_SCALAR_FUNC);
+ int func = p_func;
+ ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
+ n.param1=func;
+ _request_update();
+
+}
+ShaderGraph::ScalarFunc ShaderGraph::scalar_func_node_get_function(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_FUNC);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_FUNC);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_SCALAR_FUNC,SCALAR_MAX_FUNC);
+ int func = n.param1;
+ return ScalarFunc(func);
}
-void ShaderGraph::shader_get_default_output_nodes(ShaderGraphType p_type,List<PropertyInfo> *p_outputs) {
- switch(p_type) {
+void ShaderGraph::vec_func_node_set_function(ShaderType p_type,int p_id,VecFunc p_func){
- case SHADER_VERTEX: {
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_VEC_FUNC);
+ int func = p_func;
+ ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
+ n.param1=func;
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"vertex") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
- } break;
- case SHADER_FRAGMENT: {
+ _request_update();
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"diffuse") );
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"specular") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"emission") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"spec_exp") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"glow") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha_discard") );
+}
+ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type, int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_FUNC);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_FUNC);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_VEC_FUNC,VEC_MAX_FUNC);
+ int func = n.param1;
+ return VecFunc(func);
+}
- } break;
- case SHADER_POST_PROCESS: {
- p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
- p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
- } break;
+void ShaderGraph::input_node_set_name(ShaderType p_type,int p_id,const String& p_name){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ ERR_FAIL_COND(!p_name.is_valid_identifier());
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT);
+
+ n.param1="";
+ n.param1=_find_unique_name(p_name);
+ _request_update();
+
+}
+String ShaderGraph::input_node_get_name(ShaderType p_type,int p_id){
+
+ ERR_FAIL_INDEX_V(p_type,3,String());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT,String());
+ return n.param1;
+}
+
+
+void ShaderGraph::scalar_input_node_set_value(ShaderType p_type,int p_id,float p_value) {
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT);
+ n.param2=p_value;
+ _request_update();
+
+}
+
+float ShaderGraph::scalar_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,0);
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT,0);
+
+ return n.param2;
+}
+
+void ShaderGraph::vec_input_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_VEC_INPUT);
+
+ n.param2=p_value;
+ _request_update();
+
+}
+Vector3 ShaderGraph::vec_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Vector3());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_VEC_INPUT,Vector3());
+ return n.param2;
+}
+
+void ShaderGraph::rgb_input_node_set_value(ShaderType p_type,int p_id,const Color& p_value){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_RGB_INPUT);
+ n.param2=p_value;
+ _request_update();
+
+}
+Color ShaderGraph::rgb_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Color());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_RGB_INPUT,Color());
+ return n.param2;
+}
+
+void ShaderGraph::xform_input_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_XFORM_INPUT);
+ n.param2=p_value;
+ _request_update();
+
+}
+Transform ShaderGraph::xform_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Transform());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_XFORM_INPUT,Transform());
+ return n.param2;
+}
+
+
+void ShaderGraph::texture_input_node_set_value(ShaderType p_type,int p_id,const Ref<Texture>& p_texture) {
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT);
+ n.param2=p_texture;
+ _request_update();
+}
+
+Ref<Texture> ShaderGraph::texture_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Ref<Texture>());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<Texture>());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT,Ref<Texture>());
+ return n.param2;
+}
+
+void ShaderGraph::cubemap_input_node_set_value(ShaderType p_type,int p_id,const Ref<CubeMap>& p_cubemap){
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_CUBEMAP_INPUT);
+ n.param2=p_cubemap;
+ _request_update();
+
+}
+
+Ref<CubeMap> ShaderGraph::cubemap_input_node_get_value(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,Ref<CubeMap>());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<CubeMap>());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_CUBEMAP_INPUT,Ref<CubeMap>());
+ return n.param2;
+
+}
+
+
+void ShaderGraph::comment_node_set_text(ShaderType p_type,int p_id,const String& p_comment) {
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND(n.type!=NODE_COMMENT);
+ n.param1=p_comment;
+
+}
+
+String ShaderGraph::comment_node_get_text(ShaderType p_type,int p_id) const{
+
+ ERR_FAIL_INDEX_V(p_type,3,String());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String());
+ const Node& n = shader[p_type].node_map[p_id];
+ ERR_FAIL_COND_V(n.type!=NODE_COMMENT,String());
+ return n.param1;
+
+}
+
+void ShaderGraph::_request_update() {
+
+ if (_pending_update_shader)
+ return;
+
+ _pending_update_shader=true;
+ call_deferred("_update_shader");
+
+}
+
+Variant ShaderGraph::node_get_state(ShaderType p_type,int p_id) const {
+
+ ERR_FAIL_INDEX_V(p_type,3,Variant());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Variant());
+ const Node& n = shader[p_type].node_map[p_id];
+ Dictionary s;
+ s["pos"]=n.pos;
+ s["param1"]=n.param1;
+ s["param2"]=n.param2;
+ return s;
+
+}
+void ShaderGraph::node_set_state(ShaderType p_type,int p_id,const Variant& p_state) {
+
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ Dictionary d = p_state;
+ ERR_FAIL_COND(!d.has("pos"));
+ ERR_FAIL_COND(!d.has("param1"));
+ ERR_FAIL_COND(!d.has("param2"));
+ n.pos=d["pos"];
+ n.param1=d["param1"];
+ n.param2=d["param2"];
+
+}
+
+ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) {
+
+ //shader = VisualServer::get_singleton()->shader_create();
+ _pending_update_shader=false;
+ Node out;
+ out.id=0;
+ out.pos=Vector2(250,20);
+ out.type=NODE_OUTPUT;
+ for(int i=0;i<3;i++) {
+
+ shader[i].node_map.insert(0,out);
}
+}
+
+ShaderGraph::~ShaderGraph() {
+ //VisualServer::get_singleton()->free(shader);
+}
+
+
+const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={
+ //material vertex in
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","SRC_VERTEX","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","SRC_NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","SRC_TANGENT","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"BinormalF","SRC_BINORMALF","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","SRC_COLOR","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","SRC_ALPHA","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","SRC_UV","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","SRC_UV2","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"WorldMatrix","WORLD_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"InvCameraMatrix","INV_CAMERA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"ProjectionMatrix","PROJECTION_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"ModelviewMatrix","MODELVIEW_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"InstanceID","INSTANCE_ID","",SLOT_TYPE_SCALAR,SLOT_IN},
+
+ //material vertex out
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","UV",".xy",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","UV2",".xy",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"SpecExp","SPEC_EXP","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_VERTEX,"PointSize","POINT_SIZE","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ //pixel vertex in
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Position","POSITION.xyz","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","IN_NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0);","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV2","UV2","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UVScreen","SCREEN_UV","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"InvCameraMatrix","INV_CAMERA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
+ //pixel vertex out
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Diffuse","DIFFUSE_OUT","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"DiffuseAlpha","ALPHA_OUT","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"SpecularExp","SPECULAR","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Emission","EMISSION","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Glow","GLOW","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMap","NORMALMAP","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMapDepth","NORMALMAP_DEPTH","",SLOT_TYPE_SCALAR,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Discard","DISCARD",">0.5",SLOT_TYPE_SCALAR,SLOT_OUT},
+ //light in
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDir","LIGHT_DIR","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDiffuse","LIGHT_DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightSpecular","LIGHT_SPECULAR","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"EyeVec","EYE_VEC","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Diffuse","DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"SpecExp","SPECULAR_EXP","",SLOT_TYPE_SCALAR,SLOT_IN},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_IN},
+ //light out
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Light","LIGHT","",SLOT_TYPE_VEC,SLOT_OUT},
+ //end
+ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT},
+
+};
+
+void ShaderGraph::get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List<SlotInfo> *r_slots) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ while(iop->name) {
+ if (p_mode==iop->shader_mode && p_type==iop->shader_type) {
+
+ SlotInfo si;
+ si.dir=iop->dir;
+ si.name=iop->name;
+ si.type=iop->slot_type;
+ r_slots->push_back(si);
+ }
+ iop++;
+ }
}
-PropertyInfo ShaderGraph::shader_node_get_type_info(NodeType p_type) {
-
- switch(p_type) {
-
- case NODE_IN: return PropertyInfo(Variant::STRING,"in");
- case NODE_OUT: return PropertyInfo(Variant::STRING,"out");
- case NODE_CONSTANT: return PropertyInfo(Variant::REAL,"const");
- case NODE_PARAMETER: return PropertyInfo(Variant::STRING,"param");
- case NODE_ADD: return PropertyInfo(Variant::NIL,"add");
- case NODE_SUB: return PropertyInfo(Variant::NIL,"sub");
- case NODE_MUL: return PropertyInfo(Variant::NIL,"mul");
- case NODE_DIV: return PropertyInfo(Variant::NIL,"div");
- case NODE_MOD: return PropertyInfo(Variant::NIL,"rem");
- case NODE_SIN: return PropertyInfo(Variant::NIL,"sin");
- case NODE_COS: return PropertyInfo(Variant::NIL,"cos");
- case NODE_TAN: return PropertyInfo(Variant::NIL,"tan");
- case NODE_ARCSIN: return PropertyInfo(Variant::NIL,"arcsin");
- case NODE_ARCCOS: return PropertyInfo(Variant::NIL,"arccos");
- case NODE_ARCTAN: return PropertyInfo(Variant::NIL,"arctan");
- case NODE_POW: return PropertyInfo(Variant::NIL,"pow");
- case NODE_LOG: return PropertyInfo(Variant::NIL,"log");
- case NODE_MAX: return PropertyInfo(Variant::NIL,"max");
- case NODE_MIN: return PropertyInfo(Variant::NIL,"min");
- case NODE_COMPARE: return PropertyInfo(Variant::NIL,"cmp");
- case NODE_TEXTURE: return PropertyInfo(Variant::_RID,"texture1D",PROPERTY_HINT_RESOURCE_TYPE,"Texture");
- case NODE_TIME: return PropertyInfo(Variant::NIL,"time");
- case NODE_NOISE: return PropertyInfo(Variant::NIL,"noise");
- case NODE_PASS: return PropertyInfo(Variant::NIL,"pass");
- case NODE_VEC_IN: return PropertyInfo(Variant::STRING,"vin");
- case NODE_VEC_OUT: return PropertyInfo(Variant::STRING,"vout");
- case NODE_VEC_CONSTANT: return PropertyInfo(Variant::VECTOR3,"vconst");
- case NODE_VEC_PARAMETER: return PropertyInfo(Variant::STRING,"vparam");
- case NODE_VEC_ADD: return PropertyInfo(Variant::NIL,"vadd");
- case NODE_VEC_SUB: return PropertyInfo(Variant::NIL,"vsub");
- case NODE_VEC_MUL: return PropertyInfo(Variant::NIL,"vmul");
- case NODE_VEC_DIV: return PropertyInfo(Variant::NIL,"vdiv");
- case NODE_VEC_MOD: return PropertyInfo(Variant::NIL,"vrem");
- case NODE_VEC_CROSS: return PropertyInfo(Variant::NIL,"cross");
- case NODE_VEC_DOT: return PropertyInfo(Variant::NIL,"dot");
- case NODE_VEC_POW: return PropertyInfo(Variant::NIL,"vpow");
- case NODE_VEC_NORMALIZE: return PropertyInfo(Variant::NIL,"normalize");
- case NODE_VEC_INTERPOLATE: return PropertyInfo(Variant::NIL,"mix");
- case NODE_VEC_SCREEN_TO_UV: return PropertyInfo(Variant::NIL,"scrn2uv");
- case NODE_VEC_TRANSFORM3: return PropertyInfo(Variant::NIL,"xform3");
- case NODE_VEC_TRANSFORM4: return PropertyInfo(Variant::NIL,"xform4");
- case NODE_VEC_COMPARE: return PropertyInfo(Variant::_RID,"vcmp",PROPERTY_HINT_RESOURCE_TYPE,"Texture");
- case NODE_VEC_TEXTURE_2D: return PropertyInfo(Variant::_RID,"texture2D",PROPERTY_HINT_RESOURCE_TYPE,"Texture");
- case NODE_VEC_TEXTURE_CUBE: return PropertyInfo(Variant::NIL,"texcube");
- case NODE_VEC_NOISE: return PropertyInfo(Variant::NIL,"vec_noise");
- case NODE_VEC_0: return PropertyInfo(Variant::NIL,"vec_0");
- case NODE_VEC_1: return PropertyInfo(Variant::NIL,"vec_1");
- case NODE_VEC_2: return PropertyInfo(Variant::NIL,"vec_2");
- case NODE_VEC_BUILD: return PropertyInfo(Variant::NIL,"vbuild");
- case NODE_VEC_PASS: return PropertyInfo(Variant::NIL,"vpass");
- case NODE_COLOR_CONSTANT: return PropertyInfo(Variant::COLOR,"color_const");
- case NODE_COLOR_PARAMETER: return PropertyInfo(Variant::STRING,"color_param");
- case NODE_TEXTURE_PARAMETER: return PropertyInfo(Variant::STRING,"tex1D_param");
- case NODE_TEXTURE_2D_PARAMETER: return PropertyInfo(Variant::STRING,"tex2D_param");
- case NODE_TEXTURE_CUBE_PARAMETER: return PropertyInfo(Variant::STRING,"texcube_param");
- case NODE_TRANSFORM_CONSTANT: return PropertyInfo(Variant::TRANSFORM,"xform_const");
- case NODE_TRANSFORM_PARAMETER: return PropertyInfo(Variant::STRING,"xform_param");
- case NODE_LABEL: return PropertyInfo(Variant::STRING,"label");
-
- default: {}
+const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[]= {
+
+ {NODE_SCALAR_CONST,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, //scalar constant
+ {NODE_VEC_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, //vec3 constant
+ {NODE_RGB_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, //rgb constant (shows a color picker instead)
+ {NODE_XFORM_CONST,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // 4x4 matrix constant
+ {NODE_TIME,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // time in seconds
+ {NODE_SCREEN_TEX,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // screen texture sampler (takes UV) (only usable in fragment shader)
+ {NODE_SCALAR_OP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_VEC_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_VEC_SCALAR_OP,{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_RGB_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_XFORM_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 x mat4
+ {NODE_XFORM_VEC_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 mult (with no-translation option)
+ {NODE_XFORM_VEC_INV_MULT,{SLOT_TYPE_VEC,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 inverse mult (with no-translation option)
+ {NODE_SCALAR_FUNC,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar function (sin,{SLOT_MAX},{SLOT_MAX}}, cos,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_VEC_FUNC,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vector function (normalize,{SLOT_MAX},{SLOT_MAX}}, negate,{SLOT_MAX},{SLOT_MAX}}, reciprocal,{SLOT_MAX},{SLOT_MAX}}, rgb2hsv,{SLOT_MAX},{SLOT_MAX}}, hsv2rgb,{SLOT_MAX},{SLOT_MAX}}, etc,{SLOT_MAX},{SLOT_MAX}}, etc)
+ {NODE_VEC_LEN,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 length
+ {NODE_DOT_PROD,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 . vec3 (dot product -> scalar output)
+ {NODE_VEC_TO_SCALAR,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR}}, // 1 vec3 input,{SLOT_MAX},{SLOT_MAX}}, 3 scalar outputs
+ {NODE_SCALAR_TO_VEC,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // 3 scalar input,{SLOT_MAX},{SLOT_MAX}}, 1 vec3 output
+ {NODE_SCALAR_INTERP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar interpolation (with optional curve)
+ {NODE_VEC_INTERP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 interpolation (with optional curve)
+ {NODE_SCALAR_INPUT,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar uniform (assignable in material)
+ {NODE_VEC_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 uniform (assignable in material)
+ {NODE_RGB_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // color uniform (assignable in material)
+ {NODE_XFORM_INPUT,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 uniform (assignable in material)
+ {NODE_TEXTURE_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // texture input (assignable in material)
+ {NODE_CUBEMAP_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material)
+ {NODE_COMMENT,{SLOT_MAX},{SLOT_MAX}}, // comment
+ {NODE_TYPE_MAX,{SLOT_MAX},{SLOT_MAX}}
+};
+
+int ShaderGraph::get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type) {
+
+ if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int pc=0;
+ while(iop->name) {
+ if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+ if (iop->dir==SLOT_OUT)
+ pc++;
+ }
+ iop++;
+ }
+ return pc;
+ } else if (p_type==NODE_VEC_TO_XFORM){
+ return 4;
+ } else if (p_type==NODE_XFORM_TO_VEC){
+ return 1;
+ } else {
+
+ const NodeSlotInfo*nsi=&node_slot_info[0];
+ while(nsi->type!=NODE_TYPE_MAX) {
+
+ if (nsi->type==p_type) {
+ int pc=0;
+ for(int i=0;i<NodeSlotInfo::MAX_INS;i++) {
+ if (nsi->ins[i]==SLOT_MAX)
+ break;
+ pc++;
+ }
+ return pc;
+ }
+
+ nsi++;
+ }
+
+ return 0;
}
+}
+
+int ShaderGraph::get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type){
+
+ if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int pc=0;
+ while(iop->name) {
+ if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+ if (iop->dir==SLOT_IN)
+ pc++;
+ }
+ iop++;
+ }
+ return pc;
+ } else if (p_type==NODE_VEC_TO_XFORM){
+ return 1;
+ } else if (p_type==NODE_XFORM_TO_VEC){
+ return 4;
+ } else {
+
+ const NodeSlotInfo*nsi=&node_slot_info[0];
+ while(nsi->type!=NODE_TYPE_MAX) {
+
+ if (nsi->type==p_type) {
+ int pc=0;
+ for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) {
+ if (nsi->outs[i]==SLOT_MAX)
+ break;
+ pc++;
+ }
+ return pc;
+ }
+
+ nsi++;
+ }
+
+ return 0;
- ERR_FAIL_V( PropertyInfo(Variant::NIL,"error") );
-}
-int ShaderGraph::shader_get_input_count(NodeType p_type) {
-
- switch(p_type) {
- case NODE_IN: return 0;
- case NODE_OUT: return 1;
- case NODE_CONSTANT: return 0;
- case NODE_PARAMETER: return 0;
- case NODE_ADD: return 2;
- case NODE_SUB: return 2;
- case NODE_MUL: return 2;
- case NODE_DIV: return 2;
- case NODE_MOD: return 2;
- case NODE_SIN: return 1;
- case NODE_COS: return 1;
- case NODE_TAN: return 1;
- case NODE_ARCSIN: return 1;
- case NODE_ARCCOS: return 1;
- case NODE_ARCTAN: return 1;
- case NODE_POW: return 2;
- case NODE_LOG: return 1;
- case NODE_MAX: return 2;
- case NODE_MIN: return 2;
- case NODE_COMPARE: return 4;
- case NODE_TEXTURE: return 1; ///< param 0: texture
- case NODE_TIME: return 1; ///< param 0: interval length
- case NODE_NOISE: return 0;
- case NODE_PASS: return 1;
- case NODE_VEC_IN: return 0; ///< param 0: name
- case NODE_VEC_OUT: return 1; ///< param 0: name
- case NODE_VEC_CONSTANT: return 0; ///< param 0: value
- case NODE_VEC_PARAMETER: return 0; ///< param 0: name
- case NODE_VEC_ADD: return 2;
- case NODE_VEC_SUB: return 2;
- case NODE_VEC_MUL: return 2;
- case NODE_VEC_DIV: return 2;
- case NODE_VEC_MOD: return 2;
- case NODE_VEC_CROSS: return 2;
- case NODE_VEC_DOT: return 2;
- case NODE_VEC_POW: return 2;
- case NODE_VEC_NORMALIZE: return 1;
- case NODE_VEC_INTERPOLATE: return 3;
- case NODE_VEC_SCREEN_TO_UV: return 1;
- case NODE_VEC_TRANSFORM3: return 4;
- case NODE_VEC_TRANSFORM4: return 5;
- case NODE_VEC_COMPARE: return 4;
- case NODE_VEC_TEXTURE_2D: return 1;
- case NODE_VEC_TEXTURE_CUBE: return 1;
- case NODE_VEC_NOISE: return 0;
- case NODE_VEC_0: return 1;
- case NODE_VEC_1: return 1;
- case NODE_VEC_2: return 1;
- case NODE_VEC_BUILD: return 3;
- case NODE_VEC_PASS: return 1;
- case NODE_COLOR_CONSTANT: return 0;
- case NODE_COLOR_PARAMETER: return 0;
- case NODE_TEXTURE_PARAMETER: return 1;
- case NODE_TEXTURE_2D_PARAMETER: return 1;
- case NODE_TEXTURE_CUBE_PARAMETER: return 1;
- case NODE_TRANSFORM_CONSTANT: return 1;
- case NODE_TRANSFORM_PARAMETER: return 1;
- case NODE_LABEL: return 0;
- default: {}
}
- ERR_FAIL_V( 0 );
-}
-int ShaderGraph::shader_get_output_count(NodeType p_type) {
-
- switch(p_type) {
- case NODE_IN: return 1;
- case NODE_OUT: return 0;
- case NODE_CONSTANT: return 1;
- case NODE_PARAMETER: return 1;
- case NODE_ADD: return 1;
- case NODE_SUB: return 1;
- case NODE_MUL: return 1;
- case NODE_DIV: return 1;
- case NODE_MOD: return 1;
- case NODE_SIN: return 1;
- case NODE_COS: return 1;
- case NODE_TAN: return 1;
- case NODE_ARCSIN: return 1;
- case NODE_ARCCOS: return 1;
- case NODE_ARCTAN: return 1;
- case NODE_POW: return 1;
- case NODE_LOG: return 1;
- case NODE_MAX: return 1;
- case NODE_MIN: return 1;
- case NODE_COMPARE: return 2;
- case NODE_TEXTURE: return 3; ///< param 0: texture
- case NODE_TIME: return 1; ///< param 0: interval length
- case NODE_NOISE: return 1;
- case NODE_PASS: return 1;
- case NODE_VEC_IN: return 1; ///< param 0: name
- case NODE_VEC_OUT: return 0; ///< param 0: name
- case NODE_VEC_CONSTANT: return 1; ///< param 0: value
- case NODE_VEC_PARAMETER: return 1; ///< param 0: name
- case NODE_VEC_ADD: return 1;
- case NODE_VEC_SUB: return 1;
- case NODE_VEC_MUL: return 1;
- case NODE_VEC_DIV: return 1;
- case NODE_VEC_MOD: return 1;
- case NODE_VEC_CROSS: return 1;
- case NODE_VEC_DOT: return 1;
- case NODE_VEC_POW: return 1;
- case NODE_VEC_NORMALIZE: return 1;
- case NODE_VEC_INTERPOLATE: return 1;
- case NODE_VEC_SCREEN_TO_UV: return 1;
- case NODE_VEC_TRANSFORM3: return 1;
- case NODE_VEC_TRANSFORM4: return 1;
- case NODE_VEC_COMPARE: return 2;
- case NODE_VEC_TEXTURE_2D: return 3;
- case NODE_VEC_TEXTURE_CUBE: return 3;
- case NODE_VEC_NOISE: return 1;
- case NODE_VEC_0: return 1;
- case NODE_VEC_1: return 1;
- case NODE_VEC_2: return 1;
- case NODE_VEC_BUILD: return 1;
- case NODE_VEC_PASS: return 1;
- case NODE_COLOR_CONSTANT: return 2;
- case NODE_COLOR_PARAMETER: return 2;
- case NODE_TEXTURE_PARAMETER: return 3;
- case NODE_TEXTURE_2D_PARAMETER: return 3;
- case NODE_TEXTURE_CUBE_PARAMETER: return 3;
- case NODE_TRANSFORM_CONSTANT: return 1;
- case NODE_TRANSFORM_PARAMETER: return 1;
- case NODE_LABEL: return 0;
-
- default: {}
+}
+ShaderGraph::SlotType ShaderGraph::get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){
+
+ if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int pc=0;
+ while(iop->name) {
+ if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+ if (iop->dir==SLOT_OUT) {
+ if (pc==p_idx)
+ return iop->slot_type;
+ pc++;
+ }
+ }
+ iop++;
+ }
+ ERR_FAIL_V(SLOT_MAX);
+ } else if (p_type==NODE_VEC_TO_XFORM){
+ return SLOT_TYPE_VEC;
+ } else if (p_type==NODE_XFORM_TO_VEC){
+ return SLOT_TYPE_XFORM;
+ } else {
+
+ const NodeSlotInfo*nsi=&node_slot_info[0];
+ while(nsi->type!=NODE_TYPE_MAX) {
+
+ if (nsi->type==p_type) {
+ for(int i=0;i<NodeSlotInfo::MAX_INS;i++) {
+
+ if (nsi->ins[i]==SLOT_MAX)
+ break;
+ if (i==p_idx)
+ return nsi->ins[i];
+ }
+ }
+
+ nsi++;
+ }
+
+ ERR_FAIL_V(SLOT_MAX);
+
}
- ERR_FAIL_V( 0 );
-
-}
-
-#define RET2(m_a,m_b) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else return "";
-#define RET3(m_a,m_b,m_c) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else return "";
-#define RET4(m_a,m_b,m_c,m_d) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else if (p_idx==3) return m_d; else return "";
-
-#define RET5(m_a,m_b,m_c,m_d,m_e) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else if (p_idx==3) return m_d; else if (p_idx==4) return m_e; else return "";
-
-String ShaderGraph::shader_get_input_name(NodeType p_type,int p_idx) {
-
- switch(p_type) {
-
- case NODE_IN: return "";
- case NODE_OUT: return "out";
- case NODE_CONSTANT: return "";
- case NODE_PARAMETER: return "";
- case NODE_ADD: RET2("a","b");
- case NODE_SUB: RET2("a","b");
- case NODE_MUL: RET2("a","b");
- case NODE_DIV: RET2("a","b");
- case NODE_MOD: RET2("a","b");
- case NODE_SIN: return "rad";
- case NODE_COS: return "rad";
- case NODE_TAN: return "rad";
- case NODE_ARCSIN: return "in";
- case NODE_ARCCOS: return "in";
- case NODE_ARCTAN: return "in";
- case NODE_POW: RET2("in","exp");
- case NODE_LOG: return "in";
- case NODE_MAX: return "in";
- case NODE_MIN: return "in";
- case NODE_COMPARE: RET4("a","b","ret1","ret2");
- case NODE_TEXTURE: return "u";
- case NODE_TIME: return "";
- case NODE_NOISE: return "";
- case NODE_PASS: return "in";
- case NODE_VEC_IN: return "";
- case NODE_VEC_OUT: return "out";
- case NODE_VEC_CONSTANT: return "";
- case NODE_VEC_PARAMETER: return "";
- case NODE_VEC_ADD: RET2("a","b");
- case NODE_VEC_SUB: RET2("a","b");
- case NODE_VEC_MUL: RET2("a","b");
- case NODE_VEC_DIV: RET2("a","b");
- case NODE_VEC_MOD: RET2("a","b");
- case NODE_VEC_CROSS: RET2("a","b");
- case NODE_VEC_DOT: RET2("a","b");
- case NODE_VEC_POW: RET2("a","b");
- case NODE_VEC_NORMALIZE: return "vec";
- case NODE_VEC_INTERPOLATE: RET3("a","b","c");
- case NODE_VEC_SCREEN_TO_UV: return "scr";
- case NODE_VEC_TRANSFORM3: RET4("in","col0","col1","col2");
- case NODE_VEC_TRANSFORM4: RET5("in","col0","col1","col2","col3");
- case NODE_VEC_COMPARE: RET4("a","b","ret1","ret2");
- case NODE_VEC_TEXTURE_2D: return "uv";
- case NODE_VEC_TEXTURE_CUBE: return "uvw";
- case NODE_VEC_NOISE: return "";
- case NODE_VEC_0: return "vec";
- case NODE_VEC_1: return "vec";
- case NODE_VEC_2: return "vec";
- case NODE_VEC_BUILD: RET3("x/r","y/g","z/b");
- case NODE_VEC_PASS: return "in";
- case NODE_COLOR_CONSTANT: return "";
- case NODE_COLOR_PARAMETER: return "";
- case NODE_TEXTURE_PARAMETER: return "u";
- case NODE_TEXTURE_2D_PARAMETER: return "uv";
- case NODE_TEXTURE_CUBE_PARAMETER: return "uvw";
- case NODE_TRANSFORM_CONSTANT: return "in";
- case NODE_TRANSFORM_PARAMETER: return "in";
- case NODE_LABEL: return "";
-
- default: {}
+}
+ShaderGraph::SlotType ShaderGraph::get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){
+
+ if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int pc=0;
+ while(iop->name) {
+ if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+ if (iop->dir==SLOT_IN) {
+ if (pc==p_idx)
+ return iop->slot_type;
+ pc++;
+ }
+ }
+ iop++;
+ }
+ ERR_FAIL_V(SLOT_MAX);
+ } else if (p_type==NODE_VEC_TO_XFORM){
+ return SLOT_TYPE_XFORM;
+ } else if (p_type==NODE_XFORM_TO_VEC){
+ return SLOT_TYPE_VEC;
+ } else {
+
+ const NodeSlotInfo*nsi=&node_slot_info[0];
+ while(nsi->type!=NODE_TYPE_MAX) {
+
+ if (nsi->type==p_type) {
+ for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) {
+ if (nsi->outs[i]==SLOT_MAX)
+ break;
+ if (i==p_idx)
+ return nsi->outs[i];
+ }
+ }
+
+ nsi++;
+ }
+
+ ERR_FAIL_V(SLOT_MAX);
}
+}
+
+
- ERR_FAIL_V("");
-}
-String ShaderGraph::shader_get_output_name(NodeType p_type,int p_idx) {
-
- switch(p_type) {
-
- case NODE_IN: return "in";
- case NODE_OUT: return "";
- case NODE_CONSTANT: return "out";
- case NODE_PARAMETER: return "out";
- case NODE_ADD: return "sum";
- case NODE_SUB: return "dif";
- case NODE_MUL: return "prod";
- case NODE_DIV: return "quot";
- case NODE_MOD: return "rem";
- case NODE_SIN: return "out";
- case NODE_COS: return "out";
- case NODE_TAN: return "out";
- case NODE_ARCSIN: return "rad";
- case NODE_ARCCOS: return "rad";
- case NODE_ARCTAN: return "rad";
- case NODE_POW: RET2("in","exp");
- case NODE_LOG: return "out";
- case NODE_MAX: return "out";
- case NODE_MIN: return "out";
- case NODE_COMPARE: RET2("a/b","a/b");
- case NODE_TEXTURE: RET3("rgb","a","v");
- case NODE_TIME: return "out";
- case NODE_NOISE: return "out";
- case NODE_PASS: return "out";
- case NODE_VEC_IN: return "in";
- case NODE_VEC_OUT: return "";
- case NODE_VEC_CONSTANT: return "out";
- case NODE_VEC_PARAMETER: return "out";
- case NODE_VEC_ADD: return "sum";
- case NODE_VEC_SUB: return "sub";
- case NODE_VEC_MUL: return "mul";
- case NODE_VEC_DIV: return "div";
- case NODE_VEC_MOD: return "rem";
- case NODE_VEC_CROSS: return "crs";
- case NODE_VEC_DOT: return "prod";
- case NODE_VEC_POW: return "out";
- case NODE_VEC_NORMALIZE: return "norm";
- case NODE_VEC_INTERPOLATE: return "out";
- case NODE_VEC_SCREEN_TO_UV: return "uv";
- case NODE_VEC_TRANSFORM3: return "prod";
- case NODE_VEC_TRANSFORM4: return "prod";
- case NODE_VEC_COMPARE: RET2("a/b","a/b");
- case NODE_VEC_TEXTURE_2D: RET3("rgb","a","v");
- case NODE_VEC_TEXTURE_CUBE: RET3("rgb","a","v");
- case NODE_VEC_NOISE: return "out";
- case NODE_VEC_0: return "x/r";
- case NODE_VEC_1: return "y/g";
- case NODE_VEC_2: return "z/b";
- case NODE_VEC_BUILD: return "vec";
- case NODE_VEC_PASS: return "out";
- case NODE_COLOR_CONSTANT: RET2("rgb","a");
- case NODE_COLOR_PARAMETER: RET2("rgb","a");
- case NODE_TEXTURE_PARAMETER: RET3("rgb","a","v");
- case NODE_TEXTURE_2D_PARAMETER: RET3("rgb","a","v");
- case NODE_TEXTURE_CUBE_PARAMETER: RET3("rgb","a","v");
- case NODE_TRANSFORM_CONSTANT: return "out";
- case NODE_TRANSFORM_PARAMETER: return "out";
- case NODE_LABEL: return "";
-
- default: {}
+
+
+void ShaderGraph::_update_shader() {
+
+
+ String code[3];
+
+ List<StringName> names;
+ get_default_texture_param_list(&names);
+
+ for (List<StringName>::Element *E=names.front();E;E=E->next()) {
+ set_default_texture_param(E->get(),Ref<Texture>());
}
- ERR_FAIL_V("");
-}
-bool ShaderGraph::shader_is_input_vector(NodeType p_type,int p_input) {
-
- switch(p_type) {
-
- case NODE_IN: return false;
- case NODE_OUT: return false;
- case NODE_CONSTANT: return false;
- case NODE_PARAMETER: return false;
- case NODE_ADD: return false;
- case NODE_SUB: return false;
- case NODE_MUL: return false;
- case NODE_DIV: return false;
- case NODE_MOD: return false;
- case NODE_SIN: return false;
- case NODE_COS: return false;
- case NODE_TAN: return false;
- case NODE_ARCSIN: return false;
- case NODE_ARCCOS: return false;
- case NODE_ARCTAN: return false;
- case NODE_POW: return false;
- case NODE_LOG: return false;
- case NODE_MAX: return false;
- case NODE_MIN: return false;
- case NODE_COMPARE: return false;
- case NODE_TEXTURE: return false;
- case NODE_TIME: return false;
- case NODE_NOISE: return false;
- case NODE_PASS: return false;
- case NODE_VEC_IN: return false;
- case NODE_VEC_OUT: return true;
- case NODE_VEC_CONSTANT: return false;
- case NODE_VEC_PARAMETER: return false;
- case NODE_VEC_ADD: return true;
- case NODE_VEC_SUB: return true;
- case NODE_VEC_MUL: return true;
- case NODE_VEC_DIV: return true;
- case NODE_VEC_MOD: return true;
- case NODE_VEC_CROSS: return true;
- case NODE_VEC_DOT: return true;
- case NODE_VEC_POW: return (p_input==0)?true:false;
- case NODE_VEC_NORMALIZE: return true;
- case NODE_VEC_INTERPOLATE: return (p_input<2)?true:false;
- case NODE_VEC_SCREEN_TO_UV: return true;
- case NODE_VEC_TRANSFORM3: return true;
- case NODE_VEC_TRANSFORM4: return true;
- case NODE_VEC_COMPARE: return (p_input<2)?false:true;
- case NODE_VEC_TEXTURE_2D: return true;
- case NODE_VEC_TEXTURE_CUBE: return true;
- case NODE_VEC_NOISE: return false;
- case NODE_VEC_0: return true;
- case NODE_VEC_1: return true;
- case NODE_VEC_2: return true;
- case NODE_VEC_BUILD: return false;
- case NODE_VEC_PASS: return true;
- case NODE_COLOR_CONSTANT: return false;
- case NODE_COLOR_PARAMETER: return false;
- case NODE_TEXTURE_PARAMETER: return false;
- case NODE_TEXTURE_2D_PARAMETER: return true;
- case NODE_TEXTURE_CUBE_PARAMETER: return true;
- case NODE_TRANSFORM_CONSTANT: return true;
- case NODE_TRANSFORM_PARAMETER: return true;
- case NODE_LABEL: return false;
-
- default: {}
+
+ for(int i=0;i<3;i++) {
+
+ int idx=0;
+ for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+
+ E->get().sort_order=idx++;
+ }
+ //simple method for graph solving using bubblesort derived algorithm
+ int iters=0;
+ int iter_max=shader[i].node_map.size()*shader[i].node_map.size();
+
+ while(true) {
+ if (iters>iter_max)
+ break;
+
+ int swaps=0;
+ for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+
+ for(Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
+
+ //this is kinda slow, could be sped up
+ Map<int,Node>::Element *G = shader[i].node_map.find(F->get().id);
+ ERR_FAIL_COND(!G);
+ if (G->get().sort_order > E->get().sort_order) {
+
+ SWAP(G->get().sort_order,E->get().sort_order);
+ swaps++;
+ }
+ }
+ }
+
+ iters++;
+ if (swaps==0) {
+ iters=0;
+ break;
+ }
+ }
+
+ if (iters>0) {
+
+ shader[i].error=GRAPH_ERROR_CYCLIC;
+ continue;
+ }
+
+ Vector<Node*> order;
+ order.resize(shader[i].node_map.size());
+
+ for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+
+ order[E->get().sort_order]=&E->get();
+ }
+
+ //generate code for the ordered graph
+ bool failed=false;
+
+ if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
+ code[i]+="vec3 DIFFUSE_OUT=vec3(0,0,0);\n";
+ code[i]+="float ALPHA_OUT=0;\n";
+ }
+
+
+ Map<String,String> inputs_xlate;
+ Map<String,String> input_names_xlate;
+ Set<String> inputs_used;
+
+ for(int j=0;j<order.size();j++) {
+
+ Node *n=order[j];
+ if (n->type==NODE_INPUT) {
+
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int idx=0;
+ while(iop->name) {
+ if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_IN==iop->dir) {
+
+ const char *typestr[4]={"float","vec3","mat4","texture"};
+
+ String vname=("nd"+itos(n->id)+"sl"+itos(idx));
+ inputs_xlate[vname]=String(typestr[iop->slot_type])+" "+vname+"="+iop->variable+";\n";
+ input_names_xlate[vname]=iop->variable;
+ idx++;
+ }
+ iop++;
+ }
+
+ } else if (n->type==NODE_OUTPUT) {
+
+
+ bool use_alpha=false;
+ const InOutParamInfo* iop = &inout_param_info[0];
+ int idx=0;
+ while(iop->name) {
+ if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_OUT==iop->dir) {
+
+ if (n->connections.has(idx)) {
+ String iname=("nd"+itos(n->connections[idx].id)+"sl"+itos(n->connections[idx].slot));
+ if (node_get_type(ShaderType(i),n->connections[idx].id)==NODE_INPUT)
+ inputs_used.insert(iname);
+ code[i]+=String(iop->variable)+"="+iname+String(iop->postfix)+";\n";
+ if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL && String(iop->name)=="DiffuseAlpha")
+ use_alpha=true;
+ }
+ idx++;
+ }
+ iop++;
+ }
+
+ if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
+
+ if (use_alpha) {
+ code[i]+="DIFFUSE_ALPHA=vec4(DIFFUSE_OUT,ALPHA_OUT);\n";
+ } else {
+ code[i]+="DIFFUSE=DIFFUSE_OUT;\n";
+ }
+ }
+
+ } else {
+ Vector<String> inputs;
+ int max = get_node_input_slot_count(get_mode(),ShaderType(i),n->type);
+ for(int k=0;k<max;k++) {
+ if (!n->connections.has(k)) {
+ shader[i].error=GRAPH_ERROR_MISSING_CONNECTIONS;
+ failed=true;
+ break;
+ }
+ String iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot);
+ inputs.push_back(iname);
+ if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) {
+ inputs_used.insert(iname);
+ }
+
+ }
+
+ if (failed)
+ break;
+
+ if (n->type==NODE_TEXTURE_INPUT || n->type==NODE_CUBEMAP_INPUT) {
+
+ set_default_texture_param(n->param1,n->param2);
+ }
+ _add_node_code(ShaderType(i),n,inputs,code[i]);
+ }
+
+ }
+
+ if (failed)
+ continue;
+
+
+ for(Set<String>::Element *E=inputs_used.front();E;E=E->next()) {
+
+ ERR_CONTINUE( !inputs_xlate.has(E->get()));
+ code[i]=inputs_xlate[E->get()]+code[i];
+ String name=input_names_xlate[E->get()];
+
+ if (i==SHADER_TYPE_VERTEX && get_mode()==MODE_MATERIAL) {
+ if (name==("SRC_COLOR"))
+ code[i]="vec3 SRC_COLOR=COLOR.rgb;\n"+code[i];
+ if (name==("SRC_ALPHA"))
+ code[i]="float SRC_ALPHA=COLOR.a;\n"+code[i];
+ if (name==("SRC_UV"))
+ code[i]="vec3 SRC_UV=vec3(UV,0);\n"+code[i];
+ if (name==("SRC_UV2"))
+ code[i]="float SRC_UV2=vec3(UV2,0);\n"+code[i];
+ } else if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
+ if (name==("IN_NORMAL"))
+ code[i]="vec3 IN_NORMAL=NORMAL;\n"+code[i];
+ }
+
+ }
+
+
+
+ shader[i].error=GRAPH_OK;
+
+ }
+
+ bool all_ok=true;
+ for(int i=0;i<3;i++) {
+ if (shader[i].error!=GRAPH_OK)
+ all_ok=false;
}
- ERR_FAIL_V(false);
-}
-bool ShaderGraph::shader_is_output_vector(NodeType p_type,int p_input) {
-
- switch(p_type) {
-
- case NODE_IN: return false;
- case NODE_OUT: return false ;
- case NODE_CONSTANT: return false;
- case NODE_PARAMETER: return false;
- case NODE_ADD: return false;
- case NODE_SUB: return false;
- case NODE_MUL: return false;
- case NODE_DIV: return false;
- case NODE_MOD: return false;
- case NODE_SIN: return false;
- case NODE_COS: return false;
- case NODE_TAN: return false;
- case NODE_ARCSIN: return false;
- case NODE_ARCCOS: return false;
- case NODE_ARCTAN: return false;
- case NODE_POW: return false;
- case NODE_LOG: return false;
- case NODE_MAX: return false;
- case NODE_MIN: return false;
- case NODE_COMPARE: return false;
- case NODE_TEXTURE: return false;
- case NODE_TIME: return false;
- case NODE_NOISE: return false;
- case NODE_PASS: return false;
- case NODE_VEC_IN: return true;
- case NODE_VEC_OUT: return false;
- case NODE_VEC_CONSTANT: return true;
- case NODE_VEC_PARAMETER: return true;
- case NODE_VEC_ADD: return true;
- case NODE_VEC_SUB: return true;
- case NODE_VEC_MUL: return true;
- case NODE_VEC_DIV: return true;
- case NODE_VEC_MOD: return true;
- case NODE_VEC_CROSS: return true;
- case NODE_VEC_DOT: return false;
- case NODE_VEC_POW: return true;
- case NODE_VEC_NORMALIZE: return true;
- case NODE_VEC_INTERPOLATE: return true;
- case NODE_VEC_SCREEN_TO_UV: return true;
- case NODE_VEC_TRANSFORM3: return true;
- case NODE_VEC_TRANSFORM4: return true;
- case NODE_VEC_COMPARE: return true;
- case NODE_VEC_TEXTURE_2D: return (p_input==0)?true:false;
- case NODE_VEC_TEXTURE_CUBE: return (p_input==0)?true:false;
- case NODE_VEC_NOISE: return true;
- case NODE_VEC_0: return false;
- case NODE_VEC_1: return false;
- case NODE_VEC_2: return false;
- case NODE_VEC_BUILD: return true;
- case NODE_VEC_PASS: return true;
- case NODE_COLOR_CONSTANT: return (p_input==0)?true:false;
- case NODE_COLOR_PARAMETER: return (p_input==0)?true:false;
- case NODE_TEXTURE_PARAMETER: return (p_input==0)?true:false;
- case NODE_TEXTURE_2D_PARAMETER: return (p_input==0)?true:false;
- case NODE_TEXTURE_CUBE_PARAMETER: return (p_input==0)?true:false;
- case NODE_TRANSFORM_CONSTANT: return true;
- case NODE_TRANSFORM_PARAMETER: return true;
- case NODE_LABEL: return false;
-
- default: {}
+ if (all_ok) {
+ set_code(code[0],code[1],code[2]);
}
+ //do shader here
- ERR_FAIL_V("");
+ _pending_update_shader=false;
+ emit_signal(SceneStringNames::get_singleton()->updated);
}
-#endif
-#endif
+void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code) {
+
+
+ const char *typestr[4]={"float","vec3","mat4","texture"};
+#define OUTNAME(id,slot) (String(typestr[get_node_output_slot_type(get_mode(),p_type,p_node->type,slot)])+" "+("nd"+itos(id)+"sl"+itos(slot)))
+#define OUTVAR(id,slot) ("nd"+itos(id)+"sl"+itos(slot))
+
+ switch(p_node->type) {
+
+ case NODE_INPUT: {
+
+
+ }break;
+ case NODE_SCALAR_CONST: {
+
+ double scalar = p_node->param1;
+ code+=OUTNAME(p_node->id,0)+"="+rtos(scalar)+";\n";
+ }break;
+ case NODE_VEC_CONST: {
+ Vector3 vec = p_node->param1;
+ code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(vec.x)+","+rtos(vec.y)+","+rtos(vec.z)+");\n";
+ }break;
+ case NODE_RGB_CONST: {
+ Color col = p_node->param1;
+ code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(col.r)+","+rtos(col.g)+","+rtos(col.b)+");\n";
+ code+=OUTNAME(p_node->id,1)+"="+rtos(col.a)+";\n";
+ }break;
+ case NODE_XFORM_CONST: {
+
+ Transform xf = p_node->param1;
+ code+=OUTNAME(p_node->id,0)+"=mat4(\n";
+ code+="\tvec4(vec3("+rtos(xf.basis.get_axis(0).x)+","+rtos(xf.basis.get_axis(0).y)+","+rtos(xf.basis.get_axis(0).z)+"),0),\n";
+ code+="\tvec4(vec3("+rtos(xf.basis.get_axis(1).x)+","+rtos(xf.basis.get_axis(1).y)+","+rtos(xf.basis.get_axis(1).z)+"),0),\n";
+ code+="\tvec4(vec3("+rtos(xf.basis.get_axis(2).x)+","+rtos(xf.basis.get_axis(2).y)+","+rtos(xf.basis.get_axis(2).z)+"),0),\n";
+ code+="\tvec4(vec3("+rtos(xf.origin.x)+","+rtos(xf.origin.y)+","+rtos(xf.origin.z)+"),1)\n";
+ code+=");";
+
+ }break;
+ case NODE_TIME: {
+ code+=OUTNAME(p_node->id,0)+"=TIME;\n";
+ }break;
+ case NODE_SCREEN_TEX: {
+ code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+");\n";
+ }break;
+ case NODE_SCALAR_OP: {
+ int op = p_node->param1;
+ String optxt;
+ switch(op) {
+
+ case SCALAR_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break;
+ case SCALAR_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break;
+ case SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
+ case SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
+ case SCALAR_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case SCALAR_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case SCALAR_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case SCALAR_OP_ATAN2: optxt = "atan2("+p_inputs[0]+","+p_inputs[1]+");"; break;
+
+ }
+ code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";;
+
+ }break;
+ case NODE_VEC_OP: {
+ int op = p_node->param1;
+ String optxt;
+ switch(op) {
+ case VEC_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break;
+ case VEC_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break;
+ case VEC_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
+ case VEC_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
+ case VEC_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case VEC_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case VEC_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case VEC_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ case VEC_OP_CROSS: optxt = "cross("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ }
+ code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
+
+ }break;
+ case NODE_VEC_SCALAR_OP: {
+ int op = p_node->param1;
+ String optxt;
+ switch(op) {
+ case VEC_SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
+ case VEC_SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
+ case VEC_SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
+ }
+ code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
+
+ }break;
+ case NODE_RGB_OP: {
+
+ int op = p_node->param1;
+ static const char*axisn[3]={"x","y","z"};
+ switch(op) {
+ case RGB_OP_SCREEN: {
+
+ code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")*(vec3(1.0)-"+p_inputs[1]+");\n";
+ } break;
+ case RGB_OP_DIFFERENCE: {
+
+ code += OUTNAME(p_node->id,0)+"=abs("+p_inputs[0]+"-"+p_inputs[1]+");\n";
+
+ } break;
+ case RGB_OP_DARKEN: {
+
+ code += OUTNAME(p_node->id,0)+"=min("+p_inputs[0]+","+p_inputs[1]+");\n";
+ } break;
+ case RGB_OP_LIGHTEN: {
+
+ code += OUTNAME(p_node->id,0)+"=max("+p_inputs[0]+","+p_inputs[1]+");\n";
+
+ } break;
+ case RGB_OP_OVERLAY: {
+
+ code += OUTNAME(p_node->id,0)+";\n";
+ for(int i=0;i<3;i++) {
+ code += "{\n";
+ code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+ code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+ code += "\tif (base < 0.5) {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 2.0 * base * blend;\n";
+ code += "\t} else {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n";
+ code += "\t}\n";
+ code += "}\n";
+ }
+
+ } break;
+ case RGB_OP_DODGE: {
+
+ code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+")/(vec3(1.0)-"+p_inputs[1]+");\n";
+
+ } break;
+ case RGB_OP_BURN: {
+
+ code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")/("+p_inputs[1]+");\n";
+ } break;
+ case RGB_OP_SOFT_LIGHT: {
+
+ code += OUTNAME(p_node->id,0)+";\n";
+ for(int i=0;i<3;i++) {
+ code += "{\n";
+ code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+ code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+ code += "\tif (base < 0.5) {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (blend+0.5));\n";
+ code += "\t} else {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-(blend-0.5)));\n";
+ code += "\t}\n";
+ code += "}\n";
+ }
+
+ } break;
+ case RGB_OP_HARD_LIGHT: {
+
+ code += OUTNAME(p_node->id,0)+";\n";
+ for(int i=0;i<3;i++) {
+ code += "{\n";
+ code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+ code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+ code += "\tif (base < 0.5) {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (2*blend));\n";
+ code += "\t} else {\n";
+ code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-2*(blend-0.5)));\n";
+ code += "\t}\n";
+ code += "}\n";
+ }
+
+ } break;
+ }
+ }break;
+ case NODE_XFORM_MULT: {
+
+ code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*"+p_inputs[1]+";\n";
+
+ }break;
+ case NODE_XFORM_VEC_MULT: {
+
+ bool no_translation = p_node->param1;
+ if (no_translation) {
+ code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",0)).xyz;\n";
+ } else {
+ code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",1)).xyz;\n";
+ }
+
+ }break;
+ case NODE_XFORM_VEC_INV_MULT: {
+ bool no_translation = p_node->param1;
+ if (no_translation) {
+ code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",0)).xyz;\n";
+ } else {
+ code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",1)).xyz;\n";
+ }
+ }break;
+ case NODE_SCALAR_FUNC: {
+ static const char*scalar_func_id[SCALAR_MAX_FUNC]={
+ "sin($)",
+ "cos($)",
+ "tan($)",
+ "asin($)",
+ "acos($)",
+ "atan($)",
+ "sinh($)",
+ "cosh($)",
+ "tanh($)",
+ "log($)",
+ "exp($)",
+ "sqrt($)",
+ "abs($)",
+ "sign($)",
+ "floor($)",
+ "round($)",
+ "ceil($)",
+ "frac($)",
+ "min(max($,0),1)",
+ "-($)",
+ };
+
+ int func = p_node->param1;
+ ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
+ code += OUTNAME(p_node->id,0)+"="+String(scalar_func_id[func]).replace("$",p_inputs[0])+";\n";
+
+ } break;
+ case NODE_VEC_FUNC: {
+ static const char*vec_func_id[VEC_MAX_FUNC]={
+ "normalize($)",
+ "max(min($,vec3(1,1,1)),vec3(0,0,0))",
+ "-($)",
+ "1.0/($)",
+ "",
+ "",
+ };
+
+
+ int func = p_node->param1;
+ ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
+ if (func==VEC_FUNC_RGB2HSV) {
+ code += OUTNAME(p_node->id,0)+";\n";
+ code+="{\n";
+ code+="\tvec3 c = "+p_inputs[0]+";\n";
+ code+="\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n";
+ code+="\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n";
+ code+="\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n";
+ code+="\tfloat d = q.x - min(q.w, q.y);\n";
+ code+="\tfloat e = 1.0e-10;\n";
+ code+="\t"+OUTVAR(p_node->id,0)+"=vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n";
+ code+="}\n";
+ } else if (func==VEC_FUNC_HSV2RGB) {
+ code += OUTNAME(p_node->id,0)+";\n";;
+ code+="{\n";
+ code+="\tvec3 c = "+p_inputs[0]+";\n";
+ code+="\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n";
+ code+="\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n";
+ code+="\t"+OUTVAR(p_node->id,0)+"=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n";
+ code+="}\n";
+
+ } else {
+ code += OUTNAME(p_node->id,0)+"="+String(vec_func_id[func]).replace("$",p_inputs[0])+";\n";
+ }
+ }break;
+ case NODE_VEC_LEN: {
+
+ code += OUTNAME(p_node->id,0)+"=length("+p_inputs[1]+");\n";
+
+ }break;
+ case NODE_DOT_PROD: {
+ code += OUTNAME(p_node->id,0)+"=dot("+p_inputs[1]+","+p_inputs[0]+");\n";
+
+ }break;
+ case NODE_VEC_TO_SCALAR: {
+ code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
+ code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
+ code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
+
+ }break;
+ case NODE_SCALAR_TO_VEC: {
+ code += OUTNAME(p_node->id,0)+"=vec3("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+""+");\n";
+
+ }break;
+ case NODE_VEC_TO_XFORM: {
+ code += OUTNAME(p_node->id,0)+"=xform("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+","+","+p_inputs[3]+");\n";
+
+ }break;
+ case NODE_XFORM_TO_VEC: {
+ code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
+ code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
+ code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
+ code += OUTNAME(p_node->id,3)+"="+p_inputs[0]+".o;\n";
+ }break;
+ case NODE_SCALAR_INTERP: {
+
+ code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
+
+ }break;
+ case NODE_VEC_INTERP: {
+ code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
+
+ }break;
+ case NODE_SCALAR_INPUT: {
+ String name = p_node->param1;
+ float dv=p_node->param2;
+ code +="uniform float "+name+"="+rtos(dv)+";\n";
+ code += OUTNAME(p_node->id,0)+"="+name+";\n";
+ }break;
+ case NODE_VEC_INPUT: {
+
+ String name = p_node->param1;
+ Vector3 dv=p_node->param2;
+ code +="uniform float "+name+"=vec3("+rtos(dv.x)+","+rtos(dv.y)+","+rtos(dv.z)+");\n";
+ code += OUTNAME(p_node->id,0)+"="+name+";\n";
+ }break;
+ case NODE_RGB_INPUT: {
+
+ String name = p_node->param1;
+ Color dv= p_node->param2;
+
+ code +="uniform color "+name+"=vec4("+rtos(dv.r)+","+rtos(dv.g)+","+rtos(dv.g)+","+rtos(dv.a)+");\n";
+ code += OUTNAME(p_node->id,0)+"="+name+".rgb;\n";
+
+ }break;
+ case NODE_XFORM_INPUT: {
+
+ String name = p_node->param1;
+ Transform dv= p_node->param2;
+
+ code +="uniform mat4 "+name+"=mat4(\n";
+ code+="\tvec4(vec3("+rtos(dv.basis.get_axis(0).x)+","+rtos(dv.basis.get_axis(0).y)+","+rtos(dv.basis.get_axis(0).z)+"),0),\n";
+ code+="\tvec4(vec3("+rtos(dv.basis.get_axis(1).x)+","+rtos(dv.basis.get_axis(1).y)+","+rtos(dv.basis.get_axis(1).z)+"),0),\n";
+ code+="\tvec4(vec3("+rtos(dv.basis.get_axis(2).x)+","+rtos(dv.basis.get_axis(2).y)+","+rtos(dv.basis.get_axis(2).z)+"),0),\n";
+ code+="\tvec4(vec3("+rtos(dv.origin.x)+","+rtos(dv.origin.y)+","+rtos(dv.origin.z)+"),1)\n";
+ code+=");";
+
+ code += OUTNAME(p_node->id,0)+"="+name+";\n";
+
+ }break;
+ case NODE_TEXTURE_INPUT: {
+ String name = p_node->param1;
+ String rname="rt_read_tex"+itos(p_node->id);
+ code +="uniform texture "+name+";";
+ code +="vec4 "+rname+"=tex("+name+","+p_inputs[0]+".xy);\n";
+ code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
+ code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
+
+ }break;
+ case NODE_CUBEMAP_INPUT: {
+
+ String name = p_node->param1;
+ code +="uniform cubemap "+name+";";
+ String rname="rt_read_tex"+itos(p_node->id);
+ code +="vec4 "+rname+"=texcube("+name+","+p_inputs[0]+".xy);\n";
+ code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
+ code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
+ }break;
+ case NODE_OUTPUT: {
+
+
+ }break;
+ case NODE_COMMENT: {
+
+ }break;
+ case NODE_TYPE_MAX: {
+
+ }
+ }
+}
diff --git a/scene/resources/shader_graph.h b/scene/resources/shader_graph.h
index e20e010c6b..55d09b4c38 100644
--- a/scene/resources/shader_graph.h
+++ b/scene/resources/shader_graph.h
@@ -29,87 +29,54 @@
#ifndef SHADER_GRAPH_H
#define SHADER_GRAPH_H
-#if 0
+
#include "map.h"
#include "scene/resources/shader.h"
-class ShaderGraph : public Resource {
+class ShaderGraph : public Shader {
- OBJ_TYPE( ShaderGraph, Resource );
+ OBJ_TYPE( ShaderGraph, Shader );
RES_BASE_EXTENSION("sgp");
public:
enum NodeType {
- NODE_IN, ///< param 0: name
- NODE_OUT, ///< param 0: name
- NODE_CONSTANT, ///< param 0: value
- NODE_PARAMETER, ///< param 0: name
- NODE_ADD,
- NODE_SUB,
- NODE_MUL,
- NODE_DIV,
- NODE_MOD,
- NODE_SIN,
- NODE_COS,
- NODE_TAN,
- NODE_ARCSIN,
- NODE_ARCCOS,
- NODE_ARCTAN,
- NODE_POW,
- NODE_LOG,
- NODE_MAX,
- NODE_MIN,
- NODE_COMPARE,
- NODE_TEXTURE, ///< param 0: texture
- NODE_TIME, ///< param 0: interval length
- NODE_NOISE,
- NODE_PASS,
- NODE_VEC_IN, ///< param 0: name
- NODE_VEC_OUT, ///< param 0: name
- NODE_VEC_CONSTANT, ///< param 0: value
- NODE_VEC_PARAMETER, ///< param 0: name
- NODE_VEC_ADD,
- NODE_VEC_SUB,
- NODE_VEC_MUL,
- NODE_VEC_DIV,
- NODE_VEC_MOD,
- NODE_VEC_CROSS,
- NODE_VEC_DOT,
- NODE_VEC_POW,
- NODE_VEC_NORMALIZE,
- NODE_VEC_INTERPOLATE,
- NODE_VEC_SCREEN_TO_UV,
- NODE_VEC_TRANSFORM3,
- NODE_VEC_TRANSFORM4,
- NODE_VEC_COMPARE,
- NODE_VEC_TEXTURE_2D,
- NODE_VEC_TEXTURE_CUBE,
- NODE_VEC_NOISE,
- NODE_VEC_0,
- NODE_VEC_1,
- NODE_VEC_2,
- NODE_VEC_BUILD,
- NODE_VEC_PASS,
- NODE_COLOR_CONSTANT,
- NODE_COLOR_PARAMETER,
- NODE_TEXTURE_PARAMETER,
- NODE_TEXTURE_2D_PARAMETER,
- NODE_TEXTURE_CUBE_PARAMETER,
- NODE_TRANSFORM_CONSTANT,
- NODE_TRANSFORM_PARAMETER,
- NODE_LABEL,
+ NODE_INPUT, // all inputs (shader type dependent)
+ NODE_SCALAR_CONST, //scalar constant
+ NODE_VEC_CONST, //vec3 constant
+ NODE_RGB_CONST, //rgb constant (shows a color picker instead)
+ NODE_XFORM_CONST, // 4x4 matrix constant
+ NODE_TIME, // time in seconds
+ NODE_SCREEN_TEX, // screen texture sampler (takes UV) (only usable in fragment shader)
+ NODE_SCALAR_OP, // scalar vs scalar op (mul, add, div, etc)
+ NODE_VEC_OP, // vec3 vs vec3 op (mul,ad,div,crossprod,etc)
+ NODE_VEC_SCALAR_OP, // vec3 vs scalar op (mul, add, div, etc)
+ NODE_RGB_OP, // vec3 vs vec3 rgb op (with scalar amount), like brighten, darken, burn, dodge, multiply, etc.
+ NODE_XFORM_MULT, // mat4 x mat4
+ NODE_XFORM_VEC_MULT, // mat4 x vec3 mult (with no-translation option)
+ NODE_XFORM_VEC_INV_MULT, // mat4 x vec3 inverse mult (with no-translation option)
+ NODE_SCALAR_FUNC, // scalar function (sin, cos, etc)
+ NODE_VEC_FUNC, // vector function (normalize, negate, reciprocal, rgb2hsv, hsv2rgb, etc, etc)
+ NODE_VEC_LEN, // vec3 length
+ NODE_DOT_PROD, // vec3 . vec3 (dot product -> scalar output)
+ NODE_VEC_TO_SCALAR, // 1 vec3 input, 3 scalar outputs
+ NODE_SCALAR_TO_VEC, // 3 scalar input, 1 vec3 output
+ NODE_XFORM_TO_VEC, // 3 vec input, 1 xform output
+ NODE_VEC_TO_XFORM, // 3 vec input, 1 xform output
+ NODE_SCALAR_INTERP, // scalar interpolation (with optional curve)
+ NODE_VEC_INTERP, // vec3 interpolation (with optional curve)
+ NODE_SCALAR_INPUT, // scalar uniform (assignable in material)
+ NODE_VEC_INPUT, // vec3 uniform (assignable in material)
+ NODE_RGB_INPUT, // color uniform (assignable in material)
+ NODE_XFORM_INPUT, // mat4 uniform (assignable in material)
+ NODE_TEXTURE_INPUT, // texture input (assignable in material)
+ NODE_CUBEMAP_INPUT, // cubemap input (assignable in material)
+ NODE_OUTPUT, // output (shader type dependent)
+ NODE_COMMENT, // comment
NODE_TYPE_MAX
};
- enum ShaderType {
- SHADER_VERTEX,
- SHADER_FRAGMENT,
- SHADER_LIGHT
- };
-
-private:
struct Connection {
@@ -119,70 +86,292 @@ private:
int dst_slot;
};
+ enum SlotType {
+
+ SLOT_TYPE_SCALAR,
+ SLOT_TYPE_VEC,
+ SLOT_TYPE_XFORM,
+ SLOT_TYPE_TEXTURE,
+ SLOT_MAX
+ };
+
+ enum ShaderType {
+ SHADER_TYPE_VERTEX,
+ SHADER_TYPE_FRAGMENT,
+ SHADER_TYPE_LIGHT,
+ SHADER_TYPE_MAX
+ };
+
+ enum SlotDir {
+ SLOT_IN,
+ SLOT_OUT
+ };
+
+ enum GraphError {
+ GRAPH_OK,
+ GRAPH_ERROR_CYCLIC,
+ GRAPH_ERROR_MISSING_CONNECTIONS
+ };
+
+private:
+
+ String _find_unique_name(const String& p_base);
+
+ struct SourceSlot {
+
+ int id;
+ int slot;
+ bool operator==(const SourceSlot& p_slot) const {
+ return id==p_slot.id && slot==p_slot.slot;
+ }
+ };
+
struct Node {
- int16_t x,y;
+ Vector2 pos;
NodeType type;
- Variant param;
+ Variant param1;
+ Variant param2;
int id;
mutable int order; // used for sorting
- mutable bool out_valid;
- mutable bool in_valid;
+ int sort_order;
+ Map<int,SourceSlot> connections;
+
};
struct ShaderData {
Map<int,Node> node_map;
- List<Connection> connections;
+ GraphError error;
} shader[3];
- uint64_t version;
-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();
+ struct InOutParamInfo {
+ Mode shader_mode;
+ ShaderType shader_type;
+ const char *name;
+ const char *variable;
+ const char *postfix;
+ SlotType slot_type;
+ SlotDir dir;
+ };
+
+ static const InOutParamInfo inout_param_info[];
+
+ struct NodeSlotInfo {
+
+ enum { MAX_INS=3, MAX_OUTS=3 };
+ NodeType type;
+ const SlotType ins[MAX_INS];
+ const SlotType outs[MAX_OUTS];
+ };
- Array _get_connections_helper() const;
+ static const NodeSlotInfo node_slot_info[];
+
+ bool _pending_update_shader;
+ void _update_shader();
+ void _request_update();
+
+ void _add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code);
+
+ Array _get_node_list(ShaderType p_type) const;
+ Array _get_connections(ShaderType p_type) const;
+
+ void _set_data(const Dictionary& p_data);
+ Dictionary _get_data() const;
+protected:
+
+ static void _bind_methods();
public:
- void node_add(ShaderType p_which, NodeType p_type,int p_id);
+ void node_add(ShaderType p_type, NodeType p_node_type, int p_id);
void node_remove(ShaderType p_which,int p_id);
- void node_set_param(ShaderType p_which, int p_id, const Variant& p_value);
void node_set_pos(ShaderType p_which,int p_id,const Point2& p_pos);
- void node_change_type(ShaderType p_which,int p_id, NodeType p_type);
Point2 node_get_pos(ShaderType p_which,int p_id) const;
void get_node_list(ShaderType p_which,List<int> *p_node_list) const;
NodeType node_get_type(ShaderType p_which,int p_id) const;
- Variant node_get_param(ShaderType p_which,int p_id) const;
- Error connect(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
- bool is_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const;
- void disconnect(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
+ void scalar_const_node_set_value(ShaderType p_which,int p_id,float p_value);
+ float scalar_const_node_get_value(ShaderType p_which,int p_id) const;
- void get_connections(ShaderType p_which,List<Connection> *p_connections) const;
+ void vec_const_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value);
+ Vector3 vec_const_node_get_value(ShaderType p_which,int p_id) const;
- void clear();
+ void rgb_const_node_set_value(ShaderType p_which,int p_id,const Color& p_value);
+ Color rgb_const_node_get_value(ShaderType p_which,int p_id) const;
- uint64_t get_version() const { return version; }
+ void xform_const_node_set_value(ShaderType p_which,int p_id,const Transform& p_value);
+ Transform xform_const_node_get_value(ShaderType p_which,int p_id) const;
- static void get_default_input_nodes(Mode p_type,List<PropertyInfo> *p_inputs);
- static void get_default_output_nodes(Mode p_type,List<PropertyInfo> *p_outputs);
+ void texture_node_set_filter_size(ShaderType p_which,int p_id,int p_size);
+ int texture_node_get_filter_size(ShaderType p_which,int p_id) const;
- static PropertyInfo node_get_type_info(NodeType p_type);
- static int get_input_count(NodeType p_type);
- static int get_output_count(NodeType p_type);
- static String get_input_name(NodeType p_type,int p_input);
- static String get_output_name(NodeType p_type,int p_output);
- static bool is_input_vector(NodeType p_type,int p_input);
- static bool is_output_vector(NodeType p_type,int p_input);
+ void texture_node_set_filter_strength(ShaderType p_which,float p_id,float p_strength);
+ float texture_node_get_filter_strength(ShaderType p_which,float p_id) const;
+ enum ScalarOp {
+ SCALAR_OP_ADD,
+ SCALAR_OP_SUB,
+ SCALAR_OP_MUL,
+ SCALAR_OP_DIV,
+ SCALAR_OP_MOD,
+ SCALAR_OP_POW,
+ SCALAR_OP_MAX,
+ SCALAR_OP_MIN,
+ SCALAR_OP_ATAN2,
+ SCALAR_MAX_OP
+ };
+
+ void scalar_op_node_set_op(ShaderType p_which,float p_id,ScalarOp p_op);
+ ScalarOp scalar_op_node_get_op(ShaderType p_which,float p_id) const;
+
+ enum VecOp {
+ VEC_OP_ADD,
+ VEC_OP_SUB,
+ VEC_OP_MUL,
+ VEC_OP_DIV,
+ VEC_OP_MOD,
+ VEC_OP_POW,
+ VEC_OP_MAX,
+ VEC_OP_MIN,
+ VEC_OP_CROSS,
+ VEC_MAX_OP
+ };
- ShaderGraph();
+ void vec_op_node_set_op(ShaderType p_which,float p_id,VecOp p_op);
+ VecOp vec_op_node_get_op(ShaderType p_which,float p_id) const;
+
+ enum VecScalarOp {
+ VEC_SCALAR_OP_MUL,
+ VEC_SCALAR_OP_DIV,
+ VEC_SCALAR_OP_POW,
+ VEC_SCALAR_MAX_OP
+ };
+
+ void vec_scalar_op_node_set_op(ShaderType p_which,float p_id,VecScalarOp p_op);
+ VecScalarOp vec_scalar_op_node_get_op(ShaderType p_which,float p_id) const;
+
+ enum RGBOp {
+ RGB_OP_SCREEN,
+ RGB_OP_DIFFERENCE,
+ RGB_OP_DARKEN,
+ RGB_OP_LIGHTEN,
+ RGB_OP_OVERLAY,
+ RGB_OP_DODGE,
+ RGB_OP_BURN,
+ RGB_OP_SOFT_LIGHT,
+ RGB_OP_HARD_LIGHT,
+ RGB_MAX_OP
+ };
+
+ void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op);
+ RGBOp rgb_op_node_get_op(ShaderType p_which,float p_id) const;
+
+ void xform_vec_mult_node_set_no_translation(ShaderType p_which,int p_id,bool p_no_translation);
+ bool xform_vec_mult_node_get_no_translation(ShaderType p_which,int p_id) const;
+
+ enum ScalarFunc {
+ SCALAR_FUNC_SIN,
+ SCALAR_FUNC_COS,
+ SCALAR_FUNC_TAN,
+ SCALAR_FUNC_ASIN,
+ SCALAR_FUNC_ACOS,
+ SCALAR_FUNC_ATAN,
+ SCALAR_FUNC_SINH,
+ SCALAR_FUNC_COSH,
+ SCALAR_FUNC_TANH,
+ SCALAR_FUNC_LOG,
+ SCALAR_FUNC_EXP,
+ SCALAR_FUNC_SQRT,
+ SCALAR_FUNC_ABS,
+ SCALAR_FUNC_SIGN,
+ SCALAR_FUNC_FLOOR,
+ SCALAR_FUNC_ROUND,
+ SCALAR_FUNC_CEIL,
+ SCALAR_FUNC_FRAC,
+ SCALAR_FUNC_SATURATE,
+ SCALAR_FUNC_NEGATE,
+ SCALAR_MAX_FUNC
+ };
+
+ void scalar_func_node_set_function(ShaderType p_which,int p_id,ScalarFunc p_func);
+ ScalarFunc scalar_func_node_get_function(ShaderType p_which,int p_id) const;
+
+ enum VecFunc {
+ VEC_FUNC_NORMALIZE,
+ VEC_FUNC_SATURATE,
+ VEC_FUNC_NEGATE,
+ VEC_FUNC_RECIPROCAL,
+ VEC_FUNC_RGB2HSV,
+ VEC_FUNC_HSV2RGB,
+ VEC_MAX_FUNC
+ };
+
+ void vec_func_node_set_function(ShaderType p_which,int p_id,VecFunc p_func);
+ VecFunc vec_func_node_get_function(ShaderType p_which,int p_id) const;
+
+ void input_node_set_name(ShaderType p_which,int p_id,const String& p_name);
+ String input_node_get_name(ShaderType p_which,int p_id);
+
+ void scalar_input_node_set_value(ShaderType p_which,int p_id,float p_value);
+ float scalar_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void vec_input_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value);
+ Vector3 vec_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void rgb_input_node_set_value(ShaderType p_which,int p_id,const Color& p_value);
+ Color rgb_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void xform_input_node_set_value(ShaderType p_which,int p_id,const Transform& p_value);
+ Transform xform_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void texture_input_node_set_value(ShaderType p_which,int p_id,const Ref<Texture>& p_texture);
+ Ref<Texture> texture_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void cubemap_input_node_set_value(ShaderType p_which,int p_id,const Ref<CubeMap>& p_cubemap);
+ Ref<CubeMap> cubemap_input_node_get_value(ShaderType p_which,int p_id) const;
+
+ void comment_node_set_text(ShaderType p_which,int p_id,const String& p_comment);
+ String comment_node_get_text(ShaderType p_which,int p_id) const;
+
+ Error connect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
+ bool is_node_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const;
+ void disconnect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
+
+ void get_node_connections(ShaderType p_which,List<Connection> *p_connections) const;
+
+ void clear(ShaderType p_which);
+
+ Variant node_get_state(ShaderType p_type, int p_node) const;
+ void node_set_state(ShaderType p_type, int p_id, const Variant& p_state);
+
+ GraphError get_graph_error(ShaderType p_type) const;
+
+ static int get_type_input_count(NodeType p_type);
+ static int get_type_output_count(NodeType p_type);
+ static SlotType get_type_input_type(NodeType p_type,int p_idx);
+ static SlotType get_type_output_type(NodeType p_type,int p_idx);
+ static bool is_type_valid(Mode p_mode,ShaderType p_type);
+
+
+ struct SlotInfo {
+ String name;
+ SlotType type;
+ SlotDir dir;
+ };
+
+ static void get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List<SlotInfo> *r_slots);
+
+ static int get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type);
+ static int get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type);
+ static SlotType get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx);
+ static SlotType get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx);
+
+
+ ShaderGraph(Mode p_mode);
~ShaderGraph();
};
@@ -192,6 +381,28 @@ public:
VARIANT_ENUM_CAST( ShaderGraph::NodeType );
+VARIANT_ENUM_CAST( ShaderGraph::ShaderType );
+VARIANT_ENUM_CAST( ShaderGraph::SlotType );
+VARIANT_ENUM_CAST( ShaderGraph::ScalarOp );
+VARIANT_ENUM_CAST( ShaderGraph::VecOp );
+VARIANT_ENUM_CAST( ShaderGraph::VecScalarOp );
+VARIANT_ENUM_CAST( ShaderGraph::RGBOp );
+VARIANT_ENUM_CAST( ShaderGraph::ScalarFunc );
+VARIANT_ENUM_CAST( ShaderGraph::VecFunc );
+VARIANT_ENUM_CAST( ShaderGraph::GraphError );
+
+
+class MaterialShaderGraph : public ShaderGraph {
+
+ OBJ_TYPE( MaterialShaderGraph, ShaderGraph );
+ RES_BASE_EXTENSION("sgp");
+
+public:
+
+
+ MaterialShaderGraph() : ShaderGraph(MODE_MATERIAL) {
+
+ }
+};
-#endif
#endif // SHADER_GRAPH_H
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index ca891920da..738b642d43 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -109,7 +109,7 @@ void Shape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("collide","local_xform","with_shape:Shape2D","shape_xform"),&Shape2D::collide);
ObjectTypeDB::bind_method(_MD("collide_with_motion","local_xform","local_motion","with_shape:Shape2D","shape_xform","shape_motion"),&Shape2D::collide_with_motion);
ObjectTypeDB::bind_method(_MD("collide_and_get_contacts:var","local_xform","with_shape:Shape2D","shape_xform"),&Shape2D::collide_and_get_contacts);
- ObjectTypeDB::bind_method(_MD("collide_with_motion_and_get_contacts:var","local_xform","local_motion","with_shape:Shape2D","shape_xform","shape_motion"),&Shape2D::collide_and_get_contacts);
+ ObjectTypeDB::bind_method(_MD("collide_with_motion_and_get_contacts:var","local_xform","local_motion","with_shape:Shape2D","shape_xform","shape_motion"),&Shape2D::collide_with_motion_and_get_contacts);
ADD_PROPERTY( PropertyInfo(Variant::REAL,"custom_solver_bias",PROPERTY_HINT_RANGE,"0,1,0.001"),_SCS("set_custom_solver_bias"),_SCS("get_custom_solver_bias"));
}
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 2856101674..113fd8209d 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -105,7 +105,7 @@ void SurfaceTool::add_vertex( const Vector3& p_vertex) {
vtx.weights=last_weights;
vtx.bones=last_bones;
vtx.tangent=last_tangent.normal;
- vtx.binormal=last_tangent.normal.cross(last_normal).normalized() * last_tangent.d;
+ vtx.binormal=last_normal.cross(last_tangent.normal).normalized() * last_tangent.d;
vertex_array.push_back(vtx);
first=false;
format|=Mesh::ARRAY_FORMAT_VERTEX;
@@ -299,7 +299,9 @@ Ref<Mesh> SurfaceTool::commit(const Ref<Mesh>& p_existing) {
w[idx+0]=v.tangent.x;
w[idx+1]=v.tangent.y;
w[idx+2]=v.tangent.z;
- float d = v.binormal.dot(v.normal.cross(v.tangent));
+
+ //float d = v.tangent.dot(v.binormal,v.normal);
+ float d = v.binormal.dot( v.normal.cross(v.tangent));
w[idx+3]=d<0 ? -1 : 1;
}
@@ -565,6 +567,7 @@ void SurfaceTool::create_from(const Ref<Mesh>& p_existing, int p_surface) {
clear();
primitive=p_existing->surface_get_primitive_type(p_surface);
_create_list(p_existing,p_surface,&vertex_array,&index_array,format);
+ material=p_existing->surface_get_material(p_surface);
}
@@ -611,165 +614,96 @@ void SurfaceTool::append_from(const Ref<Mesh>& p_existing, int p_surface,const T
}
+//mikktspace callbacks
+int SurfaceTool::mikktGetNumFaces(const SMikkTSpaceContext * pContext) {
-void SurfaceTool::generate_tangents() {
-
- ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV));
- ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL));
-
-
- if (index_array.size()) {
-
- Vector<List<Vertex>::Element*> vtx;
- vtx.resize(vertex_array.size());
- int idx=0;
- for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
- vtx[idx++]=E;
- E->get().binormal=Vector3();
- E->get().tangent=Vector3();
- }
-
- for (List<int>::Element *E=index_array.front();E;) {
-
- int i[3];
- i[0]=E->get();
- E=E->next();
- ERR_FAIL_COND(!E);
- i[1]=E->get();
- E=E->next();
- ERR_FAIL_COND(!E);
- i[2]=E->get();
- E=E->next();
- ERR_FAIL_COND(!E);
-
-
- Vector3 v1 = vtx[ i[0] ]->get().vertex;
- Vector3 v2 = vtx[ i[1] ]->get().vertex;
- Vector3 v3 = vtx[ i[2] ]->get().vertex;
-
- Vector2 w1 = vtx[ i[0] ]->get().uv;
- Vector2 w2 = vtx[ i[1] ]->get().uv;
- Vector2 w3 = vtx[ i[2] ]->get().uv;
-
-
- float x1 = v2.x - v1.x;
- float x2 = v3.x - v1.x;
- float y1 = v2.y - v1.y;
- float y2 = v3.y - v1.y;
- float z1 = v2.z - v1.z;
- float z2 = v3.z - v1.z;
-
- float s1 = w2.x - w1.x;
- float s2 = w3.x - w1.x;
- float t1 = w2.y - w1.y;
- float t2 = w3.y - w1.y;
-
- float r = (s1 * t2 - s2 * t1);
-
- Vector3 binormal,tangent;
-
- if (r==0) {
- binormal=Vector3(0,0,0);
- tangent=Vector3(0,0,0);
- } else {
- tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
- (t2 * z1 - t1 * z2) * r);
- binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
- (s1 * z2 - s2 * z1) * r);
- }
-
- tangent.normalize();
- binormal.normalize();
- Vector3 normal=Plane( v1, v2, v3 ).normal;
-
- Vector3 tangentp = tangent - normal * normal.dot( tangent );
- Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal));
-
- tangentp.normalize();
- binormalp.normalize();
+ Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+ return varr.size()/3;
+}
+int SurfaceTool::mikktGetNumVerticesOfFace(const SMikkTSpaceContext * pContext, const int iFace){
+ return 3; //always 3
+}
+void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert){
- for (int j=0;j<3;j++) {
- vtx[ i[j] ]->get().binormal+=binormalp;
- vtx[ i[j] ]->get().tangent+=tangentp;
+ Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+ Vector3 v = varr[iFace*3+iVert]->get().vertex;
+ fvPosOut[0]=v.x;
+ fvPosOut[1]=v.y;
+ fvPosOut[2]=v.z;
- }
- }
- for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
- E->get().binormal.normalize();
- E->get().tangent.normalize();
- }
+}
+void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert){
- } else {
+ Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+ Vector3 v = varr[iFace*3+iVert]->get().normal;
+ fvNormOut[0]=v.x;
+ fvNormOut[1]=v.y;
+ fvNormOut[2]=v.z;
- for (List<Vertex>::Element *E=vertex_array.front();E;) {
+}
+void SurfaceTool::mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert){
- List< Vertex >::Element *v[3];
- v[0]=E;
- v[1]=v[0]->next();
- ERR_FAIL_COND(!v[1]);
- v[2]=v[1]->next();
- ERR_FAIL_COND(!v[2]);
- E=v[2]->next();
+ Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+ Vector2 v = varr[iFace*3+iVert]->get().uv;
+ fvTexcOut[0]=v.x;
+ fvTexcOut[1]=v.y;
+ //fvTexcOut[1]=1.0-v.y;
- Vector3 v1 = v[0]->get().vertex;
- Vector3 v2 = v[1]->get().vertex;
- Vector3 v3 = v[2]->get().vertex;
+}
+void SurfaceTool::mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert){
- Vector2 w1 = v[0]->get().uv;
- Vector2 w2 = v[1]->get().uv;
- Vector2 w3 = v[2]->get().uv;
+ Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+ Vertex &vtx = varr[iFace*3+iVert]->get();
+ vtx.tangent = Vector3(fvTangent[0],fvTangent[1],fvTangent[2]);
+ vtx.binormal = vtx.normal.cross(vtx.tangent) * fSign;
+}
- float x1 = v2.x - v1.x;
- float x2 = v3.x - v1.x;
- float y1 = v2.y - v1.y;
- float y2 = v3.y - v1.y;
- float z1 = v2.z - v1.z;
- float z2 = v3.z - v1.z;
- float s1 = w2.x - w1.x;
- float s2 = w3.x - w1.x;
- float t1 = w2.y - w1.y;
- float t2 = w3.y - w1.y;
+void SurfaceTool::generate_tangents() {
- float r = (s1 * t2 - s2 * t1);
+ ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV));
+ ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL));
- Vector3 binormal,tangent;
+ bool indexed = index_array.size()>0;
+ if (indexed)
+ deindex();
- if (r==0) {
- binormal=Vector3(0,0,0);
- tangent=Vector3(0,0,0);
- } else {
- tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
- (t2 * z1 - t1 * z2) * r);
- binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
- (s1 * z2 - s2 * z1) * r);
- }
- tangent.normalize();
- binormal.normalize();
- Vector3 normal=Plane( v1, v2, v3 ).normal;
+ SMikkTSpaceInterface mkif;
+ mkif.m_getNormal=mikktGetNormal;
+ mkif.m_getNumFaces=mikktGetNumFaces;
+ mkif.m_getNumVerticesOfFace=mikktGetNumVerticesOfFace;
+ mkif.m_getPosition=mikktGetPosition;
+ mkif.m_getTexCoord=mikktGetTexCoord;
+ mkif.m_setTSpaceBasic=mikktSetTSpaceBasic;
+ mkif.m_setTSpace=NULL;
- Vector3 tangentp = tangent - normal * normal.dot( tangent );
- Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal));
+ SMikkTSpaceContext msc;
+ msc.m_pInterface=&mkif;
- tangentp.normalize();
- binormalp.normalize();
+ Vector<List<Vertex>::Element*> vtx;
+ vtx.resize(vertex_array.size());
+ int idx=0;
+ for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
+ vtx[idx++]=E;
+ E->get().binormal=Vector3();
+ E->get().tangent=Vector3();
+ }
+ msc.m_pUserData=&vtx;
+ bool res = genTangSpaceDefault(&msc);
- for (int j=0;j<3;j++) {
- v[j]->get().binormal=binormalp;
- v[j]->get().tangent=tangentp;
+ ERR_FAIL_COND(!res);
+ format|=Mesh::ARRAY_FORMAT_TANGENT;
- }
- }
- }
+ if (indexed)
+ index();
- format|=Mesh::ARRAY_FORMAT_TANGENT;
}
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index fe82d3a4ce..fc5940145b 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -30,7 +30,7 @@
#define SURFACE_TOOL_H
#include "scene/resources/mesh.h"
-
+#include "mikktspace.h"
class SurfaceTool : public Reference {
@@ -82,6 +82,14 @@ private:
void _create_list(const Ref<Mesh>& p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index,int &lformat);
+
+ //mikktspace callbacks
+ static int mikktGetNumFaces(const SMikkTSpaceContext * pContext);
+ static int mikktGetNumVerticesOfFace(const SMikkTSpaceContext * pContext, const int iFace);
+ static void mikktGetPosition(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert);
+ static void mikktGetNormal(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert);
+ static void mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert);
+ static void mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert);
protected:
static void _bind_methods();
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 5b31ba1f1b..dae055890b 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -79,6 +79,8 @@ void Texture::_bind_methods() {
BIND_CONSTANT( FLAG_FILTER );
BIND_CONSTANT( FLAG_VIDEO_SURFACE );
BIND_CONSTANT( FLAGS_DEFAULT );
+ BIND_CONSTANT( FLAG_ANISOTROPIC_FILTER );
+ BIND_CONSTANT( FLAG_CONVERT_TO_LINEAR );
}
@@ -179,7 +181,7 @@ void ImageTexture::_get_property_list( List<PropertyInfo> *p_list) const {
- p_list->push_back( PropertyInfo( Variant::INT, "flags", PROPERTY_HINT_FLAGS,"Mipmaps,Repeat,Filter") );
+ p_list->push_back( PropertyInfo( Variant::INT, "flags", PROPERTY_HINT_FLAGS,"Mipmaps,Repeat,Filter,Anisotropic,sRGB") );
p_list->push_back( PropertyInfo( Variant::IMAGE, "image", img_hint,String::num(lossy_storage_quality)) );
p_list->push_back( PropertyInfo( Variant::VECTOR2, "size",PROPERTY_HINT_NONE, ""));
p_list->push_back( PropertyInfo( Variant::INT, "storage", PROPERTY_HINT_ENUM,"Uncompressed,Compress Lossy,Compress Lossless"));
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 86ff246498..4bb2f6d979 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -52,6 +52,8 @@ public:
FLAG_MIPMAPS=VisualServer::TEXTURE_FLAG_MIPMAPS,
FLAG_REPEAT=VisualServer::TEXTURE_FLAG_REPEAT,
FLAG_FILTER=VisualServer::TEXTURE_FLAG_FILTER,
+ FLAG_ANISOTROPIC_FILTER=VisualServer::TEXTURE_FLAG_ANISOTROPIC_FILTER,
+ FLAG_CONVERT_TO_LINEAR=VisualServer::TEXTURE_FLAG_CONVERT_TO_LINEAR,
FLAG_VIDEO_SURFACE=VisualServer::TEXTURE_FLAG_VIDEO_SURFACE,
FLAGS_DEFAULT=FLAG_MIPMAPS|FLAG_REPEAT|FLAG_FILTER,
};
diff --git a/scene/resources/video_stream.cpp b/scene/resources/video_stream.cpp
index fffe1ad7fa..2bbae37510 100644
--- a/scene/resources/video_stream.cpp
+++ b/scene/resources/video_stream.cpp
@@ -33,6 +33,7 @@ void VideoStream::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_pending_frame_count"),&VideoStream::get_pending_frame_count);
ObjectTypeDB::bind_method(_MD("pop_frame"),&VideoStream::pop_frame);
ObjectTypeDB::bind_method(_MD("peek_frame"),&VideoStream::peek_frame);
+ ObjectTypeDB::bind_method(_MD("set_audio_track","idx"),&VideoStream::set_audio_track);
};
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index eafacce159..18f0cc3d05 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -30,7 +30,7 @@
#define VIDEO_STREAM_H
#include "audio_stream_resampled.h"
-
+#include "scene/resources/texture.h"
class VideoStream : public Resource {
@@ -59,9 +59,11 @@ public:
virtual void seek_pos(float p_time)=0;
virtual int get_pending_frame_count() const=0;
- virtual Image pop_frame()=0;
+ virtual void pop_frame(Ref<ImageTexture> p_tex)=0;
virtual Image peek_frame() const=0;
+ virtual void set_audio_track(int p_idx) =0;
+
virtual void update(float p_time)=0;
VideoStream();
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index aee7ddde00..0dd6a3d5e7 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -364,12 +364,12 @@ World2D::World2D() {
Physics2DServer::get_singleton()->space_set_active(space,true);
Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY,GLOBAL_DEF("physics_2d/default_gravity",98));
Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY_VECTOR,GLOBAL_DEF("physics_2d/default_gravity_vector",Vector2(0,1)));
- Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_DENSITY,GLOBAL_DEF("physics_2d/default_density",0.1));
+ Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_LINEAR_DAMP,GLOBAL_DEF("physics_2d/default_density",0.1));
+ Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_ANGULAR_DAMP,GLOBAL_DEF("physics_2d/default_density",1));
Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS,1.0);
Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONTACT_MAX_SEPARATION,1.5);
Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION,0.3);
Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD,2);
- Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO,20);
Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,0.2);
indexer = memnew( SpatialIndexer2D );