Skip to content

Commit de142da

Browse files
committed
make star() another 2x faster via precompile/cache/scale (like ellipse)
1 parent 1ce2793 commit de142da

File tree

1 file changed

+44
-28
lines changed

1 file changed

+44
-28
lines changed

nodebox/graphics/context.py

+44-28
Original file line numberDiff line numberDiff line change
@@ -681,44 +681,59 @@ def arrow(x, y, width, **kwargs):
681681
glVertex2f(x, y)
682682
glEnd()
683683

684+
def gcd(a, b):
685+
return gcd(b, a % b) if b else a
686+
687+
_stars = {} #TODO: LRU?
684688
def star(x, y, points=20, outer=100, inner=50, **kwargs):
685689
""" Draws a star with the given points, outer radius and inner radius.
686690
The current stroke, strokewidth and fill color are applied.
687691
"""
688-
radii = [outer, inner] * int(points+1); radii.pop() # which radius?
689-
f = pi / points
690-
v = [(x+r*sin(i*f), y+r*cos(i*f)) for i, r in enumerate(radii)]
691-
692692
if kwargs.get("draw", True):
693-
fill, stroke, strokewidth, strokestyle = color_mixin(**kwargs)
694-
695-
if fill is not None:
696-
glColor4f(fill[0], fill[1], fill[2], fill[3] * _alpha)
697-
698-
glBegin(GL_TRIANGLE_FAN)
699-
glVertex2f(x, y)
700-
for (vx, vy) in v:
701-
glVertex2f(vx, vy)
702-
glEnd()
703-
704-
if stroke is not None and 0 < strokewidth:
705-
glLineWidth(strokewidth)
706-
if strokestyle != _strokestyle:
707-
glLineDash(strokestyle)
708-
glColor4f(stroke[0], stroke[1], stroke[2], stroke[3] * _alpha)
693+
scale = gcd(inner, outer)
694+
iscale = inner / scale
695+
oscale = outer / scale
696+
cached = _stars.get((points, iscale, oscale), [])
697+
if not cached:
698+
radii = [oscale, iscale] * int(points+1); radii.pop() # which radius?
699+
f = pi / points
700+
v = [(r*sin(i*f), r*cos(i*f)) for i, r in enumerate(radii)]
701+
cached.append(precompile(lambda:(
702+
glBegin(GL_TRIANGLE_FAN),
703+
glVertex2f(0, 0),
704+
[glVertex2f(vx, vy) for (vx, vy) in v],
705+
glEnd()
706+
)))
707+
cached.append(precompile(lambda:(
708+
glBegin(GL_LINE_LOOP),
709+
[glVertex2f(vx, vy) for (vx, vy) in v],
710+
glEnd()
711+
)))
712+
_stars[(points, iscale, oscale)] = cached
709713

710-
glBegin(GL_LINE_LOOP)
711-
for (vx, vy) in v:
712-
glVertex2f(vx, vy)
713-
glEnd()
714+
fill, stroke, strokewidth, strokestyle = color_mixin(**kwargs)
715+
for i, clr in enumerate((fill, stroke)):
716+
if clr is not None and (i == 0 or strokewidth > 0):
717+
if i == 1:
718+
glLineWidth(strokewidth)
719+
if strokestyle != _strokestyle:
720+
glLineDash(strokestyle)
721+
glColor4f(clr[0], clr[1], clr[2], clr[3] * _alpha)
722+
glPushMatrix()
723+
glTranslatef(x, y, 0)
724+
glScalef(scale, scale, 1)
725+
glCallList(cached[i])
726+
glPopMatrix()
714727
else:
715728
# For whatever reason, the original api specified that you
716-
# can get the path to the star. This is about 20x slower,
729+
# can get the path to the star. This is about 30x slower,
717730
# but I'm keeping it here for backwards compatibility.
718731
p = BezierPath(**kwargs)
719732
p.moveto(x, y+outer)
720-
for (vx, vy) in v:
721-
p.lineto(vx, vy)
733+
for i in range(0, int(2*points)+1):
734+
r = (outer, inner)[i%2]
735+
a = pi*i/points
736+
p.lineto(x+r*sin(a), y+r*cos(a))
722737
p.closepath()
723738
return p
724739

@@ -1486,7 +1501,8 @@ def texture(img, data=None):
14861501
return _texture_cache[img]
14871502
# Image file path, load it, cache it, return texture.
14881503
if isinstance(img, basestring):
1489-
try: cache(img, pyglet.image.load(img).get_texture())
1504+
try:
1505+
cache(img, pyglet.image.load(img).get_texture())
14901506
except IOError:
14911507
raise ImageError, "can't load image from %s" % repr(img)
14921508
return _texture_cache[img]

0 commit comments

Comments
 (0)