My goal:
Write a class that plots something after creating a window and using vao.render(mode=moderngl.PATCHES)
only when an update()
method is called, in order to update a dynamic VBO. imshow
by matplotlib is just toooo slow.
The issue:
Based on these Github issues #114, #216 and this example, I created a custom window setup that does not have a run()
method. Instead, a vertex array object (VAO), which is an instance attribute of the class, is rendered once when the class is initialized. Then an update(inputs)
method is used to change a dynamic vertex buffer object (VBO), also an instance attribute, by using self.vbo.write(inputs)
and the VAO is re-rendered, followed by a swap_buffers()
call.
BUT I cannot resize/move/close the window when other python codes are running.
The question:
Is there a simple way to "fix" this issue?
What I've done thus far
Taking matplotlib.pyplot.show() as inspiration, though ultimately adulterating the idea, I created a dictionary as a class attribute.
For every new object created from my class, a distinct int
is added as a key to this dictionary with the corresponding value being an alias of the object itself.
Then I created a static method that render()
s all open objects of this class indefinitely, until the last one is closed.
The issue with this is that it is a bit unresponsive...
Below there is a sample of the idea I programmed:
# to illustrate the main packages I actually use, they are written here
import numpy as np
import moderngl
import moderngl_window
from moderngl_window.conf import settings
class myViewerClass:
# A dict as a mutable class attribute to keep track
# of all instances of this class
_manager_dict = {}
def __init__(self): # there can be more inputs here
# more code here
# Edit: I initialize the windows here using settings
# close, resize, key, mouse click events, among others
# are all implemented here
self.wnd = moderngl_window.create_window_from_settings()
# if no instances of this class exists yet
if not myViewerClass._manager_dict:
# assign a key of 0 to the first instance of this class
self._num = 0
else:
# else, assign a distinct integer greater than the maximum
# one found in the dict's keys
self._num = max(myViewerClass._manager_dict.keys())+1
# save an alias of the generated object in the dict
myViewerClass._manager_dict[self._num] = self
@staticmethod
def show_all():
# run while there are still open windows
# this works because the dictionary evaluates to True
# while it is not empty
while myViewerClass._manager_dict:
for window in myViewerClass._manager_dict.values():
window.wnd.clear() # this is from moderngl_window
window.render() # this is an instance method that is
# implemented in this class using
# OpenGL (ModernGL)
window.wnd.swap_buffers() # also from moderngl_window
if window.wnd.is_closing():
# delete this object's entry in the class dict
del myViewerClass._manager_dict[window._num]
# close the window
window.wnd.destroy()
break # this is necessary because the dict's
# length has changed, which issues an
# error in the `for` loop
Edit 1: The above code does work. For either a single or multiple objects. But the myViewerClass.show_all()
method seems a bit laggy. After manipulating one window (e.g. resizing it), the others start flickering. The flickering stops after clicking on them.
And after clicking on the close button of a certain window, if there are more than one windows open, it freezes instead of closing, while the other windows continue functioning. Suppose I had originally 3 windows open and close two of them, they freeze, but the third one continues working. All of the windows close simultaneously only after closing the third one as well.