mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
198 lines
9.1 KiB
Python
198 lines
9.1 KiB
Python
"""Bars 0-16: the cold open (a prompt that the screen obeys) and the first build-up."""
|
|
import math
|
|
from anim import *
|
|
from kit import *
|
|
from devices import *
|
|
from engine import LW, LH, hexc
|
|
|
|
CLEAR_C = hexc('#0b2412')
|
|
|
|
|
|
def cold_open(E, f):
|
|
"""Bars 0-8. GL calls typed at a prompt; each one is executed by the frame itself."""
|
|
lb = f.lbeat
|
|
P = {'bloom': 0.7, 'grain': 0.032, 'vignette': 0.45}
|
|
bg(E, INK)
|
|
# glClear: flood from the prompt
|
|
if lb >= 8:
|
|
u = out_expo((lb - 8) / 1.2)
|
|
E.circle(150, 930, 2400 * u, CLEAR_C)
|
|
dot_grid(E, f, a(MOSS, 0.55 * u), 60, 2.2)
|
|
cmds = [ # text, type start, type end, execute beat
|
|
('glClearColor(0.04, 0.14, 0.07, 1.0);', 1.0, 3.6, 4.0),
|
|
('glClear(GL_COLOR_BUFFER_BIT);', 4.5, 7.0, 8.0),
|
|
('glDrawArrays(GL_TRIANGLES, 0, 3);', 9.0, 11.6, 12.0),
|
|
('glUseProgram(glue);', 16.0, 18.0, 20.0),
|
|
('// ...and now: run it on everything', 24.0, 27.5, 99.0),
|
|
]
|
|
# centre visual: triangle -> glue drop
|
|
cx, cy = 960, 470
|
|
if 12 <= lb < 22:
|
|
u = out_back((lb - 12) / 0.9, 2.2)
|
|
melt = in_out_cubic((lb - 20) / 2.0)
|
|
R = 300 * u * (1 - 0.85 * melt)
|
|
rot = 0.05 * (lb - 12) + 0.25 * melt
|
|
pts = [(cx + R * math.cos(rot - math.pi / 2 + k * 2 * math.pi / 3),
|
|
cy + 30 + R * math.sin(rot - math.pi / 2 + k * 2 * math.pi / 3)) for k in range(3)]
|
|
hp = 1 + 0.25 * f.hat
|
|
if melt < 1:
|
|
tri_rgb(E, pts, [scale_rgb(GLUE, 2.2 * hp), scale_rgb(PALE, 1.0), scale_rgb(MOSS, 1.3)])
|
|
if melt > 0: # vertices turn into glue and run to the centre
|
|
balls = [(lerp(px, cx, melt), lerp(py, cy + 30, melt), 30 + 120 * melt) for px, py in pts]
|
|
goo(E, balls, k=90, outline=6)
|
|
elif 22 <= lb:
|
|
bob = math.sin(f.lt * 3.0) * 8
|
|
stretch = 0.0
|
|
r = 150 + 10 * f.hat
|
|
if lb >= 24:
|
|
stretch = 260 * in_cubic((lb - 24) / 7.5)
|
|
balls = [(cx, cy + 30 + bob, r)]
|
|
caps = [(cx, cy + 30 + bob - stretch - 40, cx, cy + 30 + bob, r * 0.25, r * 0.95)] if stretch > 1 else []
|
|
z = 1 + 9 * in_expo((lb - 27) / 4.6)
|
|
E.cam = (cx, cy + 30 + bob, z, 0.0)
|
|
goo(E, balls, caps, k=80, outline=7, glow=0.2 * clamp01((lb - 24) / 8))
|
|
E.cam = (LW / 2, LH / 2, 1.0, 0.0)
|
|
if lb > 30.6:
|
|
bg(E, a(GLUE, clamp01((lb - 30.6) / 0.6)))
|
|
# prompt + log
|
|
py = 930
|
|
done = [c for c in cmds if lb >= c[2]]
|
|
cur = [c for c in cmds if c[1] <= lb < c[2] or (lb >= c[2] and lb < c[3])]
|
|
alpha_ui = 1.0 - clamp01((lb - 29) / 1.5)
|
|
for i, c in enumerate(reversed([c for c in cmds if lb >= c[3]])):
|
|
code_line(E, c[0], 150, py - 56 * (i + 1) - 20, 28, alpha=(0.55 - 0.1 * i) * alpha_ui)
|
|
active = None
|
|
for c in cmds:
|
|
if c[1] <= lb < c[3] and lb < 99:
|
|
active = c
|
|
E.text('>', 112, py, 30, a(GLUE, alpha_ui), font='mono', wght=700, align='left')
|
|
if active:
|
|
n = len(typed(f, active[0], active[1], active[2]))
|
|
code_line(E, active[0], 150, py, 30, chars=n, cursor=True, f=f, alpha=alpha_ui)
|
|
else:
|
|
code_line(E, '', 150, py, 30, chars=0, cursor=True, f=f, alpha=alpha_ui)
|
|
# execute flashes
|
|
for c in cmds:
|
|
u = lb - c[3]
|
|
if 0 <= u < 0.5:
|
|
E.rect(LW / 2, LH / 2, LW, LH, a(GLUE, 0.025 * (1 - u / 0.5)))
|
|
hud(E, f, 'MOBILEGL // REEL', 'OPENGL 4.6 CORE', alpha=clamp01(lb / 4) * alpha_ui)
|
|
if lb > 30.6:
|
|
P['exposure'] = 1.0 + 0.6 * clamp01((lb - 30.6) / 1.4)
|
|
return P
|
|
|
|
|
|
def your_app(E, f):
|
|
"""Bars 8-16: your app speaks GL 4.6 -> your device doesn't -> so we made the glue -> countdown."""
|
|
lb = f.lbeat
|
|
P = {'bloom': 0.5, 'grain': 0.035}
|
|
tb_ = lambda b: f.t - (lb - b) * S.BEAT # absolute time of local beat b
|
|
if lb < 8:
|
|
plate(E, f, 'mint', drift=(0, -12))
|
|
E.cam = (LW / 2, LH / 2, 1.0 + 0.004 * lb, -0.004 * lb)
|
|
x0 = 130
|
|
w = slam(E, f, 'YOUR', x0, 270, tb_(0), 210, INK, align='left')
|
|
slam(E, f, 'APP', x0 + w + 50, 270, tb_(1), 210, INK, align='left')
|
|
slam(E, f, 'SPEAKS', x0, 500, tb_(2), 210, INK, align='left')
|
|
w = slam(E, f, 'OPENGL', x0, 730, tb_(3), 210, INK, align='left')
|
|
slam(E, f, '4.6', x0 + w + 50, 730, tb_(3) + 0.06, 210, MOSS, align='left', wdth=80)
|
|
chips_ = ['#version 460 core', 'glBindVertexArray', 'glDrawElementsInstanced', 'GL_ARB_direct_state_access',
|
|
'glMultiDrawElementsIndirect', 'compute shaders', 'SSBOs', 'tessellation']
|
|
pos = [(1460, 190), (1500, 330), (1420, 470), (900, 900), (1430, 610), (420, 905), (1650, 905), (1300, 905)]
|
|
for i, s in enumerate(chips_):
|
|
bi = 4 + i * 0.5
|
|
if lb >= bi:
|
|
u = out_back((lb - bi) / 0.35)
|
|
chip(E, pos[i][0], pos[i][1], s, 30, BONE, INK, sc=u, rot=0.03 * math.sin(i * 2.3))
|
|
E.cam = (LW / 2, LH / 2, 1.0, 0.0)
|
|
elif lb < 16:
|
|
plate(E, f, 'ink')
|
|
w = slam(E, f, 'YOUR', 130, 190, tb_(8), 150, BONE, align='left')
|
|
w2 = slam(E, f, 'DEVICE', 130 + w + 40, 190, tb_(8.5), 150, BONE, align='left')
|
|
if lb >= 15:
|
|
stamp(E, f, "DOESN'T.", 960, 560, tb_(15), 210, CORAL, rot=-0.09, w_pad=50)
|
|
if lb >= 15:
|
|
P['shake'] = 1
|
|
screen_cam(E, f, shake=10 * math.exp(-(lb - 15) * 3))
|
|
devs = [('phone', 400, 'Android', 'OpenGL ES + Vulkan only'), ('laptop', 960, 'macOS', 'OpenGL 4.1, deprecated'),
|
|
('board', 1520, 'ARM Linux', 'GLES-only vendor drivers')]
|
|
for i, (kind, x, name, sub) in enumerate(devs):
|
|
bi = 9 + i
|
|
if lb < bi:
|
|
continue
|
|
u = out_back((lb - bi) / 0.4)
|
|
iso = Iso(x, 760 + 40 * (1 - u), 34 * u)
|
|
if kind == 'phone':
|
|
phone(E, iso, f)
|
|
elif kind == 'laptop':
|
|
laptop(E, iso, f, y=2.0)
|
|
else:
|
|
board(E, iso, f)
|
|
E.text(name, x, 880, 44, a(BONE, u), wght=800)
|
|
E.text(sub, x, 935, 24, a(BONE, 0.65 * u), font='mono', wght=500)
|
|
ci = 12 + i
|
|
if lb >= ci:
|
|
cross(E, x, 600, 120, CORAL, 26, (lb - ci) / 0.25)
|
|
E.cam = (LW / 2, LH / 2, 1.0, 0.0)
|
|
E.shake = (0.0, 0.0)
|
|
elif lb < 24:
|
|
plate(E, f, 'mint', drift=(10, 0))
|
|
slam(E, f, 'SO WE MADE', 960, 230, tb_(16), 120, INK, wdth=110)
|
|
size = fit_size(E, 'THE GLUE.', 1640)
|
|
if lb >= 18:
|
|
slam(E, f, 'THE GLUE.', 960, 470, tb_(18), size, INK, punch=0.25)
|
|
top = 470 - size * 0.36 # cap top
|
|
# a drop falls onto the words at beat 19 and drips over them
|
|
if lb >= 18.2:
|
|
fall = clamp01((lb - 18.2) / 0.8)
|
|
X = 1290
|
|
y = lerp(-150, top - 30, in_cubic(fall))
|
|
if fall < 1:
|
|
b, c = drop_shape(X, y, 56, 90 * fall)
|
|
goo(E, b, c, k=50)
|
|
else:
|
|
spread = out_expo((lb - 19) / 0.6)
|
|
balls = [(X, top - 18, 46 * (1 - 0.4 * spread))]
|
|
caps = [(X - 250 * spread, top - 6, X + 230 * spread, top - 6, 14, 14)]
|
|
for k, (dx, ln) in enumerate(((-230, 70), (-120, 150), (-20, 60), (80, 190), (190, 90))):
|
|
L = ln * out_cubic((lb - 19 - 0.12 * k) / 3.0)
|
|
x = X + dx * spread
|
|
if L > 2:
|
|
caps.append((x, top - 6, x, top - 6 + L, 10, 13))
|
|
balls.append((x, top - 6 + L, 17))
|
|
goo(E, balls, caps, k=34, outline=5, bevel=22)
|
|
# the crossed devices come back with checks
|
|
for i, (name, x) in enumerate((('Android', 560), ('macOS', 960), ('ARM Linux', 1360))):
|
|
bi = 20 + i
|
|
if lb < bi:
|
|
continue
|
|
u = out_back((lb - bi) / 0.3)
|
|
E.circle(x, 780, 80 * u, INK)
|
|
check(E, x, 780, 70 * u, GLUE, 14, (lb - bi - 0.1) / 0.3)
|
|
E.text(name, x, 910, 40, a(INK, u), wght=800)
|
|
E.line(x, 690, x, 600, 8, a(LEAF, u))
|
|
else:
|
|
# bars 14-15: loading bar, then 3-2-1, then one beat of silence
|
|
if lb < 28:
|
|
plate(E, f, 'ink')
|
|
u = clamp01((lb - 24) / 3.9)
|
|
k = int(u * 32)
|
|
E.text('LOADING DESKTOP OPENGL', 960, 420, 64, BONE, wght=800, wdth=110)
|
|
for i in range(32):
|
|
c = NEON if i < k else a(MOSS, 0.8)
|
|
E.rect(960 - 31 * 26 / 2 + i * 26, 540, 18, 54, c, r=3)
|
|
E.text(f'{int(u * 100):3d}%', 960, 640, 40, GLUE, font='mono', wght=700)
|
|
E.text('frontend · pipe · backend · window system', 960, 720, 24, a(BONE, 0.5), font='mono')
|
|
elif lb < 31:
|
|
i = int(lb - 28)
|
|
kind = ['glue', 'ink', 'mint'][i]
|
|
b, fg = plate(E, f, kind, grid=False)
|
|
slam(E, f, str(3 - i), 960, 560, tb_(28 + i), 760, fg if kind != 'ink' else NEON, punch=0.35, wght=900,
|
|
wdth=110)
|
|
P['shake'] = 1
|
|
screen_cam(E, f, shake=14 * math.exp(-(lb - 28 - i) * 5), seed=i)
|
|
else: # the silent beat: the block falls into the glue on the downbeat
|
|
pre_drop(E, f, 960, 330, 165, tb_(32))
|
|
P['grain'] = 0.05
|
|
return P
|