code wiki / (root) / nx_paint_blend_test.nx

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}