• Hello
    I have 3 small issues:
    1) Same code, different results in Bangle.js 1 / 2 emulator.

    const color = {
      main: g.toColor(255, 0, 0),
      back: g.getPixel(1, 30),
    }
    
    function getPixelColor(x, y) {
      var c = g.getPixel(x, y);
      if (c === color.main) {
        return color.back;
      }
      return color.main;
    }
    
    var layer = Graphics.createCallback(viewport.width, viewport.height, g.getBPP(), function(x, y) {
      g.setPixel(x, y, getPixelColor(x, y));
    });
    
    function draw() {
      ... // hour = 50, minutes = 60
      g.setColor(color.main);
      g.fillEllipse(center.x - 5 * scale, center.y - 70 * scale, center.x + 160 * scale, center.y + 90 * scale);
      layer.setFontAlign(1, 0).setFont("Vector", 90 * scale);
      layer.drawString(hour, center.x + 32 * scale, center.y - 31 * scale);
      layer.drawString(minutes, center.x + 32 * scale, center.y + 46 * scale);
      ...
    }
    

    (see attached image)

    2) There is something with the Vector font. I think the glyphs are not converted to path. :(

    3) When trying the font converter I have allot of fonts with height = 1 (maybe I'm doing something wrong). Ex:

    <link href="https://fonts.googleapis.com/css2?­family=Ubuntu+Mono:wght@700&display=swap­" rel="stylesheet">
    

    (see attached image)


    2 Attachments

    • Screen Shot 2021-10-19 at 04.54.54.png
    • Screen Shot 2021-10-19 at 04.44.21.png
  • Hi,

    1: Bangle.js 1 display can't be read back from - getPixel always returns 0 in Bangle 1, which is why you're seeing different values. You'd have to use an offscreen buffer.

    Also, I'm afraid using createCallback that way, while really neat, is going to be pretty slow on the actual device :(

    You could potentially do something different: Have 2x 1bpp ArrayBuffer graphics, render to each, and then XOR them together.

    This won't work in the emulator but something like this would be really fast:

    var W = g.getWidth();
    var H = g.getHeight()-24;
    var center = {x:W/2, y:H/2};
    var scale = 1;
    var layer1 = Graphics.createArrayBuffer(W,H,1,{msb:tr­ue});
    var layer2 = Graphics.createArrayBuffer(W,H,1,{msb:tr­ue});
      
    
    var c = E.compiledC(`
    // void combine(int, int, int)
    void combine(int len, int *dst, int *src){
      len = len>>2;
      while (len--) {
        *dst ^= *src;
        dst++;
        src++;
      }
    }
    `);
      
    function draw() {
      var hour = 12;
      var minutes = 34;
      
      layer1.fillEllipse(center.x - 5 * scale, center.y - 70 * scale, center.x + 160 * scale, center.y + 90 * scale);
      layer2.setFontAlign(1, 0).setFont("Vector", 90 * scale);
      layer2.drawString(hour, center.x + 32 * scale, center.y - 31 * scale);
      layer2.drawString(minutes, center.x + 32 * scale, center.y + 46 * scale);
      
      var l1ptr = E.getAddressOf(layer1.buffer, true);
      var l2ptr = E.getAddressOf(layer2.buffer, true);
      if (l1ptr && l2ptr) c.combine(layer1.buffer.length, l1ptr, l2ptr);
      
      g.drawImage(layer1.asImage(),0,24);
    }
    
    draw();
    

    2: There is some overdraw which is why you get the areas of black (where the same pixel has been drawn twice) but this is because the font is intentionally designed to take up very little space in memory.

    3: I don't know what's happening there. What web browser are you using?

    I just tried <link href="https://fonts.googleapis.com/css2?­family=Ubuntu+Mono:wght@700&display=swap­" rel="stylesheet"> in http://www.espruino.com/Font+Converter and it works great:

    Graphics.prototype.setFontUbuntuMono = function(scale) {
      // Actual height 15 (15 - 1)
    
  • Thanks :D
    Super quick response.

    1) I had seen the createArrayBuffer, but I was trying to get away with createCallback, now I see that I can't (so fast on the emulator... I really need my Bangle.js 2 to try then 😊 😊 😊).
    Thanks for pointing in the right direction, back to the drawing board.

    2) Ok. Vector is a very nice font, I'll probably be using it allot.

    3) I'm using brave. As it's based on Chrome I didn't remember to try in another browser. I'll try it in Chrome and FF.

  • I'm using brave

    Should work, but maybe check the debug console to see if there are errors. Also just try clicking the button again just in case? If it's working you should see a preview of the font

  • @Gordon

    You could potentially do something different: Have 2x 1bpp ArrayBuffer graphics, render to each, and then XOR them together.

    I like that... that was the thought of how to update watch face in Bangle 1 with high frequency of events / the desire of (a) smooth sweeping hand (s). The issue is that keeping an. image in memory (buffer) all the time is a lot of memory. With a smart arrangement - diving the image up into quadrants (plus a few pixels for overlap) can cut the amount of working memory down to about a quarter (1/4, 25%).

  • Actually one other (much better!) method that didn't occur to me until just now is to do two steps, and to use the transparency option when rendering to allow you to render the outside and then the inside of the circle:

    var W = g.getWidth();
    var H = g.getHeight()-24;
    var center = {x:W/2, y:H/2};
    var scale = 1;
    var buf = Graphics.createArrayBuffer(W,H,1,{msb:tr­ue});
    var bufImg = {
      width : W, height : H,
      bpp : 1, buffer : buf.buffer
    };
    
    function drawCircle() {
      buf.fillEllipse(center.x - 5 * scale, center.y - 70 * scale, center.x + 160 * scale, center.y + 90 * scale);
    }
    
    function drawText() {
      var hour = 12;
      var minutes = 34;  
      
      buf.setFontAlign(1, 0).setFont("Vector", 90 * scale);
      buf.drawString(hour, center.x + 32 * scale, center.y - 31 * scale);
      buf.drawString(minutes, center.x + 32 * scale, center.y + 46 * scale);
    }
    
    function draw() {
    
      
      // render entire image with black circle
      buf.setColor(1);
      drawText();
      buf.setColor(0);
      drawCircle();
      delete bufImg.transparent;
      g.drawImage(bufImg,0,24);
      // use transparency to render red bits
      buf.clear().setColor(1);
      drawCircle();
      buf.setColor(0);
      drawText();
      bufImg.transparent = 0;
      g.drawImage(bufImg,0,24);
    }
    
    draw();
    

    There'd still be a moderate amount of flicker in the circle on Bangle.js 1, but I doubt it'd be too much of an issue

  • Something in Brave is not working with the font converter (left: Chrome, right: Brave).
    I disable all blockers and still not good in Brave.
    Conclusion... use Chrome 😊


    1 Attachment

    • Screen Shot 2021-10-19 at 16.23.12.png
  • Interesting - thanks! Maybe as a privacy thing, Brave disables read-back from the Canvas element?

  • Update on the watch faces. Thanks for the help.
    How can I check memory consumption?


    2 Attachments

    • Screen Shot 2021-10-19 at 16.16.46.png
    • Screen Shot 2021-10-19 at 16.17.19.png
  • Looks great!

    process.memory().usage

  • I haven't explored what is the issue.
    What I can say is Brave writes some pixel on the canvas and on console I see that Brave is nudging allot more character than Chrome. Maybe this is the problem.
    ...
    Nudging character "B" down by 16 pixels to it fits
    Nudging character "C" down by 16 pixels to it fits
    Nudging character "D" down by 16 pixels to it fits
    Nudging character "E" down by 16 pixels to it fits
    ...

  • Wow, very strange. I guess you'd have to dig into the code, but the Nudging character happens when it's looked at the data that has been drawn and it sees that there's stuff above where the character should be - so it tries to move the character down.

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

Graphics.createCallback in Bangle.js 1 vs 2 | Vector Font | Font converter

Posted by Avatar for ff2005 @ff2005

Actions