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}