2 <html><head><meta http-equiv=
"Content-Type" content=
"text/html; charset=utf-8">
3 <title>fractaloids
</title>
6 fractaloids.html -- trippiness in your browser
7 Copyright (C)
2012 Claude Heiland-Allen
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU Affero General Public License as
11 published by the Free Software Foundation, either version
3 of the
12 License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Affero General Public License for more details.
19 You should have received a copy of the GNU Affero General Public License
20 along with this program. If not, see
<http://www.gnu.org/licenses
/>.
23 <style type=
"text/css">* { border:
0; padding:
0; margin:
0; } #framerate { text-align: right; }
</style>
24 <script type=
"text/javascript" src=
"webgl-utils.js"></script>
25 <script type=
"text/javascript" src=
"webgl-debug.js"></script>
26 <script type=
"text/javascript" src=
"J3DI.js"></script>
27 <script type=
"text/javascript" src=
"J3DIMath.js"></script>
28 <script id=
"vert" type=
"x-shader/x-vertex">//<![CDATA[
31 attribute vec2 vPosition;
32 varying vec2 v_texCoord;
34 gl_Position = vec4(vPosition,
0.0,
1.0);
35 v_texCoord = vec2(vMatrix * vec4(vPosition,
0.0,
1.0));
39 <script id=
"frag" type=
"x-shader/x-fragment">//<![CDATA[
40 precision mediump float;
42 uniform vec2 roots[
8];
43 uniform float epsSquared;
45 uniform int activeRoots;
47 varying vec2 v_texCoord;
49 float cmag2(vec2 z) { return dot(z,z); }
50 vec2 crecip(vec2 z) { float d = cmag2(z); return z / vec2(d, -d); }
52 vec2 newtonStep(vec2 z) {
54 for (int i =
0; i <
8; ++i) {
55 if (i < activeRoots) {
56 s += crecip(z - roots[i]);
62 vec2 newtonDelta(vec2 z00) {
69 for (int n =
0; n <
64; ++n) {
73 for (int i =
0; i <
8; ++i) {
74 if (i < activeRoots) {
75 float d = cmag2(z0 - roots[i]);
76 if (d < d0) { d0 = d; root = i; }
79 if (d0 < epsSquared) {
89 delta += clamp(log(epsSquared / d1) / log(d0 / d1),
0.0,
1.0);
92 return vec2(float(root),delta);
95 vec3 yuv2rgb(vec3 yuv) {
96 return yuv * mat3(
1.0,
1.407,
0.0,
1.0, -
0.677, -
0.236,
1.0,
0.0,
1.848);
99 vec3 splat(vec3 rgb) {
100 float m = max(max(max(rgb.x, rgb.y), rgb.z),
1.0);
101 return clamp(rgb / m,
0.0,
1.0);
105 vec2 z = v_texCoord.xy;
106 vec2 d = newtonDelta(z);
108 if (d.x
>=
0.0 && d.y
>=
0.0) {
109 float y = clamp(
1.0 / (
1.0 + d.y),
0.0,
1.0);
111 float t = d.x *
3.883222077450933;
112 c = splat(yuv2rgb(vec3(y, r * cos(t), r * sin(t))));
114 gl_FragColor = vec4(c,
1.0);
117 //]]
></script><script id=
"main" type=
"text/javascript">//<![CDATA[
122 function now() { return new Date().getTime(); }
124 function shader(gl) {
125 var vert = loadShader(gl,
"vert");
126 var frag = loadShader(gl,
"frag");
127 var prog = gl.createProgram();
128 gl.attachShader(prog, vert);
129 gl.attachShader(prog, frag);
130 gl.bindAttribLocation(prog,
0,
"vPosition");
131 gl.linkProgram(prog);
132 var linked = gl.getProgramParameter(prog, gl.LINK_STATUS);
133 if (!linked && !gl.isContextLost()) {
134 gl.deleteProgram(prog);
135 gl.deleteProgram(frag);
136 gl.deleteProgram(vert);
144 var gl = initWebGL(
"fractaloids");
145 WebGLDebugUtils.makeDebugContext(gl);
148 g.program = shader(gl);
149 gl.uniform1f(gl.getUniformLocation(g.program,
"epsSquared"),
1.0);
150 gl.uniform1i(gl.getUniformLocation(g.program,
"maxIters"),
64);
151 gl.uniform1i(gl.getUniformLocation(g.program,
"activeRoots"),
0);
152 g.points = new Float32Array([
1,
1, -
1,
1, -
1,-
1,
1,-
1]);
153 g.obj = gl.createBuffer()
154 gl.enableVertexAttribArray(
0);
155 gl.bindBuffer(gl.ARRAY_BUFFER, g.obj);
156 gl.bufferData(gl.ARRAY_BUFFER, g.points, gl.STATIC_DRAW);
157 gl.vertexAttribPointer(
0,
2, gl.FLOAT, false,
0,
0);
158 g.vMatrix = new J3DIMatrix4();
164 function reshape(gl) {
165 var canvas = document.getElementById(
"fractaloids");
166 var winW = window.innerWidth;
167 var winH = window.innerHeight;
168 if (winW == g.width && winH == g.height) {
172 g.height = winH -
60;
173 canvas.width = g.width;
174 canvas.height = g.height;
175 gl.viewport(
0,
0, g.width, g.height);
176 g.vMatrix.makeIdentity();
177 g.vMatrix.ortho(-
1.0/g.width,
1.0/g.width, -
1.0/g.height,
1.0/g.height, -
1,
1);
178 g.vMatrix.setUniform(gl, gl.getUniformLocation(g.program,
"vMatrix"), false);
181 function render(gl) {
184 var dt = t - g.frameTime;
187 gl.uniform1i(gl.getUniformLocation(g.program,
"activeRoots"), Math.min(rs.length /
2,
8));
189 gl.uniform2fv(gl.getUniformLocation(g.program,
"roots"), rs);
191 gl.drawArrays(gl.TRIANGLE_FAN,
0,
4);
192 g.framerate.snapshot();
195 function advance(dt) {
197 for (var i =
0; i < g.loops.length; ++i) {
200 l.offset = l.offset + dt;
201 while (l.offset
> l.events[l.current].dt) {
202 l.offset -= l.events[l.current].dt;
203 l.current = (l.current +
1) % l.events.length;
205 var e0 = l.events[l.current];
206 var e1 = l.events[(l.current +
1) % l.events.length];
207 var t = l.offset / e0.dt;
208 var x = e0.x * (
1 - t) + t * e1.x;
209 var y = e0.y * (
1 - t) + t * e1.y;
217 function handleContextLost(e) {
219 if (g.requestId !== undefined) {
220 window.cancelAnimFrame(g.requestId);
221 g.requestId = undefined;
225 function handleContextRestored() {
230 function handleMouseDown(event) {
231 event.preventDefault();
237 function handleMouseUp(event) {
238 event.preventDefault();
240 if (g.mouseLoop.length
> 1) {
241 g.loops[g.nextloop] = { offset:
0, current:
0, events: g.mouseLoop };
242 g.nextloop = (g.nextloop +
1) % g.maxloops;
247 function handleMouseMove(event) {
248 event.preventDefault();
249 if (! g.mouseDown) { return; }
251 var dt = t - g.mouseTime;
253 var x = g.width -
2 * event.clientX;
254 var y = g.height -
2 * event.clientY;
255 var e = { x: x, y: y, dt: dt };
256 g.mouseLoop[g.mouseLoop.length] = e;
260 var canvas = document.getElementById(
"fractaloids");
269 canvas.addEventListener(
"webglcontextlost", handleContextLost, false);
270 canvas.addEventListener(
"webglcontextrestored", handleContextRestored, false);
271 canvas.addEventListener(
"mousedown", handleMouseDown, true);
272 canvas.addEventListener(
"mouseup", handleMouseUp, true);
273 canvas.addEventListener(
"mousemove", handleMouseMove, true);
274 g.framerate = new Framerate(
"framerate");
277 g.requestId = window.requestAnimFrame(g.f, gl);
282 //]]
></script></head><body onload=
"start()">
283 <div>fractaloids ©
2012 Claude Heiland-Allen
</div>
284 <canvas id=
"fractaloids"></canvas><div id=
"framerate"></div>