nx_img_resample.nx source
↩ module page · 123 lines · 5246 B
1// nx_img_resample.nx -- selectable-model image resampler (the "easily
2// selectable models" ask). One entry point picks the model by id:
3//
4// nx_img_resample(model, src, sw, sh, nc, dst, dw, dh)
5// NEAREST -> nx_img_scale_nearest (this file)
6// BILINEAR -> nx_img_scale_bilinear (nx_img_scale.nx, reused)
7// BICUBIC -> nx_img_scale_bicubic (this file, Catmull-Rom 16-tap)
8//
9// All sovereign, hardware-rung-up (pure i64 fixed-point). New models (Lanczos,
10// and later a neural upscaler once the accel lock breaks) slot in as new ids.
11// Reuses _img_clamp / _img_srccoord / NX_IMG_Q from nx_img_scale (DRY #15).
12// license_tier: ORIGINAL
13
14import "nx_syscalls.nx"
15import "nx_img_scale.nx"
16const NX_MAGIC_32768: i64 = 32768
17const NX_MAGIC_65536: i64 = 65536
18const NX_MAGIC_131072: i64 = 131072
19const NX_MAGIC_8589934592: i64 = 8589934592
20const NX_MAGIC_17179869184: i64 = 17179869184
21
22const NX_RS_NEAREST: i64 = 0
23const NX_RS_BILINEAR: i64 = 1
24const NX_RS_BICUBIC: i64 = 2
25const NX_RS_N: i64 = 3
26
27// ===== nearest-neighbour =======================================
28func nx_img_scale_nearest(src: *u8, sw: i64, sh: i64, nc: i64,
29 dst: *u8, dw: i64, dh: i64) -> i64 {
30 if sw <= 0 { return -1 }
31 if sh <= 0 { return -1 }
32 if dw <= 0 { return -1 }
33 if dh <= 0 { return -1 }
34 if nc <= 0 { return -1 }
35 var y: i64 = 0
36 while y < dh {
37 let sy: i64 = _img_srccoord(y, sh, dh)
38 let ny: i64 = _img_clamp((sy + NX_MAGIC_32768) / NX_MAGIC_65536, 0, sh - 1)
39 var x: i64 = 0
40 while x < dw {
41 let sx: i64 = _img_srccoord(x, sw, dw)
42 let nxx: i64 = _img_clamp((sx + NX_MAGIC_32768) / NX_MAGIC_65536, 0, sw - 1)
43 let sbase: i64 = (ny * sw + nxx) * nc
44 let dbase: i64 = (y * dw + x) * nc
45 var c: i64 = 0
46 while c < nc {
47 dst[dbase + c] = src[sbase + c]
48 c = c + 1
49 }
50 x = x + 1
51 }
52 y = y + 1
53 }
54 return 0
55}
56
57// ===== bicubic (Catmull-Rom, a=-0.5) ===========================
58// weights bracket b[i] = 2 * w_i * Q16 (signed Q16); sum(b) = 2*Q16 = 131072.
59func _bicubic_w(t: i64, b: *i64) -> i64 {
60 let t2: i64 = (t * t) / NX_MAGIC_65536
61 let t3: i64 = (t2 * t) / NX_MAGIC_65536
62 b[0] = 0 - t3 + 2 * t2 - t
63 b[1] = 3 * t3 - 5 * t2 + NX_MAGIC_131072
64 b[2] = 0 - (3 * t3) + 4 * t2 + t
65 b[3] = t3 - t2
66 return 0
67}
68
69func nx_img_scale_bicubic(src: *u8, sw: i64, sh: i64, nc: i64,
70 dst: *u8, dw: i64, dh: i64) -> i64 {
71 if sw <= 0 { return -1 }
72 if sh <= 0 { return -1 }
73 if dw <= 0 { return -1 }
74 if dh <= 0 { return -1 }
75 if nc <= 0 { return -1 }
76 let bx: *i64 = sys_mmap(64) as *i64
77 let by: *i64 = sys_mmap(64) as *i64
78 var y: i64 = 0
79 while y < dh {
80 let sy: i64 = _img_srccoord(y, sh, dh)
81 let yb: i64 = sy / NX_MAGIC_65536
82 _bicubic_w(sy - yb * NX_MAGIC_65536, by)
83 let r0: i64 = _img_clamp(yb - 1, 0, sh - 1) * sw
84 let r1: i64 = _img_clamp(yb, 0, sh - 1) * sw
85 let r2: i64 = _img_clamp(yb + 1, 0, sh - 1) * sw
86 let r3: i64 = _img_clamp(yb + 2, 0, sh - 1) * sw
87 var x: i64 = 0
88 while x < dw {
89 let sx: i64 = _img_srccoord(x, sw, dw)
90 let xb: i64 = sx / NX_MAGIC_65536
91 _bicubic_w(sx - xb * NX_MAGIC_65536, bx)
92 let x0: i64 = _img_clamp(xb - 1, 0, sw - 1)
93 let x1: i64 = _img_clamp(xb, 0, sw - 1)
94 let x2: i64 = _img_clamp(xb + 1, 0, sw - 1)
95 let x3: i64 = _img_clamp(xb + 2, 0, sw - 1)
96 let dbase: i64 = (y * dw + x) * nc
97 var c: i64 = 0
98 while c < nc {
99 let h0: i64 = bx[0]*(src[(r0+x0)*nc+c] as i64) + bx[1]*(src[(r0+x1)*nc+c] as i64) + bx[2]*(src[(r0+x2)*nc+c] as i64) + bx[3]*(src[(r0+x3)*nc+c] as i64)
100 let h1: i64 = bx[0]*(src[(r1+x0)*nc+c] as i64) + bx[1]*(src[(r1+x1)*nc+c] as i64) + bx[2]*(src[(r1+x2)*nc+c] as i64) + bx[3]*(src[(r1+x3)*nc+c] as i64)
101 let h2: i64 = bx[0]*(src[(r2+x0)*nc+c] as i64) + bx[1]*(src[(r2+x1)*nc+c] as i64) + bx[2]*(src[(r2+x2)*nc+c] as i64) + bx[3]*(src[(r2+x3)*nc+c] as i64)
102 let h3: i64 = bx[0]*(src[(r3+x0)*nc+c] as i64) + bx[1]*(src[(r3+x1)*nc+c] as i64) + bx[2]*(src[(r3+x2)*nc+c] as i64) + bx[3]*(src[(r3+x3)*nc+c] as i64)
103 let acc: i64 = by[0]*h0 + by[1]*h1 + by[2]*h2 + by[3]*h3
104 var v: i64 = (acc + NX_MAGIC_8589934592) / NX_MAGIC_17179869184
105 v = _img_clamp(v, 0, 255)
106 dst[dbase + c] = v as u8
107 c = c + 1
108 }
109 x = x + 1
110 }
111 y = y + 1
112 }
113 return 0
114}
115
116// ===== selectable dispatch =====================================
117func nx_img_resample(model: i64, src: *u8, sw: i64, sh: i64, nc: i64,
118 dst: *u8, dw: i64, dh: i64) -> i64 {
119 if model == NX_RS_NEAREST { return nx_img_scale_nearest(src, sw, sh, nc, dst, dw, dh) }
120 if model == NX_RS_BILINEAR { return nx_img_scale_bilinear(src, sw, sh, nc, dst, dw, dh) }
121 if model == NX_RS_BICUBIC { return nx_img_scale_bicubic(src, sw, sh, nc, dst, dw, dh) }
122 return -1
123}