1
\$\begingroup\$

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.

200_success
145k22 gold badges190 silver badges478 bronze badges
asked May 22, 2015 at 16:49
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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()
answered May 22, 2015 at 19:08
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.