diff --git a/README.md b/README.md index 4b5ce89..8c7fa26 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,13 @@ const globe = createGlobe(canvas, { theta: 0, dark: 0, diffuse: 1.2, + scale: 1, mapSamples: 16000, mapBrightness: 6, baseColor: [0.3, 0.3, 0.3], markerColor: [1, 0.5, 1], glowColor: [1, 1, 1], + offset: [0, 0], markers: [ { location: [37.7595, -122.4367], size: 0.03 }, { location: [40.7128, -74.006], size: 0.1 }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..97a8e2a --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,185 @@ +lockfileVersion: 5.3 + +specifiers: + esbuild: ^0.13.14 + phenomenon: ^1.6.0 + typescript: ^4.5.4 + +dependencies: + phenomenon: 1.6.0 + +devDependencies: + esbuild: 0.13.15 + typescript: 4.6.3 + +packages: + + /esbuild-android-arm64/0.13.15: + resolution: {integrity: sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-64/0.13.15: + resolution: {integrity: sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-arm64/0.13.15: + resolution: {integrity: sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-freebsd-64/0.13.15: + resolution: {integrity: sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-freebsd-arm64/0.13.15: + resolution: {integrity: sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-32/0.13.15: + resolution: {integrity: sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-64/0.13.15: + resolution: {integrity: sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-arm/0.13.15: + resolution: {integrity: sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-arm64/0.13.15: + resolution: {integrity: sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-mips64le/0.13.15: + resolution: {integrity: sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-ppc64le/0.13.15: + resolution: {integrity: sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-netbsd-64/0.13.15: + resolution: {integrity: sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-openbsd-64/0.13.15: + resolution: {integrity: sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-sunos-64/0.13.15: + resolution: {integrity: sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-32/0.13.15: + resolution: {integrity: sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-64/0.13.15: + resolution: {integrity: sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-arm64/0.13.15: + resolution: {integrity: sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild/0.13.15: + resolution: {integrity: sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==} + hasBin: true + requiresBuild: true + optionalDependencies: + esbuild-android-arm64: 0.13.15 + esbuild-darwin-64: 0.13.15 + esbuild-darwin-arm64: 0.13.15 + esbuild-freebsd-64: 0.13.15 + esbuild-freebsd-arm64: 0.13.15 + esbuild-linux-32: 0.13.15 + esbuild-linux-64: 0.13.15 + esbuild-linux-arm: 0.13.15 + esbuild-linux-arm64: 0.13.15 + esbuild-linux-mips64le: 0.13.15 + esbuild-linux-ppc64le: 0.13.15 + esbuild-netbsd-64: 0.13.15 + esbuild-openbsd-64: 0.13.15 + esbuild-sunos-64: 0.13.15 + esbuild-windows-32: 0.13.15 + esbuild-windows-64: 0.13.15 + esbuild-windows-arm64: 0.13.15 + dev: true + + /phenomenon/1.6.0: + resolution: {integrity: sha512-7h9/fjPD3qNlgggzm88cY58l9sudZ6Ey+UmZsizfhtawO6E3srZQXywaNm2lBwT72TbpHYRPy7ytIHeBUD/G0A==} + dev: false + + /typescript/4.6.3: + resolution: {integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true diff --git a/src/index.js b/src/index.js index f64daa8..15b250e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,16 +1,18 @@ -import Phenomenon from "phenomenon"; +import Phenomenon from 'phenomenon' -const OPT_PHI = "phi"; -const OPT_THETA = "theta"; -const OPT_DOTS = "mapSamples"; -const OPT_MAP_BRIGHTNESS = "mapBrightness"; -const OPT_BASE_COLOR = "baseColor"; -const OPT_MARKER_COLOR = "markerColor"; -const OPT_GLOW_COLOR = "glowColor"; -const OPT_MARKERS = "markers"; -const OPT_DIFFUSE = "diffuse"; -const OPT_DPR = "devicePixelRatio"; -const OPT_DARK = "dark"; +const OPT_PHI = 'phi' +const OPT_THETA = 'theta' +const OPT_DOTS = 'mapSamples' +const OPT_MAP_BRIGHTNESS = 'mapBrightness' +const OPT_BASE_COLOR = 'baseColor' +const OPT_MARKER_COLOR = 'markerColor' +const OPT_GLOW_COLOR = 'glowColor' +const OPT_MARKERS = 'markers' +const OPT_DIFFUSE = 'diffuse' +const OPT_DPR = 'devicePixelRatio' +const OPT_DARK = 'dark' +const OPT_OFFSET = 'offset' +const OPT_SCALE = 'scale' const OPT_MAPPING = { [OPT_PHI]: GLSLX_NAME_PHI, @@ -22,31 +24,33 @@ const OPT_MAPPING = { [OPT_GLOW_COLOR]: GLSLX_NAME_GLOW_COLOR, [OPT_DIFFUSE]: GLSLX_NAME_DIFFUSE, [OPT_DARK]: GLSLX_NAME_DARK, -}; + [OPT_OFFSET]: GLSLX_NAME_OFFSET, + [OPT_SCALE]: GLSLX_NAME_SCALE, +} -const { PI, sin, cos } = Math; +const { PI, sin, cos } = Math const mapMarkers = (markers) => { return [].concat( ...markers.map((m) => { - let [a, b] = m.location; - a = (a * PI) / 180; - b = (b * PI) / 180 - PI; - const cx = cos(a); - return [-cx * cos(b), sin(a), cx * sin(b), m.size]; + let [a, b] = m.location + a = (a * PI) / 180 + b = (b * PI) / 180 - PI + const cx = cos(a) + return [-cx * cos(b), sin(a), cx * sin(b), m.size] }), // Make sure to fill zeros [0, 0, 0, 0] - ); -}; + ) +} export default (canvas, opts) => { - const createUniform = (type, name) => { + const createUniform = (type, name, fallback) => { return { type, - value: opts[name], - }; - }; + value: typeof opts[name] === 'undefined' ? fallback : opts[name], + } + } const p = new Phenomenon({ canvas, @@ -60,12 +64,12 @@ export default (canvas, opts) => { settings: { [OPT_DPR]: opts[OPT_DPR] || 1, onSetup: (gl) => { - const RGBFormat = gl.RGB; - const srcType = gl.UNSIGNED_BYTE; - const TEXTURE_2D = gl.TEXTURE_2D; + const RGBFormat = gl.RGB + const srcType = gl.UNSIGNED_BYTE + const TEXTURE_2D = gl.TEXTURE_2D - const texture = gl.createTexture(); - gl.bindTexture(TEXTURE_2D, texture); + const texture = gl.createTexture() + gl.bindTexture(TEXTURE_2D, texture) gl.texImage2D( TEXTURE_2D, 0, @@ -76,54 +80,56 @@ export default (canvas, opts) => { RGBFormat, srcType, new Uint8Array([0, 0, 0, 0]) - ); + ) - const image = new Image(); + const image = new Image() image.onload = () => { - gl.bindTexture(TEXTURE_2D, texture); - gl.texImage2D(TEXTURE_2D, 0, RGBFormat, RGBFormat, srcType, image); + gl.bindTexture(TEXTURE_2D, texture) + gl.texImage2D(TEXTURE_2D, 0, RGBFormat, RGBFormat, srcType, image) - gl.generateMipmap(TEXTURE_2D); + gl.generateMipmap(TEXTURE_2D) - const program = gl.getParameter(gl.CURRENT_PROGRAM); + const program = gl.getParameter(gl.CURRENT_PROGRAM) const textureLocation = gl.getUniformLocation( program, GLSLX_NAME_U_TEXTURE - ); - gl.texParameteri(TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.uniform1i(textureLocation, 0); - }; - image.src = __TEXTURE__; + ) + gl.texParameteri(TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) + gl.texParameteri(TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) + gl.uniform1i(textureLocation, 0) + } + image.src = __TEXTURE__ }, }, - }); + }) - p.add("", { + p.add('', { vertex: `attribute vec3 aPosition;uniform mat4 uProjectionMatrix;uniform mat4 uModelMatrix;uniform mat4 uViewMatrix;void main(){gl_Position=uProjectionMatrix*uModelMatrix*uViewMatrix*vec4(aPosition,1.);}`, fragment: GLSLX_SOURCE_MAIN, uniforms: { [GLSLX_NAME_U_RESOLUTION]: { - type: "vec2", + type: 'vec2', value: [opts.width, opts.height], }, - [GLSLX_NAME_PHI]: createUniform("float", OPT_PHI), - [GLSLX_NAME_THETA]: createUniform("float", OPT_THETA), - [GLSLX_NAME_DOTS]: createUniform("float", OPT_DOTS), - [GLSLX_NAME_DOTS_BRIGHTNESS]: createUniform("float", OPT_MAP_BRIGHTNESS), - [GLSLX_NAME_BASE_COLOR]: createUniform("vec3", OPT_BASE_COLOR), - [GLSLX_NAME_MARKER_COLOR]: createUniform("vec3", OPT_MARKER_COLOR), - [GLSLX_NAME_DIFFUSE]: createUniform("float", OPT_DIFFUSE), - [GLSLX_NAME_GLOW_COLOR]: createUniform("vec3", OPT_GLOW_COLOR), - [GLSLX_NAME_DARK]: createUniform("float", OPT_DARK), + [GLSLX_NAME_PHI]: createUniform('float', OPT_PHI), + [GLSLX_NAME_THETA]: createUniform('float', OPT_THETA), + [GLSLX_NAME_DOTS]: createUniform('float', OPT_DOTS), + [GLSLX_NAME_DOTS_BRIGHTNESS]: createUniform('float', OPT_MAP_BRIGHTNESS), + [GLSLX_NAME_BASE_COLOR]: createUniform('vec3', OPT_BASE_COLOR), + [GLSLX_NAME_MARKER_COLOR]: createUniform('vec3', OPT_MARKER_COLOR), + [GLSLX_NAME_DIFFUSE]: createUniform('float', OPT_DIFFUSE), + [GLSLX_NAME_GLOW_COLOR]: createUniform('vec3', OPT_GLOW_COLOR), + [GLSLX_NAME_DARK]: createUniform('float', OPT_DARK), [GLSLX_NAME_MARKERS]: { - type: "vec4", + type: 'vec4', value: mapMarkers(opts[OPT_MARKERS]), }, [GLSLX_NAME_MARKERS_NUM]: { - type: "float", + type: 'float', value: opts[OPT_MARKERS].length, }, + [GLSLX_NAME_OFFSET]: createUniform('vec2', OPT_OFFSET, [0, 0]), + [GLSLX_NAME_SCALE]: createUniform('float', OPT_SCALE, 1), }, mode: 4, geometry: { @@ -137,24 +143,24 @@ export default (canvas, opts) => { ], }, onRender: ({ uniforms }) => { - const state = {}; + const state = {} if (opts.onRender) { - opts.onRender(state); + opts.onRender(state) for (let k in OPT_MAPPING) { if (state[k] !== undefined) { - uniforms[OPT_MAPPING[k]].value = state[k]; + uniforms[OPT_MAPPING[k]].value = state[k] } } if (state[OPT_MARKERS] !== undefined) { - uniforms[GLSLX_NAME_MARKERS].value = mapMarkers(state[OPT_MARKERS]); - uniforms[GLSLX_NAME_MARKERS_NUM].value = state[OPT_MARKERS].length; + uniforms[GLSLX_NAME_MARKERS].value = mapMarkers(state[OPT_MARKERS]) + uniforms[GLSLX_NAME_MARKERS_NUM].value = state[OPT_MARKERS].length } if (state.width && state.height) { - uniforms[GLSLX_NAME_U_RESOLUTION].value = [state.width, state.height]; + uniforms[GLSLX_NAME_U_RESOLUTION].value = [state.width, state.height] } } }, - }); + }) - return p; -}; + return p +} diff --git a/src/shader.frag b/src/shader.frag index 9a165e7..bf87004 100644 --- a/src/shader.frag +++ b/src/shader.frag @@ -3,9 +3,11 @@ precision highp float; uniform vec2 uResolution; +uniform vec2 offset; uniform float phi; uniform float theta; uniform float dots; +uniform float scale; uniform vec3 baseColor; uniform vec3 markerColor; uniform vec3 glowColor; @@ -129,7 +131,7 @@ vec3 nearestFibonacciLattice(vec3 p, out float m) { } void main() { - vec2 uv = (gl_FragCoord.xy / uResolution) * 2. - 1.; + vec2 uv = ((gl_FragCoord.xy / uResolution) * 2. - 1.) / scale - offset * vec2(1., -1.) / uResolution; uv.x *= uResolution.x / uResolution.y; float l = dot(uv, uv); diff --git a/src/shader.min.js b/src/shader.min.js index 45978b6..b787d14 100644 --- a/src/shader.min.js +++ b/src/shader.min.js @@ -1,16 +1,18 @@ export const GLSLX_SOURCE_MAIN = - 'precision highp float;uniform vec2 u;uniform vec3 J,K,x;uniform vec4 y[64];uniform float z,A,k,B,C,D,E;uniform sampler2D F;float G=1./k;mat3 H(float a,float b){float c=cos(a),d=cos(b),e=sin(a),f=sin(b);return mat3(d,f*e,-f*c,0.,c,e,f,d*-e,d*c);}vec3 v(vec3 c,out float w){c=c.xzy;float p=max(2.,floor(log2(2.236068*k*3.141593*(1.-c.z*c.z))*.72021));vec2 g=floor(pow(1.618034,p)/2.236068*vec2(1.,1.618034)+.5),d=fract((g+1.)*.618034)*6.283185-3.883222,e=-2.*g,f=vec2(atan(c.y,c.x),c.z-1.),q=floor(vec2(e.y*f.x-d.y*(f.y*k+1.),-e.x*f.x+d.x*(f.y*k+1.))/(d.x*e.y-e.x*d.y));float n=3.141593;vec3 r;for(float h=0.;h<4.;h+=1.){vec2 s=vec2(mod(h,2.),floor(h*.5));float j=dot(g,q+s);if(j>k)continue;float a=j,b=0.;if(a>=524288.)a-=524288.,b+=.803894;if(a>=262144.)a-=262144.,b+=.901947;if(a>=131072.)a-=131072.,b+=.950973;if(a>=65536.)a-=65536.,b+=.475487;if(a>=32768.)a-=32768.,b+=.737743;if(a>=16384.)a-=16384.,b+=.868872;if(a>=8192.)a-=8192.,b+=.934436;if(a>=4096.)a-=4096.,b+=.467218;if(a>=2048.)a-=2048.,b+=.733609;if(a>=1024.)a-=1024.,b+=.866804;if(a>=512.)a-=512.,b+=.433402;if(a>=256.)a-=256.,b+=.216701;if(a>=128.)a-=128.,b+=.108351;if(a>=64.)a-=64.,b+=.554175;if(a>=32.)a-=32.,b+=.777088;if(a>=16.)a-=16.,b+=.888544;if(a>=8.)a-=8.,b+=.944272;if(a>=4.)a-=4.,b+=.472136;if(a>=2.)a-=2.,b+=.236068;if(a>=1.)a-=1.,b+=.618034;float l=fract(b)*6.283185,i=1.-2.*j*G,m=sqrt(1.-i*i);vec3 o=vec3(cos(l)*m,sin(l)*m,i);float t=length(c-o);if(t=M)break;vec4 o=y[i];vec3 p=o.xyz,w=p-f;float q=o.w;if(dot(w,w)>q*q*4.)continue;vec3 N=v(p,b);b=length(N-f),bk)continue;float a=j,b=0.;if(a>=524288.)a-=524288.,b+=.803894;if(a>=262144.)a-=262144.,b+=.901947;if(a>=131072.)a-=131072.,b+=.950973;if(a>=65536.)a-=65536.,b+=.475487;if(a>=32768.)a-=32768.,b+=.737743;if(a>=16384.)a-=16384.,b+=.868872;if(a>=8192.)a-=8192.,b+=.934436;if(a>=4096.)a-=4096.,b+=.467218;if(a>=2048.)a-=2048.,b+=.733609;if(a>=1024.)a-=1024.,b+=.866804;if(a>=512.)a-=512.,b+=.433402;if(a>=256.)a-=256.,b+=.216701;if(a>=128.)a-=128.,b+=.108351;if(a>=64.)a-=64.,b+=.554175;if(a>=32.)a-=32.,b+=.777088;if(a>=16.)a-=16.,b+=.888544;if(a>=8.)a-=8.,b+=.944272;if(a>=4.)a-=4.,b+=.472136;if(a>=2.)a-=2.,b+=.236068;if(a>=1.)a-=1.,b+=.618034;float l=fract(b)*6.283185,i=1.-2.*j*I,m=sqrt(1.-i*i);vec3 o=vec3(cos(l)*m,sin(l)*m,i);float u=length(c-o);if(u=O)break;vec4 o=z[i];vec3 p=o.xyz,w=p-f;float q=o.w;if(dot(w,w)>q*q*4.)continue;vec3 P=v(p,b);b=length(P-f),b