blob: 3dfdd4598862e2f71b1158c4a0e54c2c530725e7 [file] [edit]
export const description = "Wrapper for gl-transitions";
function load_fx(fx_name, local_dist)
{
let fx_obj = {uniforms: [], frag_shader: null, author: null, license: null};
let fx_file;
if (local_dist)
fx_file = filter.jspath + 'transitions/gl-transitions/' + fx_name + '.glsl';
else
fx_file = fx_name;
let source = sys.load_file(fx_file, true);
if (!source || !source.length) return null;
let lines = source.split('\n');
lines.forEach( line => {
let idx;
while (line.charAt(0) ==' ') {
line = line.slice(1);
}
if (!line.length) return;
if (!fx_obj.author) {
idx = line.indexOf('uthor');
if (idx>0) {
fx_obj.author = line.slice(idx+6);
while (fx_obj.author.charAt(0) == ' ') {
fx_obj.author = fx_obj.author.slice(1);
}
return;
}
}
if (!fx_obj.license) {
idx = line.indexOf('icense');
if (idx>0) {
fx_obj.license = line.slice(idx+7);
while (fx_obj.license.charAt(0) == ' ') {
fx_obj.license = fx_obj.license.slice(1);
}
return;
}
}
if (! line.startsWith('uniform')) return;
let code = line.split(' ');
let uni = {};
uni.type = code[1];
uni.name = code[2].split(';');
uni.name = uni.name[0];
code = line.split('=');
let value = code[1];
if (typeof value != 'string') {
uni.value = null;
if (uni.type != 'sampler2D') {
print(GF_LOG_ERROR, 'Uniform with no default value: ' + line);
}
} else {
while (value.charAt(0) ==' ') {
value = value.slice(1);
}
if (uni.type == 'bool') {
if (value=='true') uni.value = true;
else uni.value = false;
} else if (uni.type == 'int') {
uni.value = Number.parseInt(value);
} else if (uni.type == 'float') {
uni.value = Number.parseFloat(value);
} else if ((uni.type == 'vec2') || (uni.type == 'vec3') || (uni.type == 'vec4')
|| (uni.type == 'ivec2') || (uni.type == 'ivec3') || (uni.type == 'ivec4')
) {
idx = value.indexOf(uni.type);
let type_len = uni.type.length;
let oval = value;
let nb_vals = 2;
if (uni.type.indexOf('3')>0) nb_vals = 3;
else if (uni.type.indexOf('4')>0) nb_vals = 4;
if (idx>=0) {
value = value.slice(idx+type_len+1);
value = value.split(')');
value = value[0].split(',');
uni.value = [];
value.forEach( v => {
let f = Number.parseFloat(v);
uni.value.push(f);
});
while (uni.value.length < nb_vals) {
if (value.length==1) {
uni.value.push(uni.value[0]);
} else {
print(GF_LOG_WARNING, 'Not enough scalars for uniform type ' + uni.type + ' - value ' + value + ', padding with 0');
uni.value.push(0);
}
}
uni.value.length = nb_vals;
//safety check
for (idx=0; idx<nb_vals; idx++) {
if (uni.value[idx] != uni.value[idx]) {
print(GF_LOG_ERROR, 'Error parsing value ' + oval + ' for type ' + uni.type + ': got NaN, forcing to 0');
uni.value[idx] = 0;
}
}
} else {
print(GF_LOG_ERROR, 'Wrong format for uniform type ' + uni.type + ' - value ' + value);
}
} else {
print(GF_LOG_ERROR, 'Uniform type not handled: ' + uni.type + ' - value ' + value);
}
}
fx_obj.uniforms.push(uni);
});
source = source.replaceAll('getFromColor', 'get_pixel_from');
source = source.replaceAll('getToColor', 'get_pixel_to');
source = source.replaceAll(/\bratio\b/g, 'video_ar');
source = source.replaceAll(/\bprogress\b/g, 'ratio');
source += `
vec4 gf_apply_effect() {
return transition(txcoord_from);
}
`;
fx_obj.frag_shader = source;
return fx_obj;
}
export let help='';
let myhelp = globalThis.help_mod || null;
let full_help=false;
if (myhelp == 'gltrans') {
full_help=true;
}
//don't print in md or man for the time being
else if (sys.get_opt("temp", "gendoc") == "yes") {
// full_help=true;
}
if (full_help) {
help = `This transition module wraps gl-transitions, see https://gl-transitions.com/
## Available effects
`;
//load all modules
let effects = sys.enum_directory(filter.jspath+'transitions/gl-transitions/', "*.glsl");
effects.forEach( fx_file => {
let name = fx_file.name.split('.')[0];
let fx;
try {
fx = load_fx(name, true);
} catch (e) {
print(GF_LOG_ERROR, 'Failed to load gl transition ' + name + ': ' + e);
return;
}
if (!fx) return;
help += name;
if (fx.author || fx.license) {
help += ' (';
if (fx.author) help += 'author: ' + fx.author;
if (fx.license) help += ', license: ' + fx.license;
help += ')';
}
help += '\n';
fx.uniforms.forEach(uni =>{
help += ' - ' + uni.name + ' (' + uni.type + '): ' + uni.value + '\n';
});
help += '\n';
});
} else {
help = "This transition module wraps gl-transitions, see https://gl-transitions.com/ and `gpac -h avmix:gltrans` for builtin transitions";
}
export const options = [
{name:"fx", value: "", desc: "effect name for built-in effects, or path to gl-transition GLSL file"},
{}
];
export function load()
{
let fx;
if (arguments.length) {
let local_dist = true;
let args = arguments[0];
let fx_name = args.fx || null;
if (!fx_name) return null;
if (fx_name.indexOf('.') >= 0) {
fx_name = resolve_url(fx_name);
local_dist = false;
}
fx = load_fx(fx_name, false);
if (!fx) return null;
} else {
fx = {uniforms: [], frag_shader: null, author: null, license: null};
}
return {
setup_gl: function(webgl, program, first_available_texture_unit)
{
this.options.forEach( uni => {
uni.loc = webgl.getUniformLocation(program, uni.name);
if (uni.loc==null) {
print(GF_LOG_ERROR, 'No uniform for ' + uni.name);
return;
}
this.update_flag = UPDATE_SIZE;
});
},
apply: function(webgl, ratio, path, pids)
{
if (!this.update_flag) return;
this.update_flag = 0;
this.options.forEach( uni => {
let value = this[uni.name] || uni.value;
if (!uni.loc) return;
if (uni.type=='bool') {
webgl.uniform1i(uni.loc, value);
} else if (uni.type=='int') {
webgl.uniform1i(uni.loc, value);
} else if (uni.type=='float') {
webgl.uniform1f(uni.loc, value);
} else if (uni.type=='vec2') {
webgl.uniform2f(uni.loc, value[0], value[1]);
} else if (uni.type=='vec3') {
webgl.uniform3f(uni.loc, value[0], value[1], value[2]);
} else if (uni.type=='vec4') {
webgl.uniform4f(uni.loc, value[0], value[1], value[2], value[3]);
} else if (uni.type=='ivec2') {
webgl.uniform2i(uni.loc, value[0], value[1]);
} else if (uni.type=='ivec3') {
webgl.uniform3i(uni.loc, value[0], value[1], value[2]);
} else if (uni.type=='ivec4') {
webgl.uniform4i(uni.loc, value[0], value[1], value[2], value[3]);
} else {
print(GF_LOG_WARNING, 'uniform type ' + uni.type + ' updating not supported yet');
return;
}
});
},
get_shader_src: function()
{
return this.frag_shader;
},
frag_shader: fx.frag_shader,
options: fx.uniforms
};
}