Skip to content

Commit 36a8506

Browse files
committed
Add shader convert
1 parent 930e6bb commit 36a8506

File tree

4 files changed

+339
-8
lines changed

4 files changed

+339
-8
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ else()
99
cmake_minimum_required(VERSION 3.18)
1010
endif()
1111

12-
project(obs-shaderfilter VERSION 2.2.2)
12+
project(obs-shaderfilter VERSION 2.3.0)
1313
set(PROJECT_FULL_NAME "OBS Shaderfilter")
1414

1515
# Set new UUIDs when you start to create a new plugin.

buildspec.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,5 @@
7979
}
8080
},
8181
"name": "obs-shaderfilter",
82-
"version": "2.2.2"
82+
"version": "2.3.0"
8383
}

data/locale/en-US.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ ShaderFilter.InputScene="Scene"
1515
ShaderFilter.UseShaderElapsedTime="Use Shader Time"
1616
ShaderFilter.NoRepeat="Run Once"
1717
ShaderFilter.Error="Error"
18-
ShaderFilter.Unknown="Unknown"
18+
ShaderFilter.Unknown="Unknown"
19+
ShaderFilter.Convert="Convert Shader"

obs-shaderfilter.c

Lines changed: 335 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
714738
static 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+
7851109
static 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

Comments
 (0)