Mercurial > yawc
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" |
