Dynamic Window Layering

edited June 2017 in How To...

I'm working on a UI system where the user can move and resize windows. The focus goes where it should when you click and lets you manipulate window contents, and it overlaps correctly, but...

What I want is to be able to draw whatever I want in any particular type of window, but for it to always draw within the bounds of the window. Right now I can only draw rectangles, and it simply intersects their bounds with the window's before it draws each one, but, for example, there is no way to just draw a partial rounded rectangle (which happens to be my window shape) in Processing without an annoying manual construction, and if I ever want anything more complicated I'm probably not going to be able to / want to do it manually.

I considered using a stored PGraphics on each window, which would let me draw offscreen then paste in the area I want, but the user can resize windows (PGraphics can't be resized), and the documentation states that creating a new PGraphics is too expensive to do constantly.

Is there some faster way to draw anything I can draw on a PGraphics only within a certain rectangle? Would the slowdown from making a new PGraphics whenever the mouse drags actually not be that bad?

Tagged:

Answers

  • edited June 2017

    Use mask(). https://processing.org/reference/PImage_mask_.html

    You'll have to get creative with it.

  • Answering my own question here, (with inspiration from tfGuy44), but I've thought of three different ways to do it:

    Using a separate PGraphic and rect() for the mask (most efficient if window dimensions don't change often and myMask can be reused for each window):

    // myPGraphics and myMask are both PGraphics I create once per window at most
    // Both the same size as Processing window
    // myMask.fill(0), myMask.noStroke() already used on myMask
    myMask.beginDraw();
    myMask.background(255);
    myMask.rect(a1, a2, a3, a4) //These are my smaller window bounds
    myMask.endDraw();
    myPGraphics.beginDraw();
    // Clear PGraphics
    // Do the stuff with myPGraphics
    myPGraphics.mask(myMask);
    myPGraphics.endDraw();
    image(myPGraphics, 0, 0);
    

    Using a PImage and pixel iteration for the mask (Also efficient if window dimensions don't change, not sure if its better than the first one):

    // myPGraphics is created once, same size as Processing window
    PImage myMask = createImage(width, height, RGB);
    myMask.loadPixels();
    // Iterate through what will be the four white rectangles around the central rectangle
    // in four different for() loops in myMask, set them to white
    myMask.updatePixels();
    myPGraphics.beginDraw();
    // Clear PGraphics
    // Do the stuff with myPGraphics
    myPGraphics.mask(myMask);
    myPGraphics.endDraw();
    image(myPGraphics, 0, 0);
    

    Skipping the mask entirely and setting the pixels directly (leads to the fastest code if the window is actively moving at the time, otherwise it's pretty bad):

    // myPGraphics is created once, same size as Processing window
    myPGraphics.beginDraw();
    // Clear PGraphics if needed
    // Do the stuff with myPGraphics
    myPGraphics.endDraw();
    myPGraphics.loadPixels();
    // Iterate through what will be the four transparent rectangles around the central rectangle
    // in four different for() loops in myPGraphics, set them to transparent
    // * Not sure whether pixel manipulations need to be in draw section *
    myPGraphics.updatePixels();
    image(myPGraphics, 0, 0);
    

    My idea: cache myPGraphics and myMask whenever possible and stick with one of the first two options, but when you would need to update myMask, use the third option instead of updating it. If you get another go and it doesn't change, update, then use til it changes again.

    But I'd like to know if one of the first two options is the better one, definitely.

Sign In or Register to comment.