├── .gitignore
├── README.md
├── geometryangle.js
└── geometryangle.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /css/
2 | /js/
3 | /init.php
4 | /index.php
5 | /sitemap.xml
6 | /test.html
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Geometryangle
2 |
3 | [jQuery](http://jquery.com/) plugin that lets you create beautiful and responsive backgrounds to your site. **To get started, check out http://geometryangle.tritoncode.com/**
4 |
5 | Please consider that the project is still in beta. The current status of the milestones can be found [here](https://github.com/TritonCode/Geometryangle/milestones).
6 |
7 | ## Quick start
8 |
9 | Download the [latest release](https://github.com/TritonCode/Geometryangle/zipball/master).
10 |
11 | Put the script at the [bottom](https://developer.yahoo.com/performance/rules.html#js_bottom) of your markup right after jQuery:
12 |
13 | ```html
14 |
15 |
16 | ```
17 |
18 | To create a fixed background, do the following:
19 |
20 | ```html
21 |
22 |
23 |
24 | Content...
25 |
26 |
27 | ```
28 |
29 | Call the [plugin](http://learn.jquery.com/plugins/) function and your navigation widget is ready.
30 |
31 | ```javascript
32 | $(document).ready(function(){
33 | $('body').Geometryangle({mesh:{}, lights: [{}], line: {}, vertex: {}});
34 | });
35 | ```
36 |
37 | ## Documentation
38 |
39 | The documentation is publicly available at http://geometryangle.tritoncode.com/
40 |
41 | ## Contributing
42 |
43 | The [issue tracker](https://github.com/TritonCode/Geometryangle/issues) is the preferred channel for bug reports, features requests and submitting pull requests.
44 |
45 | **Please do not use the issue tracker for personal support requests. Stack Overflow ([`Geometryangle`](http://stackoverflow.com/questions/tagged/Geometryangle)) is a better place to get help.**
46 |
47 | ### Bug reports
48 |
49 | A bug is a **demonstrable problem** that is caused by the code in the repository. Good bug reports are extremely helpful, so thanks!
50 |
51 | Guidelines for bug reports:
52 |
53 | 1. Use the GitHub issue search — check if the issue has already been reported.
54 |
55 | 2. Check if the issue has been fixed — try to reproduce it using the latest `develop` branch in the repository.
56 |
57 | 3. Isolate the problem — ideally create a reduced test case and a live example. This [JSFiddle](http://jsfiddle.net/eqbL6vLb/) and this [JS Bin](http://jsbin.com/xuxozu/1) are helpful templates you can fork or clone.
58 |
59 | Example:
60 |
61 | > Short and descriptive example bug report title
62 | >
63 | > A summary of the issue and the browser/OS environment in which it occurs. If suitable, include the steps required to reproduce the bug.
64 | >
65 | > 1. This is the first step
66 | > 2. This is the second step
67 | > 3. Further steps, etc.
68 | >
69 | > `` - a link to the reduced test case
70 | >
71 | > Any other information you want to share that is relevant to the issue being reported. This might include the lines of code that you have identified as causing the bug, and potential solutions (and your opinions on their merits).
72 |
73 | ### Feature requests
74 |
75 | Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible.
76 |
77 | ### Pull requests
78 |
79 | Good pull requests are a fantastic help. They should remain focused in scope and avoid containing unrelated commits.
80 |
81 | **Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code, porting to a different language), otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project.
82 |
83 | Adhering to the following process is the best way to get your work included in the project:
84 |
85 | 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes:
86 |
87 | ```bash
88 | git clone https://github.com//Geometryangle.git
89 | cd Geometryangle
90 | git remote add upstream https://github.com/TritonCode/Geometryangle.git
91 | ```
92 |
93 | 2. If you cloned a while ago, get the latest changes from upstream:
94 |
95 | ```bash
96 | git checkout develop
97 | git pull [--rebase] upstream develop
98 | ```
99 |
100 | 3. Create a new topic branch (off the main project `develop` branch) to contain your feature, change, or fix:
101 |
102 | ```bash
103 | git checkout -b
104 | ```
105 |
106 | 4. Build the distribution before committing to ensure your changes follow the coding standards and all build files are up to date.
107 |
108 | ```bash
109 | grunt dist
110 | ```
111 |
112 | 5. Commit your changes in logical chunks. Please adhere to these [guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public.
113 |
114 | 6. Locally merge (or rebase) the upstream development branch into your topic branch:
115 |
116 | ```bash
117 | git pull [--rebase] upstream develop
118 | ```
119 |
120 | 7. Push your topic branch up to your fork:
121 |
122 | ```bash
123 | git push origin
124 | ```
125 |
126 | 8. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description against the `develop` branch.
127 |
128 | **By submitting a patch, you agree to allow the project owner to
129 | license your work under the terms of the [MIT License](LICENSE).**
130 |
131 | ## License
132 |
133 | The code and the documentation are released under the [MIT License](LICENSE).
134 |
--------------------------------------------------------------------------------
/geometryangle.js:
--------------------------------------------------------------------------------
1 | //============================================================
2 | //
3 | // Copyright below.
4 | //
5 | // CoAuthor: Patrick Geyer
6 | //
7 | // Twitter: https://twitter.com/PatrickGeyer_
8 | //
9 | //============================================================
10 |
11 | //============================================================
12 | //
13 | // Copyright (C) 2013 Matthew Wagerfield
14 | //
15 | // Twitter: https://twitter.com/mwagerfield
16 | //
17 | // Permission is hereby granted, free of charge, to any
18 | // person obtaining a copy of this software and associated
19 | // documentation files (the "Software"), to deal in the
20 | // Software without restriction, including without limitation
21 | // the rights to use, copy, modify, merge, publish, distribute,
22 | // sublicense, and/or sell copies of the Software, and to
23 | // permit persons to whom the Software is furnished to do
24 | // so, subject to the following conditions:
25 | //
26 | // The above copyright notice and this permission notice
27 | // shall be included in all copies or substantial portions
28 | // of the Software.
29 | //
30 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
31 | // OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
32 | // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
33 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
34 | // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
35 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
36 | // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
38 | // OR OTHER DEALINGS IN THE SOFTWARE.
39 | //
40 | //============================================================
41 |
42 | /**
43 | * Defines the Flat Surface Shader namespace for all the awesomeness to exist upon.
44 | * @author Matthew Wagerfield
45 | */
46 | FSS = {
47 | FRONT: 0,
48 | BACK: 1,
49 | DOUBLE: 2,
50 | SVGNS: 'http://www.w3.org/2000/svg'
51 | };
52 |
53 | /**
54 | * @class Array
55 | * @author Matthew Wagerfield
56 | */
57 | FSS.Array = typeof Float32Array === 'function' ? Float32Array : Array;
58 |
59 | /**
60 | * @class Utils
61 | * @author Matthew Wagerfield
62 | */
63 | FSS.Utils = {
64 | isNumber: function (value) {
65 | return !isNaN(parseFloat(value)) && isFinite(value);
66 | }
67 | };
68 |
69 | /**
70 | * Request Animation Frame Polyfill.
71 | * @author Paul Irish
72 | * @see https://gist.github.com/paulirish/1579671
73 | */
74 | (function () {
75 |
76 | var lastTime = 0;
77 | var vendors = ['ms', 'moz', 'webkit', 'o'];
78 |
79 | for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
80 | window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
81 | window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
82 | }
83 |
84 | if (!window.requestAnimationFrame) {
85 | window.requestAnimationFrame = function (callback, element) {
86 | var currentTime = new Date().getTime();
87 | var timeToCall = Math.max(0, 16 - (currentTime - lastTime));
88 | var id = window.setTimeout(function () {
89 | callback(currentTime + timeToCall);
90 | }, timeToCall);
91 | lastTime = currentTime + timeToCall;
92 | return id;
93 | };
94 | }
95 |
96 | if (!window.cancelAnimationFrame) {
97 | window.cancelAnimationFrame = function (id) {
98 | clearTimeout(id);
99 | };
100 | }
101 |
102 | }());
103 |
104 | /**
105 | * @object Math Augmentation
106 | * @author Matthew Wagerfield
107 | */
108 | Math.PIM2 = Math.PI * 2;
109 | Math.PID2 = Math.PI / 2;
110 | Math.randomInRange = function (min, max) {
111 | return min + (max - min) * Math.random();
112 | };
113 | Math.clamp = function (value, min, max) {
114 | value = Math.max(value, min);
115 | value = Math.min(value, max);
116 | return value;
117 | };
118 |
119 | /**
120 | * @object Vector3
121 | * @author Matthew Wagerfield
122 | */
123 | FSS.Vector3 = {
124 | create: function (x, y, z) {
125 | var vector = new FSS.Array(3);
126 | this.set(vector, x, y, z);
127 | return vector;
128 | },
129 | clone: function (a) {
130 | var vector = this.create();
131 | this.copy(vector, a);
132 | return vector;
133 | },
134 | set: function (target, x, y, z) {
135 | target[0] = x || 0;
136 | target[1] = y || 0;
137 | target[2] = z || 0;
138 | return this;
139 | },
140 | setX: function (target, x) {
141 | target[0] = x || 0;
142 | return this;
143 | },
144 | setY: function (target, y) {
145 | target[1] = y || 0;
146 | return this;
147 | },
148 | setZ: function (target, z) {
149 | target[2] = z || 0;
150 | return this;
151 | },
152 | copy: function (target, a) {
153 | target[0] = a[0];
154 | target[1] = a[1];
155 | target[2] = a[2];
156 | return this;
157 | },
158 | add: function (target, a) {
159 | target[0] += a[0];
160 | target[1] += a[1];
161 | target[2] += a[2];
162 | return this;
163 | },
164 | addVectors: function (target, a, b) {
165 | target[0] = a[0] + b[0];
166 | target[1] = a[1] + b[1];
167 | target[2] = a[2] + b[2];
168 | return this;
169 | },
170 | addScalar: function (target, s) {
171 | target[0] += s;
172 | target[1] += s;
173 | target[2] += s;
174 | return this;
175 | },
176 | subtract: function (target, a) {
177 | target[0] -= a[0];
178 | target[1] -= a[1];
179 | target[2] -= a[2];
180 | return this;
181 | },
182 | subtractVectors: function (target, a, b) {
183 | target[0] = a[0] - b[0];
184 | target[1] = a[1] - b[1];
185 | target[2] = a[2] - b[2];
186 | return this;
187 | },
188 | subtractScalar: function (target, s) {
189 | target[0] -= s;
190 | target[1] -= s;
191 | target[2] -= s;
192 | return this;
193 | },
194 | multiply: function (target, a) {
195 | target[0] *= a[0];
196 | target[1] *= a[1];
197 | target[2] *= a[2];
198 | return this;
199 | },
200 | multiplyVectors: function (target, a, b) {
201 | target[0] = a[0] * b[0];
202 | target[1] = a[1] * b[1];
203 | target[2] = a[2] * b[2];
204 | return this;
205 | },
206 | multiplyScalar: function (target, s) {
207 | target[0] *= s;
208 | target[1] *= s;
209 | target[2] *= s;
210 | return this;
211 | },
212 | divide: function (target, a) {
213 | target[0] /= a[0];
214 | target[1] /= a[1];
215 | target[2] /= a[2];
216 | return this;
217 | },
218 | divideVectors: function (target, a, b) {
219 | target[0] = a[0] / b[0];
220 | target[1] = a[1] / b[1];
221 | target[2] = a[2] / b[2];
222 | return this;
223 | },
224 | divideScalar: function (target, s) {
225 | if (s !== 0) {
226 | target[0] /= s;
227 | target[1] /= s;
228 | target[2] /= s;
229 | } else {
230 | target[0] = 0;
231 | target[1] = 0;
232 | target[2] = 0;
233 | }
234 | return this;
235 | },
236 | cross: function (target, a) {
237 | var x = target[0];
238 | var y = target[1];
239 | var z = target[2];
240 | target[0] = y * a[2] - z * a[1];
241 | target[1] = z * a[0] - x * a[2];
242 | target[2] = x * a[1] - y * a[0];
243 | return this;
244 | },
245 | crossVectors: function (target, a, b) {
246 | target[0] = a[1] * b[2] - a[2] * b[1];
247 | target[1] = a[2] * b[0] - a[0] * b[2];
248 | target[2] = a[0] * b[1] - a[1] * b[0];
249 | return this;
250 | },
251 | min: function (target, value) {
252 | if (target[0] < value) {
253 | target[0] = value;
254 | }
255 | if (target[1] < value) {
256 | target[1] = value;
257 | }
258 | if (target[2] < value) {
259 | target[2] = value;
260 | }
261 | return this;
262 | },
263 | max: function (target, value) {
264 | if (target[0] > value) {
265 | target[0] = value;
266 | }
267 | if (target[1] > value) {
268 | target[1] = value;
269 | }
270 | if (target[2] > value) {
271 | target[2] = value;
272 | }
273 | return this;
274 | },
275 | clamp: function (target, min, max) {
276 | this.min(target, min);
277 | this.max(target, max);
278 | return this;
279 | },
280 | limit: function (target, min, max) {
281 | var length = this.length(target);
282 | if (min !== null && length < min) {
283 | this.setLength(target, min);
284 | } else if (max !== null && length > max) {
285 | this.setLength(target, max);
286 | }
287 | return this;
288 | },
289 | dot: function (a, b) {
290 | return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
291 | },
292 | normalise: function (target) {
293 | return this.divideScalar(target, this.length(target));
294 | },
295 | negate: function (target) {
296 | return this.multiplyScalar(target, -1);
297 | },
298 | distanceSquared: function (a, b) {
299 | var dx = a[0] - b[0];
300 | var dy = a[1] - b[1];
301 | var dz = a[2] - b[2];
302 | return dx * dx + dy * dy + dz * dz;
303 | },
304 | distance: function (a, b) {
305 | return Math.sqrt(this.distanceSquared(a, b));
306 | },
307 | lengthSquared: function (a) {
308 | return a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
309 | },
310 | length: function (a) {
311 | return Math.sqrt(this.lengthSquared(a));
312 | },
313 | setLength: function (target, l) {
314 | var length = this.length(target);
315 | if (length !== 0 && l !== length) {
316 | this.multiplyScalar(target, l / length);
317 | }
318 | return this;
319 | },
320 | floor: function (target) {
321 | target[0] = Math.floor(target[0]);
322 | target[1] = Math.floor(target[1]);
323 | target[2] = Math.floor(target[2]);
324 | return target;
325 | }
326 | };
327 |
328 | /**
329 | * @object Vector4
330 | * @author Matthew Wagerfield
331 | */
332 | FSS.Vector4 = {
333 | create: function (x, y, z, w) {
334 | var vector = new FSS.Array(4);
335 | this.set(vector, x, y, z);
336 | return vector;
337 | },
338 | set: function (target, x, y, z, w) {
339 | target[0] = x || 0;
340 | target[1] = y || 0;
341 | target[2] = z || 0;
342 | target[3] = w || 0;
343 | return this;
344 | },
345 | setX: function (target, x) {
346 | target[0] = x || 0;
347 | return this;
348 | },
349 | setY: function (target, y) {
350 | target[1] = y || 0;
351 | return this;
352 | },
353 | setZ: function (target, z) {
354 | target[2] = z || 0;
355 | return this;
356 | },
357 | setW: function (target, w) {
358 | target[3] = w || 0;
359 | return this;
360 | },
361 | add: function (target, a) {
362 | target[0] += a[0];
363 | target[1] += a[1];
364 | target[2] += a[2];
365 | target[3] += a[3];
366 | return this;
367 | },
368 | multiplyVectors: function (target, a, b) {
369 | target[0] = a[0] * b[0];
370 | target[1] = a[1] * b[1];
371 | target[2] = a[2] * b[2];
372 | target[3] = a[3] * b[3];
373 | return this;
374 | },
375 | multiplyScalar: function (target, s) {
376 | target[0] *= s;
377 | target[1] *= s;
378 | target[2] *= s;
379 | target[3] *= s;
380 | return this;
381 | },
382 | min: function (target, value) {
383 | if (target[0] < value) {
384 | target[0] = value;
385 | }
386 | if (target[1] < value) {
387 | target[1] = value;
388 | }
389 | if (target[2] < value) {
390 | target[2] = value;
391 | }
392 | if (target[3] < value) {
393 | target[3] = value;
394 | }
395 | return this;
396 | },
397 | max: function (target, value) {
398 | if (target[0] > value) {
399 | target[0] = value;
400 | }
401 | if (target[1] > value) {
402 | target[1] = value;
403 | }
404 | if (target[2] > value) {
405 | target[2] = value;
406 | }
407 | if (target[3] > value) {
408 | target[3] = value;
409 | }
410 | return this;
411 | },
412 | clamp: function (target, min, max) {
413 | this.min(target, min);
414 | this.max(target, max);
415 | return this;
416 | }
417 | };
418 |
419 | /**
420 | * @class Color
421 | * @author Matthew Wagerfield
422 | */
423 | FSS.Color = function (color, opacity) {
424 | this.rgba = [];
425 | this.color = color || '#000000';
426 | this.opacity = FSS.Utils.isNumber(opacity) ? opacity : 1;
427 | this.set(this.color, this.opacity);
428 | };
429 |
430 | FSS.Color.prototype = {
431 | set: function (color, opacity) {
432 | if (color.indexOf("#") === -1) {
433 | if (color.indexOf('rgb(') === 0) {
434 | var pars = color.indexOf(',');
435 | this.rgba[0] = parseInt(color.substr(4, pars));
436 | this.rgba[1] = parseInt(color.substr(pars + 1, color.indexOf(',', pars)));
437 | this.rgba[2] = parseInt(color.substr(color.indexOf(',', pars + 1) + 1, color.indexOf(')')));
438 | this.rgba[3] = 1;
439 | } else if (color.indexOf('rgba(') === 0) {
440 |
441 | var pars = color.indexOf(',');
442 | var repars = color.indexOf(',', pars + 1);
443 | this.rgba[0] = parseInt(color.substr(5, pars));
444 | this.rgba[1] = parseInt(color.substr(pars + 1, repars));
445 | this.rgba[2] = parseInt(color.substr(color.indexOf(',', pars + 1) + 1, color.indexOf(',', repars)));
446 | this.rgba[3] = parseFloat(color.substr(color.indexOf(',', repars + 1) + 1, color.indexOf(')')));
447 | }
448 | } else {
449 | color = color.replace('#', '');
450 | var size = color.length / 3;
451 | this.rgba[0] = parseInt(color.substring(size * 0, size * 1), 16) / 255;
452 | this.rgba[1] = parseInt(color.substring(size * 1, size * 2), 16) / 255;
453 | this.rgba[2] = parseInt(color.substring(size * 2, size * 3), 16) / 255;
454 | this.rgba[3] = FSS.Utils.isNumber(opacity) ? opacity : this.rgba[3];
455 | }
456 |
457 | return this;
458 | },
459 | // hexify: function (channel) {
460 | // var hex = Math.ceil(channel * 255).toString(16);
461 | // if (hex.length === 1) {
462 | // hex = '0' + hex;
463 | // }
464 | // return hex;
465 | // },
466 | format: function () {
467 | return "rgba(" + this.rgba[0] + "," + this.rgba[1] + "," + this.rgba[2] + "," + this.rgba[3] + ")"; //this.hex
468 | // var r = this.hexify(this.rgba[0]);
469 | // var g = this.hexify(this.rgba[1]);
470 | // var b = this.hexify(this.rgba[2]);
471 | // this.hex = '#' + r + g + b;
472 | // return this.hex;
473 | }
474 | };
475 |
476 | /**
477 | * @class Object
478 | * @author Matthew Wagerfield
479 | */
480 | FSS.Object = function () {
481 | this.position = FSS.Vector3.create();
482 | };
483 |
484 | FSS.Object.prototype = {
485 | setPosition: function (x, y, z) {
486 | FSS.Vector3.set(this.position, x, y, z);
487 | return this;
488 | }
489 | };
490 |
491 | /**
492 | * @class Light
493 | * @author Matthew Wagerfield
494 | */
495 | FSS.Light = function (ambient, diffuse) {
496 | FSS.Object.call(this);
497 | this.ambient = new FSS.Color(ambient || '#FFFFFF');
498 | this.diffuse = new FSS.Color(diffuse || '#FFFFFF');
499 | this.ray = FSS.Vector3.create();
500 | };
501 |
502 | FSS.Light.prototype = Object.create(FSS.Object.prototype);
503 |
504 | /**
505 | * @class Vertex
506 | * @author Matthew Wagerfield
507 | */
508 | FSS.Vertex = function (x, y, z) {
509 | this.position = FSS.Vector3.create(x, y, z);
510 | };
511 |
512 | FSS.Vertex.prototype = {
513 | setPosition: function (x, y, z) {
514 | FSS.Vector3.set(this.position, x, y, z);
515 | return this;
516 | }
517 | };
518 |
519 | /**
520 | * @class Triangle
521 | * @author Matthew Wagerfield
522 | */
523 | FSS.Triangle = function (a, b, c) {
524 | this.a = a || new FSS.Vertex();
525 | this.b = b || new FSS.Vertex();
526 | this.c = c || new FSS.Vertex();
527 | this.vertices = [this.a, this.b, this.c];
528 | this.u = FSS.Vector3.create();
529 | this.v = FSS.Vector3.create();
530 | this.centroid = FSS.Vector3.create();
531 | this.normal = FSS.Vector3.create();
532 | this.color = new FSS.Color();
533 | this.polygon = document.createElementNS(FSS.SVGNS, 'polygon');
534 | this.polygon.setAttributeNS(null, 'stroke-linejoin', 'round');
535 | this.polygon.setAttributeNS(null, 'stroke-miterlimit', '1');
536 | this.polygon.setAttributeNS(null, 'stroke-width', '1');
537 | this.computeCentroid();
538 | this.computeNormal();
539 | };
540 |
541 | FSS.Triangle.prototype = {
542 | computeCentroid: function () {
543 | this.centroid[0] = this.a.position[0] + this.b.position[0] + this.c.position[0];
544 | this.centroid[1] = this.a.position[1] + this.b.position[1] + this.c.position[1];
545 | this.centroid[2] = this.a.position[2] + this.b.position[2] + this.c.position[2];
546 | FSS.Vector3.divideScalar(this.centroid, 3);
547 | return this;
548 | },
549 | computeNormal: function () {
550 | FSS.Vector3.subtractVectors(this.u, this.b.position, this.a.position);
551 | FSS.Vector3.subtractVectors(this.v, this.c.position, this.a.position);
552 | FSS.Vector3.crossVectors(this.normal, this.u, this.v);
553 | FSS.Vector3.normalise(this.normal);
554 | return this;
555 | }
556 | };
557 |
558 | /**
559 | * @class Geometry
560 | * @author Matthew Wagerfield
561 | */
562 | FSS.Geometry = function () {
563 | this.vertices = [];
564 | this.triangles = [];
565 | this.dirty = false;
566 | };
567 |
568 | FSS.Geometry.prototype = {
569 | update: function () {
570 | if (this.dirty) {
571 | var t, triangle;
572 | for (t = this.triangles.length - 1; t >= 0; t--) {
573 | triangle = this.triangles[t];
574 | triangle.computeCentroid();
575 | triangle.computeNormal();
576 | }
577 | this.dirty = false;
578 | }
579 | return this;
580 | }
581 | };
582 |
583 | /**
584 | * @class Plane
585 | * @author Matthew Wagerfield
586 | */
587 | FSS.Plane = function (width, height, segments, slices) {
588 | FSS.Geometry.call(this);
589 | this.width = width || 100;
590 | this.height = height || 100;
591 | this.segments = segments || 4;
592 | this.slices = slices || 4;
593 | this.segmentWidth = this.width / this.segments;
594 | this.sliceHeight = this.height / this.slices;
595 |
596 | // Cache Variables
597 | var x, y, v0, v1, v2, v3,
598 | vertex, triangle, vertices = [],
599 | offsetX = this.width * -0.5,
600 | offsetY = this.height * 0.5;
601 |
602 | // Add Vertices
603 | for (x = 0; x <= this.segments; x++) {
604 | vertices.push([]);
605 | for (y = 0; y <= this.slices; y++) {
606 | vertex = new FSS.Vertex(offsetX + x * this.segmentWidth, offsetY - y * this.sliceHeight);
607 | vertices[x].push(vertex);
608 | this.vertices.push(vertex);
609 | }
610 | }
611 |
612 | // Add Triangles
613 | for (x = 0; x < this.segments; x++) {
614 | for (y = 0; y < this.slices; y++) {
615 | v0 = vertices[x + 0][y + 0];
616 | v1 = vertices[x + 0][y + 1];
617 | v2 = vertices[x + 1][y + 0];
618 | v3 = vertices[x + 1][y + 1];
619 | t0 = new FSS.Triangle(v0, v1, v2);
620 | t1 = new FSS.Triangle(v2, v1, v3);
621 | this.triangles.push(t0, t1);
622 | }
623 | }
624 | };
625 |
626 | FSS.Plane.prototype = Object.create(FSS.Geometry.prototype);
627 |
628 | /**
629 | * @class Material
630 | * @author Matthew Wagerfield
631 | */
632 | FSS.Material = function (ambient, diffuse) {
633 | this.ambient = new FSS.Color(ambient || 'rgba(68,68,68, 1)');
634 | this.diffuse = new FSS.Color(diffuse || 'rgba(255,255,255, 1)');
635 | this.slave = new FSS.Color();
636 | };
637 |
638 | /**
639 | * @class Mesh
640 | * @author Matthew Wagerfield
641 | */
642 | FSS.Mesh = function (geometry, material) {
643 | FSS.Object.call(this);
644 | this.geometry = geometry || new FSS.Geometry();
645 | this.material = material || new FSS.Material();
646 | this.side = FSS.FRONT;
647 | this.visible = true;
648 | };
649 |
650 | FSS.Mesh.prototype = Object.create(FSS.Object.prototype);
651 |
652 | FSS.Mesh.prototype.update = function (lights, calculate) {
653 | var t, triangle, l, light, illuminance, light_count;
654 | light_count = lights.length;
655 |
656 | // Update Geometry
657 | this.geometry.update();
658 |
659 | // Calculate the triangle colors
660 | if (calculate) {
661 |
662 | // Iterate through Triangles
663 | for (t = this.geometry.triangles.length - 1; t >= 0; t--) {
664 | triangle = this.geometry.triangles[t];
665 |
666 | // Reset Triangle Color
667 | FSS.Vector4.set(triangle.color.rgba);
668 |
669 | // Iterate through Lights
670 | for (l = lights.length - 1; l >= 0; l--) {
671 | light = lights[l];
672 |
673 |
674 | // Calculate Illuminance
675 | FSS.Vector3.subtractVectors(light.ray, light.position, triangle.centroid);
676 | FSS.Vector3.normalise(light.ray);
677 | illuminance = FSS.Vector3.dot(triangle.normal, light.ray);
678 | if (this.side === FSS.FRONT) {
679 | illuminance = Math.max(illuminance, 0);
680 | } else if (this.side === FSS.BACK) {
681 | illuminance = Math.abs(Math.min(illuminance, 0));
682 | } else if (this.side === FSS.DOUBLE) {
683 | illuminance = Math.max(Math.abs(illuminance), 0);
684 | }
685 |
686 |
687 |
688 | // Calculate Ambient Light
689 | for (var i = 0; i < 3; i++) {
690 | this.material.slave.rgba[i] = (((1 / light_count) * this.material.ambient.rgba[i]) * ((1 / light_count) * light.ambient.rgba[i])) / 128;
691 | if (i !== 3) {
692 | this.material.slave.rgba[i] = Math.round(this.material.slave.rgba[i]);
693 | }
694 | }
695 | /* Add the resultant values to the triangle color vector. Not required to factor illuminance because it is ambient light. */
696 | FSS.Vector4.add(triangle.color.rgba, this.material.slave.rgba);
697 |
698 | // Calculate Diffuse Light
699 | for (var i = 0; i < 3; i++) {
700 | this.material.slave.rgba[i] = ((1 / light_count) * this.material.diffuse.rgba[i] * (1 / light_count) * light.diffuse.rgba[i]) / 128;
701 | if (i !== 3) {
702 | this.material.slave.rgba[i] = Math.round(this.material.slave.rgba[i]);
703 | }
704 | }
705 |
706 | // FSS.Vector4.multiplyVectors(this.material.slave.rgba, this.material.diffuse.rgba, light.diffuse.rgba);
707 | // FSS.Vector4.multiplyScalar(this.material.slave.rgba, illuminance);
708 | for (var i = 0; i < 3; i++) {
709 | this.material.slave.rgba[i] = Math.round(this.material.slave.rgba[i] * illuminance);
710 | }
711 | FSS.Vector4.add(triangle.color.rgba, this.material.slave.rgba);
712 | }
713 |
714 |
715 |
716 | // Clamp & Format Color
717 | FSS.Vector4.clamp(triangle.color.rgba, 0, 255);
718 | triangle.color.rgba[3] = this.material.diffuse.rgba[3]; //Math.min(triangle.color.rgba[3], 1);
719 | }
720 | }
721 | return this;
722 | };
723 |
724 | /**
725 | * @class Scene
726 | * @author Matthew Wagerfield
727 | */
728 | FSS.Scene = function () {
729 | this.meshes = [];
730 | this.lights = [];
731 | };
732 |
733 | FSS.Scene.prototype = {
734 | add: function (object) {
735 | if (object instanceof FSS.Mesh && !~this.meshes.indexOf(object)) {
736 | this.meshes.push(object);
737 | } else if (object instanceof FSS.Light && !~this.lights.indexOf(object)) {
738 | this.lights.push(object);
739 | }
740 | return this;
741 | },
742 | remove: function (object) {
743 | if (object instanceof FSS.Mesh && ~this.meshes.indexOf(object)) {
744 | this.meshes.splice(this.meshes.indexOf(object), 1);
745 | } else if (object instanceof FSS.Light && ~this.lights.indexOf(object)) {
746 | this.lights.splice(this.lights.indexOf(object), 1);
747 | }
748 | return this;
749 | }
750 | };
751 |
752 | /**
753 | * @class Renderer
754 | * @author Matthew Wagerfield
755 | */
756 | FSS.Renderer = function () {
757 | this.width = 0;
758 | this.height = 0;
759 | this.halfWidth = 0;
760 | this.halfHeight = 0;
761 | };
762 |
763 | FSS.Renderer.prototype = {
764 | setSize: function (width, height) {
765 | if (this.width === width && this.height === height)
766 | return;
767 | this.width = width;
768 | this.height = height;
769 | this.halfWidth = this.width * 0.5;
770 | this.halfHeight = this.height * 0.5;
771 | return this;
772 | },
773 | clear: function () {
774 | return this;
775 | },
776 | render: function (scene) {
777 | return this;
778 | }
779 | };
780 |
781 | /**
782 | * @class Canvas Renderer
783 | * @author Matthew Wagerfield
784 | */
785 | FSS.CanvasRenderer = function () {
786 | FSS.Renderer.call(this);
787 | this.element = document.createElement('canvas');
788 | /* this.element.style.display = 'block'; */
789 | this.element.style.zIndex = "-100";
790 | this.element.style.pointerEvents = "none";
791 | this.context = this.element.getContext('2d');
792 | this.setSize(this.element.width, this.element.height);
793 | };
794 |
795 | FSS.CanvasRenderer.prototype = Object.create(FSS.Renderer.prototype);
796 |
797 | FSS.CanvasRenderer.prototype.setSize = function (width, height) {
798 | FSS.Renderer.prototype.setSize.call(this, width, height);
799 | this.element.width = width;
800 | this.element.height = height;
801 | this.context.setTransform(1, 0, 0, 1, 0, 0);
802 | return this;
803 | };
804 |
805 | FSS.CanvasRenderer.prototype.clear = function () {
806 | FSS.Renderer.prototype.clear.call(this);
807 | this.context.clearRect(0, 0, this.width, this.height);
808 | return this;
809 | };
810 |
811 | var opacity = [];
812 | FSS.CanvasRenderer.prototype.render = function (scene) {
813 | FSS.Renderer.prototype.render.call(this, scene);
814 | var m, mesh, t, triangle, color;
815 | var pi2 = 2 * Math.PI;
816 |
817 | // Clear Context
818 | this.clear();
819 |
820 | // Configure Context
821 | this.context.lineJoin = 'round';
822 | this.context.lineWidth = 0;
823 |
824 | // Update Meshes
825 | for (m = scene.meshes.length - 1; m >= 0; m--) {
826 | mesh = scene.meshes[m];
827 | if (typeof opacity[m] == "undefined") {
828 | opacity[m] = [];
829 | }
830 | if (mesh.visible) {
831 | mesh.update(scene.lights, true);
832 |
833 | // Render Triangles
834 | for (t = mesh.geometry.triangles.length - 1; t >= 0; t--) {
835 |
836 | var now = Date.now();
837 | if (typeof opacity[m][t] === "undefined") {
838 | opacity[m][t] = {};
839 | opacity[m][t].step = FSS.Vector3.create(
840 | Math.randomInRange(0.2, 1.0),
841 | Math.randomInRange(0.2, 1.0),
842 | Math.randomInRange(0.2, 1.0)
843 | );
844 | opacity[m][t].time = Math.randomInRange(0, Math.PIM2);
845 | opacity[m][t].line = 0;
846 | } else {
847 | opacity[m][t].line = Math.sin(opacity[m][t].time + opacity[m][t].step[0] * now * (scene.LINE.fluctuationSpeed / 100)) * scene.LINE.fluctuationIntensity;
848 | opacity[m][t].vertex = Math.sin(opacity[m][t].time + opacity[m][t].step[0] * now * (scene.VERTEX.fluctuationSpeed / 100)) * scene.VERTEX.fluctuationIntensity;
849 | opacity[m][t].mesh = Math.sin(opacity[m][t].time + opacity[m][t].step[0] * now * (scene.MESH.fluctuationSpeed / 100)) * scene.MESH.fluctuationIntensity;
850 | }
851 |
852 |
853 | triangle = mesh.geometry.triangles[t];
854 | if (scene.MESH.draw !== false) {
855 | c = triangle.color.rgba;
856 | color = "rgba(" + c[0] + "," + c[1] + ", " + c[2] + "," + c[3] + ")";
857 |
858 | this.context.beginPath();
859 | this.context.moveTo(triangle.a.position[0], triangle.a.position[1]);
860 | this.context.lineTo(triangle.b.position[0], triangle.b.position[1]);
861 | this.context.lineTo(triangle.c.position[0], triangle.c.position[1]);
862 | this.context.closePath();
863 | this.context.fillStyle = color; //Color of triangle
864 | this.context.fill();
865 | }
866 |
867 |
868 | if (scene.LINE.draw !== false) {
869 | var c = new FSS.Color(scene.LINE.fill);
870 | c = c.rgba;
871 | c[3] = c[3] * (1 - opacity[m][t].line);
872 | c = "rgba(" + c[0] + "," + c[1] + ", " + c[2] + "," + c[3] + ")";
873 |
874 | this.context.beginPath();
875 | this.context.moveTo(triangle.a.position[0], triangle.a.position[1]);
876 | this.context.lineTo(triangle.b.position[0], triangle.b.position[1]);
877 | this.context.lineWidth = scene.LINE.thickness;
878 | this.context.fillStyle = c;
879 | this.context.fill();
880 | this.context.strokeStyle = c;
881 | this.context.stroke();
882 | }
883 |
884 | if (scene.VERTEX.draw !== false) {
885 | // var grd = this.context.createRadialGradient(triangle.a.position[0], triangle.a.position[1], scene.vertex.radius + 100, triangle.a.position[0], triangle.a.position[1], scene.vertex.radius + 105);
886 | // light blue
887 | // grd.addColorStop(0, '#8ED6FF');
888 | // dark blue
889 | // grd.addColorStop(1, '#004CB3');
890 |
891 | var c = new FSS.Color(scene.VERTEX.fill);
892 | c = c.rgba;
893 | c[3] = c[3] * (1 - opacity[m][t].vertex);
894 | c = "rgba(" + c[0] + "," + c[1] + ", " + c[2] + "," + c[3] + ")";
895 | var c1 = new FSS.Color(scene.VERTEX.strokeColor);
896 | c1 = c1.rgba;
897 | c1[3] = c1[3] * (1 - opacity[m][t].vertex);
898 | c1 = "rgba(" + c1[0] + "," + c1[1] + ", " + c1[2] + "," + c1[3] + ")";
899 | this.context.beginPath();
900 | this.context.arc(triangle.a.position[0], triangle.a.position[1], scene.VERTEX.radius, 0, pi2, false);
901 | this.context.fillStyle = c; //scene.VERTEX.fill;
902 | this.context.fill();
903 | this.context.lineWidth = scene.VERTEX.strokeWidth;
904 | this.context.strokeStyle = c1;
905 | this.context.stroke();
906 | }
907 |
908 | }
909 | }
910 | }
911 | return this;
912 | };
913 |
914 | /**
915 | * @class WebGL Renderer
916 | * @author Matthew Wagerfield
917 | */
918 | FSS.WebGLRenderer = function () {
919 | FSS.Renderer.call(this);
920 | this.element = document.createElement('canvas');
921 | this.element.style.display = 'block';
922 |
923 | // Set initial vertex and light count
924 | this.vertices = null;
925 | this.lights = null;
926 |
927 | // Create parameters object
928 | var parameters = {
929 | preserveDrawingBuffer: false,
930 | premultipliedAlpha: true,
931 | antialias: true,
932 | stencil: true,
933 | alpha: true
934 | };
935 |
936 | // Create and configure the gl context
937 | this.gl = this.getContext(this.element, parameters);
938 |
939 | // Set the internal support flag
940 | this.unsupported = !this.gl;
941 |
942 | // Setup renderer
943 | if (this.unsupported) {
944 | return 'WebGL is not supported by your browser.';
945 | } else {
946 | this.gl.clearColor(0.0, 0.0, 0.0, 0.0);
947 | this.gl.enable(this.gl.DEPTH_TEST);
948 | this.setSize(this.element.width, this.element.height);
949 | }
950 | };
951 |
952 | FSS.WebGLRenderer.prototype = Object.create(FSS.Renderer.prototype);
953 |
954 | FSS.WebGLRenderer.prototype.getContext = function (canvas, parameters) {
955 | var context = false;
956 | try {
957 | if (!(context = canvas.getContext('experimental-webgl', parameters))) {
958 | throw 'Error creating WebGL context.';
959 | }
960 | } catch (error) {
961 | console.error(error);
962 | }
963 | return context;
964 | };
965 |
966 | FSS.WebGLRenderer.prototype.setSize = function (width, height) {
967 | FSS.Renderer.prototype.setSize.call(this, width, height);
968 | if (this.unsupported)
969 | return;
970 |
971 | // Set the size of the canvas element
972 | this.element.width = width;
973 | this.element.height = height;
974 |
975 | // Set the size of the gl viewport
976 | this.gl.viewport(0, 0, width, height);
977 | return this;
978 | };
979 |
980 | FSS.WebGLRenderer.prototype.clear = function () {
981 | FSS.Renderer.prototype.clear.call(this);
982 | if (this.unsupported)
983 | return;
984 | this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
985 | return this;
986 | };
987 |
988 | FSS.WebGLRenderer.prototype.render = function (scene) {
989 | FSS.Renderer.prototype.render.call(this, scene);
990 | if (this.unsupported)
991 | return;
992 | var m, mesh, t, tl, triangle, l, light,
993 | attribute, uniform, buffer, data, location,
994 | update = false,
995 | lights = scene.lights.length,
996 | index, v, vl, vetex, vertices = 0;
997 |
998 | // Clear context
999 | this.clear();
1000 |
1001 | // Build the shader program
1002 | if (this.lights !== lights) {
1003 | this.lights = lights;
1004 | if (this.lights > 0) {
1005 | this.buildProgram(lights);
1006 | } else {
1007 | return;
1008 | }
1009 | }
1010 |
1011 | // Update program
1012 | if (!!this.program) {
1013 |
1014 | // Increment vertex counter
1015 | for (m = scene.meshes.length - 1; m >= 0; m--) {
1016 | mesh = scene.meshes[m];
1017 | if (mesh.geometry.dirty)
1018 | update = true;
1019 | mesh.update(scene.lights, false);
1020 | vertices += mesh.geometry.triangles.length * 3;
1021 | }
1022 |
1023 | // Compare vertex counter
1024 | if (update || this.vertices !== vertices) {
1025 | this.vertices = vertices;
1026 |
1027 | // Build buffers
1028 | for (attribute in this.program.attributes) {
1029 | buffer = this.program.attributes[attribute];
1030 | buffer.data = new FSS.Array(vertices * buffer.size);
1031 |
1032 | // Reset vertex index
1033 | index = 0;
1034 |
1035 | // Update attribute buffer data
1036 | for (m = scene.meshes.length - 1; m >= 0; m--) {
1037 | mesh = scene.meshes[m];
1038 |
1039 | for (t = 0, tl = mesh.geometry.triangles.length; t < tl; t++) {
1040 | triangle = mesh.geometry.triangles[t];
1041 |
1042 | for (v = 0, vl = triangle.vertices.length; v < vl; v++) {
1043 | vertex = triangle.vertices[v];
1044 | switch (attribute) {
1045 | case 'side':
1046 | this.setBufferData(index, buffer, mesh.side);
1047 | break;
1048 | case 'position':
1049 | this.setBufferData(index, buffer, vertex.position);
1050 | break;
1051 | case 'centroid':
1052 | this.setBufferData(index, buffer, triangle.centroid);
1053 | break;
1054 | case 'normal':
1055 | this.setBufferData(index, buffer, triangle.normal);
1056 | break;
1057 | case 'ambient':
1058 | this.setBufferData(index, buffer, mesh.material.ambient.rgba);
1059 | break;
1060 | case 'diffuse':
1061 | this.setBufferData(index, buffer, mesh.material.diffuse.rgba);
1062 | break;
1063 | }
1064 | index++;
1065 | }
1066 | }
1067 | }
1068 |
1069 | // Upload attribute buffer data
1070 | this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer.buffer);
1071 | this.gl.bufferData(this.gl.ARRAY_BUFFER, buffer.data, this.gl.DYNAMIC_DRAW);
1072 | this.gl.enableVertexAttribArray(buffer.location);
1073 | this.gl.vertexAttribPointer(buffer.location, buffer.size, this.gl.FLOAT, false, 0, 0);
1074 | }
1075 | }
1076 |
1077 | // Build uniform buffers
1078 | this.setBufferData(0, this.program.uniforms.resolution, [this.width, this.height, this.width]);
1079 | for (l = lights - 1; l >= 0; l--) {
1080 | light = scene.lights[l];
1081 | this.setBufferData(l, this.program.uniforms.lightPosition, light.position);
1082 | this.setBufferData(l, this.program.uniforms.lightAmbient, light.ambient.rgba);
1083 | this.setBufferData(l, this.program.uniforms.lightDiffuse, light.diffuse.rgba);
1084 | }
1085 |
1086 | // Update uniforms
1087 | for (uniform in this.program.uniforms) {
1088 | buffer = this.program.uniforms[uniform];
1089 | location = buffer.location;
1090 | data = buffer.data;
1091 | switch (buffer.structure) {
1092 | case '3f':
1093 | this.gl.uniform3f(location, data[0], data[1], data[2]);
1094 | break;
1095 | case '3fv':
1096 | this.gl.uniform3fv(location, data);
1097 | break;
1098 | case '4fv':
1099 | this.gl.uniform4fv(location, data);
1100 | break;
1101 | }
1102 | }
1103 | }
1104 |
1105 | // Draw those lovely triangles
1106 | this.gl.drawArrays(this.gl.TRIANGLES, 0, this.vertices);
1107 | return this;
1108 | };
1109 |
1110 | FSS.WebGLRenderer.prototype.setBufferData = function (index, buffer, value) {
1111 | if (FSS.Utils.isNumber(value)) {
1112 | buffer.data[index * buffer.size] = value;
1113 | } else {
1114 | for (var i = value.length - 1; i >= 0; i--) {
1115 | buffer.data[index * buffer.size + i] = value[i];
1116 | }
1117 | }
1118 | };
1119 |
1120 | /**
1121 | * Concepts taken from three.js WebGLRenderer
1122 | * @see https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js
1123 | */
1124 | FSS.WebGLRenderer.prototype.buildProgram = function (lights) {
1125 | if (this.unsupported)
1126 | return;
1127 |
1128 | // Create shader source
1129 | var vs = FSS.WebGLRenderer.VS(lights);
1130 | var fs = FSS.WebGLRenderer.FS(lights);
1131 |
1132 | // Derive the shader fingerprint
1133 | var code = vs + fs;
1134 |
1135 | // Check if the program has already been compiled
1136 | if (!!this.program && this.program.code === code)
1137 | return;
1138 |
1139 | // Create the program and shaders
1140 | var program = this.gl.createProgram();
1141 | var vertexShader = this.buildShader(this.gl.VERTEX_SHADER, vs);
1142 | var fragmentShader = this.buildShader(this.gl.FRAGMENT_SHADER, fs);
1143 |
1144 | // Attach an link the shader
1145 | this.gl.attachShader(program, vertexShader);
1146 | this.gl.attachShader(program, fragmentShader);
1147 | this.gl.linkProgram(program);
1148 |
1149 | // Add error handling
1150 | if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
1151 | var error = this.gl.getError();
1152 | var status = this.gl.getProgramParameter(program, this.gl.VALIDATE_STATUS);
1153 | console.error('Could not initialise shader.\nVALIDATE_STATUS: ' + status + '\nERROR: ' + error);
1154 | return null;
1155 | }
1156 |
1157 | // Delete the shader
1158 | this.gl.deleteShader(fragmentShader);
1159 | this.gl.deleteShader(vertexShader);
1160 |
1161 | // Set the program code
1162 | program.code = code;
1163 |
1164 | // Add the program attributes
1165 | program.attributes = {
1166 | side: this.buildBuffer(program, 'attribute', 'aSide', 1, 'f'),
1167 | position: this.buildBuffer(program, 'attribute', 'aPosition', 3, 'v3'),
1168 | centroid: this.buildBuffer(program, 'attribute', 'aCentroid', 3, 'v3'),
1169 | normal: this.buildBuffer(program, 'attribute', 'aNormal', 3, 'v3'),
1170 | ambient: this.buildBuffer(program, 'attribute', 'aAmbient', 4, 'v4'),
1171 | diffuse: this.buildBuffer(program, 'attribute', 'aDiffuse', 4, 'v4')
1172 | };
1173 |
1174 | // Add the program uniforms
1175 | program.uniforms = {
1176 | resolution: this.buildBuffer(program, 'uniform', 'uResolution', 3, '3f', 1),
1177 | lightPosition: this.buildBuffer(program, 'uniform', 'uLightPosition', 3, '3fv', lights),
1178 | lightAmbient: this.buildBuffer(program, 'uniform', 'uLightAmbient', 4, '4fv', lights),
1179 | lightDiffuse: this.buildBuffer(program, 'uniform', 'uLightDiffuse', 4, '4fv', lights)
1180 | };
1181 |
1182 | // Set the renderer program
1183 | this.program = program;
1184 |
1185 | // Enable program
1186 | this.gl.useProgram(this.program);
1187 |
1188 | // Return the program
1189 | return program;
1190 | };
1191 |
1192 | FSS.WebGLRenderer.prototype.buildShader = function (type, source) {
1193 | if (this.unsupported)
1194 | return;
1195 |
1196 | // Create and compile shader
1197 | var shader = this.gl.createShader(type);
1198 | this.gl.shaderSource(shader, source);
1199 | this.gl.compileShader(shader);
1200 |
1201 | // Add error handling
1202 | if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
1203 | console.error(this.gl.getShaderInfoLog(shader));
1204 | return null;
1205 | }
1206 |
1207 | // Return the shader
1208 | return shader;
1209 | };
1210 |
1211 | FSS.WebGLRenderer.prototype.buildBuffer = function (program, type, identifier, size, structure, count) {
1212 | var buffer = {
1213 | buffer: this.gl.createBuffer(),
1214 | size: size,
1215 | structure: structure,
1216 | data: null
1217 | };
1218 |
1219 | // Set the location
1220 | switch (type) {
1221 | case 'attribute':
1222 | buffer.location = this.gl.getAttribLocation(program, identifier);
1223 | break;
1224 | case 'uniform':
1225 | buffer.location = this.gl.getUniformLocation(program, identifier);
1226 | break;
1227 | }
1228 |
1229 | // Create the buffer if count is provided
1230 | if (!!count) {
1231 | buffer.data = new FSS.Array(count * size);
1232 | }
1233 |
1234 | // Return the buffer
1235 | return buffer;
1236 | };
1237 |
1238 | FSS.WebGLRenderer.VS = function (lights) {
1239 | var shader = [
1240 | // Precision
1241 | 'precision mediump float;',
1242 | // Lights
1243 | '#define LIGHTS ' + lights,
1244 | // Attributes
1245 | 'attribute float aSide;',
1246 | 'attribute vec3 aPosition;',
1247 | 'attribute vec3 aCentroid;',
1248 | 'attribute vec3 aNormal;',
1249 | 'attribute vec4 aAmbient;',
1250 | 'attribute vec4 aDiffuse;',
1251 | // Uniforms
1252 | 'uniform vec3 uResolution;',
1253 | 'uniform vec3 uLightPosition[LIGHTS];',
1254 | 'uniform vec4 uLightAmbient[LIGHTS];',
1255 | 'uniform vec4 uLightDiffuse[LIGHTS];',
1256 | // Varyings
1257 | 'varying vec4 vColor;',
1258 | // Main
1259 | 'void main() {',
1260 | // Create color
1261 | 'vColor = vec4(0.0);',
1262 | // Calculate the vertex position
1263 | 'vec3 position = aPosition / uResolution * 2.0;',
1264 | // Iterate through lights
1265 | 'for (int i = 0; i < LIGHTS; i++) {',
1266 | 'vec3 lightPosition = uLightPosition[i];',
1267 | 'vec4 lightAmbient = uLightAmbient[i];',
1268 | 'vec4 lightDiffuse = uLightDiffuse[i];',
1269 | // Calculate illuminance
1270 | 'vec3 ray = normalize(lightPosition - aCentroid);',
1271 | 'float illuminance = dot(aNormal, ray);',
1272 | 'if (aSide == 0.0) {',
1273 | 'illuminance = max(illuminance, 0.0);',
1274 | '} else if (aSide == 1.0) {',
1275 | 'illuminance = abs(min(illuminance, 0.0));',
1276 | '} else if (aSide == 2.0) {',
1277 | 'illuminance = max(abs(illuminance), 0.0);',
1278 | '}',
1279 | // Calculate ambient light
1280 | 'vColor += aAmbient * lightAmbient;',
1281 | // Calculate diffuse light
1282 | 'vColor += aDiffuse * lightDiffuse * illuminance;',
1283 | '}',
1284 | // Clamp color
1285 | 'vColor = clamp(vColor, 0.0, 1.0);',
1286 | // Set gl_Position
1287 | 'gl_Position = vec4(position, 1.0);',
1288 | '}'
1289 |
1290 | // Return the shader
1291 | ].join('\n');
1292 | return shader;
1293 | };
1294 |
1295 | FSS.WebGLRenderer.FS = function (lights) {
1296 | var shader = [
1297 | // Precision
1298 | 'precision mediump float;',
1299 | // Varyings
1300 | 'varying vec4 vColor;',
1301 | // Main
1302 | 'void main() {',
1303 | // Set gl_FragColor
1304 | 'gl_FragColor = vColor;',
1305 | '}'
1306 |
1307 | // Return the shader
1308 | ].join('\n');
1309 | return shader;
1310 | };
1311 |
1312 | /**
1313 | * @class SVG Renderer
1314 | * @author Matthew Wagerfield
1315 | */
1316 | FSS.SVGRenderer = function () {
1317 | FSS.Renderer.call(this);
1318 | this.element = document.createElementNS(FSS.SVGNS, 'svg');
1319 | this.element.setAttribute('xmlns', FSS.SVGNS);
1320 | this.element.setAttribute('version', '1.1');
1321 | this.element.style.display = 'block';
1322 | this.setSize(300, 150);
1323 | };
1324 |
1325 | FSS.SVGRenderer.prototype = Object.create(FSS.Renderer.prototype);
1326 |
1327 | FSS.SVGRenderer.prototype.setSize = function (width, height) {
1328 | FSS.Renderer.prototype.setSize.call(this, width, height);
1329 | this.element.setAttribute('width', width);
1330 | this.element.setAttribute('height', height);
1331 | return this;
1332 | };
1333 |
1334 | FSS.SVGRenderer.prototype.clear = function () {
1335 | FSS.Renderer.prototype.clear.call(this);
1336 | for (var i = this.element.childNodes.length - 1; i >= 0; i--) {
1337 | this.element.removeChild(this.element.childNodes[i]);
1338 | }
1339 | return this;
1340 | };
1341 |
1342 | FSS.SVGRenderer.prototype.render = function (scene) {
1343 | FSS.Renderer.prototype.render.call(this, scene);
1344 | var m, mesh, t, triangle, points, style;
1345 |
1346 | // Update Meshes
1347 | for (m = scene.meshes.length - 1; m >= 0; m--) {
1348 | mesh = scene.meshes[m];
1349 | if (mesh.visible) {
1350 | mesh.update(scene.lights, true);
1351 |
1352 | // Render Triangles
1353 | for (t = mesh.geometry.triangles.length - 1; t >= 0; t--) {
1354 | triangle = mesh.geometry.triangles[t];
1355 | if (triangle.polygon.parentNode !== this.element) {
1356 | this.element.appendChild(triangle.polygon);
1357 | }
1358 | points = this.formatPoint(triangle.a) + ' ';
1359 | points += this.formatPoint(triangle.b) + ' ';
1360 | points += this.formatPoint(triangle.c);
1361 | style = this.formatStyle(triangle.color.format());
1362 | triangle.polygon.setAttributeNS(null, 'points', points);
1363 | triangle.polygon.setAttributeNS(null, 'style', style);
1364 | }
1365 | }
1366 | }
1367 | return this;
1368 | };
1369 |
1370 | FSS.SVGRenderer.prototype.formatPoint = function (vertex) {
1371 | return (vertex.position[0]) + ',' + (vertex.position[1]);
1372 | };
1373 |
1374 | FSS.SVGRenderer.prototype.formatStyle = function (color) {
1375 | var style = 'fill:' + color + ';';
1376 | style += 'stroke:' + color + ';';
1377 | return style;
1378 | };
1379 |
1380 | (function () {
1381 | $.fn.Geometryangle = function (opt) {
1382 | var fss = [];
1383 | var element = $(this);
1384 | var len = element.length, k;
1385 | for (var j = 0; j < len; j++) {
1386 | k = element[j];
1387 | fss[fss.length] = FSS_Worker(opt, k);
1388 | }
1389 | return (fss.length == 1 ? fss[0] : fss);
1390 | };
1391 | var FSS_Worker = function (opt, k) {
1392 |
1393 | opt = opt || {};
1394 | var MESH = {}, LIGHT = [{}],
1395 | VERTEX = {}, LINE = {};
1396 |
1397 | var getDataAttr = function (element) {
1398 | var data_option = [
1399 | [],
1400 | []
1401 | ];
1402 | // var keys = Object.keys(option);
1403 | var d = [MESH, LIGHT];
1404 | $.each(d, function (u) {
1405 | $.each(d[u], function (i, val) {
1406 | if (typeof element.getAttribute('data-fss-' [i]) !== "undefined" && typeof element.getAttribute('data-fss-' + [i]) !== false) {
1407 | try {
1408 | data_option[u][i] = $.parseJSON(element.getAttribute('data-fss-' + [i]));
1409 | return true; //continue;
1410 | } catch (e) {
1411 | }
1412 | if (typeof data_option[u][i] !== "object") {
1413 | data_option[u][i] = element.getAttribute('data-fss-' + [i]);
1414 | }
1415 | }
1416 | });
1417 |
1418 | var data_json = (typeof element.getAttribute('data-fss') !== "undefined" && typeof element.getAttribute('data-fss') !== false ? $.parseJSON(element.getAttribute('data-fss')) : []);
1419 |
1420 | $.extend(true, data_option[u], data_json);
1421 | });
1422 |
1423 | return data_option;
1424 | };
1425 |
1426 | var rgbaToRgb = function (rgba) {
1427 | try {
1428 | var bits = rgba.split("(");
1429 | } catch (e) {
1430 | return;
1431 | }
1432 | if (typeof bits[1] !== "undefined") {
1433 | bits = bits[1].split(")")[0].split(",");
1434 | return "rgb(" + bits[0] + "," + bits[1] + "," + bits[2] + ")";
1435 | }
1436 | return;
1437 | };
1438 |
1439 | //------------------------------
1440 | // Mesh Properties
1441 | //------------------------------
1442 | var mesh_default = {
1443 | width: 1.2,
1444 | height: 1.2,
1445 | depth: 10,
1446 | columns: undefined,
1447 | columns_auto: true,
1448 | rows: undefined,
1449 | rows_auto: true,
1450 | zoom: 1,
1451 | xRange: 0.8,
1452 | yRange: 0.1,
1453 | zRange: 1.0,
1454 | ambient: 'rgba(85, 85, 85, 1)',
1455 | diffuse: 'rgba(255, 255, 255, 1)',
1456 | background: 'rgb(255, 255, 255)',
1457 | speed: 0.0002,
1458 | fluctuationSpeed: 0.5,
1459 | fluctuationIntensity: 0,
1460 | onRender: function () {
1461 | },
1462 | floorPosition: false,
1463 | draw: true
1464 | };
1465 |
1466 | var vertex_default = {
1467 | radius: 0,
1468 | fill: "rgba(0, 0, 0, 0)",
1469 | fluctuationSpeed: 0.5,
1470 | fluctuationIntensity: 0,
1471 | strokeWidth: 0,
1472 | strokeColor: "rgba(0, 0, 0, 0)",
1473 | draw: false
1474 | };
1475 |
1476 | var line_default = {
1477 | fill: "rgba(0, 0, 0, 0)",
1478 | thickness: 1,
1479 | fluctuationIntensity: 0,
1480 | fluctuationSpeed: 0.5,
1481 | draw: false
1482 | };
1483 |
1484 | //------------------------------
1485 | // Light Properties
1486 | //------------------------------
1487 | var light_default = {
1488 | count: 1,
1489 | xyScalar: 1,
1490 | zOffset: 100,
1491 | ambient: 'rgba(255,0,102, 1)',
1492 | diffuse: 'rgba(255,136,0, 1)',
1493 | speed: 0.010,
1494 | gravity: 1200,
1495 | dampening: 0.95,
1496 | minLimit: 10,
1497 | maxLimit: null,
1498 | minDistance: 20,
1499 | maxDistance: 400,
1500 | autopilot: false,
1501 | draw: false, //show circle
1502 | bounds: FSS.Vector3.create(),
1503 | step: FSS.Vector3.create(
1504 | Math.randomInRange(0.2, 1.0),
1505 | Math.randomInRange(0.2, 1.0),
1506 | Math.randomInRange(0.2, 1.0)
1507 | )
1508 | };
1509 |
1510 | var self = k;
1511 |
1512 | var createValues = function (opt) {
1513 | opt.mesh = opt.mesh || MESH;
1514 | opt.lights = opt.lights || LIGHT;
1515 | opt.vertex = opt.vertex || VERTEX;
1516 | opt.line = opt.line || LINE;
1517 |
1518 | MESH = $.extend(true, mesh_default, MESH, opt.mesh);
1519 | VERTEX = $.extend(true, vertex_default, VERTEX, opt.vertex);
1520 | LINE = $.extend(true, line_default, LINE, opt.line);
1521 | for (var i = 0; i < LIGHT.length; i++) {
1522 | LIGHT[i] = $.extend(true, light_default, LIGHT[i], opt.lights[i]);
1523 | }
1524 | var box_data_option = getDataAttr(self);
1525 | MESH = $.extend(true, box_data_option[0], MESH);
1526 |
1527 | MESH.columns_auto = (typeof opt.mesh.columns === "undefined");
1528 | MESH.rows_auto = (typeof opt.mesh.rows === "undefined");
1529 | };
1530 | createValues({
1531 | mesh: mesh_default,
1532 | line: line_default,
1533 | vertex: vertex_default,
1534 | lights: [light_default]
1535 | });
1536 | createValues(opt);
1537 |
1538 | var container = document.createElement("div");
1539 | container.style.position = "absolute";
1540 | container.style.left = "0";
1541 | container.style.right = "0";
1542 | container.style.top = "0";
1543 | container.style.bottom = "0";
1544 | container.style.background = MESH.background;
1545 | container.style.zIndex = "-100";
1546 | container.setAttribute('class', 'fss-output');
1547 | self.insertBefore(container, null);
1548 |
1549 |
1550 |
1551 | //------------------------------
1552 | // Render Properties
1553 | //------------------------------
1554 | var WEBGL = 'webgl';
1555 | var CANVAS = 'canvas';
1556 | var SVG = 'svg';
1557 | var RENDER = {
1558 | renderer: CANVAS
1559 | };
1560 |
1561 | //------------------------------
1562 | // UI Properties
1563 | //------------------------------
1564 | var UI = {
1565 | show: true
1566 | };
1567 |
1568 | //------------------------------
1569 | // Global Properties
1570 | //------------------------------
1571 | var now, start = Date.now();
1572 | var center = FSS.Vector3.create();
1573 | var attractor = FSS.Vector3.create();
1574 | //var container = document.getElementById('container'); -- taken from JQuery element
1575 | /* var output = document.getElementById('output'); */
1576 | var ui = document.getElementById('ui');
1577 | var renderer, scene, mesh, geometry, material;
1578 | var webglRenderer, canvasRenderer, svgRenderer;
1579 | var gui, autopilotController;
1580 |
1581 | //------------------------------
1582 | // Methods
1583 | //------------------------------
1584 | function initialise() {
1585 | createRenderer();
1586 | createScene();
1587 | createMesh();
1588 | createLights();
1589 | addEventListeners();
1590 | callbacks.resize(container.offsetWidth, container.offsetHeight);
1591 | animate();
1592 | }
1593 |
1594 | function createRenderer() {
1595 | webglRenderer = new FSS.WebGLRenderer();
1596 | canvasRenderer = new FSS.CanvasRenderer();
1597 | svgRenderer = new FSS.SVGRenderer();
1598 | setRenderer(RENDER.renderer);
1599 | }
1600 |
1601 | function setRenderer(index) {
1602 | if (renderer) {
1603 | /* output.removeChild(renderer.element); */
1604 | }
1605 | switch (index) {
1606 | case WEBGL:
1607 | renderer = webglRenderer;
1608 | break;
1609 | case CANVAS:
1610 | renderer = canvasRenderer;
1611 | break;
1612 | case SVG:
1613 | renderer = svgRenderer;
1614 | break;
1615 | }
1616 | renderer.setSize(container.offsetWidth, container.offsetHeight);
1617 | container.insertBefore(renderer.element, null);
1618 |
1619 | var style = window.getComputedStyle(self);
1620 |
1621 | if (style.getPropertyValue('position') == 'static' || style.getPropertyValue('position').length == 0) {
1622 | self.style.position = 'relative';
1623 | }
1624 |
1625 | }
1626 |
1627 | function createScene() {
1628 | scene = new FSS.Scene();
1629 | scene.VERTEX = VERTEX;
1630 | scene.LINE = LINE;
1631 | scene.MESH = MESH;
1632 | }
1633 |
1634 | function createMesh() {
1635 | scene.remove(mesh);
1636 | renderer.clear();
1637 | geometry = new FSS.Plane(MESH.width * renderer.width, MESH.height * renderer.height, MESH.columns, MESH.rows);
1638 | material = new FSS.Material(MESH.ambient, MESH.diffuse);
1639 | mesh = new FSS.Mesh(geometry, material);
1640 | scene.add(mesh);
1641 |
1642 | // Augment vertices for animation
1643 | var v, vertex;
1644 | for (v = geometry.vertices.length - 1; v >= 0; v--) {
1645 | vertex = geometry.vertices[v];
1646 | vertex.anchor = FSS.Vector3.floor(FSS.Vector3.clone(vertex.position));
1647 | vertex.step = FSS.Vector3.create(
1648 | Math.randomInRange(0.2, 1.0),
1649 | Math.randomInRange(0.2, 1.0),
1650 | Math.randomInRange(0.2, 1.0)
1651 | );
1652 | vertex.time = Math.randomInRange(0, Math.PIM2);
1653 | }
1654 | }
1655 |
1656 | function createLights() {
1657 | var l, light;
1658 | for (l = scene.lights.length - 1; l >= 0; l--) {
1659 | light = scene.lights[l];
1660 | scene.remove(light);
1661 | }
1662 | renderer.clear();
1663 | for (l = 0; l < LIGHT.length; l++) {
1664 | for (var u = 0; u < LIGHT[l].count; u++) {
1665 | light = new FSS.Light(LIGHT[l].ambient, LIGHT[l].diffuse);
1666 | scene.add(light);
1667 |
1668 | // Augment light for animation
1669 | light.mass = Math.randomInRange(0.5, 1);
1670 | light.velocity = FSS.Vector3.create();
1671 | light.acceleration = FSS.Vector3.create();
1672 | light.force = FSS.Vector3.create();
1673 |
1674 | // Ring SVG Circle
1675 | light.ring = document.createElementNS(FSS.SVGNS, 'circle');
1676 | light.ring.setAttributeNS(null, 'stroke', light.ambient);
1677 | light.ring.setAttributeNS(null, 'stroke-width', '0.5');
1678 | light.ring.setAttributeNS(null, 'fill', 'none');
1679 | light.ring.setAttributeNS(null, 'r', '10');
1680 |
1681 | // Core SVG Circle
1682 | light.core = document.createElementNS(FSS.SVGNS, 'circle');
1683 | light.core.setAttributeNS(null, 'fill', light.diffuseHex);
1684 | light.core.setAttributeNS(null, 'r', '4');
1685 | }
1686 | }
1687 | }
1688 | var callbacks = {
1689 | resize: function (width, height) {
1690 |
1691 | if (typeof width == "undefined" || typeof width === undefined) {
1692 | width = self.width();
1693 | }
1694 | if (typeof height == "undefined" || typeof height === undefined) {
1695 | height = self.height();
1696 | }
1697 | var ratio_x = width / 1000;
1698 | var ratio_y = height / 1000;
1699 | var x_tiles = Math.round(ratio_x * 10) * MESH.zoom;
1700 | var y_tiles = Math.round(ratio_y * 10) * MESH.zoom;
1701 | MESH.columns = (MESH.columns_auto === true ? x_tiles : MESH.columns);
1702 | MESH.rows = (MESH.rows_auto === true ? y_tiles : MESH.rows);
1703 | renderer.setSize(width, height);
1704 | FSS.Vector3.set(center, renderer.halfWidth, renderer.halfHeight);
1705 | createMesh();
1706 | },
1707 | update: function (opt) {
1708 | createValues(opt);
1709 | scene.vertex = VERTEX;
1710 | scene.line = LINE;
1711 | //Ambient
1712 | for (i = 0, l = scene.meshes.length; i < l; i++) {
1713 | scene.meshes[i].material.ambient.set(MESH.ambient);
1714 | scene.meshes[i].material.diffuse.set(MESH.diffuse);
1715 | }
1716 | //width
1717 | if (geometry.width !== MESH.width * renderer.width) {
1718 | createMesh();
1719 | }
1720 | if (geometry.height !== MESH.height * renderer.height) {
1721 | createMesh();
1722 | }
1723 | if (geometry.segments !== MESH.columns) {
1724 | createMesh();
1725 | }
1726 | if (geometry.slices !== MESH.rows) {
1727 | createMesh();
1728 | }
1729 |
1730 | var light_index = 0;
1731 |
1732 | for (l = 0; l < LIGHT.length; l++) {
1733 |
1734 | for (var i = 0; i < LIGHT[l].count; i++) {
1735 | light = scene.lights[light_index];
1736 | light.ambient.set(LIGHT[l].ambient);
1737 |
1738 | light = scene.lights[light_index];
1739 | light.diffuse.set(LIGHT[l].diffuse);
1740 |
1741 | light_index++;
1742 | }
1743 | }
1744 |
1745 | if (scene.lights.length !== light_index) {
1746 | createLights();
1747 | }
1748 |
1749 | },
1750 | animateValues: function (colors) {
1751 |
1752 | var body = document.body,
1753 | html = document.documentElement, scrollTop = ((window.pageYOffset || html.scrollTop) - (html.clientTop || 0));
1754 |
1755 | var height = Math.max(body.scrollHeight, body.offsetHeight,
1756 | html.clientHeight, html.scrollHeight, html.offsetHeight);
1757 |
1758 |
1759 | var length = colors.length;
1760 | var height = Math.round(height / length); // Height of the segment between two colors
1761 | var i = Math.floor(scrollTop / height); // Start color index
1762 | var d = scrollTop % height / height; // Which part of the segment between start color and end color is passed
1763 | var c1 = colors[i]; // Start color
1764 | var c2 = colors[(i + 1) % length]; // End color
1765 | var result = [];
1766 | for (var i = 0; i < c1.length; i++) {
1767 | result[i] = c1[i] + ((c2[i] - c1[i]) * d);
1768 | if (i !== 3) {
1769 | result[i] = Math.round(result[i]);
1770 | }
1771 | }
1772 | return result;
1773 | },
1774 | formatRGBA: function (a) {
1775 | var string = "rgba(" + a[0] + "," + a[1] + "," + a[2] + "," + a[3] + ")";
1776 | return string;
1777 | }
1778 | };
1779 |
1780 |
1781 | function animate() {
1782 | now = Date.now() - start;
1783 | update();
1784 | render();
1785 | requestAnimationFrame(animate);
1786 | }
1787 |
1788 | function update() {
1789 | var ox, oy, oz, l, light, v, vertex, offset = MESH.depth / 2;
1790 | var light_index = 0;
1791 | var render_vector = FSS.Vector3.floor(FSS.Vector3.create(renderer.halfWidth, renderer.halfHeight, 0));
1792 |
1793 | // Animate Lights
1794 | for (l = 0; l < LIGHT.length; l++) {
1795 |
1796 | for (var i = 0; i < LIGHT[l].count; i++) {
1797 |
1798 | light = scene.lights[light_index];
1799 |
1800 | // Update Bounds
1801 | FSS.Vector3.copy(LIGHT[l].bounds, center);
1802 | FSS.Vector3.multiplyScalar(LIGHT[l].bounds, LIGHT[l].xyScalar);
1803 |
1804 | // Update Attractor
1805 | FSS.Vector3.setZ(attractor, LIGHT[l].zOffset);
1806 |
1807 | // Overwrite the Attractor position
1808 | if (LIGHT[l].autopilot && typeof LIGHT[l].position === "undefined") {
1809 | ox = Math.sin(LIGHT[l].step[0] * now * LIGHT[l].speed);
1810 | oy = Math.cos(LIGHT[l].step[1] * now * LIGHT[l].speed);
1811 | FSS.Vector3.set(attractor,
1812 | LIGHT[l].bounds[0] * ox,
1813 | LIGHT[l].bounds[1] * oy,
1814 | LIGHT[l].zOffset);
1815 | }
1816 |
1817 | // Reset the z position of the light
1818 | FSS.Vector3.setZ(light.position, LIGHT[l].zOffset);
1819 |
1820 | if (typeof LIGHT[l].position !== "undefined") {
1821 | FSS.Vector3.set(light.position);
1822 | FSS.Vector3.add(light.position, FSS.Vector3.create(LIGHT[l].position[0], LIGHT[l].position[1], LIGHT[l].zOffset));
1823 | } else {
1824 | // Calculate the force Luke!
1825 | var D = Math.clamp(FSS.Vector3.distanceSquared(light.position, attractor), LIGHT[l].minDistance, LIGHT[l].maxDistance);
1826 | var F = LIGHT[l].gravity * light.mass / D;
1827 | FSS.Vector3.subtractVectors(light.force, attractor, light.position);
1828 | FSS.Vector3.normalise(light.force);
1829 | FSS.Vector3.multiplyScalar(light.force, F);
1830 | // Update the light position
1831 | FSS.Vector3.set(light.acceleration);
1832 | FSS.Vector3.add(light.acceleration, light.force);
1833 | FSS.Vector3.add(light.velocity, light.acceleration);
1834 | FSS.Vector3.multiplyScalar(light.velocity, LIGHT[l].dampening);
1835 | FSS.Vector3.limit(light.velocity, LIGHT[l].minLimit, LIGHT[l].maxLimit);
1836 | FSS.Vector3.add(light.position, light.velocity);
1837 | }
1838 |
1839 | light_index++;
1840 | }
1841 | }
1842 |
1843 |
1844 |
1845 | // Animate Vertices
1846 | for (v = geometry.vertices.length - 1; v >= 0; v--) {
1847 | vertex = geometry.vertices[v];
1848 | ox = Math.sin(vertex.time + vertex.step[0] * now * MESH.speed);
1849 | oy = Math.cos(vertex.time + vertex.step[1] * now * MESH.speed);
1850 | oz = Math.sin(vertex.time + vertex.step[2] * now * MESH.speed);
1851 | vertex.position = FSS.Vector3.create(
1852 | MESH.xRange * geometry.segmentWidth * ox,
1853 | MESH.yRange * geometry.sliceHeight * oy,
1854 | MESH.zRange * offset * oz - offset);
1855 | if (MESH.positionFloor === true) {
1856 | vertex.position = FSS.Vector3.floor(vertex.position);
1857 | }
1858 | FSS.Vector3.add(vertex.position, vertex.anchor);
1859 | FSS.Vector3.add(vertex.position, render_vector);
1860 | }
1861 |
1862 | // Set the Geometry to dirty
1863 | geometry.dirty = true;
1864 | }
1865 |
1866 | function render() {
1867 | renderer.render(scene);
1868 |
1869 | // Draw Lights
1870 | if (LIGHT.draw) {
1871 | var l, lx, ly, light;
1872 | for (l = scene.lights.length - 1; l >= 0; l--) {
1873 | light = scene.lights[l];
1874 | lx = light.position[0];
1875 | ly = light.position[1];
1876 | switch (RENDER.renderer) {
1877 | case CANVAS:
1878 | renderer.context.lineWidth = 0.5;
1879 | renderer.context.beginPath();
1880 | renderer.context.arc(lx, ly, 10, 0, Math.PIM2);
1881 | renderer.context.strokeStyle = light.ambient;
1882 | renderer.context.stroke();
1883 | renderer.context.beginPath();
1884 | renderer.context.arc(lx, ly, 4, 0, Math.PIM2);
1885 | renderer.context.fillStyle = light.diffuse;
1886 | renderer.context.fill();
1887 | break;
1888 | case SVG:
1889 | /* lx += renderer.halfWidth; */
1890 | /* ly = renderer.halfHeight - ly; */
1891 | light.core.setAttributeNS(null, 'fill', light.diffuse);
1892 | light.core.setAttributeNS(null, 'cx', lx);
1893 | light.core.setAttributeNS(null, 'cy', ly);
1894 | renderer.element.appendChild(light.core);
1895 | light.ring.setAttributeNS(null, 'stroke', light.ambient);
1896 | light.ring.setAttributeNS(null, 'cx', lx);
1897 | light.ring.setAttributeNS(null, 'cy', ly);
1898 | renderer.element.appendChild(light.ring);
1899 | break;
1900 | }
1901 | }
1902 | }
1903 | MESH.onRender(scene, renderer.context);
1904 | }
1905 |
1906 | function addEventListeners() {
1907 | if(window.attachEvent) {
1908 | window.addEventHandler = window.attachEvent;
1909 | }
1910 | window.addEventListener('resize', onWindowResize, false);
1911 | self.addEventListener('click', onMouseClick, false);
1912 | self.addEventListener('mousemove', onMouseMove, true);
1913 | }
1914 |
1915 | //------------------------------
1916 | // Callbacks
1917 | //------------------------------
1918 | function onMouseClick(event) {
1919 | FSS.Vector3.set(attractor, event.x, event.y);
1920 | /* FSS.Vector3.subtract(attractor, center); */
1921 | LIGHT.autopilot = !LIGHT.autopilot;
1922 | }
1923 |
1924 | function onMouseMove(event) {
1925 | console.log(event);
1926 | FSS.Vector3.set(attractor, event.x, event.y);
1927 | /* FSS.Vector3.subtract(attractor, center); */
1928 | }
1929 |
1930 | function onWindowResize(event) {
1931 | callbacks.resize(self.offsetWidth, self.offsetHeight);
1932 | render();
1933 | }
1934 |
1935 |
1936 | // Let there be light!
1937 | initialise();
1938 | return callbacks;
1939 | };
1940 | })();
--------------------------------------------------------------------------------
/geometryangle.min.js:
--------------------------------------------------------------------------------
1 | FSS={FRONT:0,BACK:1,DOUBLE:2,SVGNS:"http://www.w3.org/2000/svg"};FSS.Array=typeof Float32Array==="function"?Float32Array:Array;FSS.Utils={isNumber:function(a){return !isNaN(parseFloat(a))&&isFinite(a)}};(function(){var b=0;var c=["ms","moz","webkit","o"];for(var a=0;aa){b[0]=a}if(b[1]>a){b[1]=a}if(b[2]>a){b[2]=a}return this},clamp:function(c,b,a){this.min(c,b);this.max(c,a);return this},limit:function(d,b,a){var c=this.length(d);if(b!==null&&ca){this.setLength(d,a)}}return this},dot:function(d,c){return d[0]*c[0]+d[1]*c[1]+d[2]*c[2]},normalise:function(a){return this.divideScalar(a,this.length(a))},negate:function(a){return this.multiplyScalar(a,-1)},distanceSquared:function(f,d){var g=f[0]-d[0];var e=f[1]-d[1];var c=f[2]-d[2];return g*g+e*e+c*c},distance:function(d,c){return Math.sqrt(this.distanceSquared(d,c))},lengthSquared:function(b){return b[0]*b[0]+b[1]*b[1]+b[2]*b[2]},length:function(b){return Math.sqrt(this.lengthSquared(b))},setLength:function(c,a){var b=this.length(c);if(b!==0&&a!==b){this.multiplyScalar(c,a/b)}return this},floor:function(a){a[0]=Math.floor(a[0]);a[1]=Math.floor(a[1]);a[2]=Math.floor(a[2]);return a}};FSS.Vector4={create:function(a,e,d,c){var b=new FSS.Array(4);this.set(b,a,e,d);return b},set:function(c,a,e,d,b){c[0]=a||0;c[1]=e||0;c[2]=d||0;c[3]=b||0;return this},setX:function(b,a){b[0]=a||0;return this},setY:function(a,b){a[1]=b||0;return this},setZ:function(a,b){a[2]=b||0;return this},setW:function(b,a){b[3]=a||0;return this},add:function(c,b){c[0]+=b[0];c[1]+=b[1];c[2]+=b[2];c[3]+=b[3];return this},multiplyVectors:function(e,d,c){e[0]=d[0]*c[0];e[1]=d[1]*c[1];e[2]=d[2]*c[2];e[3]=d[3]*c[3];return this},multiplyScalar:function(b,a){b[0]*=a;b[1]*=a;b[2]*=a;b[3]*=a;return this},min:function(b,a){if(b[0]a){b[0]=a}if(b[1]>a){b[1]=a}if(b[2]>a){b[2]=a}if(b[3]>a){b[3]=a}return this},clamp:function(c,b,a){this.min(c,b);this.max(c,a);return this}};FSS.Color=function(a,b){this.rgba=[];this.color=a||"#000000";this.opacity=FSS.Utils.isNumber(b)?b:1;this.set(this.color,this.opacity)};FSS.Color.prototype={set:function(a,c){if(a.indexOf("#")===-1){if(a.indexOf("rgb(")===0){var e=a.indexOf(",");this.rgba[0]=parseInt(a.substr(4,e));this.rgba[1]=parseInt(a.substr(e+1,a.indexOf(",",e)));this.rgba[2]=parseInt(a.substr(a.indexOf(",",e+1)+1,a.indexOf(")")));this.rgba[3]=1}else{if(a.indexOf("rgba(")===0){var e=a.indexOf(",");var b=a.indexOf(",",e+1);this.rgba[0]=parseInt(a.substr(5,e));this.rgba[1]=parseInt(a.substr(e+1,b));this.rgba[2]=parseInt(a.substr(a.indexOf(",",e+1)+1,a.indexOf(",",b)));this.rgba[3]=parseFloat(a.substr(a.indexOf(",",b+1)+1,a.indexOf(")")))}}}else{a=a.replace("#","");var d=a.length/3;this.rgba[0]=parseInt(a.substring(d*0,d*1),16)/255;this.rgba[1]=parseInt(a.substring(d*1,d*2),16)/255;this.rgba[2]=parseInt(a.substring(d*2,d*3),16)/255;this.rgba[3]=FSS.Utils.isNumber(c)?c:this.rgba[3]}return this},format:function(){return"rgba("+this.rgba[0]+","+this.rgba[1]+","+this.rgba[2]+","+this.rgba[3]+")"}};FSS.Object=function(){this.position=FSS.Vector3.create()};FSS.Object.prototype={setPosition:function(a,c,b){FSS.Vector3.set(this.position,a,c,b);return this}};FSS.Light=function(b,a){FSS.Object.call(this);this.ambient=new FSS.Color(b||"#FFFFFF");this.diffuse=new FSS.Color(a||"#FFFFFF");this.ray=FSS.Vector3.create()};FSS.Light.prototype=Object.create(FSS.Object.prototype);FSS.Vertex=function(a,c,b){this.position=FSS.Vector3.create(a,c,b)};FSS.Vertex.prototype={setPosition:function(a,c,b){FSS.Vector3.set(this.position,a,c,b);return this}};FSS.Triangle=function(e,d,f){this.a=e||new FSS.Vertex();this.b=d||new FSS.Vertex();this.c=f||new FSS.Vertex();this.vertices=[this.a,this.b,this.c];this.u=FSS.Vector3.create();this.v=FSS.Vector3.create();this.centroid=FSS.Vector3.create();this.normal=FSS.Vector3.create();this.color=new FSS.Color();this.polygon=document.createElementNS(FSS.SVGNS,"polygon");this.polygon.setAttributeNS(null,"stroke-linejoin","round");this.polygon.setAttributeNS(null,"stroke-miterlimit","1");this.polygon.setAttributeNS(null,"stroke-width","1");this.computeCentroid();this.computeNormal()};FSS.Triangle.prototype={computeCentroid:function(){this.centroid[0]=this.a.position[0]+this.b.position[0]+this.c.position[0];this.centroid[1]=this.a.position[1]+this.b.position[1]+this.c.position[1];this.centroid[2]=this.a.position[2]+this.b.position[2]+this.c.position[2];FSS.Vector3.divideScalar(this.centroid,3);return this},computeNormal:function(){FSS.Vector3.subtractVectors(this.u,this.b.position,this.a.position);FSS.Vector3.subtractVectors(this.v,this.c.position,this.a.position);FSS.Vector3.crossVectors(this.normal,this.u,this.v);FSS.Vector3.normalise(this.normal);return this}};FSS.Geometry=function(){this.vertices=[];this.triangles=[];this.dirty=false};FSS.Geometry.prototype={update:function(){if(this.dirty){var a,b;for(a=this.triangles.length-1;a>=0;a--){b=this.triangles[a];b.computeCentroid();b.computeNormal()}this.dirty=false}return this}};FSS.Plane=function(a,p,e,n){FSS.Geometry.call(this);this.width=a||100;this.height=p||100;this.segments=e||4;this.slices=n||4;this.segmentWidth=this.width/this.segments;this.sliceHeight=this.height/this.slices;var k,i,o,m,j,h,f,d,g=[],c=this.width*-0.5,b=this.height*0.5;for(k=0;k<=this.segments;k++){g.push([]);for(i=0;i<=this.slices;i++){f=new FSS.Vertex(c+k*this.segmentWidth,b-i*this.sliceHeight);g[k].push(f);this.vertices.push(f)}}for(k=0;k=0;j--){h=this.geometry.triangles[j];FSS.Vector4.set(h.color.rgba);for(c=e.length-1;c>=0;c--){f=e[c];FSS.Vector3.subtractVectors(f.ray,f.position,h.centroid);FSS.Vector3.normalise(f.ray);a=FSS.Vector3.dot(h.normal,f.ray);if(this.side===FSS.FRONT){a=Math.max(a,0)}else{if(this.side===FSS.BACK){a=Math.abs(Math.min(a,0))}else{if(this.side===FSS.DOUBLE){a=Math.max(Math.abs(a),0)}}}for(var g=0;g<3;g++){this.material.slave.rgba[g]=(((1/b)*this.material.ambient.rgba[g])*((1/b)*f.ambient.rgba[g]))/128;if(g!==3){this.material.slave.rgba[g]=Math.round(this.material.slave.rgba[g])}}FSS.Vector4.add(h.color.rgba,this.material.slave.rgba);for(var g=0;g<3;g++){this.material.slave.rgba[g]=((1/b)*this.material.diffuse.rgba[g]*(1/b)*f.diffuse.rgba[g])/128;if(g!==3){this.material.slave.rgba[g]=Math.round(this.material.slave.rgba[g])}}for(var g=0;g<3;g++){this.material.slave.rgba[g]=Math.round(this.material.slave.rgba[g]*a)}FSS.Vector4.add(h.color.rgba,this.material.slave.rgba)}FSS.Vector4.clamp(h.color.rgba,0,255);h.color.rgba[3]=this.material.diffuse.rgba[3]}}return this};FSS.Scene=function(){this.meshes=[];this.lights=[]};FSS.Scene.prototype={add:function(a){if(a instanceof FSS.Mesh&&!~this.meshes.indexOf(a)){this.meshes.push(a)}else{if(a instanceof FSS.Light&&!~this.lights.indexOf(a)){this.lights.push(a)}}return this},remove:function(a){if(a instanceof FSS.Mesh&&~this.meshes.indexOf(a)){this.meshes.splice(this.meshes.indexOf(a),1)}else{if(a instanceof FSS.Light&&~this.lights.indexOf(a)){this.lights.splice(this.lights.indexOf(a),1)}}return this}};FSS.Renderer=function(){this.width=0;this.height=0;this.halfWidth=0;this.halfHeight=0};FSS.Renderer.prototype={setSize:function(b,a){if(this.width===b&&this.height===a){return}this.width=b;this.height=a;this.halfWidth=this.width*0.5;this.halfHeight=this.height*0.5;return this},clear:function(){return this},render:function(a){return this}};FSS.CanvasRenderer=function(){FSS.Renderer.call(this);this.element=document.createElement("canvas");this.element.style.zIndex="-100";this.element.style.pointerEvents="none";this.context=this.element.getContext("2d");this.setSize(this.element.width,this.element.height)};FSS.CanvasRenderer.prototype=Object.create(FSS.Renderer.prototype);FSS.CanvasRenderer.prototype.setSize=function(b,a){FSS.Renderer.prototype.setSize.call(this,b,a);this.element.width=b;this.element.height=a;this.context.setTransform(1,0,0,1,0,0);return this};FSS.CanvasRenderer.prototype.clear=function(){FSS.Renderer.prototype.clear.call(this);this.context.clearRect(0,0,this.width,this.height);return this};var opacity=[];FSS.CanvasRenderer.prototype.render=function(f){FSS.Renderer.prototype.render.call(this,f);var b,k,j,g,d;var h=2*Math.PI;this.clear();this.context.lineJoin="round";this.context.lineWidth=0;for(b=f.meshes.length-1;b>=0;b--){k=f.meshes[b];if(typeof opacity[b]=="undefined"){opacity[b]=[]}if(k.visible){k.update(f.lights,true);for(j=k.geometry.triangles.length-1;j>=0;j--){var a=Date.now();if(typeof opacity[b][j]==="undefined"){opacity[b][j]={};opacity[b][j].step=FSS.Vector3.create(Math.randomInRange(0.2,1),Math.randomInRange(0.2,1),Math.randomInRange(0.2,1));opacity[b][j].time=Math.randomInRange(0,Math.PIM2);opacity[b][j].line=0}else{opacity[b][j].line=Math.sin(opacity[b][j].time+opacity[b][j].step[0]*a*(f.LINE.fluctuationSpeed/100))*f.LINE.fluctuationIntensity;opacity[b][j].vertex=Math.sin(opacity[b][j].time+opacity[b][j].step[0]*a*(f.VERTEX.fluctuationSpeed/100))*f.VERTEX.fluctuationIntensity;opacity[b][j].mesh=Math.sin(opacity[b][j].time+opacity[b][j].step[0]*a*(f.MESH.fluctuationSpeed/100))*f.MESH.fluctuationIntensity}g=k.geometry.triangles[j];if(f.MESH.draw!==false){i=g.color.rgba;d="rgba("+i[0]+","+i[1]+", "+i[2]+","+i[3]+")";this.context.beginPath();this.context.moveTo(g.a.position[0],g.a.position[1]);this.context.lineTo(g.b.position[0],g.b.position[1]);this.context.lineTo(g.c.position[0],g.c.position[1]);this.context.closePath();this.context.fillStyle=d;this.context.fill()}if(f.LINE.draw!==false){var i=new FSS.Color(f.LINE.fill);i=i.rgba;i[3]=i[3]*(1-opacity[b][j].line);i="rgba("+i[0]+","+i[1]+", "+i[2]+","+i[3]+")";this.context.beginPath();this.context.moveTo(g.a.position[0],g.a.position[1]);this.context.lineTo(g.b.position[0],g.b.position[1]);this.context.lineWidth=f.LINE.thickness;this.context.fillStyle=i;this.context.fill();this.context.strokeStyle=i;this.context.stroke()}if(f.VERTEX.draw!==false){var i=new FSS.Color(f.VERTEX.fill);i=i.rgba;i[3]=i[3]*(1-opacity[b][j].vertex);i="rgba("+i[0]+","+i[1]+", "+i[2]+","+i[3]+")";var e=new FSS.Color(f.VERTEX.strokeColor);e=e.rgba;e[3]=e[3]*(1-opacity[b][j].vertex);e="rgba("+e[0]+","+e[1]+", "+e[2]+","+e[3]+")";this.context.beginPath();this.context.arc(g.a.position[0],g.a.position[1],f.VERTEX.radius,0,h,false);this.context.fillStyle=i;this.context.fill();this.context.lineWidth=f.VERTEX.strokeWidth;this.context.strokeStyle=e;this.context.stroke()}}}}return this};FSS.WebGLRenderer=function(){FSS.Renderer.call(this);this.element=document.createElement("canvas");this.element.style.display="block";this.vertices=null;this.lights=null;var a={preserveDrawingBuffer:false,premultipliedAlpha:true,antialias:true,stencil:true,alpha:true};this.gl=this.getContext(this.element,a);this.unsupported=!this.gl;if(this.unsupported){return"WebGL is not supported by your browser."}else{this.gl.clearColor(0,0,0,0);this.gl.enable(this.gl.DEPTH_TEST);this.setSize(this.element.width,this.element.height)}};FSS.WebGLRenderer.prototype=Object.create(FSS.Renderer.prototype);FSS.WebGLRenderer.prototype.getContext=function(b,d){var c=false;try{if(!(c=b.getContext("experimental-webgl",d))){throw"Error creating WebGL context."}}catch(a){console.error(a)}return c};FSS.WebGLRenderer.prototype.setSize=function(b,a){FSS.Renderer.prototype.setSize.call(this,b,a);if(this.unsupported){return}this.element.width=b;this.element.height=a;this.gl.viewport(0,0,b,a);return this};FSS.WebGLRenderer.prototype.clear=function(){FSS.Renderer.prototype.clear.call(this);if(this.unsupported){return}this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT);return this};FSS.WebGLRenderer.prototype.render=function(u){FSS.Renderer.prototype.render.call(this,u);if(this.unsupported){return}var k,a,j,c,p,n,d,i,q,o,x,b,g=false,w=u.lights.length,f,h,s,r,e=0;this.clear();if(this.lights!==w){this.lights=w;if(this.lights>0){this.buildProgram(w)}else{return}}if(!!this.program){for(k=u.meshes.length-1;k>=0;k--){a=u.meshes[k];if(a.geometry.dirty){g=true}a.update(u.lights,false);e+=a.geometry.triangles.length*3}if(g||this.vertices!==e){this.vertices=e;for(i in this.program.attributes){o=this.program.attributes[i];o.data=new FSS.Array(e*o.size);f=0;for(k=u.meshes.length-1;k>=0;k--){a=u.meshes[k];for(j=0,c=a.geometry.triangles.length;j=0;n--){d=u.lights[n];this.setBufferData(n,this.program.uniforms.lightPosition,d.position);this.setBufferData(n,this.program.uniforms.lightAmbient,d.ambient.rgba);this.setBufferData(n,this.program.uniforms.lightDiffuse,d.diffuse.rgba)}for(q in this.program.uniforms){o=this.program.uniforms[q];b=o.location;x=o.data;switch(o.structure){case"3f":this.gl.uniform3f(b,x[0],x[1],x[2]);break;case"3fv":this.gl.uniform3fv(b,x);break;case"4fv":this.gl.uniform4fv(b,x);break}}}this.gl.drawArrays(this.gl.TRIANGLES,0,this.vertices);return this};FSS.WebGLRenderer.prototype.setBufferData=function(b,a,d){if(FSS.Utils.isNumber(d)){a.data[b*a.size]=d}else{for(var c=d.length-1;c>=0;c--){a.data[b*a.size+c]=d[c]}}};FSS.WebGLRenderer.prototype.buildProgram=function(d){if(this.unsupported){return}var i=FSS.WebGLRenderer.VS(d);var f=FSS.WebGLRenderer.FS(d);var a=i+f;if(!!this.program&&this.program.code===a){return}var e=this.gl.createProgram();var h=this.buildShader(this.gl.VERTEX_SHADER,i);var b=this.buildShader(this.gl.FRAGMENT_SHADER,f);this.gl.attachShader(e,h);this.gl.attachShader(e,b);this.gl.linkProgram(e);if(!this.gl.getProgramParameter(e,this.gl.LINK_STATUS)){var g=this.gl.getError();var c=this.gl.getProgramParameter(e,this.gl.VALIDATE_STATUS);console.error("Could not initialise shader.\nVALIDATE_STATUS: "+c+"\nERROR: "+g);return null}this.gl.deleteShader(b);this.gl.deleteShader(h);e.code=a;e.attributes={side:this.buildBuffer(e,"attribute","aSide",1,"f"),position:this.buildBuffer(e,"attribute","aPosition",3,"v3"),centroid:this.buildBuffer(e,"attribute","aCentroid",3,"v3"),normal:this.buildBuffer(e,"attribute","aNormal",3,"v3"),ambient:this.buildBuffer(e,"attribute","aAmbient",4,"v4"),diffuse:this.buildBuffer(e,"attribute","aDiffuse",4,"v4")};e.uniforms={resolution:this.buildBuffer(e,"uniform","uResolution",3,"3f",1),lightPosition:this.buildBuffer(e,"uniform","uLightPosition",3,"3fv",d),lightAmbient:this.buildBuffer(e,"uniform","uLightAmbient",4,"4fv",d),lightDiffuse:this.buildBuffer(e,"uniform","uLightDiffuse",4,"4fv",d)};this.program=e;this.gl.useProgram(this.program);return e};FSS.WebGLRenderer.prototype.buildShader=function(a,c){if(this.unsupported){return}var b=this.gl.createShader(a);this.gl.shaderSource(b,c);this.gl.compileShader(b);if(!this.gl.getShaderParameter(b,this.gl.COMPILE_STATUS)){console.error(this.gl.getShaderInfoLog(b));return null}return b};FSS.WebGLRenderer.prototype.buildBuffer=function(c,f,d,e,b,g){var a={buffer:this.gl.createBuffer(),size:e,structure:b,data:null};switch(f){case"attribute":a.location=this.gl.getAttribLocation(c,d);break;case"uniform":a.location=this.gl.getUniformLocation(c,d);break}if(!!g){a.data=new FSS.Array(g*e)}return a};FSS.WebGLRenderer.VS=function(a){var b=["precision mediump float;","#define LIGHTS "+a,"attribute float aSide;","attribute vec3 aPosition;","attribute vec3 aCentroid;","attribute vec3 aNormal;","attribute vec4 aAmbient;","attribute vec4 aDiffuse;","uniform vec3 uResolution;","uniform vec3 uLightPosition[LIGHTS];","uniform vec4 uLightAmbient[LIGHTS];","uniform vec4 uLightDiffuse[LIGHTS];","varying vec4 vColor;","void main() {","vColor = vec4(0.0);","vec3 position = aPosition / uResolution * 2.0;","for (int i = 0; i < LIGHTS; i++) {","vec3 lightPosition = uLightPosition[i];","vec4 lightAmbient = uLightAmbient[i];","vec4 lightDiffuse = uLightDiffuse[i];","vec3 ray = normalize(lightPosition - aCentroid);","float illuminance = dot(aNormal, ray);","if (aSide == 0.0) {","illuminance = max(illuminance, 0.0);","} else if (aSide == 1.0) {","illuminance = abs(min(illuminance, 0.0));","} else if (aSide == 2.0) {","illuminance = max(abs(illuminance), 0.0);","}","vColor += aAmbient * lightAmbient;","vColor += aDiffuse * lightDiffuse * illuminance;","}","vColor = clamp(vColor, 0.0, 1.0);","gl_Position = vec4(position, 1.0);","}"].join("\n");return b};FSS.WebGLRenderer.FS=function(a){var b=["precision mediump float;","varying vec4 vColor;","void main() {","gl_FragColor = vColor;","}"].join("\n");return b};FSS.SVGRenderer=function(){FSS.Renderer.call(this);this.element=document.createElementNS(FSS.SVGNS,"svg");this.element.setAttribute("xmlns",FSS.SVGNS);this.element.setAttribute("version","1.1");this.element.style.display="block";this.setSize(300,150)};FSS.SVGRenderer.prototype=Object.create(FSS.Renderer.prototype);FSS.SVGRenderer.prototype.setSize=function(b,a){FSS.Renderer.prototype.setSize.call(this,b,a);this.element.setAttribute("width",b);this.element.setAttribute("height",a);return this};FSS.SVGRenderer.prototype.clear=function(){FSS.Renderer.prototype.clear.call(this);for(var a=this.element.childNodes.length-1;a>=0;a--){this.element.removeChild(this.element.childNodes[a])}return this};FSS.SVGRenderer.prototype.render=function(f){FSS.Renderer.prototype.render.call(this,f);var a,g,b,e,d,c;for(a=f.meshes.length-1;a>=0;a--){g=f.meshes[a];if(g.visible){g.update(f.lights,true);for(b=g.geometry.triangles.length-1;b>=0;b--){e=g.geometry.triangles[b];if(e.polygon.parentNode!==this.element){this.element.appendChild(e.polygon)}d=this.formatPoint(e.a)+" ";d+=this.formatPoint(e.b)+" ";d+=this.formatPoint(e.c);c=this.formatStyle(e.color.format());e.polygon.setAttributeNS(null,"points",d);e.polygon.setAttributeNS(null,"style",c)}}}return this};FSS.SVGRenderer.prototype.formatPoint=function(a){return(a.position[0])+","+(a.position[1])};FSS.SVGRenderer.prototype.formatStyle=function(a){var b="fill:"+a+";";b+="stroke:"+a+";";return b};(function(){$.fn.Geometryangle=function(g){var e=[];var f=$(this);var b=f.length,c;for(var d=0;d=0;k--){aa=o.vertices[k];aa.anchor=FSS.Vector3.floor(FSS.Vector3.clone(aa.position));aa.step=FSS.Vector3.create(Math.randomInRange(0.2,1),Math.randomInRange(0.2,1),Math.randomInRange(0.2,1));aa.time=Math.randomInRange(0,Math.PIM2)}}function s(){var aa,k;for(aa=z.lights.length-1;aa>=0;aa--){k=z.lights[aa];z.remove(k)}H.clear();for(aa=0;aa=0;ak--){aj=o.vertices[ak];ad=Math.sin(aj.time+aj.step[0]*R*M.speed);ac=Math.cos(aj.time+aj.step[1]*R*M.speed);aa=Math.sin(aj.time+aj.step[2]*R*M.speed);aj.position=FSS.Vector3.create(M.xRange*o.segmentWidth*ad,M.yRange*o.sliceHeight*ac,M.zRange*ag*aa-ag);if(M.positionFloor===true){aj.position=FSS.Vector3.floor(aj.position)}FSS.Vector3.add(aj.position,aj.anchor);FSS.Vector3.add(aj.position,ab)}o.dirty=true}function D(){H.render(z);if(B.draw){var aa,ac,ab,k;for(aa=z.lights.length-1;aa>=0;aa--){k=z.lights[aa];ac=k.position[0];ab=k.position[1];switch(n.renderer){case L:H.context.lineWidth=0.5;H.context.beginPath();H.context.arc(ac,ab,10,0,Math.PIM2);H.context.strokeStyle=k.ambient;H.context.stroke();H.context.beginPath();H.context.arc(ac,ab,4,0,Math.PIM2);H.context.fillStyle=k.diffuse;H.context.fill();break;case C:k.core.setAttributeNS(null,"fill",k.diffuse);k.core.setAttributeNS(null,"cx",ac);k.core.setAttributeNS(null,"cy",ab);H.element.appendChild(k.core);k.ring.setAttributeNS(null,"stroke",k.ambient);k.ring.setAttributeNS(null,"cx",ac);k.ring.setAttributeNS(null,"cy",ab);H.element.appendChild(k.ring);break}}}M.onRender(z,H.context)}function v(){if(window.attachEvent){window.addEventHandler=window.attachEvent}window.addEventListener("resize",d,false);i.addEventListener("click",e,false);i.addEventListener("mousemove",b,true)}function e(k){FSS.Vector3.set(Q,k.x,k.y);B.autopilot=!B.autopilot}function b(k){console.log(k);FSS.Vector3.set(Q,k.x,k.y)}function d(k){f.resize(i.offsetWidth,i.offsetHeight);D()}t();return f}})();
--------------------------------------------------------------------------------