diff --git a/docs/beztoy.js b/docs/beztoy.js new file mode 100644 index 0000000..77d0c46 --- /dev/null +++ b/docs/beztoy.js @@ -0,0 +1 @@ +let M=`undefined`,J=0,K=`Object`,G=1,I=`function`,P=4,H=`string`,F=null,N=`utf-8`,D=Array,L=Error,O=FinalizationRegistry,E=undefined;var p=(()=>{if(o===F||o.byteLength===J){o=new Int32Array(a.memory.buffer)};return o});var h=(a=>{const b=typeof a;if(b==`number`||b==`boolean`||a==F){return `${a}`};if(b==H){return `"${a}"`};if(b==`symbol`){const b=a.description;if(b==F){return `Symbol`}else{return `Symbol(${b})`}};if(b==I){const b=a.name;if(typeof b==H&&b.length>J){return `Function(${b})`}else{return `Function`}};if(D.isArray(a)){const b=a.length;let c=`[`;if(b>J){c+=h(a[J])};for(let d=G;dG){d=c[G]}else{return toString.call(a)};if(d==K){try{return `Object(`+ JSON.stringify(a)+ `)`}catch(a){return K}};if(a instanceof L){return `${a.name}: ${a.message}\n${a.stack}`};return d});var y=(()=>{const b={};b.wbg={};b.wbg.__wbindgen_object_drop_ref=(a=>{f(a)});b.wbg.__wbindgen_object_clone_ref=(a=>{const b=c(a);return g(b)});b.wbg.__wbindgen_cb_drop=(a=>{const b=f(a).original;if(b.cnt--==G){b.a=J;return !0};const c=!1;return c});b.wbg.__wbg_new_abda76e883ba8a5f=(()=>{const a=new L();return g(a)});b.wbg.__wbg_stack_658279fe44541cf6=((b,d)=>{const e=c(d).stack;const f=n(e,a.__wbindgen_malloc,a.__wbindgen_realloc);const g=i;p()[b/P+ G]=g;p()[b/P+ J]=f});b.wbg.__wbg_error_f851667af71bcfc6=((b,c)=>{let d;let e;try{d=b;e=c;console.error(r(b,c))}finally{a.__wbindgen_free(d,e,G)}});b.wbg.__wbg_instanceof_Window_f401953a2cf86220=(a=>{let b;try{b=c(a) instanceof Window}catch(a){b=!1}const d=b;return d});b.wbg.__wbg_document_5100775d18896c16=(a=>{const b=c(a).document;return v(b)?J:g(b)});b.wbg.__wbg_createElementNS_556a62fb298be5a2=function(){return w(((a,b,d,e,f)=>{const h=c(a).createElementNS(b===J?E:r(b,d),r(e,f));return g(h)}),arguments)};b.wbg.__wbg_getElementById_c369ff43f0db99cf=((a,b,d)=>{const e=c(a).getElementById(r(b,d));return v(e)?J:g(e)});b.wbg.__wbg_instanceof_Element_6945fc210db80ea9=(a=>{let b;try{b=c(a) instanceof Element}catch(a){b=!1}const d=b;return d});b.wbg.__wbg_removeAttribute_1b10a06ae98ebbd1=function(){return w(((a,b,d)=>{c(a).removeAttribute(r(b,d))}),arguments)};b.wbg.__wbg_setAttribute_3c9f6c303b696daa=function(){return w(((a,b,d,e,f)=>{c(a).setAttribute(r(b,d),r(e,f))}),arguments)};b.wbg.__wbg_setPointerCapture_0fdaad7a916c8486=function(){return w(((a,b)=>{c(a).setPointerCapture(b)}),arguments)};b.wbg.__wbg_instanceof_HtmlElement_3bcc4ff70cfdcba5=(a=>{let b;try{b=c(a) instanceof HTMLElement}catch(a){b=!1}const d=b;return d});b.wbg.__wbg_instanceof_SvggElement_6eab16f04ba1d1d5=(a=>{let b;try{b=c(a) instanceof SVGGElement}catch(a){b=!1}const d=b;return d});b.wbg.__wbg_addEventListener_53b787075bd5e003=function(){return w(((a,b,d,e)=>{c(a).addEventListener(r(b,d),c(e))}),arguments)};b.wbg.__wbg_instanceof_SvgsvgElement_ab645292b5c30322=(a=>{let b;try{b=c(a) instanceof SVGSVGElement}catch(a){b=!1}const d=b;return d});b.wbg.__wbg_firstChild_a10db88beca6812e=(a=>{const b=c(a).firstChild;return v(b)?J:g(b)});b.wbg.__wbg_appendChild_580ccb11a660db68=function(){return w(((a,b)=>{const d=c(a).appendChild(c(b));return g(d)}),arguments)};b.wbg.__wbg_removeChild_96bbfefd2f5a0261=function(){return w(((a,b)=>{const d=c(a).removeChild(c(b));return g(d)}),arguments)};b.wbg.__wbg_pointerId_e030fa156647fedd=(a=>{const b=c(a).pointerId;return b});b.wbg.__wbg_instanceof_HtmlInputElement_307512fe1252c849=(a=>{let b;try{b=c(a) instanceof HTMLInputElement}catch(a){b=!1}const d=b;return d});b.wbg.__wbg_setchecked_931ff2ed2cd3ebfd=((a,b)=>{c(a).checked=b!==J});b.wbg.__wbg_setvalue_78cb4f1fef58ae98=((a,b,d)=>{c(a).value=r(b,d)});b.wbg.__wbg_preventDefault_b1a4aafc79409429=(a=>{c(a).preventDefault()});b.wbg.__wbg_stopPropagation_fa5b666049c9fd02=(a=>{c(a).stopPropagation()});b.wbg.__wbg_clientX_fef6bf7a6bcf41b8=(a=>{const b=c(a).clientX;return b});b.wbg.__wbg_clientY_df42f8fceab3cef2=(a=>{const b=c(a).clientY;return b});b.wbg.__wbg_button_367cdc7303e3cf9b=(a=>{const b=c(a).button;return b});b.wbg.__wbg_newnoargs_e258087cd0daa0ea=((a,b)=>{const c=new Function(r(a,b));return g(c)});b.wbg.__wbg_call_27c0f87801dedf93=function(){return w(((a,b)=>{const d=c(a).call(c(b));return g(d)}),arguments)};b.wbg.__wbg_self_ce0dbfc45cf2f5be=function(){return w((()=>{const a=self.self;return g(a)}),arguments)};b.wbg.__wbg_window_c6fb939a7f436783=function(){return w((()=>{const a=window.window;return g(a)}),arguments)};b.wbg.__wbg_globalThis_d1e6af4856ba331b=function(){return w((()=>{const a=globalThis.globalThis;return g(a)}),arguments)};b.wbg.__wbg_global_207b558942527489=function(){return w((()=>{const a=global.global;return g(a)}),arguments)};b.wbg.__wbindgen_is_undefined=(a=>{const b=c(a)===E;return b});b.wbg.__wbindgen_debug_string=((b,d)=>{const e=h(c(d));const f=n(e,a.__wbindgen_malloc,a.__wbindgen_realloc);const g=i;p()[b/P+ G]=g;p()[b/P+ J]=f});b.wbg.__wbindgen_throw=((a,b)=>{throw new L(r(a,b))});b.wbg.__wbindgen_closure_wrapper107=((a,b,c)=>{const d=t(a,b,19,u);return g(d)});return b});var x=(async(a,b)=>{if(typeof Response===I&&a instanceof Response){if(typeof WebAssembly.instantiateStreaming===I){try{return await WebAssembly.instantiateStreaming(a,b)}catch(b){if(a.headers.get(`Content-Type`)!=`application/wasm`){console.warn(`\`WebAssembly.instantiateStreaming\` failed because your server does not serve wasm with \`application/wasm\` MIME type. Falling back to \`WebAssembly.instantiate\` which is slower. Original error:\\n`,b)}else{throw b}}};const c=await a.arrayBuffer();return await WebAssembly.instantiate(c,b)}else{const c=await WebAssembly.instantiate(a,b);if(c instanceof WebAssembly.Instance){return {instance:c,module:a}}else{return c}}});var k=(()=>{if(j===F||j.byteLength===J){j=new Uint8Array(a.memory.buffer)};return j});var g=(a=>{if(d===b.length)b.push(b.length+ G);const c=d;d=b[c];b[c]=a;return c});var f=(a=>{const b=c(a);e(a);return b});var z=((a,b)=>{});var u=((b,c,d)=>{a.wasm_bindgen__convert__closures__invoke1_mut__hfd4b84fc7fbe1a80(b,c,g(d))});var n=((a,b,c)=>{if(c===E){const c=l.encode(a);const d=b(c.length,G)>>>J;k().subarray(d,d+ c.length).set(c);i=c.length;return d};let d=a.length;let e=b(d,G)>>>J;const f=k();let g=J;for(;g127)break;f[e+ g]=b};if(g!==d){if(g!==J){a=a.slice(g)};e=c(e,d,d=g+ a.length*3,G)>>>J;const b=k().subarray(e+ g,e+ d);const f=m(a,b);g+=f.written;e=c(e,d,g,G)>>>J};i=g;return e});var v=(a=>a===E||a===F);var r=((a,b)=>{a=a>>>J;return q.decode(k().subarray(a,a+ b))});var B=(b=>{if(a!==E)return a;const c=y();z(c);if(!(b instanceof WebAssembly.Module)){b=new WebAssembly.Module(b)};const d=new WebAssembly.Instance(b,c);return A(d,b)});var A=((b,c)=>{a=b.exports;C.__wbindgen_wasm_module=c;o=F;j=F;a.__wbindgen_start();return a});var c=(a=>b[a]);function w(b,c){try{return b.apply(this,c)}catch(b){a.__wbindgen_exn_store(g(b))}}var t=((b,c,d,e)=>{const f={a:b,b:c,cnt:G,dtor:d};const g=(...b)=>{f.cnt++;const c=f.a;f.a=J;try{return e(c,f.b,...b)}finally{if(--f.cnt===J){a.__wbindgen_export_2.get(f.dtor)(c,f.b);s.unregister(f)}else{f.a=c}}};g.original=f;s.register(g,f,f);return g});var C=(async(b)=>{if(a!==E)return a;if(typeof b===M){b=new URL(`beztoy_bg.wasm`,import.meta.url)};const c=y();if(typeof b===H||typeof Request===I&&b instanceof Request||typeof URL===I&&b instanceof URL){b=fetch(b)};z(c);const {instance:d,module:e}=await x(await b,c);return A(d,e)});var e=(a=>{if(a<132)return;b[a]=d;d=a});let a;const b=new D(128).fill(E);b.push(E,F,!0,!1);let d=b.length;let i=J;let j=F;const l=typeof TextEncoder!==M?new TextEncoder(N):{encode:()=>{throw L(`TextEncoder not available`)}};const m=typeof l.encodeInto===I?((a,b)=>l.encodeInto(a,b)):((a,b)=>{const c=l.encode(a);b.set(c);return {read:a.length,written:c.length}});let o=F;const q=typeof TextDecoder!==M?new TextDecoder(N,{ignoreBOM:!0,fatal:!0}):{decode:()=>{throw L(`TextDecoder not available`)}};if(typeof TextDecoder!==M){q.decode()};const s=typeof O===M?{register:()=>{},unregister:()=>{}}:new O(b=>{a.__wbindgen_export_2.get(b.dtor)(b.a,b.b)});export default C;export{B as initSync} \ No newline at end of file diff --git a/docs/beztoy_bg.wasm b/docs/beztoy_bg.wasm new file mode 100644 index 0000000..bc23c06 Binary files /dev/null and b/docs/beztoy_bg.wasm differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..8aad6ae --- /dev/null +++ b/docs/index.html @@ -0,0 +1,157 @@ + + + + GPU-friendly Stroke Expansion + + + + + + + + +
+

GPU-friendly Stroke Expansion

+
+
+

Raph Levien

+
+
+

Arman Uguray

+
+
+
+ +
+
+ +
+
+
+

Abstract

+
+

+ Vector graphics includes both filled and stroked paths as the main primitives. While there are many techniques for rendering filled paths on GPU, stroked paths have proved more elusive. This paper presents a technique for performing stroke expansion, namely the generation of the outline representing the stroke of the given input path. Stroke expansion is a global problem, with challenging constraints on continuity and correctness. Nonetheless, we implement it using a fully parallel algorithm suitable for execution in a GPU compute shader, with minimal preprocessing. The output of our method can be either line or circular arc segments, both of which are well suited to GPU rendering, and the number of segments is minimal. We introduce several novel techniques, including an encoding of vector graphics primitives suitable for parallel processing, and an Euler spiral based method for computing approximations to parallel curves and evolutes. +

+
+
+
+

+ Click and drag the control points (black circles) to reshape the cubic Bézier curve below. The source curve is first approximated by Euler spiral segments that satisfy an error tolerance. The two parallel curves of each Euler spiral segment are lowered to line segments. +

+
+ + +