code wiki / (root) / nx_raster_sw_test.nx

nx_raster_sw_test.nx source

↩ module page · 118 lines · 5094 B

1// nx_raster_sw_test.nx -- KAT for nx_raster_sw.nx Pineda 1988 2// edge-function triangle rasterizer. 3// 4// Verifies: 5// T1 signed-area sign convention (positive = front, zero = 6// degenerate, negative = back-facing). 7// T2 edge function on a known directed edge. 8// T3 reference triangle (2,2)(12,2)(2,12) -> exactly 36 pixels 9// covered with strict-interior convention. 10// T4 individual known-in / known-out pixels for the reference 11// triangle. 12// T5 vertex corners themselves are NOT drawn (strict-interior 13// convention; edge function evaluates to zero on vertex). 14// T6 degenerate (collinear) triangle -> 0 pixels written. 15// T7 back-facing (CW; negative area) triangle -> 0 pixels written. 16// T8 triangle fully outside framebuffer -> 0 pixels written; 17// no crash; bounding-box clip is honest. 18// T9 triangle partially outside framebuffer -> only in-bounds 19// pixels written; clipped pixels are silently not drawn (not 20// silently corrupted past the buffer). 21 22import "nx_syscalls.nx" 23import "nx_framebuffer.nx" 24import "nx_raster_sw.nx" 25 26func main() -> i64 { 27 let w: nx_int = 16 28 let h: nx_int = 16 29 let fb: *i64 = nx_fb_alloc(w, h) 30 let black: nx_int = 0 31 let red: nx_int = nx_fb_pack_rgba(255, 0, 0, 255) 32 nx_fb_clear(fb, w, h, black) 33 34 // ----- T1 signed area sign convention ----- 35 let a_front: i64 = nx_raster_signed_area_2x(2, 2, 12, 2, 2, 12) 36 if a_front <= 0 { return 1 } 37 let a_zero: i64 = nx_raster_signed_area_2x(2, 2, 5, 5, 8, 8) 38 if a_zero != 0 { return 2 } 39 let a_back: i64 = nx_raster_signed_area_2x(2, 2, 2, 12, 12, 2) 40 if a_back >= 0 { return 3 } 41 42 // ----- T2 edge function on a known directed edge ----- 43 // Edge (2,2)->(12,2) is horizontal. Pixel (5,5) is below. 44 // E = (12-2)*(5-2) - (2-2)*(5-2) = 30 45 let e_below: i64 = nx_raster_edge(2, 2, 12, 2, 5, 5) 46 if e_below != 30 { return 10 } 47 // Pixel (5,0) is above: E = (12-2)*(0-2) - (2-2)*(5-2) = -20 48 let e_above: i64 = nx_raster_edge(2, 2, 12, 2, 5, 0) 49 if e_above != -20 { return 11 } 50 51 // ----- T3 reference triangle coverage count = 36 ----- 52 let count_front: i64 = nx_raster_triangle( 53 fb, w, h, 2, 2, 12, 2, 2, 12, red 54 ) 55 if count_front != 36 { return 20 } 56 57 // ----- T4 known-in / known-out pixel reads ----- 58 if nx_fb_get(fb, w, h, 3, 3) != red { return 30 } 59 if nx_fb_get(fb, w, h, 5, 5) != red { return 31 } 60 if nx_fb_get(fb, w, h, 10, 3) != red { return 32 } 61 if nx_fb_get(fb, w, h, 1, 5) != black { return 33 } 62 if nx_fb_get(fb, w, h, 5, 1) != black { return 34 } 63 if nx_fb_get(fb, w, h, 12, 12) != black { return 35 } 64 if nx_fb_get(fb, w, h, 15, 15) != black { return 36 } 65 66 // ----- T5 vertex corners NOT drawn (strict-interior) ----- 67 if nx_fb_get(fb, w, h, 2, 2) != black { return 40 } 68 if nx_fb_get(fb, w, h, 12, 2) != black { return 41 } 69 if nx_fb_get(fb, w, h, 2, 12) != black { return 42 } 70 71 // ----- T6 degenerate (collinear) triangle -> 0 pixels ----- 72 nx_fb_clear(fb, w, h, black) 73 let count_zero: i64 = nx_raster_triangle( 74 fb, w, h, 2, 2, 5, 5, 8, 8, red 75 ) 76 if count_zero != 0 { return 50 } 77 // Falsification: nothing was written to the framebuffer. 78 if nx_fb_get(fb, w, h, 5, 5) != black { return 51 } 79 80 // ----- T7 back-facing (CW) triangle -> 0 pixels ----- 81 let count_back: i64 = nx_raster_triangle( 82 fb, w, h, 2, 2, 2, 12, 12, 2, red 83 ) 84 if count_back != 0 { return 60 } 85 if nx_fb_get(fb, w, h, 5, 5) != black { return 61 } 86 87 // ----- T8 triangle fully outside framebuffer -> 0 pixels ----- 88 let count_oob: i64 = nx_raster_triangle( 89 fb, w, h, 20, 20, 30, 20, 20, 30, red 90 ) 91 if count_oob != 0 { return 70 } 92 93 // ----- T9 triangle partially outside -> only in-bounds written ----- 94 // Triangle (10,10)(20,10)(10,20) extends past the 16x16 bound. 95 // In-bounds strict interior: pixel (x,y) with x>=11, y>=11, x+y<=29 96 // clipped to x<=15, y<=15. Enumerate: 97 // y=11: x in [11,15], that's 5 cells with x+y in [22,26] all <=29 OK 98 // y=12: x in [11,15], 5 cells 99 // y=13: x in [11,15], 5 cells 100 // y=14: x in [11,15], 5 cells 101 // y=15: x in [11,14] (x=15 gives x+y=30, not <=29; check: e1=0 not >0 -> excluded). 4 cells 102 // actually need x+y < 30 strict (x+y<=29). 103 // y=15: x+y<=29 -> x<=14 -> x in [11,14] = 4 cells 104 // Total = 5+5+5+5+4 = 24 cells in-bounds. 105 nx_fb_clear(fb, w, h, black) 106 let count_partial: i64 = nx_raster_triangle( 107 fb, w, h, 10, 10, 20, 10, 10, 20, red 108 ) 109 if count_partial != 24 { return 80 } 110 // Verify one specific known-in pixel got the color. 111 if nx_fb_get(fb, w, h, 11, 11) != red { return 81 } 112 // Verify a clipped-out pixel position (in original triangle but 113 // outside framebuffer) does not corrupt nearby memory by checking 114 // the framebuffer's outside-bounds read returns 0 sentinel. 115 if nx_fb_get(fb, w, h, 16, 16) != 0 { return 82 } 116 117 return 0 118}