I'm moving some octagons around and I found a serious bottleneck:
@win.event
def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
for o in octagons:
o.vertices = tuple(chain.from_iterable( (o.vertices[i]+dx, o.vertices[i+1]+dy) for i in range(0, 18, 2)))
The program starts lagging when about 1000 points (111 octagons) are moved at once. I must find a way to optimize it but OpenGL is the last straw I want to draw because I don't want to use an API I don't understand. Could someone suggest a way to make it faster? Any internal solution or should I use NumPy? Here's the whole code (mere 30 lines) if you want to run it on your machine:
import pyglet
from circle import octagon
from random import randrange
from itertools import chain
SIZE = 800
RADIUS = 50
COUNT = 50
WIN = SIZE, SIZE, 'Camera', True, 'tool' # x, y, caption, resizable, style
def rnd_c():
return (randrange(256), randrange(256), randrange(256)) * 9
def rnd_pos():
return randrange(SIZE)
win = pyglet.window.Window(*WIN, vsync=False) # vsync off to unlimit FPS
batch = pyglet.graphics.Batch()
octagons = [octagon(rnd_pos(), rnd_pos(), RADIUS, rnd_c(), batch, None) for _ in range(COUNT)]
fps = pyglet.clock.ClockDisplay()
@win.event
def on_draw():
win.clear()
batch.draw()
fps.draw()
@win.event
def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
for o in octagons:
o.vertices = tuple(chain.from_iterable( (o.vertices[i]+dx, o.vertices[i+1]+dy) for i in range(0, 18, 2)))
def on_step(dt):
pass
pyglet.clock.schedule(on_step)
pyglet.app.run()
Graphics are fine (I think). I can render 1000 steady octagons @ 300 FPS.
1 Answer 1
NumPy is just plain awesome! Now I can move 3X more octagons without any lag at all! And it greatly shortens the length of lines so I can use more descriptive names, too! Here's the NumPy version:
import pyglet
import numpy as np
from circle import octagon
from random import randrange
R = 50
SIZE = 800
COUNT = 333 # NO LAG! RUNS @ >60 FPS!
WIN = SIZE, SIZE, 'Camera', True, 'tool' # x, y, caption, resizable, style
def clr():
return (randrange(256), randrange(256), randrange(256)) * 9
def coord():
return randrange(SIZE)
win = pyglet.window.Window(*WIN, vsync=False) # to unlimit FPS
batch = pyglet.graphics.Batch()
shapes = [octagon(coord(), coord(), R, clr(), batch, None) for _ in range(COUNT)]
coords = np.array( [shape.vertices for shape in shapes], dtype=int)
fps = pyglet.clock.ClockDisplay()
@win.event
def on_draw():
win.clear()
batch.draw()
fps.draw()
@win.event
def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
global coords
for i, shape in enumerate(shapes):
coords[i][::2] += dx
coords[i][1::2] += dy
shape.vertices = tuple(coords[i])
def on_step(dt):
pass
pyglet.clock.schedule(on_step)
pyglet.app.run()