Processing.py equivalent of drawing from within another thread?

Hi all, my first post here.

I’ve seen there are quite a few topics (in the old forums) about drawing from within another thread to be able to update the screen during intermediate states of different algorithms which are (because of multiple nested loops and/or recursive calls) not suitable to run from within the draw() loop (since they are not easy to convert to state machines to be called multiple times to do the task in the chunks).

This is one of the threads where that topic was discussed and I was looking for similar code for Processing in Python mode but couldn’t find one - so my question is if anyone could write a short minimal working example of drawing from outside of the draw() loop when using Python mode.

Note:
I tried to run the code from the above link which is for Java mode but that didn’t work in Processing 3.5.3 either.

1 Like

I’ve got this very ancient 1 for both Java & Python Modes: :cowboy_hat_face:

  1. Forum.Processing.org/two/discussion/25799/how-to-draw-a-rect-in-a-thread#Item_2
  2. How to draw a rect() in a Thread - Processing 2.x and 3.x Forum

But I’m also posting here shorter versions of both I’ve just made: :innocent:

// https://Discourse.Processing.org/t/
// processing-py-equivalent-of-drawing-from-within-another-thread/11983/3

// GoToLoop (2019/Jun/10)

static final int INTERVAL = 1000;
static final color ALL_COLORS = PImage.ALPHA_MASK;

PGraphics pg;
int counter;

void setup() {
  size(400, 300);
  thread("pg_thread");
  while (pg == null)  delay(1);
}

void draw() {
  background(pg);
  getSurface().setTitle("Counter: " + counter + "  -  Frame: " + frameCount);
}

void pg_thread() {
  final PGraphics pgt = pg = createGraphics(width, height);
  final int cx = pgt.width >> 1, cy = pgt.height >> 1;

  pgt.beginDraw();
  pgt.strokeWeight(2.5);
  pgt.endDraw();

  for (;; ++counter, delay(INTERVAL)) {
    pgt.beginDraw();
    pgt.background((color) random(ALL_COLORS));
    pgt.fill((color) random(ALL_COLORS));
    pgt.circle(cx, cy, cx);
    pgt.endDraw();
  }
}
# https://Discourse.Processing.org/t/
# processing-py-equivalent-of-drawing-from-within-another-thread/11983/3

# GoToLoop (2019/Jun/10)

pg, counter = None, 0

def setup():
    size(400, 300)
    thread('pg_thread')
    while not pg: delay(1)


def draw(TITLE = 'Counter: %d  -  Frame: %d'):
    background(pg)
    this.surface.title = TITLE % (counter, frameCount)


def pg_thread(INTERVAL = 1000, ALL_COLORS = PImage.ALPHA_MASK):
    global pg, counter
    pgt = pg = createGraphics(width, height)
    cx, cy = pgt.width >> 1, pgt.height >> 1

    with pgt.beginDraw(): pgt.strokeWeight(2.5)

    while True:
        with pgt.beginDraw():
            pgt.background(int(random(ALL_COLORS)))
            pgt.fill(int(random(ALL_COLORS)))
            pgt.circle(cx, cy, cx)

        counter += 1
        delay(INTERVAL)
4 Likes

Hi, thank you very much for the reply! I think this is not what I was looking for. By adding this line into the draw() loop:

this.surface.title = "frame: %d" % (frameCount)

and changing the size to (400, 300) to make the space in the window title to show the text I can see the screen is not being updated at consistent intervals but the update time depends on the time spent in the t() function. As I understand that is because what redraw() does is to only set a flag but the screen really updates only after returning from the t().

What I am looking for might be described as trying to mimic the behavior of drawing when using old 8-bit computers where pixels on the screen would change upon executing the drawing command. For example, after the execution of the draw(x, y) on ZX Spectrum the draw() command would change the bytes in the part of the RAM designated as video memory from which the hardware (ULA) would 50 times per second read the contents and generate the video signal based on current state of the video memory. In fact on old computers the screen would update even during the execution of the draw() command - if the interrupt triggers at the moment when the draw() is still changing the pixels in the video memory, the screen is then updated in the middle of drawing the line. I am however not asking for that much, I am looking for ‘just’ being able to draw from the separate function which is running for a long time while the screen is being updated at a consistent framerate.

It seems the code posted by GoToLoop does exactly what I was looking for.

Thank you
Regards

1 Like

Hi,

thank you very much for the code!! That seems to be exactly what I was looking for :-))

I thing that concept of ‘old school’ way of drawing (I explained that in my reply to tabreturn) is very important and really should be among the basic Processing tutorials. For example, here is why I need to draw from outside of the draw() loop:

A while ago I was testing a hardware device prototype of 3D printer consisting of stepper motors and electrovalves. For prototyping I used Rasbperry Pi (I will later probably use microcontrollers) running Python. Since the hardware is quite big and heavy I can’t develop the algorithms at home so I thought I might develop a visualization of how the device works to be able to test the code even at home when I can’t test it on a real hardware.

I did manage to simulate 80% of the device by changing the code so it could be called from the draw() loop but for that I had to make quite a lot of changes into the original code and the rest was just to complicated to adapt for calling from within the draw() loop.

Let me now see if I understand how the code you posted work:

The first thing I am unable to find the documentation about is PImage.ALPHA_MASK. I have a feeling the Processing documentation is missing some essential data. For example it took me a while to realize I can use certain methods not only with the display window but with the PGraphics too. When I was reading the documentation of the filter() I read:

Filters the display window using a preset filter or with a custom shader.

But later I saw in some forum posts even:

pg = createGraphics(40, 40);
pg.filter()

works well. I tried to find the documentation about that but couldn’t find any :-/

Nevertheless, I am not sure how exactly is:

ALL_COLORS = PImage.ALPHA_MASK

here used to get the colors.

Next, you are running the new thread waiting for the pg to become valid before entering the draw() loop where it is used and in the pg_thread() you create PGraphics object, calculate width/2 and height/2 (is bit shift faster), drawing the intermediate state and invoking the delay().

Although I understand the basic concept, I would appreciatte if you could explain me a few details:

The first thing is - what is the purpose of pgt? Why couldn’t you use just pg? The same for interval and all_colors - why:

interval, all_colors = INTERVAL, ALL_COLORS

I didn’t know the draw() could have arguments.

I wouldn’t expect

with pgt.beginDraw():

could be used to avoid typing pgt.endDraw(). But as you might guess, I am comming from the embedded world (read C and assembler) :slight_smile:

BTW, can you tell why the code I linked in the first post doesn’t work? I mean the code in the before the last post in this thread.

Concluding from the very last post in that thread the code should work but it doesn’t.

Thank you again for the reply! I can see from the structure of your code you do know what you are doing :slight_smile:

Regards