py5coding / py5generator

Meta-programming project that creates the py5 library code.
https://py5coding.org/
GNU General Public License v3.0
52 stars 13 forks source link

Make py5_tools.save_frames(), animated_gif(), and capture_frames(), etc available to Thonny users #67

Closed hx2A closed 2 years ago

hx2A commented 2 years ago

Have you tested py5_tools.animated_gif(} outside the Jupyter environment? I couldn't make it work yet, but I know a new release is coming out, I think next week I'll ask you some questions about this...

Originally posted by @villares in https://github.com/hx2A/py5generator/issues/58#issuecomment-1069906439

villares commented 2 years ago

Thanks for opening this!

Should it work in module mode as is? I'm afraid I have a broken mental model of how it would work....

import py5
import py5_tools

d = 0

def setup():
    py5.size(200, 200)
    # py5_tools.animated_gif('out.gif', 100, 0.2, 0.2)
    # starts collecting frames and freezes

def draw():
    global d
    py5.circle(100, 100, d)
    d += 1

py5.run_sketch()
py5_tools.animated_gif('out.gif', 100, 0.2, 0.2)  # imitating the documentation
# complains RuntimeError: The  current sketch is not running.
hx2A commented 2 years ago

Yes, that should work, but you might need a small pause between run_sketch() and the call to animated_gif().

The animated_gif() function will attach itself to module mode's "current sketch" and create a GIF from the frames. Currently the "current sketch" must be in the "running" state for it to work. It takes a short moment after calling run_sketch() for it to reach that state.

The fix that I will make for this issue it to allow animated_gif() to also attach itself to sketches in the "ready" state. That will let you call animated_gif() before run_sketch(), which will also make this work with the Thonny plugin.

It is a small fix but I seem to recall there was a reason why I did it the way it works now but I don't remember what it is. I don't want to create a bug somewhere else.

villares commented 2 years ago

Hmm, being able to attach in setup would solve this timing issue, I suppose?

I like the idea of being able to start the GIF capture from inside the sketch, maybe triggered by some event.

Would this be OK? Seems to work for me.

import py5
import py5_tools
import threading

d = 0

def setup():
    py5.size(200, 200)
    Capture().start()

def draw():
    global d
    py5.circle(100, 100, d)
    d += 1

class Capture(threading.Thread):
    def run(self):
        py5_tools.animated_gif('out.gif', 100, 0.2, 0.2)

py5.run_sketch()
hx2A commented 2 years ago

If it works, great. Threading might be more complicated than necessary though. You can also do something like this:

import py5_tools
import py5
import time

...

py5.run_sketch()

while !py5.is_running:
    time.sleep(0.1)

py5_tools.animated_gif('out.gif', 100, 0.2, 0.2)
villares commented 2 years ago

I agree, threading is rather complicated, but I suppose it is needed to start at an arbitrary, from, say, a user key_pressed() event.

Also, and that is something I'm afraid would be harder at this time, when using gifAnimation I sometimes add single frames at arbitrary times/events too...

hx2A commented 2 years ago

I agree, threading is rather complicated, but I suppose it is needed to start at an arbitrary, from, say, a user key_pressed() event.

Actually, after tomorrow's release, threading shouldn't be necessary. This should work:

def key_pressed():
    py5_tools.animated_gif('out.gif', 100, 0.2, 0.2)

And a single key press will start the gif creation process without stalling the Sketch.

What's happening here (or will be happening, after the release) is animated_gif() is adding a "hook" to the Sketch's draw method, and that hook will collect frames, create the gif, and then detach itself when it is done. The hook does all the work. The animated_gif() function returns after the hook has been added and has started doing its thing.

villares commented 2 years ago

So cool, thank you!

On Thu, 24 Mar 2022, 00:42 hx2A, @.***> wrote:

I agree, threading is rather complicated, but I suppose it is needed to start at an arbitrary, from, say, a user key_pressed() event.

Actually, after tomorrow's release, threading shouldn't be necessary. This should work:

def key_pressed(): py5_tools.animated_gif('out.gif', 100, 0.2, 0.2)

And a single key press will start the gif creation process without stalling the Sketch.

What's happening here (or will be happening, after the release) is animated_gif() is adding a "hook" to the Sketch's draw method, and that hook will collect frames, create the gif, and then detach itself when it is done. The hook does all the work. The animated_gif() function returns after the hook has been added and has started doing its thing.

— Reply to this email directly, view it on GitHub https://github.com/hx2A/py5generator/issues/67#issuecomment-1077036962, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA4GADC3GVLXLLGUSNWUEQTVBPQDDANCNFSM5RMGWT6A . You are receiving this because you were mentioned.Message ID: @.***>

hx2A commented 2 years ago

I'm fixing small bugs today.