I'm trying to draw an octagon with Python 3.4 and Pyglet 1.2, which uses OpenGL. My code seems to be correct but the drawing sometimes has additional triangle of random color (white or black most of the time) at random position (0, 0 (bottom left) corner most of the time) for a single frame. Here are some examples:
Some frames a perfect though:
Here's my short method:
from pyglet.gl import GL_TRIANGLES
from itertools import chain
C = 0.707 # const
def octagon (x, y, r, c, b, g):
""" Returns a vertex list of regular octagon with center at (x, y) and corners
distanced r away. Paints center and corners. Adds to batch b in group g. """
i = list(chain.from_iterable( (0, x+1, x+2) for x in range(8) ) )
i.extend( (0, 1, 8) )
p = x, y
p += x-r, y, x+int(-C*r), y+int(C*r), x, y+r, x+int(C*r), y+int(C*r)
p += x+r, y, x+int(C*r), y+int(-C*r), x, y-r, x+int(-C*r), y+int(-C*r)
return b.add_indexed(9, GL_TRIANGLES, g, i, ('v2i', p), ('c3B', c))
Here's my test code:
import pyglet
from circle import octagon
# Constants
WIN = 900, 900, 'TEST', False, 'tool' # x, y, caption, resizable, style
CENTER = WIN[0] // 2, WIN[1] // 2
RADIUS = 100
SPEED = 0.1 # duration of frame in seconds
# Color constants
WHITE = (255, 255, 255) # for center
RED = (255, 0, 0) # for corners
# Variables
win = pyglet.window.Window(*WIN)
batch = pyglet.graphics.Batch() # recreate batch every time
def on_step(dt):
global batch
batch = pyglet.graphics.Batch()
octagon(CENTER[0], CENTER[1], RADIUS, WHITE+RED*8, batch, None)
@win.event
def on_draw():
win.clear()
batch.draw()
pyglet.clock.schedule_interval(on_step, SPEED)
pyglet.app.run()
What I've tried:
However, nothing of these worked. What's the problem? Is this bug reproducible on your machine? The issue seems to occur randomly.
Edit: it's not that random, I suppose. I've tried a different test which doesn't delete batch every new frame and instead adds another octagon to the existing one. Here's what happens:
It seems they are all connected. Their centers, in particular. I guess it might be a bug in the code, after all.
Here's my second test:
import pyglet
from circle import octagon
from random import randrange
WIN = 900, 900, 'TEST', 0, 'tool', 0, 1, 0 # vsync off to unlimit fps
RADIUS = 60
SPEED = 1.0
WHITE = (255, 255, 255) # for center
RED = (255, 0, 0) # for points
win = pyglet.window.Window(*WIN)
batch = pyglet.graphics.Batch()
def on_step(dt):
global counter
x = randrange(RADIUS, WIN[0] - RADIUS)
y = randrange(RADIUS, WIN[1] - RADIUS)
octagon(x, y, RADIUS, WHITE+RED*8, batch, None)
@win.event
def on_draw():
win.clear()
batch.draw()
pyglet.clock.schedule_interval(on_step, SPEED)
pyglet.app.run()
Your index list is incorrect:
i = list(chain.from_iterable( (0, x+1, x+2) for x in range(8) ) )
[0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 9, 0, 1, 8]
Should be range(7)
.