Mercurial > yawc
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cursors/92h.sh Sun Aug 30 12:47:10 2026 -0500 @@ -0,0 +1,224 @@ +#!/bin/sh +# convert plan 9 cursor definitions in a C file to packed argb cursor_data[] + cursor_metadata[] for swc +# asage: +# ./92h.sh 9cursors.c > out.c +# ./92h.sh 9cursors.c tl t tr l r bl b br > out.c # explicit order/subset + +infile=${1:-/dev/stdin} +shift 2>/dev/null || true + +# remaining args are optional, desired cursor names in output order. +order="$*" + +awk -v ORDER="$order" ' +function hexval(c) { + c = toupper(c) + if (c >= "0" && c <= "9") return c + 0 + return 10 + index("ABCDEF", c) - 1 +} +function hex2dec(s, i,n) { + sub(/^0[xX]/, "", s) + n = 0 + for (i = 1; i <= length(s); i++) + n = n * 16 + hexval(substr(s, i, 1)) + return n +} +function pow2(n, i,p) { p=1; for(i=0;i<n;i++) p*=2; return p } +function bit16msb(v, col, shift) { + shift = 15 - col + return int(v / P2[shift]) % 2 +} +function pix(setb, clrb) { + # clr=0,set=0 => transparent + # clr=1,set=0 => black + # clr=0,set=1 => white + # clr=1,set=1 => invert (approximate as white for ARGB cursors) + if (!clrb && !setb) return "0x00000000" + if (clrb && !setb) return "0xff000000" + if (!clrb && setb) return "0xffffffff" + return "0xffffffff" +} +function min(a,b){ return (a<b)?a:b } +function max(a,b){ return (a>b)?a:b } + +BEGIN { + # precompute powers of two up to 15 + for (i=0;i<16;i++) P2[i]=pow2(i) + + want_cnt = 0 + if (ORDER != "") { + n = split(ORDER, want, /[[:space:]]+/) + for (i=1;i<=n;i++) if (want[i] != "") { want_cnt++; wantlist[want[i]]=i } + } + + in_cursor = 0 + arr = 0 + c1 = c2 = 0 + name_cnt = 0 +} + +# start of a cursor block: cursor foo = { +match($0, /^[[:space:]]*Cursor[[:space:]]+[A-Za-z_][A-Za-z0-9_]*[[:space:]]*=/) { + # extract the name + line = $0 + sub(/^[[:space:]]*Cursor[[:space:]]+/, "", line) + cur = line + sub(/[[:space:]]*=.*/, "", cur) + + in_cursor = 1 + got_hot = 0 + arr = 0 + c1 = 0 + c2 = 0 + next +} + +# inside cursor: hotspot like {-7, -7}, compute it properly so it offsets, +in_cursor && !got_hot && match($0, /\{[[:space:]]*-?[0-9]+[[:space:]]*,[[:space:]]*-?[0-9]+[[:space:]]*\}/) { + s = substr($0, RSTART+1, RLENGTH-2) + gsub(/[[:space:]]*/, "", s) + split(s, a, ",") + hx[cur] = a[1] + 0 + hy[cur] = a[2] + 0 + got_hot = 1 +} + +in_cursor { + while (match($0, /0[xX][0-9A-Fa-f]+/)) { + tok = substr($0, RSTART, RLENGTH) + val = hex2dec(tok) + + if (arr == 0) arr = 1 + if (arr == 1) { + clr[cur, c1++] = val + if (c1 >= 32) arr = 2 + } else { + set[cur, c2++] = val + } + + $0 = substr($0, RSTART + RLENGTH) + } +} + +# end of cursor block +in_cursor && /};/ { + in_cursor = 0 + + if (!(seen[cur]++)) { + name_cnt++ + names[name_cnt] = cur + } + + if (c1 < 32 || c2 < 32) { + warn[cur] = 1 + } +} + +END { + # decide output order + outn = 0 + if (want_cnt > 0) { + for (i=1; i<=want_cnt; i++) out[++outn] = want[i] + } else { + for (i=1; i<=name_cnt; i++) out[++outn] = names[i] + } + + print "/* generated from plan 9 cursor data */" + print "#include <stdint.h>" + print "#include <stddef.h>" + print "" + print "enum {" + for (oi=1; oi<=outn; oi++) { + n = out[oi] + if (n == "") continue + name = toupper(n) + gsub(/[^A-Z0-9]+/, "_", name) + printf "\tNEIN_CURSOR_%s = %d,\n", name, oi-1 + } + print "};" + print "" + print "static const uint32_t nein_cursor_data[] = {" + + off = 0 + perline = 0 + + for (oi=1; oi<=outn; oi++) { + n = out[oi] + if (n == "") continue + if (!(seen[n])) { + printf "/* WARNING: cursor %s not found */\n", n + continue + } + if (warn[n]) { + printf "/* WARNING: cursor %s looked incomplete (expected 32 clr + 32 set bytes) */\n", n + } + + # build full 16x16 pixels and compute tight bbox + minx=16; miny=16; maxx=-1; maxy=-1 + for (y=0; y<16; y++) { + rowc = clr[n,2*y]*256 + clr[n,2*y+1] + rows = set[n,2*y]*256 + set[n,2*y+1] + for (x=0; x<16; x++) { + pb = pix(bit16msb(rows,x), bit16msb(rowc,x)) + full[n,y,x] = pb + if (pb != "0x00000000") { + minx = min(minx, x); maxx = max(maxx, x) + miny = min(miny, y); maxy = max(maxy, y) + } + } + } + + # if entirely transparent, fall back to 1x1 + if (maxx < 0) { minx=0; maxx=0; miny=0; maxy=0 } + + w = maxx - minx + 1 + h = maxy - miny + 1 + + #offset hostspot + xhot = -hx[n] + yhot = -hy[n] + + hx2 = xhot - minx + hy2 = yhot - miny + + meta_name[oi] = n + meta_w[oi] = w + meta_h[oi] = h + meta_hx[oi] = hx2 + meta_hy[oi] = hy2 + meta_off[oi] = off + + for (y=miny; y<=maxy; y++) { + for (x=minx; x<=maxx; x++) { + v = full[n,y,x] + if (perline == 0) printf "\t" + printf "%s,", v + perline++ + off++ + if (perline >= 6) { printf "\n"; perline = 0 } + else printf " " + } + } + if (perline != 0) { printf "\n"; perline = 0 } + } + + print "};" + print "" + print "struct nein_cursor_meta {" + print "\tuint32_t width, height;" + print "\tint32_t hotspot_x, hotspot_y;" + print "\tsize_t offset;" + print "};" + print "" + print "static const struct nein_cursor_meta nein_cursor_metadata[] = {" + + for (oi=1; oi<=outn; oi++) { + n = meta_name[oi] + if (n == "") continue + printf "\t{ %d, %d, %d, %d, %d }, /* %s */\n", + meta_w[oi], meta_h[oi], meta_hx[oi], meta_hy[oi], meta_off[oi], n + } + + print "};" +} +' "$infile"
