Search code examples
pythonopenglgraphicspolygonpyglet

Incorrectly drawn octagon (random) - NEW TEST ADDED


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:

bug1 bug2 bug3

Some frames a perfect though:

fine

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:

  • Restarting computer
  • Deleting py_cache folder with *.pyc files
  • Changing framerate
  • Changing radius and position
  • Printing a list of points repeatedly. None of them ever change (though drawing changes) and are in valid ranges.
  • Printing a list of indexes. None of them change and all are valid.

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:

connected

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()

Solution

  • 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).