webGLの圧縮

#JsExe
Revision2019 の 4K Intro 優勝作品のwebGLの圧縮スキルがわかりました。
javascriptをバイナリに変換して、それをを`<img>`のソースとして読み込んで、そのソースをデコードし、eval()を使ってwebGLをやってるようです。
[JsExeというTool](http://www.pouet.net/prod.php?which=59298)を使うみたい。
出力ファイルは、バイナリとデコードのスクリプトが入っていて、そのまま使えます。
この圧縮するスキルは、[ここに書いてある事と同等](http://yomotsu.net/blog/2015/03/01/js2png.html)と思われます。
#使い方
[JsExe](http://www.pouet.net/prod.php?which=59298)をdownloadしてくる。
javascriptだけで表示が出来るfileを用意する。
こんな感じ

```javascript
var canvas = document.createElement("canvas");
canvas.style.position = "fixed";
canvas.style.cursor = "none";
canvas.style.left = canvas.style.top = 0;

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);

var gl = canvas.getContext("webgl2") || canvas.getContext("experimental-webgl2");
var compileShader = function(prog, src, type){
    var sh = gl.createShader(type);
    gl.shaderSource(sh, src.replace(/^\n/, ""));
    gl.compileShader(sh);
    gl.attachShader(prog, sh);
    gl.deleteShader(sh);
};
        
vs = `
#version 300 es
void main()
{ 
    gl_Position = vec4(ivec2(gl_VertexID&1,gl_VertexID>>1)*2-1,0,1);
}
`
fs = `
#version 300 es
precision highp float;
out vec4 fragColor;
uniform vec2 resolution;
uniform float time;
void main() {
  vec2 uv=(gl_FragCoord.xy*2.-resolution)/resolution.y;
  vec3 col=.5+.5*cos(time+uv.xyx+vec3(0,2,4));
  fragColor=vec4(col,1);
}
`

var p = gl.createProgram();
compileShader(p, vs, gl.VERTEX_SHADER);
compileShader(p, fs, gl.FRAGMENT_SHADER);
gl.linkProgram(p);
gl.useProgram(p);
gl.uniform2f(gl.getUniformLocation(p, "resolution"), canvas.width, canvas.height);

var zero = Date.now();
(function () { 
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.uniform1f(gl.getUniformLocation(p, "time"), (Date.now() - zero) * 0.001);
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
    requestAnimationFrame(arguments.callee);
})();
```

この時のポイントは  
<b>styleを使ってcanvasを固定する事とcanvasの動的生成。</b>
  
上のファイル名を `test.js` として、出力ファイル名を  `index.html`  とした場合のコマンドラインは  
 
 
```
jsexe.exe -cn test.js index.html
```    

これで、おしまい。   
オプションは、`-cn`だけで良さそう。 
  
このindex.htmlは、localhostを立てないと見れない。   
python3を使ってlocalhostを立ててみるには 

```python
python -m http.server
```

これでOK。
http://localhost:8000/
にアクセスしてください。

ここでは、複雑になるのでミニ化については、触れないでJsExeだけの使い方にとどめています。

JsExeを使ってのミニ化は、こちらを参考にすれば良いと思います。
[Bercon/CoreCritical](https://github.com/Bercon/CoreCritical)

#base64を使ってみた
バイナリだと色々と制約があるみたい。なのでbase64を使ってみた。この場合は圧縮効果は無いと思います。利点としてソースを見せたくない時に利用が出来ると思います。
雑だけど、python3でJsExeの出力ファイルから、base64のimgソースを持つhtmlファイルを作るスクリプトを書きました。

```python
import base64
import sys

def convert(inFile, outFile):
    f = open(inFile, "rb")
    data = f.read()
    f.close
    js= "<canvas id=V><img src=# onload=C=V.getContext(\'2d\');for($=_=\'\';C.drawImage(this,$--,0),X=C.getImageData(0,0,1,1).data[0];_+=String.fromCharCode(X));(1,eval)(_)>"
    b64 = base64.encodestring(data)
    js = js.replace("#","'data:image/png;base64,"+b64.decode('utf-8')+"'")
    f = open(outFile, 'w')
    f.write(js)
    f.close()

if __name__ == '__main__':
    args = sys.argv
    convert(args[1],args[2])
```

これを `b64Exe.py`として保存してもらうとしたら、


```
python b64Exe.py jsExe_Html out_Html
```

これでできます。


```HTML
<canvas id=V><img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABdYAAAABCAAAAAD25KMnAAAC2UlEQVR4Xn1UXW/aMBTtMxL/wcqk
KaEhDbR9QlRiENZKXYeAdnuYxtzkJrFm7Mx2ANbuv892SgNttzyE+J5zfL85WmGBYsxWWKI+Snhc
LoGpIBaAFUQUzMl1KoLj9ZqNihtItaUQFFwSRTjTUiclG0icl4y4FJILgzPO4BVMIVUaPLApXmhT
qKnP5DVJVK6Na8ISvg4IYyC+GFvtLgeS5eoF59IaNek5sXuebANcFMCSYU5o4lZyz3oztchoHU8G
asiZgo0uwRruM9p1PPT4+BYMmwIEMS4wbe+4verKmC8LQmGW4wRMKdKSxaZqbiF45iMpYh+pbQHe
Q7OB9GM00qSb0aoRT1LXknqWZDBprTNeihhcmdubAgEFxfp88v0bO/GR43h7ioNItGQPwkrhOK+Q
XWD7eAIU1KHyj0WrR2dqBuhHs/FuBUKamTgNQwRSA5wkaIkJc71m4wHtPC4m9fCsID5ziX53XQ3c
gVCwuRq97/h7p4uLjtfqtjt+6Hes92ZDe0v/5bUQEBNryUmWFyilHJtJ4KWy7lAqcDbklAttLBlJ
uVgaoIsESE5LE1mNVHKkyBJ6Bxkh2zOrK1d9E/3Y3stFEmy2rW7Qrq/zTurvYNt7Ep6imNN+cH4c
nLdiLl3j47hcafXm2MBu6Hf9s6qLddB9WzKtrIuxm+Bif3ImgmcCL11DOux+4aOV9A3zLprOo6+L
2eVgFE3fJKYVcTwdfPwU3cz3qNpKCfu5c1M82UoJr0xVJbupq/EM1G11vuYxrpbBR05dH8fz0f7y
21O95/W+/gbBdcIjrCBgfG0TdXcbhkyDUD3+FLAw7oefrz9PFx9ux+NI/1zN0aOBR9Fkfrln3U1/
HXznf8Gbxpmw3ToW1LbxeaiFwiAMO/v7JPB6IATeSnPlfHo1uPl4HS1m+mvio9BHZzuygF8lSDVg
ZGmdjXVVwcUis/9oMogxpQB2Cjy3KszRX33+127r/QzqRT48Y2FudmFzIGlkPVY+PGltZyBzcmM9
IyBvbmxvYWQ9Qz1WLmdldENvbnRleHQoJzJkJyk7Zm9yKCQ9Xz0nJztDLmRyYXdJbWFnZSh0aGlz
LCQtLSwwKSxYPUMuZ2V0SW1hZ2VEYXRhKDAsMCwxLDEpLmRhdGFbMF07Xys9U3RyaW5nLmZyb21D
aGFyQ29kZShYKSk7KDEsZXZhbCkoXyk+
' onload=C=V.getContext('2d');for($=_='';C.drawImage(this,$--,0),X=C.getImageData(0,0,1,1).data[0];_+=String.fromCharCode(X));(1,eval)(_)>

```
こんなに意味不明のスクリプトが動く絵を出すなんて、楽しすぎです。  
ちなみに、https://neort.io/ のhtmlに貼り付けたら動きました。