@moonbase-machines/vector 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/moonbase-vector.js +3 -3
- package/dist/moonbase-vector.js.map +3 -3
- package/font.js +5 -6
- package/package.json +2 -2
package/dist/moonbase-vector.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @moonbase-machines/vector 0.
|
|
2
|
-
var
|
|
3
|
-
`:String.fromCharCode(e&127)}return{length:r-n,value:o}}function
|
|
1
|
+
/*! @moonbase-machines/vector 0.8.0: MIT, (c) 2026 Mark Wharton (its LICENSE) */
|
|
2
|
+
var J=Object.defineProperty;var w=(t,n)=>{for(var o in n)J(t,o,{get:n[o],enumerable:!0})};var L={};w(L,{crossings:()=>E,draw:()=>K,fill:()=>j,inside:()=>B,line:()=>$,outline:()=>I,screen:()=>v,spans:()=>C,under:()=>Q});var v=(t=0)=>Array.from({length:192},()=>new Array(140).fill(t));function $(t,n,o,r){let c=Math.abs(o-t),e=Math.abs(r-n),f=o>=t?1:-1,i=r>=n?1:-1,l=c>=e,s=l?c:e,g=l?e:c,u=2*g-s,h=t,x=n,a=[[h,x]];for(let p=0;p<s;p++)u<0?(l?h+=f:x+=i,u+=2*g):(h+=f,x+=i,u+=2*g-2*s),a.push([h,x]);return a}function E(t){let n=Array.from({length:192},()=>[]),o=(u,h)=>{if(u<0||u>=192)return;let x=n[u],a=0;for(;a<x.length&&h>=x[a];)a++;x.splice(a,0,h)},r=t.length,c=0;for(let u=0;u<r;u++){let[h,x]=t[u],[a,p]=t[(u+1)%r];if(x===p)continue;let d=$(h,x,a,p);for(let m=1;m<d.length;m++)d[m][1]!==d[m-1][1]&&o(d[m-1][1],d[m-1][0]);let S=p>x?1:-1;S!==c&&(c=S,o(x,h))}let e=n.findIndex(u=>u.length);if(e<0)return null;let f=e;for(;f+1<192&&n[f+1].length;)f++;let[i,l]=t[0],s=Math.min(t[1][1],t[r-1][1]),g=Math.max(t[1][1],t[r-1][1]);return l!==e&&l!==f&&l>s&&l<g&&o(l,i),{rows:n,top:e,bottom:f}}function C(t,n){let o=E(t);if(o)for(let r=o.top;r<=o.bottom;r++){let c=o.rows[r];for(let e=(c.length&-2)-2;e>=0;e-=2)n(c[e],c[e+1],r)}}var M=(t,n,o,r)=>{n>=0&&n<140&&o>=0&&o<192&&(t[o][n]=r&15)};function j(t,n){return n.points.length<3||C(n.points,(o,r,c)=>{if(o===r)M(t,o,c,0);else for(let e=o;e<=r;e++)M(t,e,c,n.fill)}),t}function I(t,n){let o=n.points,r=o.length;if(r<2)return t;for(let c=0;c<(r===2?1:r);c++)for(let[e,f]of $(...o[c],...o[(c+1)%r]))M(t,e,f,n.line);return t}function K(t,n=v()){for(let o of t)j(n,o),I(n,o);return n}function B(t,n,o){if(t.points.length===2)return 254;let r=0;return C(t.points,(c,e,f)=>{f===o&&n>=c&&n<=e&&(r=128)}),r}function Q(t,n,o){let r=-1;return t.forEach((c,e)=>{B(c,n,o)&&(r=e)}),r}var G={};w(G,{GLYPHS:()=>y,WIDTHS:()=>b,dots:()=>X,start:()=>V,useFont:()=>Z,width:()=>A});var b=[3,1,3,5,5,5,4,1,3,3,5,5,2,5,1,5,4,3,4,4,4,4,4,4,4,4,1,2,3,3,3,4,8,4,4,4,4,4,4,4,4,3,4,4,4,5,4,4,4,4,4,4,3,4,5,5,4,5,4,5,5,5,5,5,3,4,4,4,4,4,3,4,4,3,4,4,3,5,4,4,4,4,4,4,3,4,5,5,4,4,4,3,1,3,4,5],O=[[6,"78ccccdceccccccc78"],[4,"60e0606060606060f0"],[6,"78cc0c183060c0c0fc"],[6,"78cc0c0c380c0ccc78"],[6,"0c1c2c4cccfc0c0c0c"],[6,"fcc0c0f80c0c0ccc78"],[6,"78ccc0c0f8cccccc78"],[6,"fc0c0c181830303030"],[6,"78cccccc78cccccc78"],[6,"78cccccc7c0c0ccc78"]],A=t=>{let n=t.charCodeAt(0);return n<32?n:n>=128?O[n-128]?.[0]??6:b[n-32]??4};function V(t,n,o,r){if(!r)return o;let c=0;for(let e of t)c+=e.charCodeAt(0)<32?A(e):A(e)+n;return(140-c&255)>>1}var y=["000000000000000000","808080808000800000","a0a0a0000000000000","0050f850f850000000","207080700870200000","808810204088080000","609060909090700000","808080000000000000","204080808040200000","804020202040800000","008850205088000000","002020f82020000000","000000000000408000","000000f80000000000","000000000080800000","000810204080000000","6090b0d09090600000","40c040404040e00000","609010608080f00000","609010201090600000","10305090f010100000","f080e0101090600000","609080e09090600000","f01010202040400000","609090609090600000","609090701090600000","000080800080800000","000040400040404080","002040804020000000","0000e000e000000000","008040204080000000","609010204000400000","ffffffffffffffffff","609090f09090900000","e09090e09090e00000","609080808090600000","e09090909090e00000","f08080c08080f00000","f08080c08080800000","609080b09090700000","909090f09090900000","e04040404040e00000","301010101090600000","90a0c0a0a090900000","808080808080f00000","88d8a8888888880000","90d0b0909090900000","609090909090600000","e09090e08080800000","60909090b0b0700000","e09090e09090900000","609080601090600000","e04040404040400000","909090909090600000","888888888850200000","88888888a8d8880000","909090609090900000","888850202020200000","f01020408080f00000","002060f86020000000","002030f83020000000","002020f87020000000","002070f82020000000","0000000000000000f8","804020000000000000","0000709090b0500000","8080e0909090e00000","000060908090600000","101070909090700000","00006090f080600000","2040e0404040400000","0000709090907010e0","8080e0909090900000","4000c0404040e00000","2000602020202020c0","808090a0c0a0900000","804040404040e00000","0000d0a8a8a8a80000","0000e0909090900000","000060909090600000","0000e0909090e08080","000070909090701010","0000e0908080800000","000070806010e00000","4040e0404040200000","000090909090700000","000088888850200000","00008888a8d8880000","000090906090900000","0000909090907010e0","0000f0106080f00000","204040804040200000","808080808080808080","804040204040800000","106080000000000000","ff0000000000000000"];function X(t){let n=t.charCodeAt(0),o=n>=128?O[n-128]?.[1]:y[n-32],r=[];if(!o)return r;for(let c=0;c<9;c++){let e=parseInt(o.slice(2*c,2*c+2),16);for(let f=0;f<8;f++)e>>7-f&1&&r.push([f,c])}return r}var N={widths:b.slice(),glyphs:y.slice()};function Z(t={}){b.splice(0,b.length,...N.widths),y.splice(0,y.length,...N.glyphs);for(let[n,[o,r]]of Object.entries(t))b[n.charCodeAt(0)-32]=o,y[n.charCodeAt(0)-32]=r}var D={};w(D,{INLINE:()=>t0,name:()=>R,sound:()=>q,text:()=>H});function H(t,n){let o="",r=n;for(let c=0;c<4096;c++){let e=t(r++);if(e===void 0||e===128)break;if(e===27){let f=t(r++),i=f===15||f===12?2:f===6||f===11?4:[7,8,9,10,13,14,16,17].includes(f)?0:1,l=[];for(let s=0;s<i;s++)l.push(t(r+s).toString(16));o+="{"+f.toString(16)+(i?":"+l.join(","):"")+"}",r+=i;continue}o+=e===141?`
|
|
3
|
+
`:String.fromCharCode(e&127)}return{length:r-n,value:o}}function R(t,n){let o=t(n)&127,r="";for(let c=1;c<=o;c++)r+=String.fromCharCode(t(n+c)&127);return{length:o+1,value:r}}function q(t,n){let o=[];for(let r=0;r<5;r++)o.push(t(n+r).toString(16));return{length:5,value:o.join(" ")}}var t0={text:H,picture:R,sound:q};var P={};w(P,{carry:()=>o0,decode:()=>F,put:()=>e0,tables:()=>n0});function F(t,n){let o=t[n],r=t[n+1],c=t[n+2],e=t[n+3],f=n+4,i=0,l=0,s=[];if(o&64){let g=t[f++],u=()=>{if(i)return i--,l;let h=t[f++];return h===g?(i=t[f]-1,l=t[f+1],f+=2,l):h};for(let h=0;h<e;h++){let x=[];for(let a=0;a<c+1>>1;a++){let p=u();x.push(p>>4,p&15)}s.push(x.slice(0,c))}}else{let g=()=>{if(i)return i--,l;let u=t[f++];return u&128?(l=u&127,i=t[f++]-1,l):u};for(let u=0;u<e;u++){let h=[];for(let a=0;a<r;a++){let p=g();for(let d=0;d<7;d++)h.push(p>>d&1)}let x=[];for(let a=0;a<c;a++)x.push(h[a*4]<<3|h[a*4+1]<<2|h[a*4+2]<<1|h[a*4+3]);s.push(x)}}return{flags:o,stride:r,width:c,height:e,packed:o&64?"nibbles":"bytes",clear:o&128?void 0:o&15,rows:s,end:f}}function e0(t,n,o,r,c=!1){return n.rows.forEach((e,f)=>e.forEach((i,l)=>{let s=t[r+f];!s||o+l<0||o+l>=s.length||(c||i!==n.clear)&&(s[o+l]=i)})),t}function n0(t,n){let o=[],r=(e,f)=>e[f]|e[f+1]<<8,c=e=>t.find(f=>e>=f.origin&&e<f.origin+f.bytes.length);for(let e of t){let f=e.bytes;for(let i=0;i+7<=f.length;i++){if(!(f[i]===162&&f[i+2]===160&&f[i+4]===32&&r(f,i+5)===n))continue;let l=f[i+1]|f[i+3]<<8,s=l>=e.origin&&l<e.origin+f.length?e:c(l);if(!s||o.some(u=>u.file===s.name&&u.address===l))continue;let g=[];for(let u=2;;u++){let h=l-s.origin+(u-2)*2;if(h+2>s.bytes.length)break;let x=r(s.bytes,h);if(x<s.origin||x+4>s.origin+s.bytes.length)break;let a=x-s.origin,p=s.bytes[a+2],d=s.bytes[a+3];if(!s.bytes[a+1]||!p||!d||p>140||d>192)break;g.push({number:u,at:x,...F(s.bytes,a)})}g.length&&o.push({file:s.name,setBy:e.name,address:l,objects:g})}}return o}function o0(t,n){let o=Math.floor(2*n/7),r=n%7,c=-(2*o+(r>>1&1))&255,e=0;for(let f=0;f<t.height;f++){let i=c+t.stride+1;e=i>255?1:0,c=i&255}return e}var W={};w(W,{pictures:()=>r0,shapes:()=>U,windows:()=>c0});var T=t=>String.fromCharCode(...Array.from(t,n=>n&127));function U(t,n,o=8192){let r=[],c=null;for(let e=n;e<n+o;e++){let f=t(e);if(f===255&&!c)break;if(f===254){c&&r.push(c),c=null;continue}if(!c){c={fill:f,line:t(e+1),points:[]},e++;continue}c.points.push([f,t(e+1)]),e++}return c&&r.push(c),r}function r0(t){let n=[];for(let o=0;o+16<=t.length;){let r=T(t.subarray(o,o+14)).trimEnd(),c=t[o+14]|t[o+15]<<8;if(c<18||o+c>t.length)break;n.push({name:r,at:o,length:c,shapes:U(e=>t[e],o+16,c-16)}),o+=c}return n}function c0(t,{box:n,picture:o}){let r=new Map,c=(e,f)=>e[f]|e[f+1]<<8;for(let e of t){let f;for(let i=0;i+8<e.length;i++){if(e[i]===169&&e[i+2]===162&&e[i+4]===160&&e[i+6]===32&&c(e,i+7)===n){f=e[i+1],i+=8;continue}if(e[i]===32&&c(e,i+1)===o&&e[i+3]&128){let l=e[i+3]&127,s=T(e.subarray(i+4,i+4+l)).toUpperCase().replace(/_/g," ").replace(/[\x00-\x1f]/g,"").trimEnd();f!==void 0&&!r.has(s)&&r.set(s,f),i+=3+l}}}return e=>r.get(e)??r.get(e.replace(/ ?\d$/,""))}var z={};w(z,{bounds:()=>Y,document:()=>i0,elements:()=>_});import{colors as f0}from"@moonbase-machines/apple2e";var{COLORS:u0,NAMES:a0,rgb:k}=f0;function Y(t){let n=140,o=192,r=-1,c=-1;for(let e of t)for(let[f,i]of e.points)n=Math.min(n,f),o=Math.min(o,i),r=Math.max(r,f),c=Math.max(c,i);return r<0?null:{x0:Math.max(0,n-1),y0:Math.max(0,o-1),x1:Math.min(139,r+1),y1:Math.min(191,c+1)}}function _(t,{background:n,crisp:o=!0}={}){let r=Y(t),c=o?' shape-rendering="crispEdges"':"",e=r&&n!==void 0?`<rect x="${Math.max(0,r.x0-1)}" y="${Math.max(0,r.y0-1)}" width="${r.x1-r.x0+3}" height="${r.y1-r.y0+3}" fill="${k(n)}"/>`:"";for(let f of t){let i=f.points.map(([l,s])=>l+.5+","+(s+.5)).join(" ");f.points.length===2?e+=`<polyline points="${i}" fill="none" stroke="${k(f.line)}" stroke-width="1" stroke-linecap="square"${c}/>`:f.points.length>2&&(e+=`<polygon points="${i}" fill="${k(f.fill)}" stroke="${k(f.line)}" stroke-width="1" stroke-linejoin="round"${c}/>`)}return e}function i0(t,{background:n=0,width:o=560,crisp:r=!1}={}){return`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 140 192" width="${o}" height="${o*384/560}" preserveAspectRatio="none"><rect width="140" height="192" fill="${k(n)}"/>`+_(t,{crisp:r})+"</svg>"}export{L as draw,G as font,D as inline,P as objects,W as pictures,z as svg};
|
|
4
4
|
//# sourceMappingURL=moonbase-vector.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../draw.js", "../font.js", "../inline.js", "../objects.js", "../pictures.js", "../svg.js", "moonbase-module:apple2e/colors.js"],
|
|
4
|
-
"sourcesContent": ["// The engine's drawing, dot for dot. Every rule here is the engine's own, read from PART0 and\n// checked by running PART0's code on every shape of every picture of both games (test/).\n// Addresses are Animal Rescue's; Nature Park's engine is the same code moved.\n//\n// A screen is 192 rows of 140 colors. Drawing a shape is its fill, then its outline.\n\n// a screen of 192 rows of 140 dots, cleared to `background`\nexport const screen = (background = 0) => Array.from({ length: 192 }, () => new Array(140).fill(background));\n\n// The line, $7A54: both ends drawn, and the major axis stepped every dot. The error starts at\n// 2\u00B7minor \u2212 major; while it is negative only the major axis steps and it gains 2\u00B7minor,\n// otherwise both axes step and it gains 2\u00B7minor \u2212 2\u00B7major. Returns the dots in drawing order.\nexport function line(x0, y0, x1, y1) {\n const dx = Math.abs(x1 - x0), dy = Math.abs(y1 - y0), sx = x1 >= x0 ? 1 : -1, sy = y1 >= y0 ? 1 : -1;\n const xMajor = dx >= dy, major = xMajor ? dx : dy, minor = xMajor ? dy : dx;\n let err = 2 * minor - major, x = x0, y = y0;\n const out = [[x, y]];\n for (let k = 0; k < major; k++) {\n if (err < 0) { if (xMajor) x += sx; else y += sy; err += 2 * minor; }\n else { x += sx; y += sy; err += 2 * minor - 2 * major; }\n out.push([x, y]);\n }\n return out;\n}\n\n// The crossings of a polygon's edges with each row, $7C57 to $7E24. Each row's list is kept\n// sorted, an equal x going after the ones already there ($7E87).\n//\n// - Each edge that is not level is walked with the line's own steps, and each time the walk\n// leaves a row, the x of its last dot on that row is kept for that row. So an edge gives\n// nothing to the row it ends on, and the fill meets the outline's dots exactly.\n// - Where an edge goes the other way up or down from the last edge that was not level, its\n// first point is kept too. The direction starts at neither, so the first such edge always\n// keeps its first point. Level edges are passed over and change nothing.\n// - The rows filled run from the first row with a crossing to the row before the next row with\n// none.\n// - The shape is closed back to its first point, and a crossing is added there when that point\n// is strictly between its neighbours in height and not on the first or last row filled.\n//\n// Returns { rows, top, bottom }, or null for a shape that crosses no row.\nexport function crossings(points) {\n const rows = Array.from({ length: 192 }, () => []);\n const keep = (y, x) => { if (y < 0 || y >= 192) return; const l = rows[y]; let i = 0; while (i < l.length && x >= l[i]) i++; l.splice(i, 0, x); };\n const n = points.length;\n let last = 0;\n for (let i = 0; i < n; i++) {\n const [xa, ya] = points[i], [xb, yb] = points[(i + 1) % n];\n if (ya === yb) continue;\n const dots = line(xa, ya, xb, yb);\n for (let k = 1; k < dots.length; k++) if (dots[k][1] !== dots[k - 1][1]) keep(dots[k - 1][1], dots[k - 1][0]);\n const way = yb > ya ? 1 : -1;\n if (way !== last) { last = way; keep(ya, xa); }\n }\n const top = rows.findIndex(l => l.length);\n if (top < 0) return null;\n let bottom = top;\n while (bottom + 1 < 192 && rows[bottom + 1].length) bottom++;\n const [x0, y0] = points[0], lo = Math.min(points[1][1], points[n - 1][1]), hi = Math.max(points[1][1], points[n - 1][1]);\n if (y0 !== top && y0 !== bottom && y0 > lo && y0 < hi) keep(y0, x0);\n return { rows, top, bottom };\n}\n\n// The spans the fill draws, $7E25: on each row the crossings are paired from the end of the\n// list, so a row with an odd number of crossings leaves out its largest x. Calls `each(left,\n// right, y)` for every span, in the engine's order.\nexport function spans(points, each) {\n const c = crossings(points);\n if (!c) return;\n for (let y = c.top; y <= c.bottom; y++) {\n const l = c.rows[y];\n for (let j = (l.length & ~1) - 2; j >= 0; j -= 2) each(l[j], l[j + 1], y);\n }\n}\n\nconst set = (scr, x, y, c) => { if (x >= 0 && x < 140 && y >= 0 && y < 192) scr[y][x] = c & 15; };\n\n// The fill. A span of one dot goes to the dot routine with the wrong color and is drawn black\n// ($7955); the outline, drawn next, always covers it.\nexport function fill(scr, shape) {\n if (shape.points.length < 3) return scr;\n spans(shape.points, (a, b, y) => { if (a === b) set(scr, a, y, 0); else for (let x = a; x <= b; x++) set(scr, x, y, shape.fill); });\n return scr;\n}\n\n// The outline, $7BAA: every edge in the outline color, closing back to the first point. A shape\n// of two points is one line in the outline color, and its fill color is not used.\nexport function outline(scr, shape) {\n const p = shape.points, n = p.length;\n if (n < 2) return scr;\n for (let i = 0; i < (n === 2 ? 1 : n); i++) for (const [x, y] of line(...p[i], ...p[(i + 1) % n])) set(scr, x, y, shape.line);\n return scr;\n}\n\n// a list of shapes, each filled and then outlined, as the loop at $7B8C draws a picture\nexport function draw(list, scr = screen()) {\n for (const shape of list) { fill(scr, shape); outline(scr, shape); }\n return scr;\n}\n\n// The point test, $7C54: the fill's own spans, with nothing drawn. A point is in a shape when\n// a span on its row has it between its ends, both ends counted. Returns what the engine returns\n// in A: $80 inside, 0 outside, and $FE for a shape of two points, which a caller takes as inside.\n// Nature Park's colouring-in problem uses it to find the shape under the pointer.\nexport function inside(shape, x, y) {\n if (shape.points.length === 2) return 0xfe;\n let r = 0;\n spans(shape.points, (a, b, row) => { if (row === y && x >= a && x <= b) r = 0x80; });\n return r;\n}\n\n// The shape under a point: the last of `list` that the point is inside, since later shapes are\n// drawn over earlier ones. Returns its index, or -1.\nexport function under(list, x, y) {\n let hit = -1;\n list.forEach((shape, i) => { if (inside(shape, x, y)) hit = i; });\n return hit;\n}\n", "// The engine's font, measured: the width in dots of each character from space to $7F, the first\n// byte of each glyph, found through the tables of pointers at $7551 and $75BB in Animal Rescue's\n// PART0. A line's width is each character's width and the spacing after it; a line is centred\n// at (140 \u2212 its width) / 2, worked in a byte as the engine did ($6F4D).\nexport const WIDTHS = [\n 3, 1, 3, 5, 5, 5, 4, 1, 3, 3, 5, 5, 2, 5, 1, 5, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 1, 2, 3, 3, 3, 4,\n 8, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 3, 4, 5, 5, 4, 5, 4, 5, 5, 5, 5, 5,\n 3, 4, 4, 4, 4, 4, 3, 4, 4, 3, 4, 4, 3, 5, 4, 4, 4, 4, 4, 4, 3, 4, 5, 5, 4, 4, 4, 3, 1, 3, 4, 5,\n];\n\n// The text's code $10 turns to a second set of digits, bigger, read through the same tables at\n// $80 to $89 (the digit plus $50, $63FD in Nature Park), and $11 back; each text starts with the\n// first. Both engines have the same: six dots wide, the one four, nine rows.\nconst BIG = [[6, '78ccccdceccccccc78'], [4, '60e0606060606060f0'], [6, '78cc0c183060c0c0fc'], [6, '78cc0c0c380c0ccc78'], [6, '0c1c2c4cccfc0c0c0c'],\n [6, 'fcc0c0f80c0c0ccc78'], [6, '78ccc0c0f8cccccc78'], [6, 'fc0c0c181830303030'], [6, '78cccccc78cccccc78'], [6, '78cccccc7c0c0ccc78']];\n\n// a character's width in dots; a byte below a space is a spacer that takes its own value\nexport const width = ch => { const c = ch.charCodeAt(0); return c < 0x20 ? c : c >= 0x80 ? BIG[c - 0x80]?.[0] ?? 6 : WIDTHS[c - 0x20] ?? 4; };\n\n// where a line of characters starts, in dots: its own x, or centred as the engine centres\nexport function start(chars, spacing, x, centre) {\n if (!centre) return x;\n let sum = 0;\n for (const ch of chars) sum += ch.charCodeAt(0) < 0x20 ? width(ch) : width(ch) + spacing;\n return ((0x8c - sum) & 0xff) >> 1;\n}\n\n// Each character's glyph, space to $7F: nine rows from the top, a byte a row, its high bit the\n// leftmost dot, as the glyph follows its width in PART0. Written in hexadecimal, two digits a row.\nexport const GLYPHS = [\n '000000000000000000', '808080808000800000', 'a0a0a0000000000000', '0050f850f850000000', '207080700870200000', '808810204088080000', '609060909090700000', '808080000000000000',\n '204080808040200000', '804020202040800000', '008850205088000000', '002020f82020000000', '000000000000408000', '000000f80000000000', '000000000080800000', '000810204080000000',\n '6090b0d09090600000', '40c040404040e00000', '609010608080f00000', '609010201090600000', '10305090f010100000', 'f080e0101090600000', '609080e09090600000', 'f01010202040400000',\n '609090609090600000', '609090701090600000', '000080800080800000', '000040400040404080', '002040804020000000', '0000e000e000000000', '008040204080000000', '609010204000400000',\n 'ffffffffffffffffff', '609090f09090900000', 'e09090e09090e00000', '609080808090600000', 'e09090909090e00000', 'f08080c08080f00000', 'f08080c08080800000', '609080b09090700000',\n '909090f09090900000', 'e04040404040e00000', '301010101090600000', '90a0c0a0a090900000', '808080808080f00000', '88d8a8888888880000', '90d0b0909090900000', '609090909090600000',\n 'e09090e08080800000', '60909090b0b0700000', 'e09090e09090900000', '609080601090600000', 'e04040404040400000', '909090909090600000', '888888888850200000', '88888888a8d8880000',\n '909090609090900000', '888850202020200000', 'f01020408080f00000', '002060f86020000000', '002030f83020000000', '002020f87020000000', '002070f82020000000', '0000000000000000f8',\n '804020000000000000', '0000709090b0500000', '8080e0909090e00000', '000060908090600000', '101070909090700000', '00006090f080600000', '2040e0404040400000', '0000709090907010e0',\n '8080e0909090900000', '4000c0404040e00000', '2000602020202020c0', '808090a0c0a0900000', '804040404040e00000', '0000d0a8a8a8a80000', '0000e0909090900000', '000060909090600000',\n '0000e0909090e08080', '000070909090701010', '0000e0908080800000', '000070806010e00000', '4040e0404040200000', '000090909090700000', '000088888850200000', '00008888a8d8880000',\n '000090906090900000', '0000909090907010e0', '0000f0106080f00000', '204040804040200000', '808080808080808080', '804040204040800000', '106080000000000000', 'ff0000000000000000',\n];\n\n// the dots of a character's glyph, as [x, y] from its top left\nexport function dots(ch) {\n const c = ch.charCodeAt(0), hex = c >= 0x80 ? BIG[c - 0x80]?.[1] : GLYPHS[c - 0x20], out = [];\n if (!hex) return out;\n for (let y = 0; y < 9; y++) { const row = parseInt(hex.slice(2 * y, 2 * y + 2), 16); for (let x = 0; x < 8; x++) if (row >> (7 - x) & 1) out.push([x, y]); }\n return out;\n}\n\n// Nature Park's font is Animal Rescue's but for two glyphs, read from its PART0 through its tables\n// at $6A32 and $6A9C: a zero without the stroke, and the underline a band of seven dots, which its\n// menus put either side of their names. `useFont` makes a title's font the one these read.\nconst VARIANTS = { 'nature-park-adventure': { '0': [4, '609090909090600000'], '_': [7, '000054aa5400000000'] } };\nconst BASE = { widths: WIDTHS.slice(), glyphs: GLYPHS.slice() };\nexport function useFont(slug) {\n WIDTHS.splice(0, WIDTHS.length, ...BASE.widths); GLYPHS.splice(0, GLYPHS.length, ...BASE.glyphs);\n for (const [ch, [w, rows]] of Object.entries(VARIANTS[slug] ?? {})) { WIDTHS[ch.charCodeAt(0) - 0x20] = w; GLYPHS[ch.charCodeAt(0) - 0x20] = rows; }\n}\n", "// The data the engine's routines take inline, after the call: the text routine's text, the\n// picture routine's name and the sound routine's five bytes. `read` gives the byte at an\n// address, so the same reading works on a file and on a running machine's memory. Each returns\n// { length, value }: how many bytes the data takes, and what it says.\n\n// Text: ASCII with the high bit set, $8D a new line, $80 the end. $1B comes before a code, and a\n// code takes 0, 1, 2 or 4 bytes after it: $0F and $0C take two, $06 and $0B four, $07 to $0A,\n// $0D, $0E, $10 and $11 none, and every other code one. A code is kept in the text in braces,\n// {6:42,86,69,86}, its number and its bytes in hexadecimal, so that nothing is lost.\nexport function text(read, at) {\n let s = '', i = at;\n for (let guard = 0; guard < 4096; guard++) {\n const c = read(i++);\n if (c === undefined || c === 0x80) break;\n if (c === 0x1b) {\n const code = read(i++);\n const n = code === 0x0f || code === 0x0c ? 2 : code === 0x06 || code === 0x0b ? 4 : [7, 8, 9, 10, 13, 14, 16, 17].includes(code) ? 0 : 1;\n const bytes = []; for (let k = 0; k < n; k++) bytes.push(read(i + k).toString(16));\n s += '{' + code.toString(16) + (n ? ':' + bytes.join(',') : '') + '}';\n i += n; continue;\n }\n s += c === 0x8d ? '\\n' : String.fromCharCode(c & 0x7f);\n }\n return { length: i - at, value: s };\n}\n\n// A picture's name: a length with the high bit set, then the name in small letters with\n// underscores for spaces.\nexport function name(read, at) {\n const n = read(at) & 0x7f;\n let s = ''; for (let k = 1; k <= n; k++) s += String.fromCharCode(read(at + k) & 0x7f);\n return { length: n + 1, value: s };\n}\n\n// A sound: the end pitch, the start pitch, the clicks a step, the step and the repeats.\nexport function sound(read, at) {\n const b = []; for (let k = 0; k < 5; k++) b.push(read(at + k).toString(16));\n return { length: 5, value: b.join(' ') };\n}\n\nexport const INLINE = { text, picture: name, sound };\n", "// The engine's objects: the things drawn over a picture and moved about, a wheel, a troll, an\n// animal.\n//\n// A scene points the engine at a table of objects, a list of two-byte addresses, through $685A\n// with the address in X and Y. It then draws an object by its number, counted from 2, at a\n// column and row: through $686D, or through $686F when the ground under it is to be kept so\n// that it can be put back. Numbers 0 and 1 put back the ground kept.\n//\n// An object is four bytes, its flags, the bytes to a row, its width in dots and its height in\n// rows, then its rows, packed one of two ways.\n// - With bit 6 of the flags clear, the rows are double hi-res bytes, seven dots of a bit each,\n// and a byte with its high bit set is a run: the byte less the bit, repeated as many times as\n// the byte after it says.\n// - With bit 6 set, the rows are a nibble a dot, high nibble first, a dot's nibble being its\n// color, and the first byte of all is an escape: where it appears, the two bytes after it are\n// a count and a pair of nibbles to repeat.\n// A run may carry over a row's end.\n//\n// With bit 7 of the flags clear, the color in the low four bits is the object's clear color:\n// where one of its own dots is that color, the ground under it shows through. The routine takes\n// that dot from the ground it kept ($6A7D), and so only when it keeps the ground: through $686F,\n// for object 0 to put back, or through $6863, row by row in a buffer of its own ($6C12).\n// Through $686D it goes from $69C8 straight to putting the object down whole, its clear color\n// and all: PROB6's car, gray where the road is, wipes out where it was as it moves. PROB2's\n// elephants are drawn in black boxes and flagged black, so only the elephants show. With bit 7\n// set the object is put down whole.\n\n// the object at `at` in `bytes`: { flags, stride, width, height, packed, clear, rows, end }\nexport function decode(bytes, at) {\n const flags = bytes[at], stride = bytes[at + 1], width = bytes[at + 2], height = bytes[at + 3];\n let p = at + 4, run = 0, value = 0;\n const rows = [];\n if (flags & 0x40) {\n const escape = bytes[p++];\n const next = () => { if (run) { run--; return value; } const b = bytes[p++]; if (b === escape) { run = bytes[p] - 1; value = bytes[p + 1]; p += 2; return value; } return b; };\n for (let y = 0; y < height; y++) {\n const row = [];\n for (let k = 0; k < (width + 1) >> 1; k++) { const b = next(); row.push(b >> 4, b & 15); }\n rows.push(row.slice(0, width));\n }\n } else {\n const next = () => { if (run) { run--; return value; } const b = bytes[p++]; if (b & 0x80) { value = b & 0x7f; run = bytes[p++] - 1; return value; } return b; };\n for (let y = 0; y < height; y++) {\n const bits = [];\n for (let k = 0; k < stride; k++) { const b = next(); for (let i = 0; i < 7; i++) bits.push((b >> i) & 1); }\n const row = [];\n for (let x = 0; x < width; x++) row.push(bits[x * 4] << 3 | bits[x * 4 + 1] << 2 | bits[x * 4 + 2] << 1 | bits[x * 4 + 3]);\n rows.push(row);\n }\n }\n return { flags, stride, width, height, packed: flags & 0x40 ? 'nibbles' : 'bytes', clear: flags & 0x80 ? undefined : flags & 15, rows, end: p };\n}\n\n// An object put on a screen of rows of colors at column x and row y: every dot where the object\n// is put down, all but the dots of its clear color, where the screen stays as it was; or with\n// `whole`, as $686D puts it, every dot.\nexport function put(scr, object, x, y, whole = false) {\n object.rows.forEach((row, dy) => row.forEach((c, dx) => {\n const r = scr[y + dy];\n if (!r || x + dx < 0 || x + dx >= r.length) return;\n if (whole || c !== object.clear) r[x + dx] = c;\n }));\n return scr;\n}\n\n// Every table the scenes point the engine at, with its objects. `files` is each code file's\n// { name, bytes, origin }, and `setter` the routine a scene calls with the table's address in X\n// and Y. A table's entries are read while each points inside the file that holds it, at four\n// bytes that make sense as an object.\nexport function tables(files, setter) {\n const out = [];\n const word = (b, i) => b[i] | b[i + 1] << 8;\n const holder = address => files.find(f => address >= f.origin && address < f.origin + f.bytes.length);\n for (const f of files) {\n const b = f.bytes;\n for (let i = 0; i + 7 <= b.length; i++) {\n if (!(b[i] === 0xa2 && b[i + 2] === 0xa0 && b[i + 4] === 0x20 && word(b, i + 5) === setter)) continue;\n const address = b[i + 1] | b[i + 3] << 8;\n // the parts all load at one address, and so do the problems: a table is in the file that\n // sets it when it fits there, else in whichever file it does fit, PART0 for one Nature Park uses\n const h = address >= f.origin && address < f.origin + b.length ? f : holder(address);\n if (!h || out.some(t => t.file === h.name && t.address === address)) continue;\n const objects = [];\n for (let n = 2; ; n++) {\n const at = address - h.origin + (n - 2) * 2;\n if (at + 2 > h.bytes.length) break;\n const pointer = word(h.bytes, at);\n if (pointer < h.origin || pointer + 4 > h.origin + h.bytes.length) break;\n const o = pointer - h.origin, width = h.bytes[o + 2], height = h.bytes[o + 3];\n if (!h.bytes[o + 1] || !width || !height || width > 140 || height > 192) break;\n objects.push({ number: n, at: pointer, ...decode(h.bytes, o) });\n }\n if (objects.length) out.push({ file: h.name, setBy: f.name, address, objects });\n }\n }\n return out;\n}\n\n// The carry the object routine leaves, which a scene may add in without clearing it first, as the\n// elephants' problem does when it beeps each apple onto Pip's island ($F47A). The routine builds\n// the object in a buffer and copies it out a row at a time ($6B0F); its pointer starts at\n// $D000 less twice the dot's byte column and one bit of its place in the column, and each row adds\n// the object's bytes to a row and one, with the carry set first. The carry is the last add's.\nexport function carry(object, x) {\n const column = Math.floor(2 * x / 7), place = x % 7; // the tables $17A0 and $182C that $5A17 builds\n let lo = -(2 * column + (place >> 1 & 1)) & 0xff, c = 0;\n for (let row = 0; row < object.height; row++) { const sum = lo + object.stride + 1; c = sum > 0xff ? 1 : 0; lo = sum & 0xff; }\n return c;\n}\n", "// The engine's pictures: named lists of shapes on the 140 by 192 double hi-res screen.\n//\n// PICS1 to PICS3 are each a list of pictures. A picture is its name in 14 bytes, padded with\n// spaces (one, BREAK, has the high bit set on every byte), then two bytes for its length from\n// the start of the name, then its shapes. A shape is two bytes, the color it is filled with and\n// the color of its outline, then its points as (x, y) pairs, x from 1 to 138 and y from 1 down\n// the screen. Shapes are separated by $FE, and $FE $FF ends the picture. A shape of two points\n// is a line in its outline color and is not filled.\n//\n// The picture routine, $7AFE in Animal Rescue, takes a picture's name inline after the call,\n// has the loader copy its shapes to $E000, and draws them from there.\n\nconst text = bytes => String.fromCharCode(...Array.from(bytes, b => b & 0x7f));\n\n// shapes from `read`, a function of an address, starting at `at`, until $FF where the next shape\n// would start: the form the drawing loop at $7B8C reads from $E000\nexport function shapes(read, at, limit = 0x2000) {\n const out = [];\n let shape = null;\n for (let i = at; i < at + limit; i++) {\n const b = read(i);\n if (b === 0xff && !shape) break;\n if (b === 0xfe) { if (shape) out.push(shape); shape = null; continue; }\n if (!shape) { shape = { fill: b, line: read(i + 1), points: [] }; i++; continue; }\n shape.points.push([b, read(i + 1)]); i++;\n }\n if (shape) out.push(shape);\n return out;\n}\n\n// every picture in one of PICS1 to PICS3, as { name, at, length, shapes }\nexport function pictures(bytes) {\n const out = [];\n for (let at = 0; at + 16 <= bytes.length; ) {\n const name = text(bytes.subarray(at, at + 14)).trimEnd();\n const length = bytes[at + 14] | bytes[at + 15] << 8;\n if (length < 18 || at + length > bytes.length) break;\n out.push({ name, at, length, shapes: shapes(i => bytes[i], at + 16, length - 16) });\n at += length;\n }\n return out;\n}\n\n// The color behind each picture, from the scenes' code. A scene calls the box routine with three\n// colors in A, X and Y, the picture window's and then the two text boxes', and then the picture\n// routine with the picture's name inline after the call: a length byte with its high bit set,\n// then the name in small letters with underscores for spaces. `windows` reads every code file\n// for those two calls and gives each name the window color set before it. A scene that draws\n// TRACK 1 to 4 or COL PATTERN 1 to 6 writes `track_` with a byte left for the digit, filled in\n// as it runs, so a name with a trailing digit falls back to the name without it.\nexport function windows(codes, { box, picture }) {\n const seen = new Map();\n const word = (b, i) => b[i] | b[i + 1] << 8;\n for (const code of codes) {\n let color;\n for (let i = 0; i + 8 < code.length; i++) {\n if (code[i] === 0xa9 && code[i + 2] === 0xa2 && code[i + 4] === 0xa0 && code[i + 6] === 0x20 && word(code, i + 7) === box) { color = code[i + 1]; i += 8; continue; }\n if (code[i] === 0x20 && word(code, i + 1) === picture && code[i + 3] & 0x80) {\n const n = code[i + 3] & 0x7f;\n const name = text(code.subarray(i + 4, i + 4 + n)).toUpperCase().replace(/_/g, ' ').replace(/[\\x00-\\x1f]/g, '').trimEnd();\n if (color !== undefined && !seen.has(name)) seen.set(name, color);\n i += 3 + n;\n }\n }\n }\n return name => seen.get(name) ?? seen.get(name.replace(/ ?\\d$/, ''));\n}\n", "// The engine's shapes as SVG, which draws them at any size. A shape is a polygon in its fill\n// color outlined in its outline color, or, with two points, a line. The coordinates are the\n// engine's dots, 140 across and 192 down. A dot is four times as wide on the screen as the\n// number of dots suggests and twice as high, so a whole screen is drawn 560 by 384.\nimport { rgb } from '@moonbase-machines/apple2e/colors.js';\n\n// the columns and rows the shapes cover, a dot beyond them on each side\nexport function bounds(list) {\n let x0 = 140, y0 = 192, x1 = -1, y1 = -1;\n for (const sh of list) for (const [x, y] of sh.points) { x0 = Math.min(x0, x); y0 = Math.min(y0, y); x1 = Math.max(x1, x); y1 = Math.max(y1, y); }\n return x1 < 0 ? null : { x0: Math.max(0, x0 - 1), y0: Math.max(0, y0 - 1), x1: Math.min(139, x1 + 1), y1: Math.min(191, y1 + 1) };\n}\n\n// The SVG elements for the shapes, in the 140 by 192 space. A dot is a unit square, so the\n// points are moved half a unit to the dots' centers and a stroke is a dot wide. With a\n// background, a rectangle of it goes under the shapes where the engine's fills touch dots\n// beside them. `crisp` keeps the edges hard, as the screen had them; without it the shapes are\n// drawn smooth, which is what a sharper picture wants.\nexport function elements(list, { background, crisp = true } = {}) {\n const b = bounds(list), edge = crisp ? ' shape-rendering=\"crispEdges\"' : '';\n let s = b && background !== undefined ? `<rect x=\"${Math.max(0, b.x0 - 1)}\" y=\"${Math.max(0, b.y0 - 1)}\" width=\"${b.x1 - b.x0 + 3}\" height=\"${b.y1 - b.y0 + 3}\" fill=\"${rgb(background)}\"/>` : '';\n for (const sh of list) {\n const pts = sh.points.map(([x, y]) => (x + 0.5) + ',' + (y + 0.5)).join(' ');\n if (sh.points.length === 2) s += `<polyline points=\"${pts}\" fill=\"none\" stroke=\"${rgb(sh.line)}\" stroke-width=\"1\" stroke-linecap=\"square\"${edge}/>`;\n else if (sh.points.length > 2) s += `<polygon points=\"${pts}\" fill=\"${rgb(sh.fill)}\" stroke=\"${rgb(sh.line)}\" stroke-width=\"1\" stroke-linejoin=\"round\"${edge}/>`;\n }\n return s;\n}\n\n// a whole picture as an SVG document, `width` wide and in the screen's proportions, on its\n// background color\nexport function document(list, { background = 0, width = 560, crisp = false } = {}) {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 140 192\" width=\"${width}\" height=\"${width * 384 / 560}\" preserveAspectRatio=\"none\">` +\n `<rect width=\"140\" height=\"192\" fill=\"${rgb(background)}\"/>` + elements(list, { crisp }) + '</svg>';\n}\n", "import { colors as m } from '@moonbase-machines/apple2e';\nexport const { COLORS, NAMES, rgb } = m;"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["draw_exports", "__export", "crossings", "draw", "fill", "inside", "line", "outline", "screen", "spans", "under", "background", "x0", "y0", "x1", "y1", "dx", "dy", "sx", "sy", "xMajor", "major", "minor", "err", "x", "y", "out", "k", "points", "rows", "keep", "l", "i", "n", "last", "xa", "ya", "xb", "yb", "dots", "way", "top", "bottom", "lo", "hi", "each", "c", "j", "set", "scr", "shape", "a", "b", "p", "list", "row", "hit", "font_exports", "__export", "GLYPHS", "WIDTHS", "dots", "start", "useFont", "width", "BIG", "ch", "c", "chars", "spacing", "x", "centre", "sum", "hex", "out", "y", "row", "
|
|
4
|
+
"sourcesContent": ["// The engine's drawing, dot for dot. Every rule here is the engine's own, read from PART0 and\n// checked by running PART0's code on every shape of every picture of both games (test/).\n// Addresses are Animal Rescue's; Nature Park's engine is the same code moved.\n//\n// A screen is 192 rows of 140 colors. Drawing a shape is its fill, then its outline.\n\n// a screen of 192 rows of 140 dots, cleared to `background`\nexport const screen = (background = 0) => Array.from({ length: 192 }, () => new Array(140).fill(background));\n\n// The line, $7A54: both ends drawn, and the major axis stepped every dot. The error starts at\n// 2\u00B7minor \u2212 major; while it is negative only the major axis steps and it gains 2\u00B7minor,\n// otherwise both axes step and it gains 2\u00B7minor \u2212 2\u00B7major. Returns the dots in drawing order.\nexport function line(x0, y0, x1, y1) {\n const dx = Math.abs(x1 - x0), dy = Math.abs(y1 - y0), sx = x1 >= x0 ? 1 : -1, sy = y1 >= y0 ? 1 : -1;\n const xMajor = dx >= dy, major = xMajor ? dx : dy, minor = xMajor ? dy : dx;\n let err = 2 * minor - major, x = x0, y = y0;\n const out = [[x, y]];\n for (let k = 0; k < major; k++) {\n if (err < 0) { if (xMajor) x += sx; else y += sy; err += 2 * minor; }\n else { x += sx; y += sy; err += 2 * minor - 2 * major; }\n out.push([x, y]);\n }\n return out;\n}\n\n// The crossings of a polygon's edges with each row, $7C57 to $7E24. Each row's list is kept\n// sorted, an equal x going after the ones already there ($7E87).\n//\n// - Each edge that is not level is walked with the line's own steps, and each time the walk\n// leaves a row, the x of its last dot on that row is kept for that row. So an edge gives\n// nothing to the row it ends on, and the fill meets the outline's dots exactly.\n// - Where an edge goes the other way up or down from the last edge that was not level, its\n// first point is kept too. The direction starts at neither, so the first such edge always\n// keeps its first point. Level edges are passed over and change nothing.\n// - The rows filled run from the first row with a crossing to the row before the next row with\n// none.\n// - The shape is closed back to its first point, and a crossing is added there when that point\n// is strictly between its neighbours in height and not on the first or last row filled.\n//\n// Returns { rows, top, bottom }, or null for a shape that crosses no row.\nexport function crossings(points) {\n const rows = Array.from({ length: 192 }, () => []);\n const keep = (y, x) => { if (y < 0 || y >= 192) return; const l = rows[y]; let i = 0; while (i < l.length && x >= l[i]) i++; l.splice(i, 0, x); };\n const n = points.length;\n let last = 0;\n for (let i = 0; i < n; i++) {\n const [xa, ya] = points[i], [xb, yb] = points[(i + 1) % n];\n if (ya === yb) continue;\n const dots = line(xa, ya, xb, yb);\n for (let k = 1; k < dots.length; k++) if (dots[k][1] !== dots[k - 1][1]) keep(dots[k - 1][1], dots[k - 1][0]);\n const way = yb > ya ? 1 : -1;\n if (way !== last) { last = way; keep(ya, xa); }\n }\n const top = rows.findIndex(l => l.length);\n if (top < 0) return null;\n let bottom = top;\n while (bottom + 1 < 192 && rows[bottom + 1].length) bottom++;\n const [x0, y0] = points[0], lo = Math.min(points[1][1], points[n - 1][1]), hi = Math.max(points[1][1], points[n - 1][1]);\n if (y0 !== top && y0 !== bottom && y0 > lo && y0 < hi) keep(y0, x0);\n return { rows, top, bottom };\n}\n\n// The spans the fill draws, $7E25: on each row the crossings are paired from the end of the\n// list, so a row with an odd number of crossings leaves out its largest x. Calls `each(left,\n// right, y)` for every span, in the engine's order.\nexport function spans(points, each) {\n const c = crossings(points);\n if (!c) return;\n for (let y = c.top; y <= c.bottom; y++) {\n const l = c.rows[y];\n for (let j = (l.length & ~1) - 2; j >= 0; j -= 2) each(l[j], l[j + 1], y);\n }\n}\n\nconst set = (scr, x, y, c) => { if (x >= 0 && x < 140 && y >= 0 && y < 192) scr[y][x] = c & 15; };\n\n// The fill. A span of one dot goes to the dot routine with the wrong color and is drawn black\n// ($7955); the outline, drawn next, always covers it.\nexport function fill(scr, shape) {\n if (shape.points.length < 3) return scr;\n spans(shape.points, (a, b, y) => { if (a === b) set(scr, a, y, 0); else for (let x = a; x <= b; x++) set(scr, x, y, shape.fill); });\n return scr;\n}\n\n// The outline, $7BAA: every edge in the outline color, closing back to the first point. A shape\n// of two points is one line in the outline color, and its fill color is not used.\nexport function outline(scr, shape) {\n const p = shape.points, n = p.length;\n if (n < 2) return scr;\n for (let i = 0; i < (n === 2 ? 1 : n); i++) for (const [x, y] of line(...p[i], ...p[(i + 1) % n])) set(scr, x, y, shape.line);\n return scr;\n}\n\n// a list of shapes, each filled and then outlined, as the loop at $7B8C draws a picture\nexport function draw(list, scr = screen()) {\n for (const shape of list) { fill(scr, shape); outline(scr, shape); }\n return scr;\n}\n\n// The point test, $7C54: the fill's own spans, with nothing drawn. A point is in a shape when\n// a span on its row has it between its ends, both ends counted. Returns what the engine returns\n// in A: $80 inside, 0 outside, and $FE for a shape of two points, which a caller takes as inside.\n// Nature Park's colouring-in problem uses it to find the shape under the pointer.\nexport function inside(shape, x, y) {\n if (shape.points.length === 2) return 0xfe;\n let r = 0;\n spans(shape.points, (a, b, row) => { if (row === y && x >= a && x <= b) r = 0x80; });\n return r;\n}\n\n// The shape under a point: the last of `list` that the point is inside, since later shapes are\n// drawn over earlier ones. Returns its index, or -1.\nexport function under(list, x, y) {\n let hit = -1;\n list.forEach((shape, i) => { if (inside(shape, x, y)) hit = i; });\n return hit;\n}\n", "// The engine's font, measured: the width in dots of each character from space to $7F, the first\n// byte of each glyph, found through the tables of pointers at $7551 and $75BB in Animal Rescue's\n// PART0. A line's width is each character's width and the spacing after it; a line is centred\n// at (140 \u2212 its width) / 2, worked in a byte as the engine did ($6F4D).\nexport const WIDTHS = [\n 3, 1, 3, 5, 5, 5, 4, 1, 3, 3, 5, 5, 2, 5, 1, 5, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 1, 2, 3, 3, 3, 4,\n 8, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 3, 4, 5, 5, 4, 5, 4, 5, 5, 5, 5, 5,\n 3, 4, 4, 4, 4, 4, 3, 4, 4, 3, 4, 4, 3, 5, 4, 4, 4, 4, 4, 4, 3, 4, 5, 5, 4, 4, 4, 3, 1, 3, 4, 5,\n];\n\n// The text's code $10 turns to a second set of digits, bigger, read through the same tables at\n// $80 to $89 (the digit plus $50, $63FD in Nature Park), and $11 back; each text starts with the\n// first. Both engines have the same: six dots wide, the one four, nine rows.\nconst BIG = [[6, '78ccccdceccccccc78'], [4, '60e0606060606060f0'], [6, '78cc0c183060c0c0fc'], [6, '78cc0c0c380c0ccc78'], [6, '0c1c2c4cccfc0c0c0c'],\n [6, 'fcc0c0f80c0c0ccc78'], [6, '78ccc0c0f8cccccc78'], [6, 'fc0c0c181830303030'], [6, '78cccccc78cccccc78'], [6, '78cccccc7c0c0ccc78']];\n\n// a character's width in dots; a byte below a space is a spacer that takes its own value\nexport const width = ch => { const c = ch.charCodeAt(0); return c < 0x20 ? c : c >= 0x80 ? BIG[c - 0x80]?.[0] ?? 6 : WIDTHS[c - 0x20] ?? 4; };\n\n// where a line of characters starts, in dots: its own x, or centred as the engine centres\nexport function start(chars, spacing, x, centre) {\n if (!centre) return x;\n let sum = 0;\n for (const ch of chars) sum += ch.charCodeAt(0) < 0x20 ? width(ch) : width(ch) + spacing;\n return ((0x8c - sum) & 0xff) >> 1;\n}\n\n// Each character's glyph, space to $7F: nine rows from the top, a byte a row, its high bit the\n// leftmost dot, as the glyph follows its width in PART0. Written in hexadecimal, two digits a row.\nexport const GLYPHS = [\n '000000000000000000', '808080808000800000', 'a0a0a0000000000000', '0050f850f850000000', '207080700870200000', '808810204088080000', '609060909090700000', '808080000000000000',\n '204080808040200000', '804020202040800000', '008850205088000000', '002020f82020000000', '000000000000408000', '000000f80000000000', '000000000080800000', '000810204080000000',\n '6090b0d09090600000', '40c040404040e00000', '609010608080f00000', '609010201090600000', '10305090f010100000', 'f080e0101090600000', '609080e09090600000', 'f01010202040400000',\n '609090609090600000', '609090701090600000', '000080800080800000', '000040400040404080', '002040804020000000', '0000e000e000000000', '008040204080000000', '609010204000400000',\n 'ffffffffffffffffff', '609090f09090900000', 'e09090e09090e00000', '609080808090600000', 'e09090909090e00000', 'f08080c08080f00000', 'f08080c08080800000', '609080b09090700000',\n '909090f09090900000', 'e04040404040e00000', '301010101090600000', '90a0c0a0a090900000', '808080808080f00000', '88d8a8888888880000', '90d0b0909090900000', '609090909090600000',\n 'e09090e08080800000', '60909090b0b0700000', 'e09090e09090900000', '609080601090600000', 'e04040404040400000', '909090909090600000', '888888888850200000', '88888888a8d8880000',\n '909090609090900000', '888850202020200000', 'f01020408080f00000', '002060f86020000000', '002030f83020000000', '002020f87020000000', '002070f82020000000', '0000000000000000f8',\n '804020000000000000', '0000709090b0500000', '8080e0909090e00000', '000060908090600000', '101070909090700000', '00006090f080600000', '2040e0404040400000', '0000709090907010e0',\n '8080e0909090900000', '4000c0404040e00000', '2000602020202020c0', '808090a0c0a0900000', '804040404040e00000', '0000d0a8a8a8a80000', '0000e0909090900000', '000060909090600000',\n '0000e0909090e08080', '000070909090701010', '0000e0908080800000', '000070806010e00000', '4040e0404040200000', '000090909090700000', '000088888850200000', '00008888a8d8880000',\n '000090906090900000', '0000909090907010e0', '0000f0106080f00000', '204040804040200000', '808080808080808080', '804040204040800000', '106080000000000000', 'ff0000000000000000',\n];\n\n// the dots of a character's glyph, as [x, y] from its top left\nexport function dots(ch) {\n const c = ch.charCodeAt(0), hex = c >= 0x80 ? BIG[c - 0x80]?.[1] : GLYPHS[c - 0x20], out = [];\n if (!hex) return out;\n for (let y = 0; y < 9; y++) { const row = parseInt(hex.slice(2 * y, 2 * y + 2), 16); for (let x = 0; x < 8; x++) if (row >> (7 - x) & 1) out.push([x, y]); }\n return out;\n}\n\n// A title's font: the engine's, these, but for any glyphs its own PART0 has otherwise, given as { character: [its\n// width, its rows as hex] } (Nature Park's: a zero without the stroke, and the underline a band of seven dots, read\n// through its tables at $6A32 and $6A9C). `useFont` makes them the ones these read; none, the engine's.\nconst BASE = { widths: WIDTHS.slice(), glyphs: GLYPHS.slice() };\nexport function useFont(variants = {}) {\n WIDTHS.splice(0, WIDTHS.length, ...BASE.widths); GLYPHS.splice(0, GLYPHS.length, ...BASE.glyphs);\n for (const [ch, [w, rows]] of Object.entries(variants)) { WIDTHS[ch.charCodeAt(0) - 0x20] = w; GLYPHS[ch.charCodeAt(0) - 0x20] = rows; }\n}\n", "// The data the engine's routines take inline, after the call: the text routine's text, the\n// picture routine's name and the sound routine's five bytes. `read` gives the byte at an\n// address, so the same reading works on a file and on a running machine's memory. Each returns\n// { length, value }: how many bytes the data takes, and what it says.\n\n// Text: ASCII with the high bit set, $8D a new line, $80 the end. $1B comes before a code, and a\n// code takes 0, 1, 2 or 4 bytes after it: $0F and $0C take two, $06 and $0B four, $07 to $0A,\n// $0D, $0E, $10 and $11 none, and every other code one. A code is kept in the text in braces,\n// {6:42,86,69,86}, its number and its bytes in hexadecimal, so that nothing is lost.\nexport function text(read, at) {\n let s = '', i = at;\n for (let guard = 0; guard < 4096; guard++) {\n const c = read(i++);\n if (c === undefined || c === 0x80) break;\n if (c === 0x1b) {\n const code = read(i++);\n const n = code === 0x0f || code === 0x0c ? 2 : code === 0x06 || code === 0x0b ? 4 : [7, 8, 9, 10, 13, 14, 16, 17].includes(code) ? 0 : 1;\n const bytes = []; for (let k = 0; k < n; k++) bytes.push(read(i + k).toString(16));\n s += '{' + code.toString(16) + (n ? ':' + bytes.join(',') : '') + '}';\n i += n; continue;\n }\n s += c === 0x8d ? '\\n' : String.fromCharCode(c & 0x7f);\n }\n return { length: i - at, value: s };\n}\n\n// A picture's name: a length with the high bit set, then the name in small letters with\n// underscores for spaces.\nexport function name(read, at) {\n const n = read(at) & 0x7f;\n let s = ''; for (let k = 1; k <= n; k++) s += String.fromCharCode(read(at + k) & 0x7f);\n return { length: n + 1, value: s };\n}\n\n// A sound: the end pitch, the start pitch, the clicks a step, the step and the repeats.\nexport function sound(read, at) {\n const b = []; for (let k = 0; k < 5; k++) b.push(read(at + k).toString(16));\n return { length: 5, value: b.join(' ') };\n}\n\nexport const INLINE = { text, picture: name, sound };\n", "// The engine's objects: the things drawn over a picture and moved about, a wheel, a troll, an\n// animal.\n//\n// A scene points the engine at a table of objects, a list of two-byte addresses, through $685A\n// with the address in X and Y. It then draws an object by its number, counted from 2, at a\n// column and row: through $686D, or through $686F when the ground under it is to be kept so\n// that it can be put back. Numbers 0 and 1 put back the ground kept.\n//\n// An object is four bytes, its flags, the bytes to a row, its width in dots and its height in\n// rows, then its rows, packed one of two ways.\n// - With bit 6 of the flags clear, the rows are double hi-res bytes, seven dots of a bit each,\n// and a byte with its high bit set is a run: the byte less the bit, repeated as many times as\n// the byte after it says.\n// - With bit 6 set, the rows are a nibble a dot, high nibble first, a dot's nibble being its\n// color, and the first byte of all is an escape: where it appears, the two bytes after it are\n// a count and a pair of nibbles to repeat.\n// A run may carry over a row's end.\n//\n// With bit 7 of the flags clear, the color in the low four bits is the object's clear color:\n// where one of its own dots is that color, the ground under it shows through. The routine takes\n// that dot from the ground it kept ($6A7D), and so only when it keeps the ground: through $686F,\n// for object 0 to put back, or through $6863, row by row in a buffer of its own ($6C12).\n// Through $686D it goes from $69C8 straight to putting the object down whole, its clear color\n// and all: PROB6's car, gray where the road is, wipes out where it was as it moves. PROB2's\n// elephants are drawn in black boxes and flagged black, so only the elephants show. With bit 7\n// set the object is put down whole.\n\n// the object at `at` in `bytes`: { flags, stride, width, height, packed, clear, rows, end }\nexport function decode(bytes, at) {\n const flags = bytes[at], stride = bytes[at + 1], width = bytes[at + 2], height = bytes[at + 3];\n let p = at + 4, run = 0, value = 0;\n const rows = [];\n if (flags & 0x40) {\n const escape = bytes[p++];\n const next = () => { if (run) { run--; return value; } const b = bytes[p++]; if (b === escape) { run = bytes[p] - 1; value = bytes[p + 1]; p += 2; return value; } return b; };\n for (let y = 0; y < height; y++) {\n const row = [];\n for (let k = 0; k < (width + 1) >> 1; k++) { const b = next(); row.push(b >> 4, b & 15); }\n rows.push(row.slice(0, width));\n }\n } else {\n const next = () => { if (run) { run--; return value; } const b = bytes[p++]; if (b & 0x80) { value = b & 0x7f; run = bytes[p++] - 1; return value; } return b; };\n for (let y = 0; y < height; y++) {\n const bits = [];\n for (let k = 0; k < stride; k++) { const b = next(); for (let i = 0; i < 7; i++) bits.push((b >> i) & 1); }\n const row = [];\n for (let x = 0; x < width; x++) row.push(bits[x * 4] << 3 | bits[x * 4 + 1] << 2 | bits[x * 4 + 2] << 1 | bits[x * 4 + 3]);\n rows.push(row);\n }\n }\n return { flags, stride, width, height, packed: flags & 0x40 ? 'nibbles' : 'bytes', clear: flags & 0x80 ? undefined : flags & 15, rows, end: p };\n}\n\n// An object put on a screen of rows of colors at column x and row y: every dot where the object\n// is put down, all but the dots of its clear color, where the screen stays as it was; or with\n// `whole`, as $686D puts it, every dot.\nexport function put(scr, object, x, y, whole = false) {\n object.rows.forEach((row, dy) => row.forEach((c, dx) => {\n const r = scr[y + dy];\n if (!r || x + dx < 0 || x + dx >= r.length) return;\n if (whole || c !== object.clear) r[x + dx] = c;\n }));\n return scr;\n}\n\n// Every table the scenes point the engine at, with its objects. `files` is each code file's\n// { name, bytes, origin }, and `setter` the routine a scene calls with the table's address in X\n// and Y. A table's entries are read while each points inside the file that holds it, at four\n// bytes that make sense as an object.\nexport function tables(files, setter) {\n const out = [];\n const word = (b, i) => b[i] | b[i + 1] << 8;\n const holder = address => files.find(f => address >= f.origin && address < f.origin + f.bytes.length);\n for (const f of files) {\n const b = f.bytes;\n for (let i = 0; i + 7 <= b.length; i++) {\n if (!(b[i] === 0xa2 && b[i + 2] === 0xa0 && b[i + 4] === 0x20 && word(b, i + 5) === setter)) continue;\n const address = b[i + 1] | b[i + 3] << 8;\n // the parts all load at one address, and so do the problems: a table is in the file that\n // sets it when it fits there, else in whichever file it does fit, PART0 for one Nature Park uses\n const h = address >= f.origin && address < f.origin + b.length ? f : holder(address);\n if (!h || out.some(t => t.file === h.name && t.address === address)) continue;\n const objects = [];\n for (let n = 2; ; n++) {\n const at = address - h.origin + (n - 2) * 2;\n if (at + 2 > h.bytes.length) break;\n const pointer = word(h.bytes, at);\n if (pointer < h.origin || pointer + 4 > h.origin + h.bytes.length) break;\n const o = pointer - h.origin, width = h.bytes[o + 2], height = h.bytes[o + 3];\n if (!h.bytes[o + 1] || !width || !height || width > 140 || height > 192) break;\n objects.push({ number: n, at: pointer, ...decode(h.bytes, o) });\n }\n if (objects.length) out.push({ file: h.name, setBy: f.name, address, objects });\n }\n }\n return out;\n}\n\n// The carry the object routine leaves, which a scene may add in without clearing it first, as the\n// elephants' problem does when it beeps each apple onto Pip's island ($F47A). The routine builds\n// the object in a buffer and copies it out a row at a time ($6B0F); its pointer starts at\n// $D000 less twice the dot's byte column and one bit of its place in the column, and each row adds\n// the object's bytes to a row and one, with the carry set first. The carry is the last add's.\nexport function carry(object, x) {\n const column = Math.floor(2 * x / 7), place = x % 7; // the tables $17A0 and $182C that $5A17 builds\n let lo = -(2 * column + (place >> 1 & 1)) & 0xff, c = 0;\n for (let row = 0; row < object.height; row++) { const sum = lo + object.stride + 1; c = sum > 0xff ? 1 : 0; lo = sum & 0xff; }\n return c;\n}\n", "// The engine's pictures: named lists of shapes on the 140 by 192 double hi-res screen.\n//\n// PICS1 to PICS3 are each a list of pictures. A picture is its name in 14 bytes, padded with\n// spaces (one, BREAK, has the high bit set on every byte), then two bytes for its length from\n// the start of the name, then its shapes. A shape is two bytes, the color it is filled with and\n// the color of its outline, then its points as (x, y) pairs, x from 1 to 138 and y from 1 down\n// the screen. Shapes are separated by $FE, and $FE $FF ends the picture. A shape of two points\n// is a line in its outline color and is not filled.\n//\n// The picture routine, $7AFE in Animal Rescue, takes a picture's name inline after the call,\n// has the loader copy its shapes to $E000, and draws them from there.\n\nconst text = bytes => String.fromCharCode(...Array.from(bytes, b => b & 0x7f));\n\n// shapes from `read`, a function of an address, starting at `at`, until $FF where the next shape\n// would start: the form the drawing loop at $7B8C reads from $E000\nexport function shapes(read, at, limit = 0x2000) {\n const out = [];\n let shape = null;\n for (let i = at; i < at + limit; i++) {\n const b = read(i);\n if (b === 0xff && !shape) break;\n if (b === 0xfe) { if (shape) out.push(shape); shape = null; continue; }\n if (!shape) { shape = { fill: b, line: read(i + 1), points: [] }; i++; continue; }\n shape.points.push([b, read(i + 1)]); i++;\n }\n if (shape) out.push(shape);\n return out;\n}\n\n// every picture in one of PICS1 to PICS3, as { name, at, length, shapes }\nexport function pictures(bytes) {\n const out = [];\n for (let at = 0; at + 16 <= bytes.length; ) {\n const name = text(bytes.subarray(at, at + 14)).trimEnd();\n const length = bytes[at + 14] | bytes[at + 15] << 8;\n if (length < 18 || at + length > bytes.length) break;\n out.push({ name, at, length, shapes: shapes(i => bytes[i], at + 16, length - 16) });\n at += length;\n }\n return out;\n}\n\n// The color behind each picture, from the scenes' code. A scene calls the box routine with three\n// colors in A, X and Y, the picture window's and then the two text boxes', and then the picture\n// routine with the picture's name inline after the call: a length byte with its high bit set,\n// then the name in small letters with underscores for spaces. `windows` reads every code file\n// for those two calls and gives each name the window color set before it. A scene that draws\n// TRACK 1 to 4 or COL PATTERN 1 to 6 writes `track_` with a byte left for the digit, filled in\n// as it runs, so a name with a trailing digit falls back to the name without it.\nexport function windows(codes, { box, picture }) {\n const seen = new Map();\n const word = (b, i) => b[i] | b[i + 1] << 8;\n for (const code of codes) {\n let color;\n for (let i = 0; i + 8 < code.length; i++) {\n if (code[i] === 0xa9 && code[i + 2] === 0xa2 && code[i + 4] === 0xa0 && code[i + 6] === 0x20 && word(code, i + 7) === box) { color = code[i + 1]; i += 8; continue; }\n if (code[i] === 0x20 && word(code, i + 1) === picture && code[i + 3] & 0x80) {\n const n = code[i + 3] & 0x7f;\n const name = text(code.subarray(i + 4, i + 4 + n)).toUpperCase().replace(/_/g, ' ').replace(/[\\x00-\\x1f]/g, '').trimEnd();\n if (color !== undefined && !seen.has(name)) seen.set(name, color);\n i += 3 + n;\n }\n }\n }\n return name => seen.get(name) ?? seen.get(name.replace(/ ?\\d$/, ''));\n}\n", "// The engine's shapes as SVG, which draws them at any size. A shape is a polygon in its fill\n// color outlined in its outline color, or, with two points, a line. The coordinates are the\n// engine's dots, 140 across and 192 down. A dot is four times as wide on the screen as the\n// number of dots suggests and twice as high, so a whole screen is drawn 560 by 384.\nimport { rgb } from '@moonbase-machines/apple2e/colors.js';\n\n// the columns and rows the shapes cover, a dot beyond them on each side\nexport function bounds(list) {\n let x0 = 140, y0 = 192, x1 = -1, y1 = -1;\n for (const sh of list) for (const [x, y] of sh.points) { x0 = Math.min(x0, x); y0 = Math.min(y0, y); x1 = Math.max(x1, x); y1 = Math.max(y1, y); }\n return x1 < 0 ? null : { x0: Math.max(0, x0 - 1), y0: Math.max(0, y0 - 1), x1: Math.min(139, x1 + 1), y1: Math.min(191, y1 + 1) };\n}\n\n// The SVG elements for the shapes, in the 140 by 192 space. A dot is a unit square, so the\n// points are moved half a unit to the dots' centers and a stroke is a dot wide. With a\n// background, a rectangle of it goes under the shapes where the engine's fills touch dots\n// beside them. `crisp` keeps the edges hard, as the screen had them; without it the shapes are\n// drawn smooth, which is what a sharper picture wants.\nexport function elements(list, { background, crisp = true } = {}) {\n const b = bounds(list), edge = crisp ? ' shape-rendering=\"crispEdges\"' : '';\n let s = b && background !== undefined ? `<rect x=\"${Math.max(0, b.x0 - 1)}\" y=\"${Math.max(0, b.y0 - 1)}\" width=\"${b.x1 - b.x0 + 3}\" height=\"${b.y1 - b.y0 + 3}\" fill=\"${rgb(background)}\"/>` : '';\n for (const sh of list) {\n const pts = sh.points.map(([x, y]) => (x + 0.5) + ',' + (y + 0.5)).join(' ');\n if (sh.points.length === 2) s += `<polyline points=\"${pts}\" fill=\"none\" stroke=\"${rgb(sh.line)}\" stroke-width=\"1\" stroke-linecap=\"square\"${edge}/>`;\n else if (sh.points.length > 2) s += `<polygon points=\"${pts}\" fill=\"${rgb(sh.fill)}\" stroke=\"${rgb(sh.line)}\" stroke-width=\"1\" stroke-linejoin=\"round\"${edge}/>`;\n }\n return s;\n}\n\n// a whole picture as an SVG document, `width` wide and in the screen's proportions, on its\n// background color\nexport function document(list, { background = 0, width = 560, crisp = false } = {}) {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 140 192\" width=\"${width}\" height=\"${width * 384 / 560}\" preserveAspectRatio=\"none\">` +\n `<rect width=\"140\" height=\"192\" fill=\"${rgb(background)}\"/>` + elements(list, { crisp }) + '</svg>';\n}\n", "import { colors as m } from '@moonbase-machines/apple2e';\nexport const { COLORS, NAMES, rgb } = m;"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["draw_exports", "__export", "crossings", "draw", "fill", "inside", "line", "outline", "screen", "spans", "under", "background", "x0", "y0", "x1", "y1", "dx", "dy", "sx", "sy", "xMajor", "major", "minor", "err", "x", "y", "out", "k", "points", "rows", "keep", "l", "i", "n", "last", "xa", "ya", "xb", "yb", "dots", "way", "top", "bottom", "lo", "hi", "each", "c", "j", "set", "scr", "shape", "a", "b", "p", "list", "row", "hit", "font_exports", "__export", "GLYPHS", "WIDTHS", "dots", "start", "useFont", "width", "BIG", "ch", "c", "chars", "spacing", "x", "centre", "sum", "hex", "out", "y", "row", "BASE", "variants", "w", "rows", "inline_exports", "__export", "INLINE", "name", "sound", "text", "read", "at", "s", "i", "guard", "c", "code", "n", "bytes", "k", "b", "objects_exports", "__export", "carry", "decode", "put", "tables", "bytes", "at", "flags", "stride", "width", "height", "p", "run", "value", "rows", "escape", "next", "b", "y", "row", "k", "bits", "i", "x", "scr", "object", "whole", "dy", "c", "dx", "r", "files", "setter", "out", "word", "holder", "address", "f", "h", "t", "objects", "n", "pointer", "o", "column", "place", "lo", "sum", "pictures_exports", "__export", "pictures", "shapes", "windows", "text", "bytes", "b", "read", "at", "limit", "out", "shape", "i", "name", "length", "codes", "box", "picture", "seen", "word", "code", "color", "n", "svg_exports", "__export", "bounds", "document", "elements", "m", "COLORS", "NAMES", "rgb", "bounds", "list", "x0", "y0", "x1", "y1", "sh", "x", "y", "elements", "background", "crisp", "b", "edge", "s", "rgb", "pts", "document", "width"]
|
|
7
7
|
}
|
package/font.js
CHANGED
|
@@ -50,12 +50,11 @@ export function dots(ch) {
|
|
|
50
50
|
return out;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
const VARIANTS = { 'nature-park-adventure': { '0': [4, '609090909090600000'], '_': [7, '000054aa5400000000'] } };
|
|
53
|
+
// A title's font: the engine's, these, but for any glyphs its own PART0 has otherwise, given as { character: [its
|
|
54
|
+
// width, its rows as hex] } (Nature Park's: a zero without the stroke, and the underline a band of seven dots, read
|
|
55
|
+
// through its tables at $6A32 and $6A9C). `useFont` makes them the ones these read; none, the engine's.
|
|
57
56
|
const BASE = { widths: WIDTHS.slice(), glyphs: GLYPHS.slice() };
|
|
58
|
-
export function useFont(
|
|
57
|
+
export function useFont(variants = {}) {
|
|
59
58
|
WIDTHS.splice(0, WIDTHS.length, ...BASE.widths); GLYPHS.splice(0, GLYPHS.length, ...BASE.glyphs);
|
|
60
|
-
for (const [ch, [w, rows]] of Object.entries(
|
|
59
|
+
for (const [ch, [w, rows]] of Object.entries(variants)) { WIDTHS[ch.charCodeAt(0) - 0x20] = w; GLYPHS[ch.charCodeAt(0) - 0x20] = rows; }
|
|
61
60
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moonbase-machines/vector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Mark Wharton's vector graphics engine for the Apple IIe (Animal Rescue, Nature Park Adventure, 1989): its pictures, objects, font and drawing, dot for dot.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"./*": "./*"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@moonbase-machines/apple2e": "0.
|
|
13
|
+
"@moonbase-machines/apple2e": "0.8.0"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"test": "node --test test/*.test.js",
|