nx_paint_blend_test.nx source
↩ module page · 124 lines · 4938 B
1// nx_paint_blend_test.nx -- smoke for alpha-blending rect fill.
2// Verifies (a) src.a=0 is a no-op, (b) src.a=255 overwrites, (c)
3// intermediate alpha mixes correctly per source-over math, (d)
4// clipping matches nx_paint_solid_rect semantics.
5
6import "nx_syscalls.nx"
7import "nx_css_color_decode.nx"
8import "nx_paint_solid_rect.nx"
9import "nx_paint_blend.nx"
10
11func main() -> i64 {
12 let w: i64 = 16
13 let h: i64 = 16
14 let pixels: *u8 = (sys_mmap((w * h * 4) as nx_size)) as *u8
15 let fb: *Framebuffer = (sys_mmap(NX_FRAMEBUFFER_BYTES as nx_size)) as *Framebuffer
16 nx_framebuffer_init(fb, pixels, w, h)
17 nx_framebuffer_clear(fb)
18
19 let green: *CssColor = (sys_mmap(NX_CSS_COLOR_BYTES as nx_size)) as *CssColor
20 green.r = 0
21 green.g = 255
22 green.b = 0
23 green.a = 255
24
25 let red_half: *CssColor = (sys_mmap(NX_CSS_COLOR_BYTES as nx_size)) as *CssColor
26 red_half.r = 255
27 red_half.g = 0
28 red_half.b = 0
29 red_half.a = 128 // ~50% alpha
30
31 let red_zero: *CssColor = (sys_mmap(NX_CSS_COLOR_BYTES as nx_size)) as *CssColor
32 red_zero.r = 255
33 red_zero.g = 0
34 red_zero.b = 0
35 red_zero.a = 0
36
37 let blue_full: *CssColor = (sys_mmap(NX_CSS_COLOR_BYTES as nx_size)) as *CssColor
38 blue_full.r = 0
39 blue_full.g = 0
40 blue_full.b = 255
41 blue_full.a = 255
42
43 let probe: *CssColor = (sys_mmap(NX_CSS_COLOR_BYTES as nx_size)) as *CssColor
44
45 // ---- 1. Fill background with green via solid rect ----
46 nx_paint_solid_rect(fb, 0, 0, w, h, green)
47 nx_framebuffer_get_pixel(fb, 5, 5, probe)
48 if probe.g != 255 { return 1 }
49 if probe.r != 0 { return 2 }
50
51 // ---- 2. Blend 50%-alpha red over green ----
52 // Source-over math for src=(255, 0, 0, 128), dst=(0, 255, 0, 255):
53 // inv_a = 127
54 // nr = (255*128 + 0*127 + 127) / 255 = (32640 + 127) / 255 = 32767/255 = 128
55 // ng = (0*128 + 255*127 + 127) / 255 = (32385 + 127) / 255 = 32512/255 = 127
56 // nb = (0*128 + 0*127 + 127) / 255 = 127/255 = 0
57 // na = 255 (we keep opaque dest)
58 let n_blend: i64 = nx_paint_blend_rect(fb, 4, 4, 8, 8, red_half)
59 if n_blend != 64 { return 10 }
60 nx_framebuffer_get_pixel(fb, 5, 5, probe)
61 if probe.r != 128 { return 11 }
62 if probe.g != 127 { return 12 }
63 if probe.b != 0 { return 13 }
64 if probe.a != 255 { return 14 }
65
66 // ---- 3. src.a == 0 is no-op (returns 0, no pixel change) ----
67 nx_framebuffer_get_pixel(fb, 10, 10, probe)
68 let r_before: i64 = probe.r
69 let g_before: i64 = probe.g
70 if nx_paint_blend_rect(fb, 0, 0, w, h, red_zero) != 0 { return 20 }
71 nx_framebuffer_get_pixel(fb, 10, 10, probe)
72 if probe.r != r_before { return 21 }
73 if probe.g != g_before { return 22 }
74
75 // ---- 4. src.a == 255 falls through to overwrite ----
76 let n_full: i64 = nx_paint_blend_rect(fb, 0, 0, 4, 4, blue_full)
77 if n_full != 16 { return 30 }
78 nx_framebuffer_get_pixel(fb, 2, 2, probe)
79 if probe.b != 255 { return 31 }
80 if probe.g != 0 { return 32 }
81 if probe.r != 0 { return 33 }
82
83 // ---- 5. Clipping matches nx_paint_solid_rect: oversized rect at
84 // (12, 12) of size 10x10 clips to 4x4 = 16 pixels ----
85 nx_framebuffer_clear(fb)
86 let n_clip: i64 = nx_paint_blend_rect(fb, 12, 12, 10, 10, red_half)
87 if n_clip != 16 { return 40 }
88
89 // ---- 6. Negative origin clipping: rect at (-3, -3) of size 6x6
90 // clips to 3x3 = 9 pixels ----
91 nx_framebuffer_clear(fb)
92 let n_neg: i64 = nx_paint_blend_rect(fb, 0 - 3, 0 - 3, 6, 6, red_half)
93 if n_neg != 9 { return 50 }
94
95 // ---- 7. Fully out-of-bounds returns 0 ----
96 if nx_paint_blend_rect(fb, 100, 100, 5, 5, red_half) != 0 { return 60 }
97 if nx_paint_blend_rect(fb, 0 - 100, 0 - 100, 5, 5, red_half) != 0 { return 61 }
98
99 // ---- 8. Zero / negative dims are no-ops ----
100 if nx_paint_blend_rect(fb, 0, 0, 0, 5, red_half) != 0 { return 70 }
101 if nx_paint_blend_rect(fb, 0, 0, 5, 0, red_half) != 0 { return 71 }
102 if nx_paint_blend_rect(fb, 0, 0, 0 - 1, 5, red_half) != 0 { return 72 }
103
104 // ---- 9. Stack blends: paint two half-alpha layers on top of green ----
105 // Reset framebuffer to green.
106 nx_paint_solid_rect(fb, 0, 0, w, h, green)
107 // Layer 1: half-red. Result at (5, 5) = (128, 127, 0) as computed above.
108 nx_paint_blend_rect(fb, 0, 0, w, h, red_half)
109 nx_framebuffer_get_pixel(fb, 5, 5, probe)
110 if probe.r != 128 { return 80 }
111 if probe.g != 127 { return 81 }
112 // Layer 2: another half-red. src=(255,0,0,128), dst=(128,127,0,255):
113 // inv_a = 127
114 // nr = (255*128 + 128*127 + 127) / 255 = (32640 + 16256 + 127) / 255
115 // = 49023 / 255 = 192
116 // ng = (0*128 + 127*127 + 127) / 255 = (16129 + 127) / 255
117 // = 16256 / 255 = 63
118 nx_paint_blend_rect(fb, 0, 0, w, h, red_half)
119 nx_framebuffer_get_pixel(fb, 5, 5, probe)
120 if probe.r != 192 { return 90 }
121 if probe.g != 63 { return 91 }
122
123 return 0
124}