• Hi there !

    I'm currently looking for ways to optimise the way curves are drawn on an OLED screen ( & later rounded polygons ;) ).

    By lessenning the number of "steps" used for a curve, I'm getting close to "instantaneous refresh", but I bet there's some way to use "compiled" flag to get even faster calls ( which 'll get handy when drawing more than one curve, for example two rounded polys ).

    I tried rewriting the following functions, but always ended up with either an error ( "ObjectExpression is not implemented yet" or "ArrayExpression is not implemented yet" ).
    When trying "E.compiledC()", it seems there's a limit on the maximum number of args for a function ( 4 arguments if I got it right from the below test code, if more I got a "Error Parsing signature at argument number " )

    Any hint on getting this as fast as can be ? ( I plan to using the above two "tricks" - "compiled" & "E.compiledC" - and also to later drive some strips of APA102 in a POV manner, and this before moving onto creating a "firmware Extension" ( .. ) )

    Thanks in advance ! ;)

    Curves helpers

    function bezierCurve(t, p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y){
      var t2 = t * t;
      var t3 = t2 * t;
      var oneMinT = 1 - t;
      var oneMinT2 = oneMinT * oneMinT;
      var oneMinT3 = oneMinT2 * oneMinT;
    
      return {
        x: p0x * oneMinT3 + 3 * p1x * t * oneMinT2 + 3 * p2x * t2 * oneMinT + p3x * t3,
        y: p0y * oneMinT3 + 3 * p1y * t * oneMinT2 + 3 * p2y * t2 * oneMinT + p3y * t3
      };
    }
    function quadraticCurve(t, p0x, p0y, p1x, p1y, p2x, p2y){
      var t2 = t * t;
      var oneMinT = 1 - t;
      var oneMinT2 = oneMinT * oneMinT;
    
      return {
        x: p0x * oneMinT2 + 2 * p1x * t * oneMinT + p2x *t2,
        y: p0y * oneMinT2 + 2 * p1y * t * oneMinT + p2y *t2
      };
    }
    

    no-that-fast curve drawing

    function drawCurve(){
      var p0 = { x: 20, y: 10};
      var p1 = { x: 20, y: 63};
      var p2 = { x: 127, y: 10};
      var time = 0;
      //var stepping = 0.005; // seems the nicest
      //var stepping = 0.05; // a little less neat, yet faster
      var stepping = 0.1; // quick enough ?
      var pathPts = [];
      for(time = 0; time <= 1; time+= stepping){
        var pos = quadraticCurve(time, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
        pathPts.push(pos.x, pos.y);
      }
      g.drawPoly(pathPts, false);
      g.flip();
    }
    

    Max 4 arguments limit ? ( and yes, I put 'int' instead of 'float' to test out .. )

    var c = E.compiledC(`
    // int quadraticCurveCX(int, int , int ,int)
    int quadraticCurveCX(int t, int p0x, int p0y, int p1x){ // maximum 4 args ..
     //int t2 = t*t;
     //int oneMinT = 1-t;
     //int oneMinT2 = oneMinT * oneMinT;
     return 0; //p0x * oneMinT2 + 2 * p1x * t * oneMinT + p2x *t2;
    }
    `);
    

    Chunks of code from last unsuccessful try

    function quadraticCurveCY(t, p0x, p0y, p1x, p1y, p2x, p2y){
      //"compiled";
      var t2 = t*t;
      var oneMinT = 1-t;
      var oneMinT2 = oneMinT * oneMinT;
      //return p0x * oneMinT2 + 2 * p1x * t * oneMinT + p2x *t2;
      return p0y * oneMinT2 + 2 * p1y * t * oneMinT + p2y *t2;
    }
    function getCurvePts(){
      //"compiled";
      var p0x = 20, p0y = 10;
      var p1x = 20, p1y = 63;
      var p2x = 127, p2y =10;
      var time = 0;
      var stepping = 0.005; // seems the nicest
      var pathPts = [];
      for(time = 0; time <= 1; time+= stepping){
        //var pos = quadraticCurveC(time, p0x, p0y, p1x, p1y, p2x, p2y);
        //pathPts.push(pos[0], pos[0]);
        //var posX, posY;
        //var pos = quadraticCurveC(time, p0x, p0y, p1x, p1y, p2x, p2y, posX, posY);
        //pathPts.push(posX, posY);
        //var posX = c.quadraticCurveCX(time, p0x, p0y, p1x, p1y, p2x, p2y);
      }
      return pathPts;
    }
    
    function drawCurve(){
      g.drawPoly(getCurvePts(), false);
      g.flip();
    }
    

    I see if I can find time to learn & try writing my own C extensions today ( right after some test on OLED screen SSD1306: it seems passing a bitrate of 800000 works, but I'm not sure if the difference 'll be visible since I'm not sure of the "resolution*" of 'setInterval/setTimeout' on Espruino).

    *Putting it another way, does Espruino handle <1ms as setInterval/setTimeout arg ?
    ( & If so, how to get such small delay in a reliable manner ? )

    This being said, good weekend everyone ;)
    ++

  • Sun 2019.01.27

    Hi @stephaneAG

    'Max 4 arguments limit ?'

    I happened to be running a chunk of E.compiledC as I read this post and wondered the same, but after a quick hack, concur that four arguments seems to be the max.

    Uncaught Error: Error Parsing signature at argument number 5

     

    'does Espruino handle <1ms as setInterval'

    As an observation only as I don't have a scope to validate, from the FAQ page:

    https://www.espruino.com/FAQ

    There is an example that indicates as fast as 333 microseconds, but to perform any useful task most likely would require a function wrapper.
    The best I was able to obtain with minimal code inside that wrapper was around 30msec.

    Hope that provides some insight, but get the input from others also.

  • Hi,

    Yes, there's a 4 argument limit. I believe you could always just pass in an array? Either direct to compiled JS, or as an array of bytes to compiled C.

    And yes, Espruino will reliably handle less than 1ms in an interval, but JS code execution speed will probably hit you around that point.

    Also http://www.espruino.com/Compilation says under 'doesn't work': Creating arrays or structs ( [1,2,3] and {a:5} ) which is why you get ObjectExpression/ArrayExpression is not implemented yet

    One thing to note is that when writing inline C you can't use float/double math - so you'll have to do it all in integers. However if you can do that then you should be ok, and you can call a function with more than 4 arguments from C. It's just when calling C from JS that you're limited to 4 arguments.

  • @Robin thx ! -> same conclusion for the 4 args max, & thks for the 333 us /30 ms reminder ;)

    @Gordon:

    • yes, I could actually pass those as arrays no troubles
    • got it for the 1ms js execution limit
    • ok, I'll try to find alternatives to the creation of structs/array in my current code
    • for the "all in ints" part, I tested using ints but I intended to ultimately use floats ( ex: for the bezierCurve() fcn ), but I guess it could be done with "* tricks"

    -> I'll have another take on this as soon as I make further progress in some other projects ;)

    thanks a lot :)
    +

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

"compiled" functions to draw curves on OLED quickly ? ( bezier, quadratic, .. )

Posted by Avatar for stephaneAG @stephaneAG

Actions