How to draw a transparent PGraphics image? [SOLVED]

edited November 2016 in Questions about Code

EDIT: I do not believe this should be moved to / belongs in the Raspberry Pi category. The Pi is my motivation for doing this but I am running this at the moment on a normal windows install of Processing. The Pi is irrelevant for the time being.

I am using processing to make some gauge meters. My usual method is to draw a lot of primitives, but now that I'm trying to move to use the Raspberry Pi, I've noticed that my previous techniques are too intensive for it and the FPS drop makes it unusable.

So I'm trying a new technique. To simply draw an overlay to stamp over a primitive that represents the meter, to reduce the math required. This presents a problem, however, as I can't appear to figure out how to 'draw' transparency into a PGraphics thing. I want transparency where black is, essentially. How do I achieve this? I want the ring of black in the square gauge to be transparent and to show whatever I have behind it, in this case, the white pie graph. I will then draw text on top of this, and it should be a pretty clean way to draw gauges.

Thank you for the help!

PGraphics gaugeoverlay;

void setup() {
  size(500, 500);
  gaugeoverlay = createGraphics(200, 200); gaugeoverlay.beginDraw();
  gaugeoverlay.background(0);
  gaugeoverlay.endDraw();

  drawgauge();
}

void draw() {
  fill(255);
  noStroke();
  arc(100, 100, 170, 170, 0, PI+QUARTER_PI, PIE);

  image(gaugeoverlay, 0, 0);
}

void drawgauge() {
  gaugeoverlay.beginDraw();
  gaugeoverlay.fill(100);
  gaugeoverlay.noStroke();
  gaugeoverlay.rect(10, 10, 180, 180, 10);
  gaugeoverlay.fill(0);
  gaugeoverlay.ellipse(100, 100, 170, 170);
  gaugeoverlay.fill(100);
  gaugeoverlay.ellipse(100, 100, 150, 150);
  gaugeoverlay.endDraw();
}

Answers

  • Both fill() & stroke() got the alpha parameter:
    https://Processing.org/reference/fill_.html

  • I have attempted to add those values but all it does is make the ring transparent in relation to the grey rectangles in the PGraphics. What I want to do is make it so the grey is drawn, and all the black in the image is actually transparent so when I draw it on top of something else, I can see whatever is revealed by the black ring, which should have no pixels at all. I'm not sure how to do this.

  • The only black at your PGraphics is this 1: gaugeoverlay.fill(0);
    Have you really tried the alpha parameter, as taught by the reference? gaugeoverlay.fill(0, 0);

  • Yes, I have tried that, the result appears to be that the black ring disappears. I assume because it is completely transparent and not drawn? Or am I mistaken and something else is happening?

    Is there some kind of mode for drawing shapes/lines that 'erases' pixels instead of setting them? There appears to not be a way to set transparent pixels.

    Here is what I have tried. The ring simply no longer renders.

    PGraphics gaugeoverlay;
    
    void setup() {
      size(500, 500);
      gaugeoverlay = createGraphics(200, 200); gaugeoverlay.beginDraw();
      gaugeoverlay.background(0);
      gaugeoverlay.endDraw();
    
      drawgauge();
    }
    
    void draw() {
      fill(255);
      noStroke();
      arc(100, 100, 170, 170, 0, PI+QUARTER_PI, PIE);
    
      image(gaugeoverlay, 0, 0);
    }
    
    void drawgauge() {
      gaugeoverlay.beginDraw();
      gaugeoverlay.fill(100);
      gaugeoverlay.noStroke();
      gaugeoverlay.rect(10, 10, 180, 180, 10);
      gaugeoverlay.fill(0, 0);  //attempt to make ring transparent
      gaugeoverlay.ellipse(100, 100, 170, 170);
      gaugeoverlay.fill(100);
      gaugeoverlay.ellipse(100, 100, 150, 150);
      gaugeoverlay.endDraw();
    }
    
  • Answer ✓

    You're right. Indeed Processing doesn't have a way to erase things, but background() & clear().

    Once something is drawn at some place, drawing primitives like ellipse(), rect(), etc, can't remove it.

    That happens b/c Processing blends the colors of the existing pixel w/ the pixel about to be drawn.

    You'll have to create your own ellipse() function which got a chosen unblending color via pixels[].

  • Darn. Okay, thank you. I'll have to try something else, then.

  • edited November 2016

    Here's a very antique example: O:-)
    https://forum.Processing.org/two/discussion/598/mousewheel-syntax-question-solved

    However, given it's very old, in order to work w/ latest Processing versions, you're gonna have to add some canvas.beginDraw(); statements there. :-<

  • Is it possible to adapt the program on this thread to operate on a PGraphics instead of a PImage?

    https://forum.processing.org/one/topic/turn-white-pixels-transparent.html

  • edited November 2016

    Class PGraphics is a subclass of class PImage.
    Everything (members) which PImage have, PGraphics have equally and more! :-bd

  • edited November 2016 Answer ✓

    PGraphics transparency is possible and even normal. The thread title "impossible" is misleading.

    You are conceptually on the wrong track about masking with trying to "erase" pixels. This is because you are trying to draw the controls first, then the control plate. A much easier approach: draw on transparent surfaces.

    1. draw your controls in one layer.
    2. create a "cutouts" mask layer -- e.g. draw white rings for ring control cutouts, white boxes for box control cutouts, etc.
    3. apply mask to controls; draw the resulting "windows" on top of your backing / frame.

    Here is an example sketch with one control, and the mask cutout shown next to it. Notice the mask is drawn into a transparent PGraphics image: possible!

    /**
     * Transparent PGraphics
     * 2016-10-31 Jeremy Douglass - Processing 3.2.1
     * https:// forum.processing.org/two/discussion/18818/how-to-draw-a-transparent-pgraphics-image-not-possible-as-it-turns-out
     **/
    
    PGraphics gcontrols;
    PGraphics gmask;
    int gw, gh;
    
    void setup() {
      size(440, 220);
      gw = 220;
      gh = 220;
      gcontrols = createGraphics(gw, gh);
      gmask = createGraphics(gw, gh);
      //// make mask
      gmask.beginDraw();
        gmask.fill(0,0,0,0);      // transparent (ellipse is ring, not circle)
        gmask.stroke(255);        // white (mask area)
        gmask.strokeWeight(20);   // ring thickness
        gmask.ellipse(gw/2, gh/2, gw/2, gh/2);  // draw ring
      gmask.endDraw();
    }
    
    void draw() {
      background(64);
      //// draw plate
      fill(100);
      rect(10, 10, gw-20, gh-20, 10);
      //// render controls
      gcontrols.beginDraw();
        gcontrols.background(64,50,0);
        gcontrols.fill(255,56,0);
        gcontrols.arc(gw/2, gh/2, gw*0.75, gh*0.75, 0, (millis()%4000.0)/4000*TWO_PI, PIE); 
      gcontrols.endDraw();
      //// mask controls and draw
      gcontrols.mask(gmask);
      image(gcontrols, 0, 0);
    
      //// show mask
      image(gmask,220,0);
    }
    

    TransparentPGraphics

    Add as many cutouts to gmask and as many controls as you want to gcontrols, (two screen-size PGraphics layers), then combine once and display once with gcontrols.mask(gmask); image(gcontrols,0,0);.

  • edited November 2016 Answer ✓

    (accidental duplicate post)

  • Thank you so much! This is exactly what I wanted to do. I'm going to adapt my old gauge routine to do this instead.

  • edited November 2016

    Indeed mask() is a more advanced way to force transparent "holes" through PGraphics layer.

    But I think Processing should have some kinda hint() for turning off the auto-color blending for primitive drawings like ellipse(), rect(), etc.

    That is, the color set in fill() & stroke() would be drawn as is, rather than blending pixel-by-pixel over the existing pixels already in the canvas.

    That'd be much faster too! \m/

  • Of course, if you weren't developing a whole interface and just wanted simple gauges, you don't need masking. Instead you can use the OPEN mode of arc() and draw a heavy strokeWeight with no fill.

    /**
     * Simple Gauge
     * 2016-11-01 Jeremy Douglass Processing 3.2.1
     **/
    void setup(){
      size(200,200);
      fill(0,0,0,0);
      strokeWeight(20);
      stroke(255,56,0);
    }
    void draw(){
      background(0);
      arc(200/2, 200/2, 200*0.7, 200*0.7, 0, (millis()%4000.0)/4000*TWO_PI,OPEN); 
    }
    

    SimpleGauge

  • @GoToLoop -- so, if I'm understanding you right, something like PImage.blend() or PGraphics.blend() would be set on by default, but setting PGraphics.noBlend() could have all write operations replace target with source? Then "erasing" would work e.g.

    PGraphics pg = createGraphics(200,200);
    ....
    pg.noBlend();          // overwrite pixels without blending
    pg.fill(0,0,0,0);
    pg.rect(0,0,10,10); // make area fully transparent
    pg.blend();             // resume normal mode
    

    ...although it wouldn't work on the main sketch surface -- because no transparency.

  • I'm mostly looking to convert an existing program to involve less intensive operations so the Pi doesn't choke, as it appears to have massively less processing performance then the PC does. It takes a billion drawing operations to do it though, which I assume is why.

    This is what it looks like, I'm hoping to update it a bit and make it a bit slicker looking, too. I'm already having a good time with this masking system.

    It flashes red and stuff when values are critical, obviously. I like it.

  • Very cool! I see the stroke-nofill mask approach to your gauges also helps helping with those rounded-rect buttons.

  • edited November 2016

    @jeremydouglass, something like that. That'd make alpha "holes" more easily.
    And most importantly, pixel color blending is surely very expensive.
    Having the option to turn that off would gr8 increase performance for primitive drawings. $-)

  • @GoToLoop --

    I thought about writing this up as a feature request, then I just realized, isn't blendMode(REPLACE) already a hint() for turning off the auto-color blending for primitive drawings? I wasn't aware it existed.

    blendMode() reference

  • edited November 2016

    I wasn't aware it existed.

    Wow, me neither! 3:-O I didn't pay attention of that new stuff b/c I thought it was related to PImage rendering, like blend(), instead of primitive drawings. b-(

  • @itman -- could you share that image from above ( dronedisplayanimation.gif ) again?

  • edited October 2018

    @jeremydouglass

    Hello! I apologize for not noticing this sooner. I did not get any sort of notification. Here is the original gif, it appears dropbox nuked it when public sharing died?

  • edited October 2018

    Thanks so much, @ITman496. I'll cross-post it somewhere in the new forum -- unless you would like to list it there in the Gallery as a project to inspire others working on similar things.

    https://discourse.processing.org/c/gallery

    ...I had actually found a copy a couple weeks ago -- somehow -- and posted it here.

    https://discourse.processing.org/t/turn-gauge-arc-into-gradient/4103/11

  • @jeremydouglass

    Glad you found a copy! I will move to the new forum. I'm no longer working on this particular project anymore (finished!) so you can cross-post however you like =)

    I actually am back here because I want to adapt this trick to build a very similar gauge display for my ultralight aircraft I just got! And it is running on a Pi, so I do need it to be optimized. So again, thank you for the help.

  • See you on the other forum -- and looking forward to hearing more about the ultralight

Sign In or Register to comment.