jit.gl.polymovie modification to read PNG files

Gary Leyrn's icon

Hello,

I need the object jit.gl.gl.polymovie to read PNG files, so I added the "PNG" filetype in the javascript code inside this abstraction. It did not worked. However , it worked for JPEG image files.

Could someone please help me so I can read simultaneous png files as textures by modifying this javascript code, please ? this is the contents of the original <js jitpolymovie > object , and I added PNG at the beginning of the filetypes var filetypes = ["PNG","MPEG", "mpg4","MooV", "WVC1", "WMVA", "WMV3", "WMV2", "M4V ", "VfW "];

autowatch=1;
outlets=3;
// outlet 0 = jit_matrix / jit_gl_texture
// outlet 1 = movie attributes
// outlet 2 = special messages

const cachemode_static = 0;
const cachemode_auto = 1;
var cachemode = cachemode_static;
declareattribute("cachemode");
var cache_size = 0.5;
declareattribute("cache_size");
var cache_sizeauto = 5;
declareattribute("cache_sizeauto");

var drawto = "";
declareattribute("drawto", null, "setdrawto");

var verbose = 0;
declareattribute("verbose", null, null);

// for poly~ type addressing of individual movie instances
var target = 0;
declareattribute("target", null, "settarget");

var curmov=-1;
var isstopped=false;
var saveargs=true;
var readcount = 0;
var loopmode = 1;

var targets = [];

// viddll supports all these, first 3 are supported by avf
var filetypes = ["PNG","MPEG", "mpg4","MooV", "WVC1", "WMVA", "WMV3", "WMV2", "M4V ", "VfW "];

var moviedict = new Dict();
var movies = new Object();
// "movie" : jit.movie object,
// "index" : movie index,
// "listener" : movie listener,

var movnames = [];
var curmovob = null;
var movct = 0;

var savedargs = new Array();
var dummymatrix = new JitterMatrix(4,"char",320,240);
var swaplisten=null;
const outtex = "jit_gl_texture";
const outmat = "jit_matrix";


function postln(arg) {
    if(verbose)
        post(arg+"\n");
}
postln.local = 1;

const is820 = (max.version >= 820);
var tmp = JitterObject("jit.movie");
const engine = tmp.engine;
tmp.freepeer();
const isviddll = (engine === "viddll");
if(isviddll) {
    postln("polymovie using viddll engine");
}
else {
    postln("polymovie using avf engine");
}

// bug in viddll engine asyncread if version is < 8.2
const useasync = (is820 || !isviddll);
// force override here if asyncread is causing issues
//const useasync = false;


function bang() {
    if(!drawtexture())
        drawmovies();
}

function swapcallback(event){
    //post("callback: " + event.subjectname + " sent "+ event.eventname + " with (" + event.args + ")\n");            

    // if context is root we use swap, if jit.gl.node use draw or capture
    if (event.eventname=="swap" || event.eventname=="capture" || event.eventname=="draw") {
        drawmovies();
    }
}
swapcallback.local = 1;

function movcallback(event){
    if(event.eventname==="read") {
        var m = movies[event.subjectname];
        finalizemovie(m);

        if(readcount == movnames.length) {
            finalizeread();
        }
    }
    else if(event.eventname==="seeknotify") {
        outlet(2, "seeknotify", target);
    }
    else if(event.eventname==="loopreport") {
        outlet(2, "loopnotify", target);
    }
    //post("callback: " + event.subjectname + " sent "+ event.eventname + " with (" + event.args + ")\n");        
}
movcallback.local = 1;

function drawmovies() {
    if(!targets.length) {
        drawmovie();
    }
    else {
        outtype = outtex;
        outnames = [];
        outpositions = [];
        for(i = 0; i < targets.length; i++) {
            var o = targets[i];
            if(!o)
                continue;

            if(drawtexture()) {
                o.matrixcalc(dummymatrix,dummymatrix);
                outnames.push(o.texture_name);
            }
            else {
                outtype = outmat;
                var movdim = o.movie_dim;
                var matdim = dummymatrix.dim;
                if(movdim[0]!=matdim[0] || movdim[1]!=matdim[1])
                    dummymatrix.dim=movdim;
                o.matrixcalc(dummymatrix,dummymatrix);
                outnames.push(dummymatrix.name);
            }
            outpositions.push(o.position);
        }        
        outlet(0, outtype, outnames);
        outlet(2, "position", outpositions);
    }
}
drawmovies.local = 1;

function drawmovie() {
    if(!curmovob)
        return;

    var o = curmovob;
    if(drawtexture()) {
        o.matrixcalc(dummymatrix,dummymatrix);
        outlet(0,outtex,o.texture_name);
    }
    else {
        var movdim = o.movie_dim;
        var matdim = dummymatrix.dim;
        if(movdim[0]!=matdim[0] || movdim[1]!=matdim[1])
            dummymatrix.dim=movdim;
        o.matrixcalc(dummymatrix,dummymatrix);
        outlet(0,outmat,dummymatrix.name);
    }
    outlet(2, "position", o.position);
}
drawmovie.local = 1;

function drawtexture() {
    return !(drawto==="");
}
drawtexture.local = 1;

function getmovie_index(i) {
    if(i>=0 && i<movnames.length) 
        return movies[movnames[i]]["movie"];
    return null;
}
getmovie_index.local = 1;

function getmovie_name(n) {
    return movies[n]["movie"];
}
getmovie_name.local = 1;

/////////////////////////////////////////////
// #mark GL Context
/////////////////////////////////////////////

var implicitdrawto = "";
var explicitdrawto = false;
var implicit_tracker = new JitterObject("jit_gl_implicit");
var implicit_lstnr = new JitterListener(implicit_tracker.name, implicit_callback);

function implicit_callback(event) { 
    if(!explicitdrawto && implicitdrawto != implicit_tracker.drawto[0]) {
        // important! drawto is an array so get first element
        implicitdrawto = implicit_tracker.drawto[0];
        dosetdrawto(implicitdrawto);
    }
}
implicit_callback.local = 1;

function setdrawto(val) {
    explicitdrawto = true;
    dosetdrawto(val);
}

function dosetdrawto(arg) {
    if(arg === drawto || !arg) {
        // bounce
        return;
    }

    postln("setdrawto " + arg);
    drawto=arg;    
    setmovieattr("drawto",drawto);
    setmovieattr("output_texture",1);
    if(swaplisten)
        swaplisten.subjectname = "";
    swaplisten = new JitterListener(drawto,swapcallback);
}

/////////////////////////////////////////////
// #mark Read and Init
/////////////////////////////////////////////

function clear() {
    settarget(0);
    readcount = 0;
    curmovob = null;
    for(n in movies) {
        getmovie_name(n).freepeer();
    }
    movnames.splice(0,movnames.length);
    movies = new Object();
    moviedict.clear();
    movct = 0;
    outlet(2, "movielist", "clear");
}

function readfolder(path) {
    clear();
    appendfolder(path);
}

function appendfolder(path) {
    var f = new Folder(path);
    var fpath = f.pathname;
    var fcount = f.count;
    f.reset();

    while (!f.end) {
        if(ismovie(f.filetype)) {
            postln(fpath + f.filename);
            addmovie(fpath + f.filename);
        }
        f.next();
    }
    doargattrs();
    if(!useasync) {
        finalizeread();
    }
}

function appendmovie(path) {
    addmovie(path)
    doargattrs();
}

function dictionary(dname) {
    postln("reading dictionary " + dname);
    var d = new Dict(dname);
    var keys = d.getkeys();
    if(!keys)
        return;
    
    clear();

    // convert single value to array
    if(typeof(keys) === "string") {
        keys = [keys];
    }
    keys.forEach(function (key, i) {
        var m = d.get(key);
        addmovie(m.get("path"));
    });

    // apply arg attrs first...
    doargattrs();

    // then apply dictionary attrs
    keys.forEach(function (key, i) {
        var m = d.get(key)
        var attrs = m.get("attributes");
        if(attrs) {
            var akeys = attrs.getkeys();
            var movie = getmovie_index(i);

            // convert single value to array
            if(typeof(akeys) === "string") {
                akeys = [akeys];
            }
            akeys.forEach(function (akey, j) {
                //postln("attribute: " + akey + ", vals: " + attrs.get(akey));
                if(movie) {
                    sendmovie(movie, akey, attrs.get(akey));
                }
            });
        }
    });
    
    if(!useasync) {
        finalizeread();
    }
}

function writedict() {
    writeloopstatetodict(curmovob);
    if(arguments.length) {
        moviedict.export_json(arguments[0]);
    }
    else {
        moviedict.export_json();
    }
}

function readdict() {
    var d = new Dict();
    if(arguments.length) {
        d.import_json(arguments[0]);
    }
    else {
        d.import_json();
    }
    dictionary(d.name);
}

function getdict() {
    writeloopstatetodict(curmovob);
    outlet(2, "dictionary", moviedict.name);
}

// from patcherargs
function done() {
    saveargs=false;
    doargattrs();
}

function addmovie(path) {
    var o = new JitterObject("jit.movie");
    o.autostart=0;
    o.automatic=0;
    if(!swaplisten) {
        postln("disable output_texture")
        o.output_texture=0;
    }
    else {
        postln("enable output_texture")
        o.output_texture=1;
        o.drawto=drawto;
    }

    // engine specific stuff goes here...
    if(isviddll) {
        o.cache_size = cache_size;
    }
    
    var idx = movct++;
    var regname = o.getregisteredname();
    movnames.push(regname);
    var m = new Object();
    movies[regname] = m;
    m.movie = o;
    m.index = idx;
    m.listener = new JitterListener(regname, movcallback);

    // placeholder values, will overwrite in finalizemovie
    moviedict.setparse(m.index, '{ "name" : "'+m.movie.moviename+'", "path" : "' + m.movie.moviepath + '"}' );
    
    // placeholder for proper umenu ordering
    outlet(2, "movielist", "append", m.path);
    
    if(useasync) {
        o.asyncread(path);
    }
    else {
        o.read(path);
        finalizemovie(m);
    }
}
addmovie.local = 1;

function ismovie(t) {
    for(f in filetypes) {
        if(filetypes[f]===t)
            return true;
    }
    return false;
}
ismovie.local = 1;

function finalizeread() {
    outlet(2, "readfolder", "done", readcount);
    outlet(2, "dictionary", moviedict.name);
}
finalizeread.local = 1;

function finalizemovie(m) {
    readcount++;
    moviedict.replace(m.index+"::name", m.movie.moviename);
    moviedict.replace(m.index+"::path", m.movie.moviepath);

    // overwrite full path with filename
    outlet(2, "movielist", "setitem", m.index, m.movie.moviename);
    
    postln("movie info for movie index: "+m.index);
    postln("name: "+m.movie.moviename);
}
finalizemovie.local = 1;

// maybe not an issue, but only write looppoints on movie changes or dictionary writes
function writeloopstatetodict(ob) {
    if(ob) {
        var idx = movies[ob.getregisteredname()].index;
        moviedict.replace(idx + "::attributes::looppoints_secs", ob.looppoints_secs);
    }
}
writeloopstatetodict.local = 1;

// loop state is reset on file read, so grab it from the dictionary when playback triggered
function readloopstatefromdict(ob) {
    if(ob) {
        var idx = movies[ob.getregisteredname()].index;
        if(moviedict.contains(idx + "::attributes::looppoints_secs")) {
            ob.looppoints_secs = moviedict.get(idx + "::attributes::looppoints_secs");
        }
    }
}
readloopstatefromdict.local = 1;

/////////////////////////////////////////////
// #mark Playback
/////////////////////////////////////////////

function settarget(t) {
    postln("setting target " + t);
    target = t;
    if(target === 0 && targets.length) {
        curmovob = targets[0];
        targets.splice(0, targets.length);
        postln("target length is: " + targets.length);
    }
    else if(target > 0) { 
        if(target <= targets.length)
            curmovob = targets[target - 1];
        else 
            curmovob = null;
    }
}

function play() {
    var i=0;    
    if(arguments.length)
        var i=arguments[0];

    if(movieindexvalid(i)) {
        endmovie();
        curmov = i;
        curmovob = getmovie_index(curmov);
        postln("playing movie: " + curmov + " " + curmovob.moviefile);
        if(!isstopped || target > 0)
            doplay();
        
        curmovob.loop = loopmode;
        readloopstatefromdict(curmovob);
        var loopi = curmovob.looppoints_secs[0] / curmovob.seconds;
        var loopo = curmovob.looppoints_secs[1] / curmovob.seconds;
        // output normalized looppoints for GUI
        outlet(2, "looppoints", loopi, loopo);

        if(isviddll && cachemode == cachemode_auto) {
            postln("autosizing cache: "+cache_sizeauto);
            curmovob.cache_size = cache_sizeauto;
        }
    }

    if(target > 0) {
        targets[target-1] = curmovob;
        postln("added target, length is: " + targets.length);
    }
}

function start() {
    doplay();
}

function stop() {
    if(curmovob)
        curmovob.stop();
    isstopped = true;
}

function scrub(pos) {
    if(curmovob) {
        curmovob.position = pos;
    }
}

function doplay() {
    if(curmovob) {
        curmovob.start();
    }
    isstopped = false;
}
doplay.local = 1;

function endmovie() {
    if(curmovob) {
        curmovob.stop();
        writeloopstatetodict(curmovob);
        if(isviddll && curmovob && cachemode == cachemode_auto) {
            postln("zeroing cache");
            curmovob.cache_size = 0;
        }
    }
}
endmovie.local = 1;

function movieindexvalid(idx) {
    return (idx < movnames.length && idx >= 0);
}
movieindexvalid.local = 1;

/////////////////////////////////////////////
// #mark Args Attrs and Messages
/////////////////////////////////////////////

function anything() {
    if(saveargs) {
        var a = arrayfromargs(arguments);
        var e = messagename+","+a.join();
        savedargs.push(e);
    }
    if(curmovob) {
        var a = arrayfromargs(arguments);
        sendmovie(curmovob, messagename, a);
    }
}

function sendmovies() {
    var a = arrayfromargs(arguments);
    var mess = a[0];
    if(a.length>1)
        a.splice(0,1)
        
    for(n in movies) {
        sendmovie(getmovie_name(n),mess, a);
    }    
}

// special case handlers for position and loop attrs
function position(p) {
    if(curmovob) {
        curmovob.position = p;
    }
}

function loop(state) {
    loopmode = state;
    if(curmovob) {
        curmovob.loop = loopmode;
    }
}

function looppoints(loopi, loopo) {
    if(curmovob) {
        if(loopi <= 1. && loopo <= 1.) {
            // special polymovie normalized looppoints
            var loopsecin = (loopi < loopo ? loopi : loopo) * curmovob.seconds;
            var loopsecout = (loopi < loopo ? loopo : loopi) * curmovob.seconds;
            curmovob.looppoints_secs = [loopsecin, loopsecout];
        }
        else {
            // conventional looppoints
            curmovob.looppoints = [loopi, loopo];
        }
    }
}

function automatic(v) {
    post("modifying automatic unsupported\n");
}

function autostart(v) {
    post("modifying autostart unsupported\n");
}

function output_texture(v) {
    post("modifying output_texture unsupported\n");
}

function sendmovie(movie, mess, args) {
    if (Function.prototype.isPrototypeOf(movie[mess])) {
        postln("sending message " + mess + " with args " + args);
        movie[mess](args);
    } 
    else if(mess.search("get")==0) {
        var attr=mess.substr(3, mess.length);
        postln("getting attr " + attr);
        outlet(1, attr, movie[attr]);
    }
    else {
        postln("setting attr " + mess + " with args " + args);
        movie[mess] = args;    
        var regname = movie.getregisteredname();
        var idx = movies[regname].index;
        moviedict.replace(idx + "::attributes::" + mess, args);
    }    
}
sendmovie.local = 1;

function doargattrs() {
    for(n in movies) {
        var m = getmovie_name(n);
        for(i in savedargs) {
            var str = savedargs[i];
            var ary = str.split(",");
            sendmovie(m, ary[0], ary.slice(1,ary.length));
        }
    }
}
doargattrs.local = 1;

function setmovieattr(arg, val) {    
    for(n in movies) 
        getmovie_name(n)[arg] = val;
}
setmovieattr.local = 1;
riccardo dapelo's icon

what video engine are you using?
Here with no edit of the js it's running
Mac osx 12.7, Max 8.5.6, video engine :viddll

TFL's icon

Working out of the box with PNG here as well. Windows 10, Max 8.5.6, viddll as video engine.

Rob Ramirez's icon

this change was snuck into 8.5.6, apologies is it's not on the changelist