comparison cursors/92h.sh @ 0:f0372d3356b4 default tip

initial import
author Yasuri <linuxoverwindows@charliesmp.net>
date Sun, 30 Aug 2026 12:47:10 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f0372d3356b4
1 #!/bin/sh
2 # convert plan 9 cursor definitions in a C file to packed argb cursor_data[] + cursor_metadata[] for swc
3 # asage:
4 # ./92h.sh 9cursors.c > out.c
5 # ./92h.sh 9cursors.c tl t tr l r bl b br > out.c # explicit order/subset
6
7 infile=${1:-/dev/stdin}
8 shift 2>/dev/null || true
9
10 # remaining args are optional, desired cursor names in output order.
11 order="$*"
12
13 awk -v ORDER="$order" '
14 function hexval(c) {
15 c = toupper(c)
16 if (c >= "0" && c <= "9") return c + 0
17 return 10 + index("ABCDEF", c) - 1
18 }
19 function hex2dec(s, i,n) {
20 sub(/^0[xX]/, "", s)
21 n = 0
22 for (i = 1; i <= length(s); i++)
23 n = n * 16 + hexval(substr(s, i, 1))
24 return n
25 }
26 function pow2(n, i,p) { p=1; for(i=0;i<n;i++) p*=2; return p }
27 function bit16msb(v, col, shift) {
28 shift = 15 - col
29 return int(v / P2[shift]) % 2
30 }
31 function pix(setb, clrb) {
32 # clr=0,set=0 => transparent
33 # clr=1,set=0 => black
34 # clr=0,set=1 => white
35 # clr=1,set=1 => invert (approximate as white for ARGB cursors)
36 if (!clrb && !setb) return "0x00000000"
37 if (clrb && !setb) return "0xff000000"
38 if (!clrb && setb) return "0xffffffff"
39 return "0xffffffff"
40 }
41 function min(a,b){ return (a<b)?a:b }
42 function max(a,b){ return (a>b)?a:b }
43
44 BEGIN {
45 # precompute powers of two up to 15
46 for (i=0;i<16;i++) P2[i]=pow2(i)
47
48 want_cnt = 0
49 if (ORDER != "") {
50 n = split(ORDER, want, /[[:space:]]+/)
51 for (i=1;i<=n;i++) if (want[i] != "") { want_cnt++; wantlist[want[i]]=i }
52 }
53
54 in_cursor = 0
55 arr = 0
56 c1 = c2 = 0
57 name_cnt = 0
58 }
59
60 # start of a cursor block: cursor foo = {
61 match($0, /^[[:space:]]*Cursor[[:space:]]+[A-Za-z_][A-Za-z0-9_]*[[:space:]]*=/) {
62 # extract the name
63 line = $0
64 sub(/^[[:space:]]*Cursor[[:space:]]+/, "", line)
65 cur = line
66 sub(/[[:space:]]*=.*/, "", cur)
67
68 in_cursor = 1
69 got_hot = 0
70 arr = 0
71 c1 = 0
72 c2 = 0
73 next
74 }
75
76 # inside cursor: hotspot like {-7, -7}, compute it properly so it offsets,
77 in_cursor && !got_hot && match($0, /\{[[:space:]]*-?[0-9]+[[:space:]]*,[[:space:]]*-?[0-9]+[[:space:]]*\}/) {
78 s = substr($0, RSTART+1, RLENGTH-2)
79 gsub(/[[:space:]]*/, "", s)
80 split(s, a, ",")
81 hx[cur] = a[1] + 0
82 hy[cur] = a[2] + 0
83 got_hot = 1
84 }
85
86 in_cursor {
87 while (match($0, /0[xX][0-9A-Fa-f]+/)) {
88 tok = substr($0, RSTART, RLENGTH)
89 val = hex2dec(tok)
90
91 if (arr == 0) arr = 1
92 if (arr == 1) {
93 clr[cur, c1++] = val
94 if (c1 >= 32) arr = 2
95 } else {
96 set[cur, c2++] = val
97 }
98
99 $0 = substr($0, RSTART + RLENGTH)
100 }
101 }
102
103 # end of cursor block
104 in_cursor && /};/ {
105 in_cursor = 0
106
107 if (!(seen[cur]++)) {
108 name_cnt++
109 names[name_cnt] = cur
110 }
111
112 if (c1 < 32 || c2 < 32) {
113 warn[cur] = 1
114 }
115 }
116
117 END {
118 # decide output order
119 outn = 0
120 if (want_cnt > 0) {
121 for (i=1; i<=want_cnt; i++) out[++outn] = want[i]
122 } else {
123 for (i=1; i<=name_cnt; i++) out[++outn] = names[i]
124 }
125
126 print "/* generated from plan 9 cursor data */"
127 print "#include <stdint.h>"
128 print "#include <stddef.h>"
129 print ""
130 print "enum {"
131 for (oi=1; oi<=outn; oi++) {
132 n = out[oi]
133 if (n == "") continue
134 name = toupper(n)
135 gsub(/[^A-Z0-9]+/, "_", name)
136 printf "\tNEIN_CURSOR_%s = %d,\n", name, oi-1
137 }
138 print "};"
139 print ""
140 print "static const uint32_t nein_cursor_data[] = {"
141
142 off = 0
143 perline = 0
144
145 for (oi=1; oi<=outn; oi++) {
146 n = out[oi]
147 if (n == "") continue
148 if (!(seen[n])) {
149 printf "/* WARNING: cursor %s not found */\n", n
150 continue
151 }
152 if (warn[n]) {
153 printf "/* WARNING: cursor %s looked incomplete (expected 32 clr + 32 set bytes) */\n", n
154 }
155
156 # build full 16x16 pixels and compute tight bbox
157 minx=16; miny=16; maxx=-1; maxy=-1
158 for (y=0; y<16; y++) {
159 rowc = clr[n,2*y]*256 + clr[n,2*y+1]
160 rows = set[n,2*y]*256 + set[n,2*y+1]
161 for (x=0; x<16; x++) {
162 pb = pix(bit16msb(rows,x), bit16msb(rowc,x))
163 full[n,y,x] = pb
164 if (pb != "0x00000000") {
165 minx = min(minx, x); maxx = max(maxx, x)
166 miny = min(miny, y); maxy = max(maxy, y)
167 }
168 }
169 }
170
171 # if entirely transparent, fall back to 1x1
172 if (maxx < 0) { minx=0; maxx=0; miny=0; maxy=0 }
173
174 w = maxx - minx + 1
175 h = maxy - miny + 1
176
177 #offset hostspot
178 xhot = -hx[n]
179 yhot = -hy[n]
180
181 hx2 = xhot - minx
182 hy2 = yhot - miny
183
184 meta_name[oi] = n
185 meta_w[oi] = w
186 meta_h[oi] = h
187 meta_hx[oi] = hx2
188 meta_hy[oi] = hy2
189 meta_off[oi] = off
190
191 for (y=miny; y<=maxy; y++) {
192 for (x=minx; x<=maxx; x++) {
193 v = full[n,y,x]
194 if (perline == 0) printf "\t"
195 printf "%s,", v
196 perline++
197 off++
198 if (perline >= 6) { printf "\n"; perline = 0 }
199 else printf " "
200 }
201 }
202 if (perline != 0) { printf "\n"; perline = 0 }
203 }
204
205 print "};"
206 print ""
207 print "struct nein_cursor_meta {"
208 print "\tuint32_t width, height;"
209 print "\tint32_t hotspot_x, hotspot_y;"
210 print "\tsize_t offset;"
211 print "};"
212 print ""
213 print "static const struct nein_cursor_meta nein_cursor_metadata[] = {"
214
215 for (oi=1; oi<=outn; oi++) {
216 n = meta_name[oi]
217 if (n == "") continue
218 printf "\t{ %d, %d, %d, %d, %d }, /* %s */\n",
219 meta_w[oi], meta_h[oi], meta_hx[oi], meta_hy[oi], meta_off[oi], n
220 }
221
222 print "};"
223 }
224 ' "$infile"