Blend Modes¶
a multiply day/night tint and an additive flash.
▶ Run in browserTags: 2d
renderer.rect, renderer.polygon and renderer.texture take a blend= keyword that says how
the new colour combines with what is already on screen:
"alpha"(the default) paints over what is beneath, weighted by the colour’s alpha."multiply"multiplies the screen by the colour. White leaves it unchanged, 50% grey halves it, and a blue-tinted grey darkens it and pushes it toward blue, which is a day/night cycle in one full-screen rect."add"adds the colour to the screen, brightening toward white: the usual glow, muzzle-flash and explosion idiom.
Ops composite in the order they are drawn, so an overlay goes after the scene it affects. Here a row of opaque squares is drawn with the default blend, a multiply rect over the whole view cycles between day and night, and an additive rect flashes and fades on top.
A Timer fires a flash every three seconds; press Space, click or tap to fire one yourself.
Source¶
1# /// simvx
2# web = { width = 960, height = 540 }
3# screenshot_frame = 70
4# ///
5"""Blend Modes: a multiply day/night tint and an additive flash.
6
7`renderer.rect`, `renderer.polygon` and `renderer.texture` take a `blend=` keyword that says how
8the new colour combines with what is already on screen:
9
10- `"alpha"` (the default) paints over what is beneath, weighted by the colour's alpha.
11- `"multiply"` multiplies the screen by the colour. White leaves it unchanged, 50% grey halves
12 it, and a blue-tinted grey darkens it and pushes it toward blue, which is a day/night cycle
13 in one full-screen rect.
14- `"add"` adds the colour to the screen, brightening toward white: the usual glow,
15 muzzle-flash and explosion idiom.
16
17Ops composite in the order they are drawn, so an overlay goes after the scene it affects. Here a
18row of opaque squares is drawn with the default blend, a multiply rect over the whole view
19cycles between day and night, and an additive rect flashes and fades on top.
20
21A `Timer` fires a flash every three seconds; press Space, click or tap to fire one yourself.
22"""
23
24import math
25
26from simvx.core import Input, Key, Node2D, Pointer, Timer
27from simvx.graphics import App
28
29SQUARE_COLOURS = [
30 (0.90, 0.30, 0.25),
31 (0.95, 0.70, 0.20),
32 (0.30, 0.80, 0.40),
33 (0.25, 0.55, 0.95),
34 (0.65, 0.40, 0.90),
35]
36
37
38class BlendDemo(Node2D):
39 dynamic = True # the tint and the flash change every frame
40 input_context = {"flash": [Key.SPACE, Pointer.PRIMARY]}
41
42 def on_ready(self):
43 self.time = 0.0
44 self.flash = 0.0 # additive flash strength, fading from 1 to 0
45 timer = self.add_child(Timer(duration=3.0, one_shot=False, autostart=True))
46 timer.timeout.connect(self.fire_flash)
47
48 def fire_flash(self):
49 self.flash = 1.0
50
51 def on_update(self, dt):
52 if Input.just_pressed("flash"):
53 self.fire_flash()
54 self.time += dt
55 self.flash = max(0.0, self.flash - dt * 1.8)
56
57 def on_draw(self, renderer):
58 width, height = self.viewport_size
59 renderer.rect((0, 0), (width, height), fill=(0.85, 0.88, 0.92))
60 gap = width / (len(SQUARE_COLOURS) + 1)
61 size = min(120, gap * 0.8, height * 0.4)
62 for i, colour in enumerate(SQUARE_COLOURS):
63 renderer.rect((gap * (i + 1) - size / 2, (height - size) / 2), (size, size), fill=colour)
64
65 # Night goes 0 (noon, white: no change) to 1 (midnight); red drops most, blue least.
66 night = 0.5 - 0.5 * math.cos(self.time * 0.6)
67 tint = (1.0 - 0.75 * night, 1.0 - 0.65 * night, 1.0 - 0.35 * night)
68 renderer.rect((0, 0), (width, height), fill=tint, blend="multiply")
69
70 if self.flash > 0:
71 f = self.flash
72 renderer.rect((0, 0), (width, height), fill=(0.9 * f, 0.85 * f, 0.6 * f), blend="add")
73
74 # Example help overlay: not part of the technique shown.
75 text_width = width - 40
76 renderer.text("BLEND MODES", rect=(20, 16, text_width, 40), fit_to_width=True, fill=(0.1, 0.1, 0.12), scale=3)
77 renderer.text(
78 "multiply = day/night tint add = flash (Space, click or tap)",
79 rect=(20, 60, text_width, 30),
80 fit_to_width=True,
81 fill=(0.2, 0.2, 0.25),
82 scale=2,
83 )
84
85
86if __name__ == "__main__":
87 App(title="Blend Modes", width=960, height=540).run(BlendDemo())