-
Notifications
You must be signed in to change notification settings - Fork 480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve pretty_poly performance #840
Conversation
(cherry picked from commit 1077a12ff4fd958a7ea6d9e4fa5a86551eba5126)
This new commit should bringit into line with lowfatcode/pretty-poly#1 |
Confirmed with tests on 320x240 PicoW Explorer, significant improvement in regular polygons and quite a bump in the brutal Jokerman test. Awesome stuff, thank you! Spinny G testBefore60 frames in 8246.00ms, 137.43ms per frame avg After60 frames in 2068.00ms, 34.47ms per frame avg Jokerman testBefore60 frames in 7571ms, avg 126.18ms per frame, 7.92 FPS After60 frames in 6457ms, avg 107.62ms per frame, 9.29 FPS Spiny G: import time
import math
import gc
import random
from picographics import PicoGraphics, DISPLAY_PICO_W_EXPLORER, PEN_RGB332
from picovector import PicoVector, Polygon, RegularPolygon, Rectangle, ANTIALIAS_NONE, ANTIALIAS_X4, ANTIALIAS_X16
import pngdec
display = PicoGraphics(DISPLAY_PICO_W_EXPLORER, pen_type=PEN_RGB332)
display.set_backlight(0.5)
png = pngdec.PNG(display)
png.open_file("Untitled1.png")
vector = PicoVector(display)
vector.set_antialiasing(ANTIALIAS_X4)
BLACK = display.create_pen(0, 0, 0)
WHITE = display.create_pen(255, 255, 255)
WIDTH, HEIGHT = display.get_bounds()
def bake_radial_graph(ox, oy, radius, thickness, resolution=45):
outer_points = []
inner_points = []
angle_per_point = math.radians(360.0 / resolution)
outer = radius
inner = radius - thickness
for x in range(resolution):
a = angle_per_point * x
s = math.cos(a)
c = math.sin(a)
in_x = int(c * inner) + ox
out_x = int(c * outer) + ox
in_y = int(s * inner) + oy
out_y = int(s * outer) + oy
outer_points.append((out_x, out_y))
inner_points.insert(0, (in_x, in_y))
return outer_points, inner_points
a = 2
d = 1
clr_outer_points, clr_inner_points = bake_radial_graph(int(WIDTH / 2), int(HEIGHT / 2), 122, 24)
outer_points, inner_points = bake_radial_graph(int(WIDTH / 2), int(HEIGHT / 2), 120, 20)
num_points = len(outer_points)
angle = 0
display.set_pen(BLACK)
display.clear()
png.decode(59, 20)
poly_list = []
inner_start = inner_points[0]
outer_start = outer_points[-1]
for hue in range(1, len(inner_points)):
points = [inner_start, inner_points[hue], outer_points[-(hue + 1)], outer_start]
inner_start = inner_points[hue]
outer_start = outer_points[-(hue + 1)]
poly_list.append(Polygon(*points))
points = [inner_start, inner_points[0], outer_points[-1], outer_start]
poly_list.append(Polygon(*points))
hue_map = []
for hue in range(0, len(inner_points)):
hue_map.append(display.create_pen_hsv(hue / num_points, 1.0, 1.0))
MX = int(WIDTH / 2)
MY = int(HEIGHT / 2)
clra, clrb = Polygon(*clr_inner_points), Polygon(*clr_outer_points)
clrboth = clra, clrb
t_total = 0
f_total = 0
while True:
t_start = time.ticks_ms()
display.set_pen(BLACK)
vector.draw(clra, clrb)
#vector.draw(*clrboth)
#vector.draw(Polygon(*clr_inner_points), Polygon(*clr_outer_points))
for p in poly_list:
vector.rotate(p, 8, MX, MY)
for hue in range(0, num_points):
display.set_pen(hue_map[hue])
#p = Polygon(*list(poly_list[hue]))
#vector.rotate(p, angle, int(WIDTH / 2), int(HEIGHT / 2))
p = poly_list[hue]
vector.draw(p)
t_end = time.ticks_ms()
t_total += t_end - t_start
f_total += 1
if f_total == 60:
print(f"60 frames in {t_total:.02f}ms, {t_total / 60:.02f}ms per frame avg")
f_total = 0
t_total = 0
display.update()
a += d
if a >= num_points:
d = -1
if a <= 2:
d = 1
angle += 8
angle %= 360
time.sleep(1.0 / 60) Jokerman: import time
import math
import random
import machine
from picographics import PicoGraphics, DISPLAY_PICO_W_EXPLORER, PEN_RGB332
from picovector import PicoVector, Polygon, RegularPolygon, Rectangle, ANTIALIAS_NONE, ANTIALIAS_X4, ANTIALIAS_X16
machine.freq(250_000_000)
display = PicoGraphics(DISPLAY_PICO_W_EXPLORER, pen_type=PEN_RGB332)
display.set_backlight(0.8)
vector = PicoVector(display)
vector.set_antialiasing(ANTIALIAS_NONE)
RED = display.create_pen(255, 0, 0)
ORANGE = display.create_pen(255, 128, 0)
YELLOW = display.create_pen(255, 255, 0)
GREEN = display.create_pen(0, 255, 0)
BLUE = display.create_pen(0, 0, 255)
VIOLET = display.create_pen(255, 0, 255)
BLACK = display.create_pen(0, 0, 0)
GREY = display.create_pen(128, 128, 128)
WHITE = display.create_pen(255, 255, 255)
result = vector.set_font("/Jokerman-Regular.af", 30)
WIDTH, HEIGHT = display.get_bounds()
X = int(WIDTH / 2)
Y = int(HEIGHT / 2)
a = 0
frames = 0
t_count = 0
t_total = 0
while True:
tstart = time.ticks_ms()
display.set_pen(BLACK)
display.clear()
for x in range(8):
c = 31 + (x * 32)
display.set_pen(display.create_pen(255-c, 0, c))
vector.text("Hello World\nHello World", X, Y, angle=x * 45 + a)
display.update()
a += 1
tfinish = time.ticks_ms()
total = tfinish - tstart
t_total += total
t_count += 1
if t_count == 60:
per_frame_avg = t_total / t_count
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
t_count = 0
t_total = 0
# pause for a moment (important or the USB serial device will fail)
# try to pace at 60fps or 30fps
if total > 1000 / 30:
time.sleep(0.0001)
elif total > 1000 / 60:
t = 1000 / 30 - total
time.sleep(t / 1000)
else:
t = 1000 / 60 - total
time.sleep(t / 1000) |
While looking at the performance of the alpha blend, I noticed there were lots of blank rows. This led me to suspect there would be some easy wins in the polygon rendering side of things.
Main change is to track the actually used tile bounds in render_nodes so the graphics callback only renders the used part of the tile (and indeed only if it is used at all). Potentially this could be done more efficiently earlier, but this way is relatively simple.
Additionally I fixed up the todo in
add_line_segment_to_nodes
so it's not running through out of bounds rows.