@@ -711,6 +711,30 @@ static bool shader_filter_from_file_changed(obs_properties_t *props,
711711 return true;
712712}
713713
714+ static bool shader_filter_text_changed (obs_properties_t * props ,
715+ obs_property_t * p , obs_data_t * settings )
716+ {
717+ UNUSED_PARAMETER (p );
718+ struct shader_filter_data * filter = obs_properties_get_param (props );
719+ if (!filter )
720+ return false;
721+
722+ const char * shader_text = obs_data_get_string (settings , "shader_text" );
723+ bool can_convert = strstr (shader_text , "void mainImage( out vec4" ) ||
724+ strstr (shader_text , "void mainImage(out vec4" ) ||
725+ strstr (shader_text , "void main()" );
726+ obs_property_t * shader_convert =
727+ obs_properties_get (props , "shader_convert" );
728+ bool visible =
729+ obs_property_visible (obs_properties_get (props , "shader_text" ));
730+ if (obs_property_visible (shader_convert ) != (can_convert && visible )) {
731+ obs_property_set_visible (shader_convert ,
732+ can_convert && visible );
733+ return true;
734+ }
735+ return false;
736+ }
737+
714738static bool shader_filter_file_name_changed (obs_properties_t * props ,
715739 obs_property_t * p ,
716740 obs_data_t * settings )
@@ -719,8 +743,9 @@ static bool shader_filter_file_name_changed(obs_properties_t *props,
719743 const char * new_file_name =
720744 obs_data_get_string (settings , obs_property_name (p ));
721745
722- if (dstr_is_empty (& filter -> last_path ) ||
723- dstr_cmp (& filter -> last_path , new_file_name ) != 0 ) {
746+ if ((dstr_is_empty (& filter -> last_path ) && strlen (new_file_name )) ||
747+ (filter -> last_path .array &&
748+ dstr_cmp (& filter -> last_path , new_file_name ) != 0 )) {
724749 filter -> reload_effect = true;
725750 dstr_copy (& filter -> last_path , new_file_name );
726751 size_t l = strlen (new_file_name );
@@ -782,6 +807,305 @@ static bool add_source_to_list(void *data, obs_source_t *source)
782807 return true;
783808}
784809
810+ static void convert_float_init (struct dstr * effect_text , char * name , int count )
811+ {
812+ const size_t len = strlen (name );
813+
814+ char * pos = strstr (effect_text -> array , name );
815+ while (pos ) {
816+ size_t diff = pos - effect_text -> array ;
817+ char * begin = strstr (pos + len , "(" );
818+ char * end = strstr (pos + len , ")" );
819+ char * comma = strstr (pos + len , "," );
820+ if (end && (!begin || end < begin ) && (!comma || end < comma )) {
821+ bool only_numbers = true;
822+ for (char * ch = pos + len ; ch < end ; ch ++ ) {
823+ if ((* ch < '0' || * ch > '9' ) && * ch != '.' &&
824+ * ch != ' ' ) {
825+ only_numbers = false;
826+ break ;
827+ }
828+ }
829+ if (only_numbers ) {
830+ //only 1 simple arg in the float4
831+ struct dstr found = {0 };
832+ dstr_init (& found );
833+ dstr_ncat (& found , pos , end - pos + 1 );
834+
835+ struct dstr replacement = {0 };
836+ dstr_init_copy (& replacement , name );
837+ dstr_ncat (& replacement , pos + len ,
838+ end - (pos + len ));
839+ for (int i = 1 ; i < count ; i ++ ) {
840+ dstr_cat (& replacement , "," );
841+ dstr_ncat (& replacement , pos + len ,
842+ end - (pos + len ));
843+ }
844+ dstr_cat (& replacement , ")" );
845+
846+ dstr_replace (effect_text , found .array ,
847+ replacement .array );
848+
849+ dstr_free (& replacement );
850+ dstr_free (& found );
851+ }
852+ }
853+ pos = strstr (effect_text -> array + diff + len , name );
854+ }
855+ }
856+
857+ static bool shader_filter_convert (obs_properties_t * props ,
858+ obs_property_t * property , void * data )
859+ {
860+ UNUSED_PARAMETER (props );
861+ if (!data )
862+ return false;
863+ struct shader_filter_data * filter = data ;
864+ obs_data_t * settings = obs_source_get_settings (filter -> context );
865+ if (!settings )
866+ return false;
867+ struct dstr effect_text = {0 };
868+ dstr_init_copy (& effect_text ,
869+ obs_data_get_string (settings , "shader_text" ));
870+
871+ size_t start_diff = 24 ;
872+ bool main_no_args = false;
873+ char * main_pos = strstr (effect_text .array , "void mainImage(out vec4" );
874+ if (!main_pos ) {
875+ main_pos =
876+ strstr (effect_text .array , "void mainImage( out vec4" );
877+ start_diff ++ ;
878+ }
879+ if (!main_pos ) {
880+ main_pos = strstr (effect_text .array , "void main()" );
881+ if (main_pos )
882+ main_no_args = true;
883+ }
884+ if (!main_pos ) {
885+ dstr_free (& effect_text );
886+ obs_data_release (settings );
887+ return false;
888+ }
889+ bool uv = false;
890+ struct dstr return_color_name = {0 };
891+ struct dstr coord_name = {0 };
892+ if (main_no_args ) {
893+
894+ dstr_replace (& effect_text , "void main()" ,
895+ "float4 mainImage(VertData v_in) : TARGET" );
896+
897+ if (strstr (effect_text .array , "fNormal" )) {
898+ uv = true;
899+ dstr_init_copy (& coord_name , "fNormal" );
900+ } else {
901+ uv = false;
902+ dstr_init_copy (& coord_name , "gl_FragCoord" );
903+ }
904+
905+ char * out_start = strstr (effect_text .array , "out vec4" );
906+ if (out_start ) {
907+ char * start = out_start + 9 ;
908+ while (* start == ' ' )
909+ start ++ ;
910+ char * end = start ;
911+ while (* end != ' ' && * end != ',' && * end != '(' &&
912+ * end != ')' && * end != ';' && * end != 0 )
913+ end ++ ;
914+ dstr_ncat (& return_color_name , start , end - start );
915+ while (* end == ' ' )
916+ end ++ ;
917+ if (* end == ';' )
918+ dstr_remove (& effect_text ,
919+ out_start - effect_text .array ,
920+ (end + 1 ) - out_start );
921+ } else {
922+ dstr_init_copy (& return_color_name , "gl_FragColor" );
923+ }
924+ } else {
925+
926+ char * start = main_pos + start_diff ;
927+ while (* start == ' ' )
928+ start ++ ;
929+ char * end = start ;
930+ while (* end != ' ' && * end != ',' && * end != ')' && * end != 0 )
931+ end ++ ;
932+
933+ dstr_ncat (& return_color_name , start , end - start );
934+
935+ start = strstr (end , "," );
936+ if (!start ) {
937+ dstr_free (& effect_text );
938+ dstr_free (& return_color_name );
939+ obs_data_release (settings );
940+ return false;
941+ }
942+ start ++ ;
943+ while (* start == ' ' )
944+ start ++ ;
945+ if (* start == 'i' && * (start + 1 ) == 'n' && * (start + 2 ) == ' ' )
946+ start += 3 ;
947+ while (* start == ' ' )
948+ start ++ ;
949+ if (* start == 'v' && * (start + 1 ) == 'e' &&
950+ * (start + 2 ) == 'c' && * (start + 3 ) == '2' &&
951+ * (start + 4 ) == ' ' )
952+ start += 5 ;
953+ while (* start == ' ' )
954+ start ++ ;
955+
956+ end = start ;
957+ while (* end != ' ' && * end != ',' && * end != ')' && * end != 0 )
958+ end ++ ;
959+
960+ dstr_ncat (& coord_name , start , end - start );
961+
962+ while (* end != ')' && * end != 0 )
963+ end ++ ;
964+ size_t idx = main_pos - effect_text .array ;
965+ dstr_remove (& effect_text , idx , end - main_pos + 1 );
966+ dstr_insert (& effect_text , idx ,
967+ "float4 mainImage(VertData v_in) : TARGET" );
968+ }
969+
970+ if (dstr_cmp (& coord_name , "fragCoord" ) != 0 ) {
971+ dstr_replace (& effect_text , coord_name .array , "fragCoord" );
972+ }
973+ dstr_free (& coord_name );
974+
975+ dstr_replace (& effect_text , "varying vec3" , "//varying vec3" );
976+ dstr_replace (& effect_text , "precision highp float;" ,
977+ "//precision highp float;" );
978+ if (uv ) {
979+ dstr_replace (& effect_text , "fragCoord.xy" , "v_in.uv" );
980+ dstr_replace (& effect_text , "fragCoord" , "float3(v_in.uv,0.0)" );
981+ } else {
982+
983+ dstr_replace (& effect_text , "fragCoord.xy / iResolution.xy" ,
984+ "v_in.uv" );
985+ dstr_replace (& effect_text , "fragCoord / iResolution.xy" ,
986+ "v_in.uv" );
987+ dstr_replace (& effect_text , "fragCoord" , "(v_in.uv * uv_size)" );
988+ }
989+ dstr_replace (& effect_text , "u_resolution" , "uv_size" );
990+ dstr_replace (& effect_text , "uResolution" , "uv_size" );
991+ dstr_replace (& effect_text , "iResolution.xy" , "uv_size" );
992+ dstr_replace (& effect_text , "iResolution.x" , "uv_size.x" );
993+ dstr_replace (& effect_text , "iResolution.y" , "uv_size.y" );
994+ dstr_replace (& effect_text , "iResolution" ,
995+ "float4(uv_size,uv_pixel_interval)" );
996+
997+ dstr_replace (& effect_text , "uniform vec2 uv_size;" , "" );
998+
999+ if (strstr (effect_text .array , "iTime" ))
1000+ dstr_replace (& effect_text , "iTime" , "elapsed_time" );
1001+ else if (strstr (effect_text .array , "uTime" ))
1002+ dstr_replace (& effect_text , "uTime" , "elapsed_time" );
1003+ else if (strstr (effect_text .array , "u_time" ))
1004+ dstr_replace (& effect_text , "u_time" , "elapsed_time" );
1005+ else
1006+ dstr_replace (& effect_text , "time" , "elapsed_time" );
1007+
1008+ dstr_replace (& effect_text , "uniform float elapsed_time;" , "" );
1009+
1010+ dstr_replace (& effect_text , "vec4" , "float4" );
1011+ dstr_replace (& effect_text , "vec3" , "float3" );
1012+
1013+ dstr_replace (& effect_text , "vec2" , "float2" );
1014+
1015+ convert_float_init (& effect_text , "float2(" , 2 );
1016+ convert_float_init (& effect_text , "float3(" , 3 );
1017+ convert_float_init (& effect_text , "float4(" , 4 );
1018+
1019+ dstr_cat (& return_color_name , "=" );
1020+ dstr_replace (& effect_text , return_color_name .array , "return " );
1021+ dstr_replace (& return_color_name , "=" , " =" );
1022+ dstr_replace (& effect_text , return_color_name .array , "return " );
1023+
1024+ dstr_free (& return_color_name );
1025+
1026+ dstr_replace (& effect_text , "#version " , "//#version " );
1027+
1028+ struct dstr insert_text = {0 };
1029+ dstr_init_copy (& insert_text , "#ifndef OPENGL\n" );
1030+
1031+ if (dstr_find (& effect_text , "mat2" ))
1032+ dstr_cat (& insert_text , "#define mat2 float2x2\n" );
1033+ if (dstr_find (& effect_text , "mat3" ))
1034+ dstr_cat (& insert_text , "#define mat3 float3x3\n" );
1035+ if (dstr_find (& effect_text , "mat3" ))
1036+ dstr_cat (& insert_text , "#define mat4 float4x4\n" );
1037+ if (dstr_find (& effect_text , "fract(" ))
1038+ dstr_cat (& insert_text , "#define fract frac\n" );
1039+ if (dstr_find (& effect_text , "mix(" ))
1040+ dstr_cat (& insert_text , "#define mix lerp\n" );
1041+ if (dstr_find (& effect_text , "mod(" ))
1042+ dstr_cat (& insert_text , "float mod(float x, float y)\n\
1043+ {\n\
1044+ return x - y * floor(x / y);\n\
1045+ }\n" );
1046+ dstr_cat (& insert_text , "#endif\n" );
1047+
1048+ int num_textures = 0 ;
1049+ struct dstr texture_name = {0 };
1050+ struct dstr replacing = {0 };
1051+ struct dstr replacement = {0 };
1052+
1053+ char * texture = strstr (effect_text .array , "texture(" );
1054+ while (texture ) {
1055+ const size_t diff = texture - effect_text .array ;
1056+ char * start = texture + 8 ;
1057+ while (* start == ' ' )
1058+ start ++ ;
1059+ char * end = start ;
1060+ while (* end != ' ' && * end != ',' && * end != ')' &&
1061+ * end != '\n' && * end != 0 )
1062+ end ++ ;
1063+ texture_name .len = 0 ;
1064+ dstr_ncat (& texture_name , start , end - start );
1065+
1066+ replacing .len = 0 ;
1067+ dstr_ncat (& replacing , texture , end - texture );
1068+
1069+ replacement .len = 0 ;
1070+
1071+ if (num_textures ) {
1072+ dstr_cat_dstr (& replacement , & texture_name );
1073+ dstr_cat (& replacement , ".Sample(textureSampler" );
1074+
1075+ dstr_insert (& effect_text , diff , texture_name .array );
1076+ dstr_cat (& insert_text , "uniform texture2d " );
1077+ dstr_cat (& insert_text , texture_name .array );
1078+ dstr_cat (& insert_text , ";\n" );
1079+ } else {
1080+ dstr_cat (& replacement , "image.Sample(textureSampler" );
1081+ }
1082+ dstr_replace (& effect_text , replacing .array , replacement .array );
1083+ num_textures ++ ;
1084+
1085+ texture = strstr (effect_text .array + diff + 8 , "texture(" );
1086+ }
1087+ dstr_free (& replacing );
1088+ dstr_free (& replacement );
1089+ dstr_free (& texture_name );
1090+
1091+ if (insert_text .len > 24 ) {
1092+ dstr_insert_dstr (& effect_text , 0 , & insert_text );
1093+ }
1094+ dstr_free (& insert_text );
1095+
1096+ obs_data_set_string (settings , "shader_text" , effect_text .array );
1097+
1098+ dstr_free (& effect_text );
1099+
1100+ obs_data_release (settings );
1101+ obs_property_set_visible (property , false);
1102+
1103+ filter -> reload_effect = true;
1104+
1105+ obs_source_update (filter -> context , NULL );
1106+ return true;
1107+ }
1108+
7851109static const char * shader_filter_texture_file_filter =
7861110 "Textures (*.bmp *.tga *.png *.jpeg *.jpg *.gif);;" ;
7871111
@@ -825,9 +1149,15 @@ static obs_properties_t *shader_filter_properties(void *data)
8251149 obs_property_set_modified_callback (from_file ,
8261150 shader_filter_from_file_changed );
8271151
828- obs_properties_add_text (props , "shader_text" ,
829- obs_module_text ("ShaderFilter.ShaderText" ),
830- OBS_TEXT_MULTILINE );
1152+ obs_property_t * shader_text = obs_properties_add_text (
1153+ props , "shader_text" ,
1154+ obs_module_text ("ShaderFilter.ShaderText" ), OBS_TEXT_MULTILINE );
1155+ obs_property_set_modified_callback (shader_text ,
1156+ shader_filter_text_changed );
1157+
1158+ obs_properties_add_button2 (props , "shader_convert" ,
1159+ obs_module_text ("ShaderFilter.Convert" ),
1160+ shader_filter_convert , data );
8311161
8321162 obs_property_t * file_name = obs_properties_add_path (
8331163 props , "shader_file_name" ,
0 commit comments