|
0
|
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" |