-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreal-shaders.html
301 lines (287 loc) · 41.6 KB
/
real-shaders.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>🌱 real shaders</title>
<style>
body {
background-color: #222;
max-width: 500px;
margin: auto;
font-family: serif;
font-size: 1.2em;
color: #edd;
text-align: left;
padding: 20px 8px;
}
@font-face {
font-family: "FontWithASyntaxHighlighter";
src: url("/fonts/FontWithASyntaxHighlighter-Regular.woff2")
format("woff2");
}
a {
color: cyan;
font-size: 1em;
}
textarea,
pre {
overflow: auto;
font-family: "FontWithASyntaxHighlighter", monospace;
padding: 8px;
font-size: 12px;
border: 0;
outline: none;
background-color: #44444490;
color: white;
width: 100%;
margin-top: 8px;
box-sizing: border-box;
}
ul,
ol {
padding-left: 20px;
}
canvas {
max-width: 100%;
}
</style>
</head>
<body>
<h2>🌱 real shaders</h2>
<p>
After faking shaders<sup>1</sup>, now let's see how "real" shaders work..
This implementation is based on schattenspiel<sup>2</sup>, trying to
simplify it further..
</p>
<canvas id="canvas" width="500" height="500"></canvas>
<span id="hint"
><small>💡 hit ctrl+enter to update the code.</small>
<small
style="cursor: pointer; opacity: 50%"
onclick="document.querySelector('#hint').remove()"
>hide</small
></span
>
<textarea id="code" type="text" rows="16" spellcheck="false"></textarea>
<p>
the code above is GLSL, implementing <i>mainImage</i>, similar to
shadertoy<sup>2</sup>.
</p>
<p>You can use these uniforms:</p>
<ul style="font-size: 12px; font-family: monospace">
<li>uniform vec2 iResolution: width and height of the canvas</li>
<li>uniform float iTime: Elapsed time in seconds</li>
</ul>
<p>here are some examples (mostly from shadertoy):</p>
<ul>
<li>
<a
href="#Ly8gY3J1bXBsZWRXYXZlIGJ5IG5hc2FuYSBvbiAyMDIwLTAxLTI5Ci8vIGh0dHBzOi8vd3d3LnNoYWRlcnRveS5jb20vdmlldy8zdHRTenIKCnZvaWQgbWFpbkltYWdlKCBvdXQgdmVjNCBmcmFnQ29sb3IsIGluIHZlYzIgZnJhZ0Nvb3JkICl7CiAgICB2ZWMyIHV2ID0gICgyLjAgKiBmcmFnQ29vcmQgLSBpUmVzb2x1dGlvbi54eSkgLyBtaW4oaVJlc29sdXRpb24ueCwgaVJlc29sdXRpb24ueSk7CiAgIAogICAgZm9yKGZsb2F0IGkgPSAxLjA7IGkgPCA4LjA7IGkrKyl7CiAgICB1di55ICs9IGkgKiAwLjEgLyBpICogCiAgICAgIHNpbih1di54ICogaSAqIGkgKyBpVGltZSAqIDAuNSkgKiBzaW4odXYueSAqIGkgKiBpICsgaVRpbWUgKiAwLjUpOwogIH0KICAgIAogICB2ZWMzIGNvbDsKICAgY29sLnIgID0gdXYueSAtIDAuMTsKICAgY29sLmcgPSB1di55ICsgMC4zOwogICBjb2wuYiA9IHV2LnkgKyAwLjk1OwogICAgCiAgICBmcmFnQ29sb3IgPSB2ZWM0KGNvbCwxLjApOwp9"
>
crumpled wave
</a>
</li>
<li>
<a
href="#LyoKaHR0cHM6Ly93d3cuc2hhZGVydG95LmNvbS92aWV3L2xsWGZScgptYWNib29rdGFsbCBvbiAyMDE3LTExLTE1Cgp0aGUgaWRlYSBpcyB0byByb3RhdGUgdGhlIGZyYWN0YWwgYmFzZWQgb24gZGlzdGFuY2UgZnJvbSB0aGUgY2FtZXJhLgppIHVzZWQgaXQgdG8gbWFrZSB0aGlzIGdpZiBodHRwczovL21lZGlhLmdpcGh5LmNvbS9tZWRpYS9sMlFFMW1sVFJWeTdZN0hmYS9naXBoeS5naWYKKi8KI2RlZmluZSBNQVhESVNUIDUwLgoKc3RydWN0IFJheSB7Cgl2ZWMzIHJvOwogICAgdmVjMyByZDsKfTsKICAKLy8gZnJvbSBuZXRncmluZAp2ZWMzIGh1ZSh2ZWMzIGNvbG9yLCBmbG9hdCBzaGlmdCkgewoKICAgIGNvbnN0IHZlYzMgIGtSR0JUb1lQcmltZSA9IHZlYzMgKDAuMjk5LCAwLjU4NywgMC4xMTQpOwogICAgY29uc3QgdmVjMyAga1JHQlRvSSAgICAgPSB2ZWMzICgwLjU5NiwgLTAuMjc1LCAtMC4zMjEpOwogICAgY29uc3QgdmVjMyAga1JHQlRvUSAgICAgPSB2ZWMzICgwLjIxMiwgLTAuNTIzLCAwLjMxMSk7CgogICAgY29uc3QgdmVjMyAga1lJUVRvUiAgID0gdmVjMyAoMS4wLCAwLjk1NiwgMC42MjEpOwogICAgY29uc3QgdmVjMyAga1lJUVRvRyAgID0gdmVjMyAoMS4wLCAtMC4yNzIsIC0wLjY0Nyk7CiAgICBjb25zdCB2ZWMzICBrWUlRVG9CICAgPSB2ZWMzICgxLjAsIC0xLjEwNywgMS43MDQpOwoKICAgIC8vIENvbnZlcnQgdG8gWUlRCiAgICBmbG9hdCAgIFlQcmltZSAgPSBkb3QgKGNvbG9yLCBrUkdCVG9ZUHJpbWUpOwogICAgZmxvYXQgICBJICAgICAgPSBkb3QgKGNvbG9yLCBrUkdCVG9JKTsKICAgIGZsb2F0ICAgUSAgICAgID0gZG90IChjb2xvciwga1JHQlRvUSk7CgogICAgLy8gQ2FsY3VsYXRlIHRoZSBodWUgYW5kIGNocm9tYQogICAgZmxvYXQgICBodWUgICAgID0gYXRhbiAoUSwgSSk7CiAgICBmbG9hdCAgIGNocm9tYSAgPSBzcXJ0IChJICogSSArIFEgKiBRKTsKCiAgICAvLyBNYWtlIHRoZSB1c2VyJ3MgYWRqdXN0bWVudHMKICAgIGh1ZSArPSBzaGlmdDsKCiAgICAvLyBDb252ZXJ0IGJhY2sgdG8gWUlRCiAgICBRID0gY2hyb21hICogc2luIChodWUpOwogICAgSSA9IGNocm9tYSAqIGNvcyAoaHVlKTsKCiAgICAvLyBDb252ZXJ0IGJhY2sgdG8gUkdCCiAgICB2ZWMzICAgIHlJUSAgID0gdmVjMyAoWVByaW1lLCBJLCBRKTsKICAgIGNvbG9yLnIgPSBkb3QgKHlJUSwga1lJUVRvUik7CiAgICBjb2xvci5nID0gZG90ICh5SVEsIGtZSVFUb0cpOwogICAgY29sb3IuYiA9IGRvdCAoeUlRLCBrWUlRVG9CKTsKCiAgICByZXR1cm4gY29sb3I7Cn0KCi8vIC0tLS0tLQoKLy8gYnkgaXEKCmZsb2F0IG9wVSggZmxvYXQgZDEsIGZsb2F0IGQyICkKewogICAgcmV0dXJuIG1pbihkMSxkMik7Cn0KCmZsb2F0IHNtaW4oIGZsb2F0IGEsIGZsb2F0IGIsIGZsb2F0IGsgKXsKICAgIGZsb2F0IGggPSBjbGFtcCggMC41KzAuNSooYi1hKS9rLCAwLjAsIDEuMCApOwogICAgcmV0dXJuIG1peCggYiwgYSwgaCApIC0gaypoKigxLjAtaCk7Cn0KCmZsb2F0IGxlbmd0aDYoIHZlYzMgcCApCnsKCXAgPSBwKnAqcDsgcCA9IHAqcDsKCXJldHVybiBwb3coIHAueCArIHAueSArIHAueiwgMS4wLzYuMCApOwp9CgovLyAtLS0tLS0KCi8vIGZyb20gaGdfc2RmIAoKZmxvYXQgZlBsYW5lKHZlYzMgcCwgdmVjMyBuLCBmbG9hdCBkaXN0YW5jZUZyb21PcmlnaW4pIHsKCXJldHVybiBkb3QocCwgbikgKyBkaXN0YW5jZUZyb21PcmlnaW47Cn0KCnZvaWQgcFIoaW5vdXQgdmVjMiBwLCBmbG9hdCBhKSB7CglwID0gY29zKGEpKnAgKyBzaW4oYSkqdmVjMihwLnksIC1wLngpOwp9CgovLyAtLS0tLS0tCgoKZmxvYXQgZnJhY3RhbCh2ZWMzIHApCnsKICAgIGNvbnN0IGludCBpdGVyYXRpb25zID0gMjA7CgkKICAgIGZsb2F0IGQgPSBpVGltZSo1LiAtIHAuejsKICAgCXA9cC55eHo7CiAgICBwUihwLnl6LCAxLjU3MDc5NSk7CiAgICBwLnggKz0gNi41OwoKICAgIHAueXogPSBtb2QoYWJzKHAueXopLS4wLCAyMC4pIC0gMTAuOwogICAgZmxvYXQgc2NhbGUgPSAxLjI1OwogICAgCiAgICBwLnh5IC89ICgxLitkKmQqMC4wMDA1KTsKICAgIAoJZmxvYXQgbCA9IDAuOwoJCiAgICBmb3IgKGludCBpPTA7IGk8aXRlcmF0aW9uczsgaSsrKSB7CgkJcC54eSA9IGFicyhwLnh5KTsKCQlwID0gcCpzY2FsZSArIHZlYzMoLTMuICsgZCowLjAwOTUsLTEuNSwtLjUpOwogICAgICAgIAoJCXBSKHAueHksMC4zNS1kKjAuMDE1KTsKCQlwUihwLnl6LDAuNStkKjAuMDIpOwoJCQogICAgICAgIGwgPWxlbmd0aDYocCk7Cgl9CglyZXR1cm4gbCpwb3coc2NhbGUsIC1mbG9hdChpdGVyYXRpb25zKSktLjE1Owp9Cgp2ZWMyIG1hcCh2ZWMzIHBvcykgCnsKICAgIGZsb2F0IGRpc3QgPSAxMC47IAogICAgZGlzdCA9IG9wVShkaXN0LCBmcmFjdGFsKHBvcykpOwogICAgZGlzdCA9IHNtaW4oZGlzdCwgZlBsYW5lKHBvcyx2ZWMzKDAuMCwxLjAsMC4wKSwxMC4pLCA0LjYpOwogICAgcmV0dXJuIHZlYzIoZGlzdCwgMC4pOwp9Cgp2ZWMzIHZtYXJjaChSYXkgcmF5LCBmbG9hdCBkaXN0KQp7ICAgCiAgICB2ZWMzIHAgPSByYXkucm87CiAgICB2ZWMyIHIgPSB2ZWMyKDAuKTsKICAgIHZlYzMgc3VtID0gdmVjMygwKTsKICAgIHZlYzMgYyA9IGh1ZSh2ZWMzKDAuLDAuLDEuKSw1LjUpOwogICAgZm9yKCBpbnQgaT0wOyBpPDIwOyBpKysgKQogICAgewogICAgICAgIHIgPSBtYXAocCk7CiAgICAgICAgaWYgKHIueCA+IC4wMSkgYnJlYWs7CiAgICAgICAgcCArPSByYXkucmQqLjAxNTsKICAgICAgICB2ZWMzIGNvbCA9IGM7CiAgICAgICAgY29sLnJnYiAqPSBzbW9vdGhzdGVwKC4wLDAuMTUsLXIueCk7CiAgICAgICAgc3VtICs9IGFicyhjb2wpKi41OwogICAgfQogICAgcmV0dXJuIHN1bTsKfQoKdmVjMiBtYXJjaChSYXkgcmF5KSAKewogICAgY29uc3QgaW50IHN0ZXBzID0gNTA7CiAgICBjb25zdCBmbG9hdCBwcmVjID0gMC4wMDE7CiAgICB2ZWMyIHJlcyA9IHZlYzIoMC4pOwogICAgCiAgICBmb3IgKGludCBpID0gMDsgaSA8IHN0ZXBzOyBpKyspIAogICAgeyAgICAgICAgCiAgICAgICAgdmVjMiBzID0gbWFwKHJheS5ybyArIHJheS5yZCAqIHJlcy54KTsKICAgICAgICAKICAgICAgICBpZiAocmVzLnggPiBNQVhESVNUIHx8IHMueCA8IHByZWMpIAogICAgICAgIHsKICAgICAgICAJYnJlYWs7ICAgIAogICAgICAgIH0KICAgICAgICAKICAgICAgICByZXMueCArPSBzLng7CiAgICAgICAgcmVzLnkgPSBzLnk7CiAgICAgICAgCiAgICB9CiAgIAogICAgcmV0dXJuIHJlczsKfQoKdmVjMyBjYWxjTm9ybWFsKHZlYzMgcG9zKSAKewoJY29uc3QgdmVjMyBlcHMgPSB2ZWMzKDAuMDA1LCAwLjAsIDAuMCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICByZXR1cm4gbm9ybWFsaXplKAogICAgICAgIHZlYzMobWFwKHBvcyArIGVwcykueCAtIG1hcChwb3MgLSBlcHMpLngsCiAgICAgICAgICAgICBtYXAocG9zICsgZXBzLnl4eikueCAtIG1hcChwb3MgLSBlcHMueXh6KS54LAogICAgICAgICAgICAgbWFwKHBvcyArIGVwcy55engpLnggLSBtYXAocG9zIC0gZXBzLnl6eCkueCApIAogICAgKTsKfQoKdmVjNCByZW5kZXIoUmF5IHJheSkgCnsKICAgIHZlYzMgY29sID0gdmVjMygwLik7Cgl2ZWMyIHJlcyA9IG1hcmNoKHJheSk7CiAgIAogICAgaWYgKHJlcy54ID4gTUFYRElTVCkgCiAgICB7CiAgICAgICAgcmV0dXJuIHZlYzQoY29sLCA1MC4pOwogICAgfQogICAgCiAgICB2ZWMzIHBvcyA9IHJheS5ybytyZXMueCpyYXkucmQ7CiAgICByYXkucm8gPSBwb3M7CiAgIAljb2wgPSB2bWFyY2gocmF5LCByZXMueCk7CiAgICAKICAgIGNvbCA9IG1peChjb2wsIHZlYzMoMC4pLCBjbGFtcChyZXMueC81MC4sIDAuLCAxLikpOwogICAJcmV0dXJuIHZlYzQoY29sLCByZXMueCk7Cn0KCm1hdDMgY2FtZXJhKGluIHZlYzMgcm8sIGluIHZlYzMgcmQsIGZsb2F0IHJvdCkgCnsKCXZlYzMgZm9yd2FyZCA9IG5vcm1hbGl6ZShyZCAtIHJvKTsKICAgIHZlYzMgd29ybGRVcCA9IHZlYzMoc2luKHJvdCksIGNvcyhyb3QpLCAwLjApOwogICAgdmVjMyB4ID0gbm9ybWFsaXplKGNyb3NzKGZvcndhcmQsIHdvcmxkVXApKTsKICAgIHZlYzMgeSA9IG5vcm1hbGl6ZShjcm9zcyh4LCBmb3J3YXJkKSk7CiAgICByZXR1cm4gbWF0Myh4LCB5LCBmb3J3YXJkKTsKfQoKdm9pZCBtYWluSW1hZ2UoIG91dCB2ZWM0IGZyYWdDb2xvciwgaW4gdmVjMiBmcmFnQ29vcmQgKQp7Cgl2ZWMyIHV2ID0gZnJhZ0Nvb3JkLnh5IC8gaVJlc29sdXRpb24ueHk7CiAgICB1diA9IHV2ICogMi4wIC0gMS4wOwogICAgdXYueCAqPSBpUmVzb2x1dGlvbi54IC8gaVJlc29sdXRpb24ueTsKICAgIHV2LnkgLT0gdXYueCp1di54KjAuMTU7CiAgICB2ZWMzIGNhbVBvcyA9IHZlYzMoMy4sIC0xLjUsIGlUaW1lKjUuKTsKICAgIHZlYzMgY2FtRGlyID0gY2FtUG9zK3ZlYzMoLTEuMjUsMC4xLCAxLik7CiAgICBtYXQzIGNhbSA9IGNhbWVyYShjYW1Qb3MsIGNhbURpciwgMC4pOwogICAgdmVjMyByYXlEaXIgPSBjYW0gKiBub3JtYWxpemUoIHZlYzModXYsIC44KSk7CiAgICAKICAgIFJheSByYXk7CiAgICByYXkucm8gPSBjYW1Qb3M7CiAgICByYXkucmQgPSByYXlEaXI7CiAgICAKICAgIHZlYzQgY29sID0gcmVuZGVyKHJheSk7CiAgICAKCWZyYWdDb2xvciA9IHZlYzQoMS4tY29sLnh5eixjbGFtcCgxLi1jb2wudy9NQVhESVNULCAwLiwgMS4pKTsKfQ=="
>
fractal trees
</a>
</li>
<li>
<a
href="#LyoqCiAqIFBhcnQgNiBDaGFsbGVuZ2VzOgogKiAtIE1ha2UgYSBzY2VuZSBvZiB5b3VyIG93biEgVHJ5IHRvIHVzZSB0aGUgcm90YXRpb24gdHJhbnNmb3JtcywgdGhlIENTRyBwcmltaXRpdmVzLAogKiAgIGFuZCB0aGUgZ2VvbWV0cmljIHByaW1pdGl2ZXMuIFJlbWVtYmVyIHlvdSBjYW4gdXNlIHZlY3RvciBzdWJ0cmFjdGlvbiBmb3IgdHJhbnNsYXRpb24sCiAqICAgYW5kIGNvbXBvbmVudC13aXNlIHZlY3RvciBtdWx0aXBsaWNhdGlvbiBmb3Igc2NhbGluZy4KICovCgpjb25zdCBpbnQgTUFYX01BUkNISU5HX1NURVBTID0gMjU1Owpjb25zdCBmbG9hdCBNSU5fRElTVCA9IDAuMDsKY29uc3QgZmxvYXQgTUFYX0RJU1QgPSAxMDAuMDsKY29uc3QgZmxvYXQgRVBTSUxPTiA9IDAuMDAwMTsKCi8qKgogKiBSb3RhdGlvbiBtYXRyaXggYXJvdW5kIHRoZSBYIGF4aXMuCiAqLwptYXQzIHJvdGF0ZVgoZmxvYXQgdGhldGEpIHsKICAgIGZsb2F0IGMgPSBjb3ModGhldGEpOwogICAgZmxvYXQgcyA9IHNpbih0aGV0YSk7CiAgICByZXR1cm4gbWF0MygKICAgICAgICB2ZWMzKDEsIDAsIDApLAogICAgICAgIHZlYzMoMCwgYywgLXMpLAogICAgICAgIHZlYzMoMCwgcywgYykKICAgICk7Cn0KCi8qKgogKiBSb3RhdGlvbiBtYXRyaXggYXJvdW5kIHRoZSBZIGF4aXMuCiAqLwptYXQzIHJvdGF0ZVkoZmxvYXQgdGhldGEpIHsKICAgIGZsb2F0IGMgPSBjb3ModGhldGEpOwogICAgZmxvYXQgcyA9IHNpbih0aGV0YSk7CiAgICByZXR1cm4gbWF0MygKICAgICAgICB2ZWMzKGMsIDAsIHMpLAogICAgICAgIHZlYzMoMCwgMSwgMCksCiAgICAgICAgdmVjMygtcywgMCwgYykKICAgICk7Cn0KCi8qKgogKiBSb3RhdGlvbiBtYXRyaXggYXJvdW5kIHRoZSBaIGF4aXMuCiAqLwptYXQzIHJvdGF0ZVooZmxvYXQgdGhldGEpIHsKICAgIGZsb2F0IGMgPSBjb3ModGhldGEpOwogICAgZmxvYXQgcyA9IHNpbih0aGV0YSk7CiAgICByZXR1cm4gbWF0MygKICAgICAgICB2ZWMzKGMsIC1zLCAwKSwKICAgICAgICB2ZWMzKHMsIGMsIDApLAogICAgICAgIHZlYzMoMCwgMCwgMSkKICAgICk7Cn0KCi8qKgogKiBDb25zdHJ1Y3RpdmUgc29saWQgZ2VvbWV0cnkgaW50ZXJzZWN0aW9uIG9wZXJhdGlvbiBvbiBTREYtY2FsY3VsYXRlZCBkaXN0YW5jZXMuCiAqLwpmbG9hdCBpbnRlcnNlY3RTREYoZmxvYXQgZGlzdEEsIGZsb2F0IGRpc3RCKSB7CiAgICByZXR1cm4gbWF4KGRpc3RBLCBkaXN0Qik7Cn0KCi8qKgogKiBDb25zdHJ1Y3RpdmUgc29saWQgZ2VvbWV0cnkgdW5pb24gb3BlcmF0aW9uIG9uIFNERi1jYWxjdWxhdGVkIGRpc3RhbmNlcy4KICovCmZsb2F0IHVuaW9uU0RGKGZsb2F0IGRpc3RBLCBmbG9hdCBkaXN0QikgewogICAgcmV0dXJuIG1pbihkaXN0QSwgZGlzdEIpOwp9CgovKioKICogQ29uc3RydWN0aXZlIHNvbGlkIGdlb21ldHJ5IGRpZmZlcmVuY2Ugb3BlcmF0aW9uIG9uIFNERi1jYWxjdWxhdGVkIGRpc3RhbmNlcy4KICovCmZsb2F0IGRpZmZlcmVuY2VTREYoZmxvYXQgZGlzdEEsIGZsb2F0IGRpc3RCKSB7CiAgICByZXR1cm4gbWF4KGRpc3RBLCAtZGlzdEIpOwp9CgovKioKICogU2lnbmVkIGRpc3RhbmNlIGZ1bmN0aW9uIGZvciBhIGN1YmUgY2VudGVyZWQgYXQgdGhlIG9yaWdpbgogKiB3aXRoIGRpbWVuc2lvbnMgc3BlY2lmaWVkIGJ5IHNpemUuCiAqLwpmbG9hdCBib3hTREYodmVjMyBwLCB2ZWMzIHNpemUpIHsKICAgIHZlYzMgZCA9IGFicyhwKSAtIChzaXplIC8gMi4wKTsKICAgIAogICAgLy8gQXNzdW1pbmcgcCBpcyBpbnNpZGUgdGhlIGN1YmUsIGhvdyBmYXIgaXMgaXQgZnJvbSB0aGUgc3VyZmFjZT8KICAgIC8vIFJlc3VsdCB3aWxsIGJlIG5lZ2F0aXZlIG9yIHplcm8uCiAgICBmbG9hdCBpbnNpZGVEaXN0YW5jZSA9IG1pbihtYXgoZC54LCBtYXgoZC55LCBkLnopKSwgMC4wKTsKICAgIAogICAgLy8gQXNzdW1pbmcgcCBpcyBvdXRzaWRlIHRoZSBjdWJlLCBob3cgZmFyIGlzIGl0IGZyb20gdGhlIHN1cmZhY2U/CiAgICAvLyBSZXN1bHQgd2lsbCBiZSBwb3NpdGl2ZSBvciB6ZXJvLgogICAgZmxvYXQgb3V0c2lkZURpc3RhbmNlID0gbGVuZ3RoKG1heChkLCAwLjApKTsKICAgIAogICAgcmV0dXJuIGluc2lkZURpc3RhbmNlICsgb3V0c2lkZURpc3RhbmNlOwp9CgovKioKICogU2lnbmVkIGRpc3RhbmNlIGZ1bmN0aW9uIGZvciBhIHNwaGVyZSBjZW50ZXJlZCBhdCB0aGUgb3JpZ2luIHdpdGggcmFkaXVzIHIuCiAqLwpmbG9hdCBzcGhlcmVTREYodmVjMyBwLCBmbG9hdCByKSB7CiAgICByZXR1cm4gbGVuZ3RoKHApIC0gcjsKfQoKLyoqCiAqIFNpZ25lZCBkaXN0YW5jZSBmdW5jdGlvbiBmb3IgYW4gWFkgYWxpZ25lZCBjeWxpbmRlciBjZW50ZXJlZCBhdCB0aGUgb3JpZ2luIHdpdGgKICogaGVpZ2h0IGggYW5kIHJhZGl1cyByLgogKi8KZmxvYXQgY3lsaW5kZXJTREYodmVjMyBwLCBmbG9hdCBoLCBmbG9hdCByKSB7CiAgICAvLyBIb3cgZmFyIGluc2lkZSBvciBvdXRzaWRlIHRoZSBjeWxpbmRlciB0aGUgcG9pbnQgaXMsIHJhZGlhbGx5CiAgICBmbG9hdCBpbk91dFJhZGl1cyA9IGxlbmd0aChwLnh5KSAtIHI7CiAgICAKICAgIC8vIEhvdyBmYXIgaW5zaWRlIG9yIG91dHNpZGUgdGhlIGN5bGluZGVyIGlzLCBheGlhbGx5IGFsaWduZWQgd2l0aCB0aGUgY3lsaW5kZXIKICAgIGZsb2F0IGluT3V0SGVpZ2h0ID0gYWJzKHAueikgLSBoLzIuMDsKICAgIAogICAgLy8gQXNzdW1pbmcgcCBpcyBpbnNpZGUgdGhlIGN5bGluZGVyLCBob3cgZmFyIGlzIGl0IGZyb20gdGhlIHN1cmZhY2U/CiAgICAvLyBSZXN1bHQgd2lsbCBiZSBuZWdhdGl2ZSBvciB6ZXJvLgogICAgZmxvYXQgaW5zaWRlRGlzdGFuY2UgPSBtaW4obWF4KGluT3V0UmFkaXVzLCBpbk91dEhlaWdodCksIDAuMCk7CgogICAgLy8gQXNzdW1pbmcgcCBpcyBvdXRzaWRlIHRoZSBjeWxpbmRlciwgaG93IGZhciBpcyBpdCBmcm9tIHRoZSBzdXJmYWNlPwogICAgLy8gUmVzdWx0IHdpbGwgYmUgcG9zaXRpdmUgb3IgemVyby4KICAgIGZsb2F0IG91dHNpZGVEaXN0YW5jZSA9IGxlbmd0aChtYXgodmVjMihpbk91dFJhZGl1cywgaW5PdXRIZWlnaHQpLCAwLjApKTsKICAgIAogICAgcmV0dXJuIGluc2lkZURpc3RhbmNlICsgb3V0c2lkZURpc3RhbmNlOwp9CgovKioKICogU2lnbmVkIGRpc3RhbmNlIGZ1bmN0aW9uIGRlc2NyaWJpbmcgdGhlIHNjZW5lLgogKiAKICogQWJzb2x1dGUgdmFsdWUgb2YgdGhlIHJldHVybiB2YWx1ZSBpbmRpY2F0ZXMgdGhlIGRpc3RhbmNlIHRvIHRoZSBzdXJmYWNlLgogKiBTaWduIGluZGljYXRlcyB3aGV0aGVyIHRoZSBwb2ludCBpcyBpbnNpZGUgb3Igb3V0c2lkZSB0aGUgc3VyZmFjZSwKICogbmVnYXRpdmUgaW5kaWNhdGluZyBpbnNpZGUuCiAqLwpmbG9hdCBzY2VuZVNERih2ZWMzIHNhbXBsZVBvaW50KSB7ICAgIAogICAgLy8gU2xvd2x5IHNwaW4gdGhlIHdob2xlIHNjZW5lCiAgICBzYW1wbGVQb2ludCA9IHJvdGF0ZVkoaVRpbWUgLyAyLjApICogc2FtcGxlUG9pbnQ7CiAgICAKICAgIGZsb2F0IGN5bGluZGVyUmFkaXVzID0gMC40ICsgKDEuMCAtIDAuNCkgKiAoMS4wICsgc2luKDEuNyAqIGlUaW1lKSkgLyAyLjA7CiAgICBmbG9hdCBjeWxpbmRlcjEgPSBjeWxpbmRlclNERihzYW1wbGVQb2ludCwgMi4wLCBjeWxpbmRlclJhZGl1cyk7CiAgICBmbG9hdCBjeWxpbmRlcjIgPSBjeWxpbmRlclNERihyb3RhdGVYKHJhZGlhbnMoOTAuMCkpICogc2FtcGxlUG9pbnQsIDIuMCwgY3lsaW5kZXJSYWRpdXMpOwogICAgZmxvYXQgY3lsaW5kZXIzID0gY3lsaW5kZXJTREYocm90YXRlWShyYWRpYW5zKDkwLjApKSAqIHNhbXBsZVBvaW50LCAyLjAsIGN5bGluZGVyUmFkaXVzKTsKICAgIAogICAgZmxvYXQgY3ViZSA9IGJveFNERihzYW1wbGVQb2ludCwgdmVjMygxLjgsIDEuOCwgMS44KSk7CiAgICAKICAgIGZsb2F0IHNwaGVyZSA9IHNwaGVyZVNERihzYW1wbGVQb2ludCwgMS4yKTsKICAgIAogICAgZmxvYXQgYmFsbE9mZnNldCA9IDAuNCArIDEuMCArIHNpbigxLjcgKiBpVGltZSk7CiAgICBmbG9hdCBiYWxsUmFkaXVzID0gMC4zOwogICAgZmxvYXQgYmFsbHMgPSBzcGhlcmVTREYoc2FtcGxlUG9pbnQgLSB2ZWMzKGJhbGxPZmZzZXQsIDAuMCwgMC4wKSwgYmFsbFJhZGl1cyk7CiAgICBiYWxscyA9IHVuaW9uU0RGKGJhbGxzLCBzcGhlcmVTREYoc2FtcGxlUG9pbnQgKyB2ZWMzKGJhbGxPZmZzZXQsIDAuMCwgMC4wKSwgYmFsbFJhZGl1cykpOwogICAgYmFsbHMgPSB1bmlvblNERihiYWxscywgc3BoZXJlU0RGKHNhbXBsZVBvaW50IC0gdmVjMygwLjAsIGJhbGxPZmZzZXQsIDAuMCksIGJhbGxSYWRpdXMpKTsKICAgIGJhbGxzID0gdW5pb25TREYoYmFsbHMsIHNwaGVyZVNERihzYW1wbGVQb2ludCArIHZlYzMoMC4wLCBiYWxsT2Zmc2V0LCAwLjApLCBiYWxsUmFkaXVzKSk7CiAgICBiYWxscyA9IHVuaW9uU0RGKGJhbGxzLCBzcGhlcmVTREYoc2FtcGxlUG9pbnQgLSB2ZWMzKDAuMCwgMC4wLCBiYWxsT2Zmc2V0KSwgYmFsbFJhZGl1cykpOwogICAgYmFsbHMgPSB1bmlvblNERihiYWxscywgc3BoZXJlU0RGKHNhbXBsZVBvaW50ICsgdmVjMygwLjAsIDAuMCwgYmFsbE9mZnNldCksIGJhbGxSYWRpdXMpKTsKICAgIAogICAgCiAgICAKICAgIGZsb2F0IGNzZ051dCA9IGRpZmZlcmVuY2VTREYoaW50ZXJzZWN0U0RGKGN1YmUsIHNwaGVyZSksCiAgICAgICAgICAgICAgICAgICAgICAgICB1bmlvblNERihjeWxpbmRlcjEsIHVuaW9uU0RGKGN5bGluZGVyMiwgY3lsaW5kZXIzKSkpOwogICAgCiAgICByZXR1cm4gdW5pb25TREYoYmFsbHMsIGNzZ051dCk7Cn0KCi8qKgogKiBSZXR1cm4gdGhlIHNob3J0ZXN0IGRpc3RhbmNlIGZyb20gdGhlIGV5ZXBvaW50IHRvIHRoZSBzY2VuZSBzdXJmYWNlIGFsb25nCiAqIHRoZSBtYXJjaGluZyBkaXJlY3Rpb24uIElmIG5vIHBhcnQgb2YgdGhlIHN1cmZhY2UgaXMgZm91bmQgYmV0d2VlbiBzdGFydCBhbmQgZW5kLAogKiByZXR1cm4gZW5kLgogKiAKICogZXllOiB0aGUgZXllIHBvaW50LCBhY3RpbmcgYXMgdGhlIG9yaWdpbiBvZiB0aGUgcmF5CiAqIG1hcmNoaW5nRGlyZWN0aW9uOiB0aGUgbm9ybWFsaXplZCBkaXJlY3Rpb24gdG8gbWFyY2ggaW4KICogc3RhcnQ6IHRoZSBzdGFydGluZyBkaXN0YW5jZSBhd2F5IGZyb20gdGhlIGV5ZQogKiBlbmQ6IHRoZSBtYXggZGlzdGFuY2UgYXdheSBmcm9tIHRoZSBleSB0byBtYXJjaCBiZWZvcmUgZ2l2aW5nIHVwCiAqLwpmbG9hdCBzaG9ydGVzdERpc3RhbmNlVG9TdXJmYWNlKHZlYzMgZXllLCB2ZWMzIG1hcmNoaW5nRGlyZWN0aW9uLCBmbG9hdCBzdGFydCwgZmxvYXQgZW5kKSB7CiAgICBmbG9hdCBkZXB0aCA9IHN0YXJ0OwogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBNQVhfTUFSQ0hJTkdfU1RFUFM7IGkrKykgewogICAgICAgIGZsb2F0IGRpc3QgPSBzY2VuZVNERihleWUgKyBkZXB0aCAqIG1hcmNoaW5nRGlyZWN0aW9uKTsKICAgICAgICBpZiAoZGlzdCA8IEVQU0lMT04pIHsKCQkJcmV0dXJuIGRlcHRoOwogICAgICAgIH0KICAgICAgICBkZXB0aCArPSBkaXN0OwogICAgICAgIGlmIChkZXB0aCA+PSBlbmQpIHsKICAgICAgICAgICAgcmV0dXJuIGVuZDsKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gZW5kOwp9CiAgICAgICAgICAgIAoKLyoqCiAqIFJldHVybiB0aGUgbm9ybWFsaXplZCBkaXJlY3Rpb24gdG8gbWFyY2ggaW4gZnJvbSB0aGUgZXllIHBvaW50IGZvciBhIHNpbmdsZSBwaXhlbC4KICogCiAqIGZpZWxkT2ZWaWV3OiB2ZXJ0aWNhbCBmaWVsZCBvZiB2aWV3IGluIGRlZ3JlZXMKICogc2l6ZTogcmVzb2x1dGlvbiBvZiB0aGUgb3V0cHV0IGltYWdlCiAqIGZyYWdDb29yZDogdGhlIHgseSBjb29yZGluYXRlIG9mIHRoZSBwaXhlbCBpbiB0aGUgb3V0cHV0IGltYWdlCiAqLwp2ZWMzIHJheURpcmVjdGlvbihmbG9hdCBmaWVsZE9mVmlldywgdmVjMiBzaXplLCB2ZWMyIGZyYWdDb29yZCkgewogICAgdmVjMiB4eSA9IGZyYWdDb29yZCAtIHNpemUgLyAyLjA7CiAgICBmbG9hdCB6ID0gc2l6ZS55IC8gdGFuKHJhZGlhbnMoZmllbGRPZlZpZXcpIC8gMi4wKTsKICAgIHJldHVybiBub3JtYWxpemUodmVjMyh4eSwgLXopKTsKfQoKLyoqCiAqIFVzaW5nIHRoZSBncmFkaWVudCBvZiB0aGUgU0RGLCBlc3RpbWF0ZSB0aGUgbm9ybWFsIG9uIHRoZSBzdXJmYWNlIGF0IHBvaW50IHAuCiAqLwp2ZWMzIGVzdGltYXRlTm9ybWFsKHZlYzMgcCkgewogICAgcmV0dXJuIG5vcm1hbGl6ZSh2ZWMzKAogICAgICAgIHNjZW5lU0RGKHZlYzMocC54ICsgRVBTSUxPTiwgcC55LCBwLnopKSAtIHNjZW5lU0RGKHZlYzMocC54IC0gRVBTSUxPTiwgcC55LCBwLnopKSwKICAgICAgICBzY2VuZVNERih2ZWMzKHAueCwgcC55ICsgRVBTSUxPTiwgcC56KSkgLSBzY2VuZVNERih2ZWMzKHAueCwgcC55IC0gRVBTSUxPTiwgcC56KSksCiAgICAgICAgc2NlbmVTREYodmVjMyhwLngsIHAueSwgcC56ICArIEVQU0lMT04pKSAtIHNjZW5lU0RGKHZlYzMocC54LCBwLnksIHAueiAtIEVQU0lMT04pKQogICAgKSk7Cn0KCi8qKgogKiBMaWdodGluZyBjb250cmlidXRpb24gb2YgYSBzaW5nbGUgcG9pbnQgbGlnaHQgc291cmNlIHZpYSBQaG9uZyBpbGx1bWluYXRpb24uCiAqIAogKiBUaGUgdmVjMyByZXR1cm5lZCBpcyB0aGUgUkdCIGNvbG9yIG9mIHRoZSBsaWdodCdzIGNvbnRyaWJ1dGlvbi4KICoKICoga19hOiBBbWJpZW50IGNvbG9yCiAqIGtfZDogRGlmZnVzZSBjb2xvcgogKiBrX3M6IFNwZWN1bGFyIGNvbG9yCiAqIGFscGhhOiBTaGluaW5lc3MgY29lZmZpY2llbnQKICogcDogcG9zaXRpb24gb2YgcG9pbnQgYmVpbmcgbGl0CiAqIGV5ZTogdGhlIHBvc2l0aW9uIG9mIHRoZSBjYW1lcmEKICogbGlnaHRQb3M6IHRoZSBwb3NpdGlvbiBvZiB0aGUgbGlnaHQKICogbGlnaHRJbnRlbnNpdHk6IGNvbG9yL2ludGVuc2l0eSBvZiB0aGUgbGlnaHQKICoKICogU2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1Bob25nX3JlZmxlY3Rpb25fbW9kZWwjRGVzY3JpcHRpb24KICovCnZlYzMgcGhvbmdDb250cmliRm9yTGlnaHQodmVjMyBrX2QsIHZlYzMga19zLCBmbG9hdCBhbHBoYSwgdmVjMyBwLCB2ZWMzIGV5ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWMzIGxpZ2h0UG9zLCB2ZWMzIGxpZ2h0SW50ZW5zaXR5KSB7CiAgICB2ZWMzIE4gPSBlc3RpbWF0ZU5vcm1hbChwKTsKICAgIHZlYzMgTCA9IG5vcm1hbGl6ZShsaWdodFBvcyAtIHApOwogICAgdmVjMyBWID0gbm9ybWFsaXplKGV5ZSAtIHApOwogICAgdmVjMyBSID0gbm9ybWFsaXplKHJlZmxlY3QoLUwsIE4pKTsKICAgIAogICAgZmxvYXQgZG90TE4gPSBkb3QoTCwgTik7CiAgICBmbG9hdCBkb3RSViA9IGRvdChSLCBWKTsKICAgIAogICAgaWYgKGRvdExOIDwgMC4wKSB7CiAgICAgICAgLy8gTGlnaHQgbm90IHZpc2libGUgZnJvbSB0aGlzIHBvaW50IG9uIHRoZSBzdXJmYWNlCiAgICAgICAgcmV0dXJuIHZlYzMoMC4wLCAwLjAsIDAuMCk7CiAgICB9IAogICAgCiAgICBpZiAoZG90UlYgPCAwLjApIHsKICAgICAgICAvLyBMaWdodCByZWZsZWN0aW9uIGluIG9wcG9zaXRlIGRpcmVjdGlvbiBhcyB2aWV3ZXIsIGFwcGx5IG9ubHkgZGlmZnVzZQogICAgICAgIC8vIGNvbXBvbmVudAogICAgICAgIHJldHVybiBsaWdodEludGVuc2l0eSAqIChrX2QgKiBkb3RMTik7CiAgICB9CiAgICByZXR1cm4gbGlnaHRJbnRlbnNpdHkgKiAoa19kICogZG90TE4gKyBrX3MgKiBwb3coZG90UlYsIGFscGhhKSk7Cn0KCi8qKgogKiBMaWdodGluZyB2aWEgUGhvbmcgaWxsdW1pbmF0aW9uLgogKiAKICogVGhlIHZlYzMgcmV0dXJuZWQgaXMgdGhlIFJHQiBjb2xvciBvZiB0aGF0IHBvaW50IGFmdGVyIGxpZ2h0aW5nIGlzIGFwcGxpZWQuCiAqIGtfYTogQW1iaWVudCBjb2xvcgogKiBrX2Q6IERpZmZ1c2UgY29sb3IKICoga19zOiBTcGVjdWxhciBjb2xvcgogKiBhbHBoYTogU2hpbmluZXNzIGNvZWZmaWNpZW50CiAqIHA6IHBvc2l0aW9uIG9mIHBvaW50IGJlaW5nIGxpdAogKiBleWU6IHRoZSBwb3NpdGlvbiBvZiB0aGUgY2FtZXJhCiAqCiAqIFNlZSBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QaG9uZ19yZWZsZWN0aW9uX21vZGVsI0Rlc2NyaXB0aW9uCiAqLwp2ZWMzIHBob25nSWxsdW1pbmF0aW9uKHZlYzMga19hLCB2ZWMzIGtfZCwgdmVjMyBrX3MsIGZsb2F0IGFscGhhLCB2ZWMzIHAsIHZlYzMgZXllKSB7CiAgICBjb25zdCB2ZWMzIGFtYmllbnRMaWdodCA9IDAuNSAqIHZlYzMoMS4wLCAxLjAsIDEuMCk7CiAgICB2ZWMzIGNvbG9yID0gYW1iaWVudExpZ2h0ICoga19hOwogICAgCiAgICB2ZWMzIGxpZ2h0MVBvcyA9IHZlYzMoNC4wICogc2luKGlUaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAyLjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgNC4wICogY29zKGlUaW1lKSk7CiAgICB2ZWMzIGxpZ2h0MUludGVuc2l0eSA9IHZlYzMoMC40LCAwLjQsIDAuNCk7CiAgICAKICAgIGNvbG9yICs9IHBob25nQ29udHJpYkZvckxpZ2h0KGtfZCwga19zLCBhbHBoYSwgcCwgZXllLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlnaHQxUG9zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlnaHQxSW50ZW5zaXR5KTsKICAgIAogICAgdmVjMyBsaWdodDJQb3MgPSB2ZWMzKDIuMCAqIHNpbigwLjM3ICogaVRpbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgIDIuMCAqIGNvcygwLjM3ICogaVRpbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgIDIuMCk7CiAgICB2ZWMzIGxpZ2h0MkludGVuc2l0eSA9IHZlYzMoMC40LCAwLjQsIDAuNCk7CiAgICAKICAgIGNvbG9yICs9IHBob25nQ29udHJpYkZvckxpZ2h0KGtfZCwga19zLCBhbHBoYSwgcCwgZXllLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlnaHQyUG9zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlnaHQySW50ZW5zaXR5KTsgICAgCiAgICByZXR1cm4gY29sb3I7Cn0KCi8qKgogKiBSZXR1cm4gYSB0cmFuc2Zvcm0gbWF0cml4IHRoYXQgd2lsbCB0cmFuc2Zvcm0gYSByYXkgZnJvbSB2aWV3IHNwYWNlCiAqIHRvIHdvcmxkIGNvb3JkaW5hdGVzLCBnaXZlbiB0aGUgZXllIHBvaW50LCB0aGUgY2FtZXJhIHRhcmdldCwgYW5kIGFuIHVwIHZlY3Rvci4KICoKICogVGhpcyBhc3N1bWVzIHRoYXQgdGhlIGNlbnRlciBvZiB0aGUgY2FtZXJhIGlzIGFsaWduZWQgd2l0aCB0aGUgbmVnYXRpdmUgeiBheGlzIGluCiAqIHZpZXcgc3BhY2Ugd2hlbiBjYWxjdWxhdGluZyB0aGUgcmF5IG1hcmNoaW5nIGRpcmVjdGlvbi4gU2VlIHJheURpcmVjdGlvbi4KICovCm1hdDMgdmlld01hdHJpeCh2ZWMzIGV5ZSwgdmVjMyBjZW50ZXIsIHZlYzMgdXApIHsKICAgIC8vIEJhc2VkIG9uIGdsdUxvb2tBdCBtYW4gcGFnZQogICAgdmVjMyBmID0gbm9ybWFsaXplKGNlbnRlciAtIGV5ZSk7CiAgICB2ZWMzIHMgPSBub3JtYWxpemUoY3Jvc3MoZiwgdXApKTsKICAgIHZlYzMgdSA9IGNyb3NzKHMsIGYpOwogICAgcmV0dXJuIG1hdDMocywgdSwgLWYpOwp9Cgp2b2lkIG1haW5JbWFnZSggb3V0IHZlYzQgZnJhZ0NvbG9yLCBpbiB2ZWMyIGZyYWdDb29yZCApCnsKCXZlYzMgdmlld0RpciA9IHJheURpcmVjdGlvbig0NS4wLCBpUmVzb2x1dGlvbi54eSwgZnJhZ0Nvb3JkKTsKICAgIHZlYzMgZXllID0gdmVjMyg4LjAsIDUuMCAqIHNpbigwLjIgKiBpVGltZSksIDcuMCk7CiAgICAKICAgIG1hdDMgdmlld1RvV29ybGQgPSB2aWV3TWF0cml4KGV5ZSwgdmVjMygwLjAsIDAuMCwgMC4wKSwgdmVjMygwLjAsIDEuMCwgMC4wKSk7CiAgICAKICAgIHZlYzMgd29ybGREaXIgPSB2aWV3VG9Xb3JsZCAqIHZpZXdEaXI7CiAgICAKICAgIGZsb2F0IGRpc3QgPSBzaG9ydGVzdERpc3RhbmNlVG9TdXJmYWNlKGV5ZSwgd29ybGREaXIsIE1JTl9ESVNULCBNQVhfRElTVCk7CiAgICAKICAgIGlmIChkaXN0ID4gTUFYX0RJU1QgLSBFUFNJTE9OKSB7CiAgICAgICAgLy8gRGlkbid0IGhpdCBhbnl0aGluZwogICAgICAgIGZyYWdDb2xvciA9IHZlYzQoMC4wLCAwLjAsIDAuMCwgMC4wKTsKCQlyZXR1cm47CiAgICB9CiAgICAKICAgIC8vIFRoZSBjbG9zZXN0IHBvaW50IG9uIHRoZSBzdXJmYWNlIHRvIHRoZSBleWVwb2ludCBhbG9uZyB0aGUgdmlldyByYXkKICAgIHZlYzMgcCA9IGV5ZSArIGRpc3QgKiB3b3JsZERpcjsKICAgIAogICAgLy8gVXNlIHRoZSBzdXJmYWNlIG5vcm1hbCBhcyB0aGUgYW1iaWVudCBjb2xvciBvZiB0aGUgbWF0ZXJpYWwKICAgIHZlYzMgS19hID0gKGVzdGltYXRlTm9ybWFsKHApICsgdmVjMygxLjApKSAvIDIuMDsKICAgIHZlYzMgS19kID0gS19hOwogICAgdmVjMyBLX3MgPSB2ZWMzKDEuMCwgMS4wLCAxLjApOwogICAgZmxvYXQgc2hpbmluZXNzID0gMTAuMDsKICAgIAogICAgdmVjMyBjb2xvciA9IHBob25nSWxsdW1pbmF0aW9uKEtfYSwgS19kLCBLX3MsIHNoaW5pbmVzcywgcCwgZXllKTsKICAgIAogICAgZnJhZ0NvbG9yID0gdmVjNChjb2xvciwgMS4wKTsKfQ=="
>
ray marching
</a>
</li>
<li>
<a
href="#Ly8gQ3JlYXRlZCBieSBldmlscnl1Ci8vIExpY2Vuc2UgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob25Db21tZXJjaWFsLVNoYXJlQWxpa2UgMy4wIFVucG9ydGVkIExpY2Vuc2UuCgoKLy8gd2hldGhlciB0dXJuIG9uIHRoZSBhbmltYXRpb24KLy8jZGVmaW5lIHBoYXNlX3NoaWZ0X29uIAoKZmxvYXQgc3RpbWUsIGN0aW1lOwogdm9pZCByeShpbm91dCB2ZWMzIHAsIGZsb2F0IGEpeyAgCiAJZmxvYXQgYyxzO3ZlYzMgcT1wOyAgCiAgCWMgPSBjb3MoYSk7IHMgPSBzaW4oYSk7ICAKICAJcC54ID0gYyAqIHEueCArIHMgKiBxLno7ICAKICAJcC56ID0gLXMgKiBxLnggKyBjICogcS56OyAKIH0gIAoKZmxvYXQgcGl4ZWxfc2l6ZSA9IDAuMDsKCi8qIAoKeiA9IHIqKHNpbih0aGV0YSljb3MocGhpKSArIGkgY29zKHRoZXRhKSArIGogc2luKHRoZXRhKXNpbihwaGkpCgp6bisxID0gem5eOCArYwoKel44ID0gcl44ICogKHNpbig4KnRoZXRhKSpjb3MoOCpwaGkpICsgaSBjb3MoOCp0aGV0YSkgKyBqIHNpbig4KnRoZXRhKSpzaW4oOCp0aGV0YSkKCnpuKzEnID0gOCAqIHpuXjcgKiB6bicgKyAxCgoqLwoKdmVjMyBtYih2ZWMzIHApIHsKCXAueHl6ID0gcC54enk7Cgl2ZWMzIHogPSBwOwoJdmVjMyBkej12ZWMzKDAuMCk7CglmbG9hdCBwb3dlciA9IDguMDsKCWZsb2F0IHIsIHRoZXRhLCBwaGk7CglmbG9hdCBkciA9IDEuMDsKCQoJZmxvYXQgdDAgPSAxLjA7Cglmb3IoaW50IGkgPSAwOyBpIDwgNzsgKytpKSB7CgkJciA9IGxlbmd0aCh6KTsKCQlpZihyID4gMi4wKSBjb250aW51ZTsKCQl0aGV0YSA9IGF0YW4oei55IC8gei54KTsKICAgICAgICAjaWZkZWYgcGhhc2Vfc2hpZnRfb24KCQlwaGkgPSBhc2luKHoueiAvIHIpICsgaVRpbWUqMC4xOwogICAgICAgICNlbHNlCiAgICAgICAgcGhpID0gYXNpbih6LnogLyByKTsKICAgICAgICAjZW5kaWYKCQkKCQlkciA9IHBvdyhyLCBwb3dlciAtIDEuMCkgKiBkciAqIHBvd2VyICsgMS4wOwoJCgkJciA9IHBvdyhyLCBwb3dlcik7CgkJdGhldGEgPSB0aGV0YSAqIHBvd2VyOwoJCXBoaSA9IHBoaSAqIHBvd2VyOwoJCQoJCXogPSByICogdmVjMyhjb3ModGhldGEpKmNvcyhwaGkpLCBzaW4odGhldGEpKmNvcyhwaGkpLCBzaW4ocGhpKSkgKyBwOwoJCQoJCXQwID0gbWluKHQwLCByKTsKCX0KCXJldHVybiB2ZWMzKDAuNSAqIGxvZyhyKSAqIHIgLyBkciwgdDAsIDAuMCk7Cn0KCiB2ZWMzIGYodmVjMyBwKXsgCgkgcnkocCwgaVRpbWUqMC4yKTsKICAgICByZXR1cm4gbWIocCk7IAogfSAKCgogZmxvYXQgc29mdHNoYWRvdyh2ZWMzIHJvLCB2ZWMzIHJkLCBmbG9hdCBrICl7IAogICAgIGZsb2F0IGFrdW1hPTEuMCxoPTAuMDsgCgkgZmxvYXQgdCA9IDAuMDE7CiAgICAgZm9yKGludCBpPTA7IGkgPCA1MDsgKytpKXsgCiAgICAgICAgIGg9ZihybytyZCp0KS54OyAKICAgICAgICAgaWYoaDwwLjAwMSlyZXR1cm4gMC4wMjsgCiAgICAgICAgIGFrdW1hPW1pbihha3VtYSwgaypoL3QpOyAKIAkJIHQrPWNsYW1wKGgsMC4wMSwyLjApOyAKICAgICB9IAogICAgIHJldHVybiBha3VtYTsgCiB9IAoKdmVjMyBub3IoIGluIHZlYzMgcG9zICkKewogICAgdmVjMyBlcHMgPSB2ZWMzKDAuMDAxLDAuMCwwLjApOwoJcmV0dXJuIG5vcm1hbGl6ZSggdmVjMygKICAgICAgICAgICBmKHBvcytlcHMueHl5KS54IC0gZihwb3MtZXBzLnh5eSkueCwKICAgICAgICAgICBmKHBvcytlcHMueXh5KS54IC0gZihwb3MtZXBzLnl4eSkueCwKICAgICAgICAgICBmKHBvcytlcHMueXl4KS54IC0gZihwb3MtZXBzLnl5eCkueCApICk7Cn0KCnZlYzMgaW50ZXJzZWN0KCBpbiB2ZWMzIHJvLCBpbiB2ZWMzIHJkICkKewogICAgZmxvYXQgdCA9IDEuMDsKICAgIGZsb2F0IHJlc190ID0gMC4wOwogICAgZmxvYXQgcmVzX2QgPSAxMDAwLjA7CiAgICB2ZWMzIGMsIHJlc19jOwogICAgZmxvYXQgbWF4X2Vycm9yID0gMTAwMC4wOwoJZmxvYXQgZCA9IDEuMDsKICAgIGZsb2F0IHBkID0gMTAwLjA7CiAgICBmbG9hdCBvcyA9IDAuMDsKICAgIGZsb2F0IHN0ZXAgPSAwLjA7CiAgICBmbG9hdCBlcnJvciA9IDEwMDAuMDsKICAgIAogICAgZm9yKCBpbnQgaT0wOyBpPDQ4OyBpKysgKQogICAgewogICAgICAgIGlmKCBlcnJvciA8IHBpeGVsX3NpemUqMC41IHx8IHQgPiAyMC4wICkKICAgICAgICB7CiAgICAgICAgfQogICAgICAgIGVsc2V7ICAvLyBhdm9pZCBicm9rZW4gc2hhZGVyIG9uIHdpbmRvd3MKICAgICAgICAKICAgICAgICAgICAgYyA9IGYocm8gKyByZCp0KTsKICAgICAgICAgICAgZCA9IGMueDsKCiAgICAgICAgICAgIGlmKGQgPiBvcykKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgb3MgPSAwLjQgKiBkKmQvcGQ7CiAgICAgICAgICAgICAgICBzdGVwID0gZCArIG9zOwogICAgICAgICAgICAgICAgcGQgPSBkOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgc3RlcCA9LW9zOyBvcyA9IDAuMDsgcGQgPSAxMDAuMDsgZCA9IDEuMDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZXJyb3IgPSBkIC8gdDsKCiAgICAgICAgICAgIGlmKGVycm9yIDwgbWF4X2Vycm9yKSAKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgbWF4X2Vycm9yID0gZXJyb3I7CiAgICAgICAgICAgICAgICByZXNfdCA9IHQ7CiAgICAgICAgICAgICAgICByZXNfYyA9IGM7CiAgICAgICAgICAgIH0KICAgICAgICAKICAgICAgICAgICAgdCArPSBzdGVwOwogICAgICAgIH0KCiAgICB9CglpZiggdD4yMC4wLyogfHwgbWF4X2Vycm9yID4gcGl4ZWxfc2l6ZSovICkgcmVzX3Q9LTEuMDsKICAgIHJldHVybiB2ZWMzKHJlc190LCByZXNfYy55LCByZXNfYy56KTsKfQoKIHZvaWQgbWFpbkltYWdlKCBvdXQgdmVjNCBmcmFnQ29sb3IsIGluIHZlYzIgZnJhZ0Nvb3JkICkgCiB7IAogICAgdmVjMiBxPWZyYWdDb29yZC54eS9pUmVzb2x1dGlvbi54eTsgCiAJdmVjMiB1diA9IC0xLjAgKyAyLjAqcTsgCiAJdXYueCo9aVJlc29sdXRpb24ueC9pUmVzb2x1dGlvbi55OyAKICAgICAKICAgIHBpeGVsX3NpemUgPSAxLjAvKGlSZXNvbHV0aW9uLnggKiAzLjApOwoJLy8gY2FtZXJhCiAJc3RpbWU9MC43KzAuMypzaW4oaVRpbWUqMC40KTsgCiAJY3RpbWU9MC43KzAuMypjb3MoaVRpbWUqMC40KTsgCgogCXZlYzMgdGE9dmVjMygwLjAsMC4wLDAuMCk7IAoJdmVjMyBybyA9IHZlYzMoMC4wLCAzLipzdGltZSpjdGltZSwgMy4qKDEuLXN0aW1lKmN0aW1lKSk7CgogCXZlYzMgY2YgPSBub3JtYWxpemUodGEtcm8pOyAKICAgIHZlYzMgY3MgPSBub3JtYWxpemUoY3Jvc3MoY2YsdmVjMygwLjAsMS4wLDAuMCkpKTsgCiAgICB2ZWMzIGN1ID0gbm9ybWFsaXplKGNyb3NzKGNzLGNmKSk7IAogCXZlYzMgcmQgPSBub3JtYWxpemUodXYueCpjcyArIHV2LnkqY3UgKyAzLjAqY2YpOyAgLy8gdHJhbnNmb3JtIGZyb20gdmlldyB0byB3b3JsZAoKICAgIHZlYzMgc3VuZGlyID0gbm9ybWFsaXplKHZlYzMoMC4xLCAwLjgsIDAuNikpOyAKICAgIHZlYzMgc3VuID0gdmVjMygxLjY0LCAxLjI3LCAwLjk5KTsgCiAgICB2ZWMzIHNreWNvbG9yID0gdmVjMygwLjYsIDEuNSwgMS4wKTsgCgoJdmVjMyBiZyA9IGV4cCh1di55LTIuMCkqdmVjMygwLjQsIDEuNiwgMS4wKTsKCiAgICBmbG9hdCBoYWxvPWNsYW1wKGRvdChub3JtYWxpemUodmVjMygtcm8ueCwgLXJvLnksIC1yby56KSksIHJkKSwgMC4wLCAxLjApOyAKICAgIHZlYzMgY29sPWJnK3ZlYzMoMS4wLDAuOCwwLjQpKnBvdyhoYWxvLDE3LjApOyAKCgogICAgZmxvYXQgdD0wLjA7CiAgICB2ZWMzIHA9cm87IAoJIAoJdmVjMyByZXMgPSBpbnRlcnNlY3Qocm8sIHJkKTsKCSBpZihyZXMueCA+IDAuMCl7CgkJICAgcCA9IHJvICsgcmVzLnggKiByZDsKICAgICAgICAgICB2ZWMzIG49bm9yKHApOyAKICAgICAgICAgICBmbG9hdCBzaGFkb3cgPSBzb2Z0c2hhZG93KHAsIHN1bmRpciwgMTAuMCApOwoKICAgICAgICAgICBmbG9hdCBkaWYgPSBtYXgoMC4wLCBkb3Qobiwgc3VuZGlyKSk7IAogICAgICAgICAgIGZsb2F0IHNreSA9IDAuNiArIDAuNCAqIG1heCgwLjAsIGRvdChuLCB2ZWMzKDAuMCwgMS4wLCAwLjApKSk7IAogCQkgICBmbG9hdCBiYWMgPSBtYXgoMC4zICsgMC43ICogZG90KHZlYzMoLXN1bmRpci54LCAtMS4wLCAtc3VuZGlyLnopLCBuKSwgMC4wKTsgCiAgICAgICAgICAgZmxvYXQgc3BlID0gbWF4KDAuMCwgcG93KGNsYW1wKGRvdChzdW5kaXIsIHJlZmxlY3QocmQsIG4pKSwgMC4wLCAxLjApLCAxMC4wKSk7IAoKICAgICAgICAgICB2ZWMzIGxpbiA9IDQuNSAqIHN1biAqIGRpZiAqIHNoYWRvdzsgCiAgICAgICAgICAgbGluICs9IDAuOCAqIGJhYyAqIHN1bjsgCiAgICAgICAgICAgbGluICs9IDAuNiAqIHNreSAqIHNreWNvbG9yKnNoYWRvdzsgCiAgICAgICAgICAgbGluICs9IDMuMCAqIHNwZSAqIHNoYWRvdzsgCgoJCSAgIHJlcy55ID0gcG93KGNsYW1wKHJlcy55LCAwLjAsIDEuMCksIDAuNTUpOwoJCSAgIHZlYzMgdGMwID0gMC41ICsgMC41ICogc2luKDMuMCArIDQuMiAqIHJlcy55ICsgdmVjMygwLjAsIDAuNSwgMS4wKSk7CiAgICAgICAgICAgY29sID0gbGluICp2ZWMzKDAuOSwgMC44LCAwLjYpICogIDAuMiAqIHRjMDsKIAkJICAgY29sPW1peChjb2wsYmcsIDEuMC1leHAoLTAuMDAxKnJlcy54KnJlcy54KSk7IAogICAgfSAKCiAgICAvLyBwb3N0CiAgICBjb2w9cG93KGNsYW1wKGNvbCwwLjAsMS4wKSx2ZWMzKDAuNDUpKTsgCiAgICBjb2w9Y29sKjAuNiswLjQqY29sKmNvbCooMy4wLTIuMCpjb2wpOyAgLy8gY29udHJhc3QKICAgIGNvbD1taXgoY29sLCB2ZWMzKGRvdChjb2wsIHZlYzMoMC4zMykpKSwgLTAuNSk7ICAvLyBzYXR1YXRpb24KICAgIGNvbCo9MC41KzAuNSpwb3coMTYuMCpxLngqcS55KigxLjAtcS54KSooMS4wLXEueSksMC43KTsgIC8vIHZpZ25ldGluZwogCWZyYWdDb2xvciA9IHZlYzQoY29sLnh5eiwgc21vb3Roc3RlcCgwLjU1LCAuNzYsIDEuLXJlcy54LzUuKSk7IAogfQ=="
>
mandel bulb
</a>
</li>
<li>
<a
href="#Ly8gdGhpcyBpcyBhIGh5ZHJhIHBhdGNoIGluIGl0cyBjb21waWxlZCBmb3JtIGFkanVzdGVkIGZvciBzaGFkZXJ0b3kgZm9ybWF0Ci8vIGNoYW5nZSB0aW1lIC0+IGlUaW1lCi8vIGNoYW5nZSByZXNvbHV0aW9uIC0+IGlSZXNvbHV0aW9uCi8vIHJlbW92ZSB1bmlmb3JtIGRlZmluaXRpb25zCi8vIHJlZmFjdG9yIG1haW4gZnVuY3Rpb24gdG8gbWFpbkltYWdlCi8vIHNwbGl0IGZyYWdDb2xvciBjYWxjdWxhdGlvbiBpbnRvIG11bHRpcGxlIHN0ZXBzCgoKZmxvYXQgX2x1bWluYW5jZSh2ZWMzIHJnYikgewogIGNvbnN0IHZlYzMgVyA9IHZlYzMoMC4yMTI1LCAwLjcxNTQsIDAuMDcyMSk7CiAgcmV0dXJuIGRvdChyZ2IsIFcpOwp9CgovLwlTaW1wbGV4IDNEIE5vaXNlCi8vCWJ5IElhbiBNY0V3YW4sIEFzaGltYSBBcnRzCnZlYzQgcGVybXV0ZSh2ZWM0IHgpIHsKICByZXR1cm4gbW9kKCgoeCAqIDM0LjApICsgMS4wKSAqIHgsIDI4OS4wKTsKfQp2ZWM0IHRheWxvckludlNxcnQodmVjNCByKSB7CiAgcmV0dXJuIDEuNzkyODQyOTE0MDAxNTkgLSAwLjg1MzczNDcyMDk1MzE0ICogcjsKfQoKZmxvYXQgX25vaXNlKHZlYzMgdikgewogIGNvbnN0IHZlYzIgQyA9IHZlYzIoMS4wIC8gNi4wLCAxLjAgLyAzLjApOwogIGNvbnN0IHZlYzQgRCA9IHZlYzQoMC4wLCAwLjUsIDEuMCwgMi4wKTsKCiAgLy8gRmlyc3QgY29ybmVyCiAgdmVjMyBpID0gZmxvb3IodiArIGRvdCh2LCBDLnl5eSkpOwogIHZlYzMgeDAgPSB2IC0gaSArIGRvdChpLCBDLnh4eCk7CgogIC8vIE90aGVyIGNvcm5lcnMKICB2ZWMzIGcgPSBzdGVwKHgwLnl6eCwgeDAueHl6KTsKICB2ZWMzIGwgPSAxLjAgLSBnOwogIHZlYzMgaTEgPSBtaW4oZy54eXosIGwuenh5KTsKICB2ZWMzIGkyID0gbWF4KGcueHl6LCBsLnp4eSk7CgogIC8vIHgwID0geDAgLSAwLiArIDAuMCAqIEMKICB2ZWMzIHgxID0geDAgLSBpMSArIDEuMCAqIEMueHh4OwogIHZlYzMgeDIgPSB4MCAtIGkyICsgMi4wICogQy54eHg7CiAgdmVjMyB4MyA9IHgwIC0gMS4gKyAzLjAgKiBDLnh4eDsKCiAgLy8gUGVybXV0YXRpb25zCiAgaSA9IG1vZChpLCAyODkuMCk7CiAgdmVjNCBwID0gcGVybXV0ZShwZXJtdXRlKHBlcm11dGUoaS56ICsgdmVjNCgwLjAsIGkxLnosIGkyLnosIDEuMCkpICsgaS55ICsgdmVjNCgwLjAsIGkxLnksIGkyLnksIDEuMCkpICsgaS54ICsgdmVjNCgwLjAsIGkxLngsIGkyLngsIDEuMCkpOwoKICAvLyBHcmFkaWVudHMKICAvLyAoIE4qTiBwb2ludHMgdW5pZm9ybWx5IG92ZXIgYSBzcXVhcmUsIG1hcHBlZCBvbnRvIGFuIG9jdGFoZWRyb24uKQogIGZsb2F0IG5fID0gMS4wIC8gNy4wOyAvLyBOPTcKICB2ZWMzIG5zID0gbl8gKiBELnd5eiAtIEQueHp4OwoKICB2ZWM0IGogPSBwIC0gNDkuMCAqIGZsb29yKHAgKiBucy56ICogbnMueik7ICAvLyAgbW9kKHAsTipOKQoKICB2ZWM0IHhfID0gZmxvb3IoaiAqIG5zLnopOwogIHZlYzQgeV8gPSBmbG9vcihqIC0gNy4wICogeF8pOy8vIG1vZChqLE4pCgogIHZlYzQgeCA9IHhfICogbnMueCArIG5zLnl5eXk7CiAgdmVjNCB5ID0geV8gKiBucy54ICsgbnMueXl5eTsKICB2ZWM0IGggPSAxLjAgLSBhYnMoeCkgLSBhYnMoeSk7CgogIHZlYzQgYjAgPSB2ZWM0KHgueHksIHkueHkpOwogIHZlYzQgYjEgPSB2ZWM0KHguencsIHkuencpOwoKICB2ZWM0IHMwID0gZmxvb3IoYjApICogMi4wICsgMS4wOwogIHZlYzQgczEgPSBmbG9vcihiMSkgKiAyLjAgKyAxLjA7CiAgdmVjNCBzaCA9IC1zdGVwKGgsIHZlYzQoMC4wKSk7CgogIHZlYzQgYTAgPSBiMC54enl3ICsgczAueHp5dyAqIHNoLnh4eXk7CiAgdmVjNCBhMSA9IGIxLnh6eXcgKyBzMS54enl3ICogc2guenp3dzsKCiAgdmVjMyBwMCA9IHZlYzMoYTAueHksIGgueCk7CiAgdmVjMyBwMSA9IHZlYzMoYTAuencsIGgueSk7CiAgdmVjMyBwMiA9IHZlYzMoYTEueHksIGgueik7CiAgdmVjMyBwMyA9IHZlYzMoYTEuencsIGgudyk7CgogIC8vTm9ybWFsaXNlIGdyYWRpZW50cwogIHZlYzQgbm9ybSA9IHRheWxvckludlNxcnQodmVjNChkb3QocDAsIHAwKSwgZG90KHAxLCBwMSksIGRvdChwMiwgcDIpLCBkb3QocDMsIHAzKSkpOwogIHAwICo9IG5vcm0ueDsKICBwMSAqPSBub3JtLnk7CiAgcDIgKj0gbm9ybS56OwogIHAzICo9IG5vcm0udzsKCiAgLy8gTWl4IGZpbmFsIG5vaXNlIHZhbHVlCiAgdmVjNCBtID0gbWF4KDAuNiAtIHZlYzQoZG90KHgwLCB4MCksIGRvdCh4MSwgeDEpLCBkb3QoeDIsIHgyKSwgZG90KHgzLCB4MykpLCAwLjApOwogIG0gPSBtICogbTsKICByZXR1cm4gNDIuMCAqIGRvdChtICogbSwgdmVjNChkb3QocDAsIHgwKSwgZG90KHAxLCB4MSksIGRvdChwMiwgeDIpLCBkb3QocDMsIHgzKSkpOwp9Cgp2ZWMzIF9yZ2JUb0hzdih2ZWMzIGMpIHsKICB2ZWM0IEsgPSB2ZWM0KDAuMCwgLTEuMCAvIDMuMCwgMi4wIC8gMy4wLCAtMS4wKTsKICB2ZWM0IHAgPSBtaXgodmVjNChjLmJnLCBLLnd6KSwgdmVjNChjLmdiLCBLLnh5KSwgc3RlcChjLmIsIGMuZykpOwogIHZlYzQgcSA9IG1peCh2ZWM0KHAueHl3LCBjLnIpLCB2ZWM0KGMuciwgcC55engpLCBzdGVwKHAueCwgYy5yKSk7CgogIGZsb2F0IGQgPSBxLnggLSBtaW4ocS53LCBxLnkpOwogIGZsb2F0IGUgPSAxLjBlLTEwOwogIHJldHVybiB2ZWMzKGFicyhxLnogKyAocS53IC0gcS55KSAvICg2LjAgKiBkICsgZSkpLCBkIC8gKHEueCArIGUpLCBxLngpOwp9Cgp2ZWMzIF9oc3ZUb1JnYih2ZWMzIGMpIHsKICB2ZWM0IEsgPSB2ZWM0KDEuMCwgMi4wIC8gMy4wLCAxLjAgLyAzLjAsIDMuMCk7CiAgdmVjMyBwID0gYWJzKGZyYWN0KGMueHh4ICsgSy54eXopICogNi4wIC0gSy53d3cpOwogIHJldHVybiBjLnogKiBtaXgoSy54eHgsIGNsYW1wKHAgLSBLLnh4eCwgMC4wLCAxLjApLCBjLnkpOwp9Cgp2ZWM0IG9zYyh2ZWMyIF9zdCwgZmxvYXQgZnJlcXVlbmN5LCBmbG9hdCBzeW5jLCBmbG9hdCBvZmZzZXQpIHsKICB2ZWMyIHN0ID0gX3N0OwogIGZsb2F0IHIgPSBzaW4oKHN0LnggLSBvZmZzZXQgLyBmcmVxdWVuY3kgKyBpVGltZSAqIHN5bmMpICogZnJlcXVlbmN5KSAqIDAuNSArIDAuNTsKICBmbG9hdCBnID0gc2luKChzdC54ICsgaVRpbWUgKiBzeW5jKSAqIGZyZXF1ZW5jeSkgKiAwLjUgKyAwLjU7CiAgZmxvYXQgYiA9IHNpbigoc3QueCArIG9mZnNldCAvIGZyZXF1ZW5jeSArIGlUaW1lICogc3luYykgKiBmcmVxdWVuY3kpICogMC41ICsgMC41OwogIHJldHVybiB2ZWM0KHIsIGcsIGIsIDEuMCk7Cn0KCnZlYzIgcm90YXRlKHZlYzIgX3N0LCBmbG9hdCBhbmdsZSwgZmxvYXQgc3BlZWQpIHsKICB2ZWMyIHh5ID0gX3N0IC0gdmVjMigwLjUpOwogIGZsb2F0IGFuZyA9IGFuZ2xlICsgc3BlZWQgKiBpVGltZTsKICB4eSA9IG1hdDIoY29zKGFuZyksIC1zaW4oYW5nKSwgc2luKGFuZyksIGNvcyhhbmcpKSAqIHh5OwogIHh5ICs9IDAuNTsKICByZXR1cm4geHk7Cn0KCnZlYzQgbXVsdCh2ZWM0IF9jMCwgdmVjNCBfYzEsIGZsb2F0IGFtb3VudCkgewogIHJldHVybiBfYzAgKiAoMS4wIC0gYW1vdW50KSArIChfYzAgKiBfYzEpICogYW1vdW50Owp9Cgp2ZWM0IGNvbG9yKHZlYzQgX2MwLCBmbG9hdCByLCBmbG9hdCBnLCBmbG9hdCBiLCBmbG9hdCBhKSB7CiAgdmVjNCBjID0gdmVjNChyLCBnLCBiLCBhKTsKICB2ZWM0IHBvcyA9IHN0ZXAoMC4wLCBjKTsgLy8gZGV0ZWN0IHdoZXRoZXIgbmVnYXRpdmUKICAgLy8gaWYgPiAwLCByZXR1cm4gciAqIF9jMAogICAvLyBpZiA8IDAgcmV0dXJuICgxLjAtcikgKiBfYzAKICByZXR1cm4gdmVjNChtaXgoKDEuMCAtIF9jMCkgKiBhYnMoYyksIGMgKiBfYzAsIHBvcykpOwp9Cgp2ZWMyIG1vZHVsYXRlKHZlYzIgX3N0LCB2ZWM0IF9jMCwgZmxvYXQgYW1vdW50KSB7CiAgICAgLy8gIHJldHVybiBmcmFjdChzdCsoX2MwLnh5LTAuNSkqYW1vdW50KTsKICByZXR1cm4gX3N0ICsgX2MwLnh5ICogYW1vdW50Owp9Cgp2b2lkIG1haW5JbWFnZShvdXQgdmVjNCBmcmFnQ29sb3IsIGluIHZlYzIgZnJhZ0Nvb3JkKSB7CgogIHZlYzIgc3QgPSBmcmFnQ29vcmQueHkgLyBpUmVzb2x1dGlvbi54eTsKCiAgdmVjMiBuMSA9IHJvdGF0ZShzdCwgMC4sIDAuMSk7CiAgdmVjNCBuMiA9IG9zYyhuMSwgMTEuLCAwLjAxLCAxLjQpOwogIHZlYzIgbjMgPSByb3RhdGUoc3QsIDAuLCAtMC4xKTsKICB2ZWM0IG40ID0gb3NjKG4zLCAxMC4sIDAuMSwgMC4pOwogIHZlYzIgbjUgPSBtb2R1bGF0ZShzdCwgbjQsIDEuKTsKICB2ZWM0IG42ID0gb3NjKG41LCAxMC4sIDAuMSwgMC4pOwogIHZlYzQgbjcgPSBtdWx0KG4yLCBuNiwgMS4pOwogIHZlYzQgbjggPSBjb2xvcihuNywgMi44MywgMC45MSwgMC4zOSwgMS4pOwoKICBmcmFnQ29sb3IgPSBuODsKfQoKLyoKLy8gb2cgaHlkcmEgc291cmNlOgoKLy8gbGljZW5zZWQgd2l0aCBDQyBCWS1OQy1TQSA0LjAgaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMC8KLy8gYnkgT2xpdmlhIEphY2sKLy8gaHR0cHM6Ly9vamFjay5naXRodWIuaW8KCm9zYygxMSwgMC4wMSwgMS40KQoucm90YXRlKDAsIDAuMSkKLm11bHQoCiBvc2MoMTAsIDAuMSkKIC5tb2R1bGF0ZSgKICBvc2MoMTApCiAgLnJvdGF0ZSgwLCAtMC4xKSwgCiAgMQogKQopCi5jb2xvcigyLjgzLDAuOTEsMC4zOSkKLm91dChvMCkKKi8="
>
a hydra patch
</a>
</li>
<li>
<a
href="#dm9pZCBtYWluSW1hZ2Uob3V0IHZlYzQgZnJhZ0NvbG9yLCBpbiB2ZWMyIGZyYWdDb29yZCkgewogIHZlYzIgdXYgPSBmcmFnQ29vcmQgLyBpUmVzb2x1dGlvbi54eTsKICB2ZWMzIGNvbCA9IDAuNSArIDAuNSAqIGNvcyhpVGltZSArIHV2Lnh5eCArIHZlYzMoMCwgMiwgNCkpOwogIGZyYWdDb2xvciA9IHZlYzQoY29sLCAxLjApOwp9Cg=="
>
hello shader
</a>
</li>
</ul>
<p>links</p>
<ol>
<li><a href="fake-shaders.html">faking shaders</a></li>
<li>
<a
style="color: yellow"
href="https://www.shadertoy.com/"
target="_blank"
>shadertoy</a
>
</li>
<li>
<a
style="color: yellow"
href="https://github.com/felixroos/schattenspiel"
target="_blank"
>schattenspiel</a
>
</li>
</ol>
<details>
<summary>show page source</summary>
<pre id="pre"></pre>
</details>
<p>
<a href="/">back to garten.salat</a>
</p>
<script>
// read base64 code from url
let urlCode = window.location.hash.slice(1);
if (urlCode) {
urlCode = atob(urlCode);
console.log("loaded code from url!");
}
// use urlCode or fall back to default shadertoy example
const initialShader =
urlCode ||
`void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
vec3 col = 0.5 + 0.5 * cos(iTime + uv.xyx + vec3(0, 2, 4));
fragColor = vec4(col, 1.0);
}
`;
// set up code input
const input = document.querySelector("#code");
input.value = initialShader;
window.addEventListener("hashchange", function () {
const urlCode = atob(window.location.hash.slice(1));
input.value = urlCode;
updateShader(urlCode);
});
// vertex shader
const vs = `attribute vec4 a_position;
void main() {
gl_Position = a_position;
}`;
// set up canvas
const canvas = document.querySelector("#canvas");
const gl = canvas.getContext("webgl");
const rect = canvas.getBoundingClientRect();
canvas.width = rect.width; // * window.devicePixelRatio;
canvas.height = rect.height; // * window.devicePixelRatio;
// animation frame logic
let requestId;
function requestFrame(render) {
if (!requestId) {
requestId = requestAnimationFrame(render);
}
}
function cancelFrame() {
if (requestId) {
cancelAnimationFrame(requestId);
requestId = undefined;
}
}
// runs on eval
let then = 0;
let time = 0;
function updateShader(mainImageFunction) {
// fragment shader
const fs = `
precision highp float;
uniform vec2 iResolution;
uniform float iTime;
${mainImageFunction}
void main() {
mainImage(gl_FragColor, gl_FragCoord.xy);
}`;
cancelFrame();
const program = createProgram(gl, vs, fs);
const positionLoc = gl.getAttribLocation(program, "a_position");
const resolutionLoc = gl.getUniformLocation(program, "iResolution");
const mouseLoc = gl.getUniformLocation(program, "iMouse");
const timeLoc = gl.getUniformLocation(program, "iTime");
const vertices = new Float32Array([
-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0,
]);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const framebuffer = gl.createFramebuffer();
function render(now) {
requestId = undefined;
now *= 0.001; // convert to seconds
const elapsedTime = Math.min(now - then, 0.1);
time += elapsedTime;
then = now;
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.useProgram(program);
gl.enableVertexAttribArray(positionLoc);
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
gl.uniform2f(resolutionLoc, gl.canvas.width, gl.canvas.height);
gl.uniform1f(timeLoc, time);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); // draw to canvas
requestFrame(render);
}
requestFrame(render);
}
// start rendering
updateShader(input.value);
// update on ctrl+enter
input.addEventListener("keydown", (e) => {
if ((e.ctrlKey || e.altKey) && e.key === "Enter") {
// updateShader(input.value); // hash update already updates it...
window.location.hash = "#" + btoa(input.value);
console.log("update", input.value);
}
});
document.querySelector("#pre").textContent =
document.querySelector("html").outerHTML;
// webgl boilerplate code
function loadShader(gl, src, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);
const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
const error = gl.getShaderInfoLog(shader);
console.error(
`Error compiling shader '${shader}': ${error}
${src
.split("\n")
.map((l, i) => `${i + 1}: ${l}`)
.join("\n")}`
);
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(gl, vs, fs) {
const program = gl.createProgram();
gl.attachShader(program, loadShader(gl, vs, gl.VERTEX_SHADER));
gl.attachShader(program, loadShader(gl, fs, gl.FRAGMENT_SHADER));
gl.linkProgram(program);
const success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!success) {
const error = gl.getProgramInfoLog(program);
console.error("Linker Error:" + error);
gl.deleteProgram(program);
return null;
}
return program;
}
</script>
</body>
</html>