Best JavaScript code snippet using wpt
PhiloGL.js
Source:PhiloGL.js
1/**2@preserve3Copyright (c) 2011 Sencha Labs - Author: Nicolas Garcia Belmonte (http://philogb.github.com/)4Permission is hereby granted, free of charge, to any person obtaining a copy5of this software and associated documentation files (the "Software"), to deal6in the Software without restriction, including without limitation the rights7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell8copies of the Software, and to permit persons to whom the Software is9furnished to do so, subject to the following conditions:10The above copyright notice and this permission notice shall be included in11all copies or substantial portions of the Software.12THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR13IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,14FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE15AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER16LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,17OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN18THE SOFTWARE.19*/20(function() { 21//core.js22//Provides general utility methods, module unpacking methods and the PhiloGL app creation method.23//Global24this.PhiloGL = null;25//Creates a single application object asynchronously26//with a gl context, a camera, a program, a scene, and an event system.27(function () {28 PhiloGL = function(canvasId, opt) {29 opt = $.merge({30 context: {31 /*32 debug: true33 */34 },35 camera: {36 fov: 45,37 near: 0.1,38 far: 50039 },40 program: {41 from: 'defaults', //(defaults|ids|sources|uris)42 vs: 'Default',43 fs: 'Default'44 },45 scene: {46 /*47 All the scene.js options:48 lights: { ... }49 */50 },51 textures: {52 src: []53 },54 events: {55 /*56 All the events.js options:57 onClick: fn,58 onTouchStart: fn...59 */60 },61 onLoad: $.empty,62 onError: $.empty63 }, opt || {});64 var optContext = opt.context,65 optCamera = opt.camera,66 optEvents = opt.events,67 optTextures = opt.textures,68 optProgram = $.splat(opt.program),69 optScene = opt.scene;70 //get Context global to all framework71 gl = PhiloGL.WebGL.getContext(canvasId, optContext);72 if (!gl) {73 opt.onError("The WebGL context couldn't been initialized");74 return null;75 }76 //get Program77 var popt = {78 'defaults': 'fromDefaultShaders',79 'ids': 'fromShaderIds',80 'sources': 'fromShaderSources',81 'uris': 'fromShaderURIs'82 };83 var programLength = optProgram.length,84 programCallback = (function() {85 var count = programLength,86 programs = {},87 error = false;88 return {89 onSuccess: function(p, popt) {90 programs[popt.id || (programLength - count)] = p;91 count--;92 if (count === 0 && !error) {93 loadProgramDeps(gl, programLength == 1? p : programs, function(app) {94 opt.onLoad(app);95 });96 }97 },98 onError: function(p) {99 count--;100 opt.onError(p);101 error = true;102 }103 };104 })();105 optProgram.forEach(function(optProgram, i) {106 var pfrom = optProgram.from, program;107 for (var p in popt) {108 if (pfrom == p) {109 try {110 program = PhiloGL.Program[popt[p]]($.extend(programCallback, optProgram));111 } catch(e) {112 programCallback.onError(e);113 }114 break;115 }116 }117 if (program) {118 programCallback.onSuccess(program, optProgram);119 }120 });121 function loadProgramDeps(gl, program, callback) {122 //get Camera123 var canvas = gl.canvas,124 camera = new PhiloGL.Camera(optCamera.fov,125 canvas.width / canvas.height,126 optCamera.near,127 optCamera.far, optCamera);128 camera.update();129 //get Scene130 var scene = new PhiloGL.Scene(program, camera, optScene);131 //make app instance global to all framework132 app = new PhiloGL.WebGL.Application({133 gl: gl,134 canvas: canvas,135 program: program,136 scene: scene,137 camera: camera138 });139 //Use program140 if (program.$$family == 'program') {141 program.use();142 }143 //get Events144 if (optEvents) {145 PhiloGL.Events.create(app, $.extend(optEvents, {146 bind: app147 }));148 }149 //load Textures150 if (optTextures.src.length) {151 new PhiloGL.IO.Textures($.extend(optTextures, {152 onComplete: function() {153 callback(app);154 }155 }));156 } else {157 callback(app);158 }159 }160 };161})();162//Unpacks the submodules to the global space.163PhiloGL.unpack = function(branch) {164 branch = branch || globalContext;165 ['Vec3', 'Mat4', 'Quat', 'Camera', 'Program', 'WebGL', 'O3D',166 'Scene', 'Shaders', 'IO', 'Events', 'WorkerGroup', 'Fx', 'Media'].forEach(function(module) {167 branch[module] = PhiloGL[module];168 });169 branch.gl = gl;170 branch.Utils = $;171};172//Version173PhiloGL.version = '1.5.2';174//Holds the 3D context, holds the application175var gl, app, globalContext = this;176//Utility functions177function $(d) {178 return document.getElementById(d);179}180$.empty = function() {};181$.time = Date.now;182$.uid = (function() {183 var t = $.time();184 return function() {185 return t++;186 };187})();188$.extend = function(to, from) {189 for (var p in from) {190 to[p] = from[p];191 }192 return to;193};194$.type = (function() {195 var oString = Object.prototype.toString,196 type = function(e) {197 var t = oString.call(e);198 return t.substr(8, t.length - 9).toLowerCase();199 };200 return function(elem) {201 var elemType = type(elem);202 if (elemType != 'object') {203 return elemType;204 }205 if (elem.$$family) return elem.$$family;206 return (elem && elem.nodeName && elem.nodeType == 1) ? 'element' : elemType;207 };208})();209(function() {210 function detach(elem) {211 var type = $.type(elem), ans;212 if (type == 'object') {213 ans = {};214 for (var p in elem) {215 ans[p] = detach(elem[p]);216 }217 return ans;218 } else if (type == 'array') {219 ans = [];220 for (var i = 0, l = elem.length; i < l; i++) {221 ans[i] = detach(elem[i]);222 }223 return ans;224 } else {225 return elem;226 }227 }228 $.merge = function() {229 var mix = {};230 for (var i = 0, l = arguments.length; i < l; i++){231 var object = arguments[i];232 if ($.type(object) != 'object') continue;233 for (var key in object){234 var op = object[key], mp = mix[key];235 if (mp && $.type(op) == 'object' && $.type(mp) == 'object') {236 mix[key] = $.merge(mp, op);237 } else{238 mix[key] = detach(op);239 }240 }241 }242 return mix;243 };244})();245$.splat = (function() {246 var isArray = Array.isArray;247 return function(a) {248 return isArray(a) && a || [a];249 };250})();251//webgl.js252//Checks if WebGL is enabled and creates a context for using WebGL.253(function () {254 var WebGL = {255 getContext: function(canvas, opt) {256 var canvas = typeof canvas == 'string'? $(canvas) : canvas, ctx;257 ctx = canvas.getContext('experimental-webgl', opt);258 if (!ctx) {259 ctx = canvas.getContext('webgl', opt);260 }261 //Set as debug handler262 if (ctx && opt && opt.debug) {263 gl = {};264 for (var m in ctx) {265 var f = ctx[m];266 if (typeof f == 'function') {267 gl[m] = (function(k, v) {268 return function() {269 console.log(k, Array.prototype.join.call(arguments), Array.prototype.slice.call(arguments));270 try {271 var ans = v.apply(ctx, arguments);272 } catch (e) {273 throw k + " " + e;274 }275 var errorStack = [], error;276 while((error = ctx.getError()) !== ctx.NO_ERROR) {277 errorStack.push(error);278 }279 if (errorStack.length) {280 throw errorStack.join();281 }282 return ans;283 };284 })(m, f);285 } else {286 gl[m] = f;287 }288 }289 } else {290 gl = ctx;291 }292 //add a get by name param293 if (gl) {294 gl.get = function(name) {295 return typeof name == 'string'? gl[name] : name;296 };297 }298 return gl;299 }300 };301 function Application(options) {302 //copy program, scene, camera, etc.303 for (var prop in options) {304 this[prop] = options[prop];305 }306 //handle buffers307 this.buffers = {};308 this.bufferMemo = {};309 //handle framebuffers310 this.frameBuffers = {};311 this.frameBufferMemo = {};312 //handle renderbuffers313 this.renderBuffers = {};314 this.renderBufferMemo = {};315 //handle textures316 this.textures = {};317 this.textureMemo = {};318 }319 Application.prototype = {320 $$family: 'application',321 setBuffer: function(program, name, opt) {322 //unbind buffer323 if (opt === false || opt === null) {324 opt = this.bufferMemo[name];325 //reset buffer326 if(opt) {327 gl.bindBuffer(opt.bufferType, null);328 }329 //disable vertex attrib array if the buffer maps to an attribute.330 var attributeName = opt && opt.attribute || name,331 loc = program.attributes[attributeName];332 //disable the attribute array333 if (loc !== undefined) {334 gl.disableVertexAttribArray(loc);335 }336 return;337 }338 //set defaults339 opt = $.extend(this.bufferMemo[name] || {340 bufferType: gl.ARRAY_BUFFER,341 size: 1,342 dataType: gl.FLOAT,343 stride: 0,344 offset: 0,345 drawType: gl.STATIC_DRAW346 }, opt || {});347 var attributeName = opt.attribute || name,348 bufferType = opt.bufferType,349 hasBuffer = name in this.buffers,350 buffer = hasBuffer? this.buffers[name] : gl.createBuffer(),351 hasValue = 'value' in opt,352 value = opt.value,353 size = opt.size,354 dataType = opt.dataType,355 stride = opt.stride,356 offset = opt.offset,357 drawType = opt.drawType,358 loc = program.attributes[attributeName],359 isAttribute = loc !== undefined;360 if (!hasBuffer) {361 this.buffers[name] = buffer;362 }363 if (isAttribute) {364 gl.enableVertexAttribArray(loc);365 }366 gl.bindBuffer(bufferType, buffer);367 if (hasValue) {368 gl.bufferData(bufferType, value, drawType);369 }370 if (isAttribute) {371 gl.vertexAttribPointer(loc, size, dataType, false, stride, offset);372 }373 //set default options so we don't have to next time.374 //set them under the buffer name and attribute name (if an375 //attribute is defined)376 delete opt.value;377 this.bufferMemo[name] = opt;378 if (isAttribute) {379 this.bufferMemo[attributeName] = opt;380 }381 return this;382 },383 setBuffers: function(program, obj) {384 for (var name in obj) {385 this.setBuffer(program, name, obj[name]);386 }387 return this;388 },389 setFrameBuffer: function(name, opt) {390 //bind/unbind framebuffer391 if (typeof opt != 'object') {392 gl.bindFramebuffer(gl.FRAMEBUFFER, opt? this.frameBuffers[name] : null);393 return;394 }395 //get options396 opt = $.merge(this.frameBufferMemo[name] || {397 width: 0,398 height: 0,399 //All texture params400 bindToTexture: false,401 textureOptions: {402 attachment: gl.COLOR_ATTACHMENT0403 },404 //All render buffer params405 bindToRenderBuffer: false,406 renderBufferOptions: {407 attachment: gl.DEPTH_ATTACHMENT408 }409 }, opt || {});410 var bindToTexture = opt.bindToTexture,411 bindToRenderBuffer = opt.bindToRenderBuffer,412 hasBuffer = name in this.frameBuffers,413 frameBuffer = hasBuffer? this.frameBuffers[name] : gl.createFramebuffer();414 gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);415 if (!hasBuffer) {416 this.frameBuffers[name] = frameBuffer;417 }418 if (bindToTexture) {419 var texBindOpt = $.merge({420 data: {421 width: opt.width,422 height: opt.height423 }424 }, $.type(bindToTexture) == 'object'? bindToTexture : {}),425 texName = name + '-texture',426 texOpt = opt.textureOptions;427 this.setTexture(texName, texBindOpt);428 gl.framebufferTexture2D(gl.FRAMEBUFFER, texOpt.attachment, this.textureMemo[texName].textureType, this.textures[texName], 0);429 }430 if (bindToRenderBuffer) {431 var rbBindOpt = $.extend({432 width: opt.width,433 height: opt.height434 }, $.type(bindToRenderBuffer) == 'object'? bindToRenderBuffer : {}),435 rbName = name + '-renderbuffer',436 rbOpt = opt.renderBufferOptions;437 this.setRenderBuffer(rbName, rbBindOpt);438 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, rbOpt.attachment, gl.RENDERBUFFER, this.renderBuffers[rbName]);439 }440 gl.bindTexture(gl.TEXTURE_2D, null);441 gl.bindRenderbuffer(gl.RENDERBUFFER, null);442 gl.bindFramebuffer(gl.FRAMEBUFFER, null);443 this.frameBufferMemo[name] = opt;444 return this;445 },446 setFrameBuffers: function(obj) {447 for (var name in obj) {448 this.setFrameBuffer(name, obj[name]);449 }450 return this;451 },452 setRenderBuffer: function(name, opt) {453 if (typeof opt != 'object') {454 gl.bindRenderbuffer(gl.RENDERBUFFER, opt? this.renderBufferMemo[name] : null);455 return;456 }457 opt = $.extend(this.renderBufferMemo[name] || {458 storageType: gl.DEPTH_COMPONENT16,459 width: 0,460 height: 0461 }, opt || {});462 var hasBuffer = name in this.renderBuffers,463 renderBuffer = hasBuffer? this.renderBuffers[name] : gl.createRenderbuffer(gl.RENDERBUFFER);464 if (!hasBuffer) {465 this.renderBuffers[name] = renderBuffer;466 }467 gl.bindRenderbuffer(gl.RENDERBUFFER, renderBuffer);468 gl.renderbufferStorage(gl.RENDERBUFFER, opt.storageType, opt.width, opt.height);469 this.renderBufferMemo[name] = opt;470 return this;471 },472 setRenderBuffers: function(obj) {473 for (var name in obj) {474 this.setRenderBuffer(name, obj[name]);475 }476 return this;477 },478 setTexture: function(name, opt) {479 //bind texture480 if (!opt || typeof opt != 'object') {481 gl.activeTexture(opt || gl.TEXTURE0);482 gl.bindTexture(this.textureMemo[name].textureType || gl.TEXTURE_2D, this.textures[name]);483 return;484 }485 if (opt.data && opt.data.type === gl.FLOAT) {486 // Enable floating-point texture.487 if (!gl.getExtension('OES_texture_float')) {488 throw 'OES_texture_float is not supported';489 }490 }491 //get defaults492 opt = $.merge(this.textureMemo[name] || {493 textureType: gl.TEXTURE_2D,494 pixelStore: [{495 name: gl.UNPACK_FLIP_Y_WEBGL,496 value: true497 }, {498 name: gl.UNPACK_ALIGNMENT,499 value: 1500 }],501 parameters: [{502 name: gl.TEXTURE_MAG_FILTER,503 value: gl.NEAREST504 }, {505 name: gl.TEXTURE_MIN_FILTER,506 value: gl.NEAREST507 }, {508 name: gl.TEXTURE_WRAP_S,509 value: gl.CLAMP_TO_EDGE510 }, {511 name: gl.TEXTURE_WRAP_T,512 value: gl.CLAMP_TO_EDGE513 }],514 data: {515 format: gl.RGBA,516 value: false,517 type: gl.UNSIGNED_BYTE,518 width: 0,519 height: 0,520 border: 0521 }522 }, opt || {});523 var textureType = ('textureType' in opt)? opt.textureType = gl.get(opt.textureType) : gl.TEXTURE_2D,524 textureTarget = ('textureTarget' in opt)? opt.textureTarget = gl.get(opt.textureTarget) : textureType,525 isCube = textureType == gl.TEXTURE_CUBE_MAP,526 hasTexture = name in this.textures,527 texture = hasTexture? this.textures[name] : gl.createTexture(),528 pixelStore = opt.pixelStore,529 parameters = opt.parameters,530 data = opt.data,531 value = data.value,532 type = data.type,533 format = data.format,534 hasValue = !!data.value;535 //save texture536 if (!hasTexture) {537 this.textures[name] = texture;538 }539 gl.bindTexture(textureType, texture);540 if (!hasTexture) {541 //set texture properties542 pixelStore.forEach(function(opt) {543 opt.name = typeof opt.name == 'string'? gl.get(opt.name) : opt.name;544 gl.pixelStorei(opt.name, opt.value);545 });546 }547 //load texture548 if (hasValue) {549 //beware that we can be loading multiple textures (i.e. it could be a cubemap)550 if (isCube) {551 for (var i = 0; i < 6; ++i) {552 if ((data.width || data.height) && (!value.width && !value.height)) {553 gl.texImage2D(textureTarget[i], 0, format, data.width, data.height, data.border, format, type, value[i]);554 } else {555 gl.texImage2D(textureTarget[i], 0, format, format, type, value[i]);556 }557 }558 } else {559 if ((data.width || data.height) && (!value.width && !value.height)) {560 gl.texImage2D(textureTarget, 0, format, data.width, data.height, data.border, format, type, value);561 } else {562 gl.texImage2D(textureTarget, 0, format, format, type, value);563 }564 }565 //we're setting a texture to a framebuffer566 } else if (data.width || data.height) {567 gl.texImage2D(textureTarget, 0, format, data.width, data.height, data.border, format, type, null);568 }569 //set texture parameters570 if (!hasTexture) {571 for (i = 0; i < parameters.length ;i++) {572 var opti = parameters[i];573 opti.name = gl.get(opti.name);574 opti.value = gl.get(opti.value);575 gl.texParameteri(textureType, opti.name, opti.value);576 if (opti.generateMipmap) {577 gl.generateMipmap(textureType);578 }579 }580 }581 //remember whether the texture is a cubemap or not582 opt.isCube = isCube;583 //set default options so we don't have to next time.584 if (hasValue) {585 opt.data.value = false;586 }587 this.textureMemo[name] = opt;588 return this;589 },590 setTextures: function(obj) {591 for (var name in obj) {592 this.setTexture(name, obj[name]);593 }594 return this;595 },596 use: function(program) {597 gl.useProgram(program.program);598 //remember last used program.599 this.usedProgram = program;600 return this;601 }602 };603 WebGL.Application = Application;604 //Feature test WebGL605 (function() {606 try {607 var canvas = document.createElement('canvas');608 PhiloGL.hasWebGL = function() {609 return !!(window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));610 };611 } catch(e) {612 PhiloGL.hasWebGL = function() {613 return false;614 };615 }616 PhiloGL.hasExtension = function(name) {617 if (!PhiloGL.hasWebGL()) return false;618 var canvas = document.createElement('canvas');619 return (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')).getExtension(name);620 };621 })();622 PhiloGL.WebGL = WebGL;623})();624//math.js625//Vec3, Mat4 and Quat classes626(function() {627 var sqrt = Math.sqrt, 628 sin = Math.sin,629 cos = Math.cos,630 tan = Math.tan,631 pi = Math.PI,632 slice = Array.prototype.slice,633 typedArray = this.Float32Array,634 //As of version 12 Chrome does not support call/apply on typed array constructors.635 ArrayImpl = (function() {636 if (!typedArray || !typedArray.call) {637 return Array;638 }639 try {640 typedArray.call({}, 10);641 } catch (e) {642 return Array;643 }644 return typedArray;645 })(),646 typed = ArrayImpl != Array;647 //create property descriptor648 function descriptor(index) {649 return {650 get: function() {651 return this[index];652 },653 set: function(val) {654 this[index] = val;655 },656 configurable: false,657 enumerable: false658 };659 }660 //Vec3 Class661 var Vec3 = function(x, y, z) {662 if (typed) {663 typedArray.call(this, 3);664 this[0] = x || 0;665 this[1] = y || 0;666 this[2] = z || 0;667 } else {668 669 this.push(x || 0,670 y || 0,671 z || 0);672 }673 this.typedContainer = new typedArray(3);674 };675 //fast Vec3 create.676 Vec3.create = function() {677 return new typedArray(3);678 };679 //create fancy x, y, z setters and getters.680 Vec3.prototype = Object.create(ArrayImpl.prototype, {681 $$family: {682 value: 'Vec3'683 },684 685 x: descriptor(0),686 y: descriptor(1),687 z: descriptor(2)688 });689 var generics = {690 691 setVec3: function(dest, vec) {692 dest[0] = vec[0];693 dest[1] = vec[1];694 dest[2] = vec[2];695 return dest;696 },697 set: function(dest, x, y, z) {698 dest[0] = x;699 dest[1] = y;700 dest[2] = z;701 return dest;702 },703 704 add: function(dest, vec) {705 return new Vec3(dest[0] + vec[0],706 dest[1] + vec[1], 707 dest[2] + vec[2]);708 },709 710 $add: function(dest, vec) {711 dest[0] += vec[0];712 dest[1] += vec[1];713 dest[2] += vec[2];714 return dest;715 },716 717 add2: function(dest, a, b) {718 dest[0] = a[0] + b[0];719 dest[1] = a[1] + b[1];720 dest[2] = a[2] + b[2];721 return dest;722 },723 724 sub: function(dest, vec) {725 return new Vec3(dest[0] - vec[0],726 dest[1] - vec[1], 727 dest[2] - vec[2]);728 },729 730 $sub: function(dest, vec) {731 dest[0] -= vec[0];732 dest[1] -= vec[1];733 dest[2] -= vec[2];734 return dest;735 },736 737 sub2: function(dest, a, b) {738 dest[0] = a[0] - b[0];739 dest[1] = a[1] - b[1];740 dest[2] = a[2] - b[2];741 return dest;742 },743 744 scale: function(dest, s) {745 return new Vec3(dest[0] * s,746 dest[1] * s,747 dest[2] * s);748 },749 750 $scale: function(dest, s) {751 dest[0] *= s;752 dest[1] *= s;753 dest[2] *= s;754 return dest;755 },756 neg: function(dest) {757 return new Vec3(-dest[0],758 -dest[1],759 -dest[2]);760 },761 $neg: function(dest) {762 dest[0] = -dest[0];763 dest[1] = -dest[1];764 dest[2] = -dest[2];765 return dest;766 },767 unit: function(dest) {768 var len = Vec3.norm(dest);769 770 if (len > 0) {771 return Vec3.scale(dest, 1 / len);772 }773 return Vec3.clone(dest);774 },775 $unit: function(dest) {776 var len = Vec3.norm(dest);777 if (len > 0) {778 return Vec3.$scale(dest, 1 / len);779 }780 return dest;781 },782 783 cross: function(dest, vec) {784 var dx = dest[0],785 dy = dest[1],786 dz = dest[2],787 vx = vec[0],788 vy = vec[1],789 vz = vec[2];790 791 return new Vec3(dy * vz - dz * vy,792 dz * vx - dx * vz,793 dx * vy - dy * vx);794 },795 796 $cross: function(dest, vec) {797 var dx = dest[0],798 dy = dest[1],799 dz = dest[2],800 vx = vec[0],801 vy = vec[1],802 vz = vec[2];803 dest[0] = dy * vz - dz * vy;804 dest[1] = dz * vx - dx * vz;805 dest[2] = dx * vy - dy * vx;806 return dest;807 },808 distTo: function(dest, vec) {809 var dx = dest[0] - vec[0],810 dy = dest[1] - vec[1],811 dz = dest[2] - vec[2];812 813 return sqrt(dx * dx + 814 dy * dy + 815 dz * dz);816 },817 distToSq: function(dest, vec) {818 var dx = dest[0] - vec[0],819 dy = dest[1] - vec[1],820 dz = dest[2] - vec[2];821 return dx * dx + dy * dy + dz * dz;822 },823 norm: function(dest) {824 var dx = dest[0], dy = dest[1], dz = dest[2];825 return sqrt(dx * dx + dy * dy + dz * dz);826 },827 normSq: function(dest) {828 var dx = dest[0], dy = dest[1], dz = dest[2];829 return dx * dx + dy * dy + dz * dz;830 },831 dot: function(dest, vec) {832 return dest[0] * vec[0] + dest[1] * vec[1] + dest[2] * vec[2];833 },834 clone: function(dest) {835 if (dest.$$family) {836 return new Vec3(dest[0], dest[1], dest[2]);837 } else {838 return Vec3.setVec3(new typedArray(3), dest);839 }840 },841 toFloat32Array: function(dest) {842 var ans = dest.typedContainer;843 if (!ans) return dest;844 845 ans[0] = dest[0];846 ans[1] = dest[1];847 ans[2] = dest[2];848 return ans;849 }850 };851 852 //add generics and instance methods853 var proto = Vec3.prototype;854 for (var method in generics) {855 Vec3[method] = generics[method];856 proto[method] = (function (m) {857 return function() {858 var args = slice.call(arguments);859 860 args.unshift(this);861 return Vec3[m].apply(Vec3, args);862 };863 })(method);864 }865 //Mat4 Class866 var Mat4 = function(n11, n12, n13, n14,867 n21, n22, n23, n24,868 n31, n32, n33, n34,869 n41, n42, n43, n44) {870 871 ArrayImpl.call(this, 16);872 this.length = 16;873 874 if (typeof n11 == 'number') {875 876 this.set(n11, n12, n13, n14,877 n21, n22, n23, n24,878 n31, n32, n33, n34,879 n41, n42, n43, n44);880 881 } else {882 this.id();883 }884 this.typedContainer = new typedArray(16);885 };886 Mat4.create = function() {887 return new typedArray(16);888 };889 //create fancy components setters and getters.890 Mat4.prototype = Object.create(ArrayImpl.prototype, {891 892 $$family: {893 value: 'Mat4'894 },895 896 n11: descriptor(0),897 n12: descriptor(4),898 n13: descriptor(8),899 n14: descriptor(12),900 901 n21: descriptor(1),902 n22: descriptor(5),903 n23: descriptor(9),904 n24: descriptor(13),905 n31: descriptor(2),906 n32: descriptor(6),907 n33: descriptor(10),908 n34: descriptor(14),909 n41: descriptor(3),910 n42: descriptor(7),911 n43: descriptor(11),912 n44: descriptor(15)913 914 });915 generics = {916 917 id: function(dest) {918 919 dest[0 ] = 1;920 dest[1 ] = 0;921 dest[2 ] = 0;922 dest[3 ] = 0;923 dest[4 ] = 0;924 dest[5 ] = 1;925 dest[6 ] = 0;926 dest[7 ] = 0;927 dest[8 ] = 0;928 dest[9 ] = 0;929 dest[10] = 1;930 dest[11] = 0;931 dest[12] = 0;932 dest[13] = 0;933 dest[14] = 0;934 dest[15] = 1;935 936 return dest;937 },938 clone: function(dest) {939 if (dest.$$family) {940 return new Mat4(dest[0], dest[4], dest[8], dest[12],941 dest[1], dest[5], dest[9], dest[13],942 dest[2], dest[6], dest[10], dest[14],943 dest[3], dest[7], dest[11], dest[15]);944 } else {945 return new typedArray(dest);946 }947 },948 set: function(dest, n11, n12, n13, n14,949 n21, n22, n23, n24,950 n31, n32, n33, n34,951 n41, n42, n43, n44) {952 953 dest[0 ] = n11;954 dest[4 ] = n12;955 dest[8 ] = n13;956 dest[12] = n14;957 dest[1 ] = n21;958 dest[5 ] = n22;959 dest[9 ] = n23;960 dest[13] = n24;961 dest[2 ] = n31;962 dest[6 ] = n32;963 dest[10] = n33;964 dest[14] = n34;965 dest[3 ] = n41;966 dest[7 ] = n42;967 dest[11] = n43;968 dest[15] = n44;969 970 return dest;971 },972 mulVec3: function(dest, vec) {973 var ans = Vec3.clone(vec);974 return Mat4.$mulVec3(dest, ans);975 },976 $mulVec3: function(dest, vec) {977 var vx = vec[0],978 vy = vec[1],979 vz = vec[2],980 d = 1 / (dest[3] * vx + dest[7] * vy + dest[11] * vz + dest[15]);981 vec[0] = (dest[0] * vx + dest[4] * vy + dest[8 ] * vz + dest[12]) * d;982 vec[1] = (dest[1] * vx + dest[5] * vy + dest[9 ] * vz + dest[13]) * d;983 vec[2] = (dest[2] * vx + dest[6] * vy + dest[10] * vz + dest[14]) * d;984 return vec;985 },986 mulMat42: function(dest, a, b) {987 var a11 = a[0 ], a12 = a[1 ], a13 = a[2 ], a14 = a[3 ],988 a21 = a[4 ], a22 = a[5 ], a23 = a[6 ], a24 = a[7 ],989 a31 = a[8 ], a32 = a[9 ], a33 = a[10], a34 = a[11],990 a41 = a[12], a42 = a[13], a43 = a[14], a44 = a[15],991 b11 = b[0 ], b12 = b[1 ], b13 = b[2 ], b14 = b[3 ],992 b21 = b[4 ], b22 = b[5 ], b23 = b[6 ], b24 = b[7 ],993 b31 = b[8 ], b32 = b[9 ], b33 = b[10], b34 = b[11],994 b41 = b[12], b42 = b[13], b43 = b[14], b44 = b[15];995 dest[0 ] = b11 * a11 + b12 * a21 + b13 * a31 + b14 * a41;996 dest[1 ] = b11 * a12 + b12 * a22 + b13 * a32 + b14 * a42;997 dest[2 ] = b11 * a13 + b12 * a23 + b13 * a33 + b14 * a43;998 dest[3 ] = b11 * a14 + b12 * a24 + b13 * a34 + b14 * a44;999 dest[4 ] = b21 * a11 + b22 * a21 + b23 * a31 + b24 * a41;1000 dest[5 ] = b21 * a12 + b22 * a22 + b23 * a32 + b24 * a42;1001 dest[6 ] = b21 * a13 + b22 * a23 + b23 * a33 + b24 * a43;1002 dest[7 ] = b21 * a14 + b22 * a24 + b23 * a34 + b24 * a44;1003 dest[8 ] = b31 * a11 + b32 * a21 + b33 * a31 + b34 * a41;1004 dest[9 ] = b31 * a12 + b32 * a22 + b33 * a32 + b34 * a42;1005 dest[10] = b31 * a13 + b32 * a23 + b33 * a33 + b34 * a43;1006 dest[11] = b31 * a14 + b32 * a24 + b33 * a34 + b34 * a44;1007 dest[12] = b41 * a11 + b42 * a21 + b43 * a31 + b44 * a41;1008 dest[13] = b41 * a12 + b42 * a22 + b43 * a32 + b44 * a42;1009 dest[14] = b41 * a13 + b42 * a23 + b43 * a33 + b44 * a43;1010 dest[15] = b41 * a14 + b42 * a24 + b43 * a34 + b44 * a44;1011 return dest;1012 },1013 1014 mulMat4: function(a, b) {1015 var m = Mat4.clone(a);1016 return Mat4.mulMat42(m, a, b);1017 },1018 $mulMat4: function(a, b) {1019 return Mat4.mulMat42(a, a, b);1020 },1021 add: function(dest, m) {1022 var copy = Mat4.clone(dest);1023 return Mat4.$add(copy, m);1024 },1025 1026 $add: function(dest, m) {1027 dest[0 ] += m[0];1028 dest[1 ] += m[1];1029 dest[2 ] += m[2];1030 dest[3 ] += m[3];1031 dest[4 ] += m[4];1032 dest[5 ] += m[5];1033 dest[6 ] += m[6];1034 dest[7 ] += m[7];1035 dest[8 ] += m[8];1036 dest[9 ] += m[9];1037 dest[10] += m[10];1038 dest[11] += m[11];1039 dest[12] += m[12];1040 dest[13] += m[13];1041 dest[14] += m[14];1042 dest[15] += m[15];1043 1044 return dest;1045 },1046 transpose: function(dest) {1047 var m = Mat4.clone(dest);1048 return Mat4.$transpose(m);1049 },1050 $transpose: function(dest) {1051 var n4 = dest[4], n8 = dest[8], n12 = dest[12],1052 n1 = dest[1], n9 = dest[9], n13 = dest[13],1053 n2 = dest[2], n6 = dest[6], n14 = dest[14],1054 n3 = dest[3], n7 = dest[7], n11 = dest[11];1055 dest[1] = n4;1056 dest[2] = n8;1057 dest[3] = n12;1058 dest[4] = n1;1059 dest[6] = n9;1060 dest[7] = n13;1061 dest[8] = n2;1062 dest[9] = n6;1063 dest[11] = n14;1064 dest[12] = n3;1065 dest[13] = n7;1066 dest[14] = n11;1067 return dest;1068 },1069 rotateAxis: function(dest, theta, vec) {1070 var m = Mat4.clone(dest);1071 return Mat4.$rotateAxis(m, theta, vec);1072 },1073 $rotateAxis: function(dest, theta, vec) {1074 var s = sin(theta), 1075 c = cos(theta), 1076 nc = 1 - c,1077 vx = vec[0], 1078 vy = vec[1], 1079 vz = vec[2],1080 m11 = vx * vx * nc + c, 1081 m12 = vx * vy * nc + vz * s, 1082 m13 = vx * vz * nc - vy * s,1083 m21 = vy * vx * nc - vz * s, 1084 m22 = vy * vy * nc + c, 1085 m23 = vy * vz * nc + vx * s,1086 m31 = vx * vz * nc + vy * s, 1087 m32 = vy * vz * nc - vx * s, 1088 m33 = vz * vz * nc + c,1089 d11 = dest[0],1090 d12 = dest[1],1091 d13 = dest[2],1092 d14 = dest[3],1093 d21 = dest[4],1094 d22 = dest[5],1095 d23 = dest[6],1096 d24 = dest[7],1097 d31 = dest[8],1098 d32 = dest[9],1099 d33 = dest[10],1100 d34 = dest[11],1101 d41 = dest[12],1102 d42 = dest[13],1103 d43 = dest[14],1104 d44 = dest[15];1105 1106 dest[0 ] = d11 * m11 + d21 * m12 + d31 * m13;1107 dest[1 ] = d12 * m11 + d22 * m12 + d32 * m13;1108 dest[2 ] = d13 * m11 + d23 * m12 + d33 * m13;1109 dest[3 ] = d14 * m11 + d24 * m12 + d34 * m13;1110 dest[4 ] = d11 * m21 + d21 * m22 + d31 * m23;1111 dest[5 ] = d12 * m21 + d22 * m22 + d32 * m23;1112 dest[6 ] = d13 * m21 + d23 * m22 + d33 * m23;1113 dest[7 ] = d14 * m21 + d24 * m22 + d34 * m23;1114 dest[8 ] = d11 * m31 + d21 * m32 + d31 * m33;1115 dest[9 ] = d12 * m31 + d22 * m32 + d32 * m33;1116 dest[10] = d13 * m31 + d23 * m32 + d33 * m33;1117 dest[11] = d14 * m31 + d24 * m32 + d34 * m33;1118 return dest;1119 },1120 rotateXYZ: function(dest, rx, ry, rz) {1121 var ans = Mat4.clone(dest);1122 return Mat4.$rotateXYZ(ans, rx, ry, rz);1123 },1124 $rotateXYZ: function(dest, rx, ry, rz) {1125 var d11 = dest[0 ],1126 d12 = dest[1 ],1127 d13 = dest[2 ],1128 d14 = dest[3 ],1129 d21 = dest[4 ],1130 d22 = dest[5 ],1131 d23 = dest[6 ],1132 d24 = dest[7 ],1133 d31 = dest[8 ],1134 d32 = dest[9 ],1135 d33 = dest[10],1136 d34 = dest[11],1137 crx = cos(rx),1138 cry = cos(ry),1139 crz = cos(rz),1140 srx = sin(rx),1141 sry = sin(ry),1142 srz = sin(rz),1143 m11 = cry * crz,1144 m21 = -crx * srz + srx * sry * crz,1145 m31 = srx * srz + crx * sry * crz,1146 m12 = cry * srz, 1147 m22 = crx * crz + srx * sry * srz, 1148 m32 = -srx * crz + crx * sry * srz, 1149 m13 = -sry,1150 m23 = srx * cry,1151 m33 = crx * cry;1152 dest[0 ] = d11 * m11 + d21 * m12 + d31 * m13;1153 dest[1 ] = d12 * m11 + d22 * m12 + d32 * m13;1154 dest[2 ] = d13 * m11 + d23 * m12 + d33 * m13;1155 dest[3 ] = d14 * m11 + d24 * m12 + d34 * m13;1156 1157 dest[4 ] = d11 * m21 + d21 * m22 + d31 * m23;1158 dest[5 ] = d12 * m21 + d22 * m22 + d32 * m23;1159 dest[6 ] = d13 * m21 + d23 * m22 + d33 * m23;1160 dest[7 ] = d14 * m21 + d24 * m22 + d34 * m23;1161 1162 dest[8 ] = d11 * m31 + d21 * m32 + d31 * m33;1163 dest[9 ] = d12 * m31 + d22 * m32 + d32 * m33;1164 dest[10] = d13 * m31 + d23 * m32 + d33 * m33;1165 dest[11] = d14 * m31 + d24 * m32 + d34 * m33;1166 return dest;1167 },1168 translate: function(dest, x, y, z) {1169 var m = Mat4.clone(dest);1170 return Mat4.$translate(m, x, y, z);1171 },1172 $translate: function(dest, x, y, z) {1173 dest[12] = dest[0 ] * x + dest[4 ] * y + dest[8 ] * z + dest[12];1174 dest[13] = dest[1 ] * x + dest[5 ] * y + dest[9 ] * z + dest[13];1175 dest[14] = dest[2 ] * x + dest[6 ] * y + dest[10] * z + dest[14];1176 dest[15] = dest[3 ] * x + dest[7 ] * y + dest[11] * z + dest[15];1177 1178 return dest;1179 },1180 scale: function(dest, x, y, z) {1181 var m = Mat4.clone(dest);1182 return Mat4.$scale(m, x, y, z);1183 },1184 $scale: function(dest, x, y, z) {1185 dest[0 ] *= x;1186 dest[1 ] *= x;1187 dest[2 ] *= x;1188 dest[3 ] *= x;1189 dest[4 ] *= y;1190 dest[5 ] *= y;1191 dest[6 ] *= y;1192 dest[7 ] *= y;1193 dest[8 ] *= z;1194 dest[9 ] *= z;1195 dest[10] *= z;1196 dest[11] *= z;1197 1198 return dest;1199 },1200 //Method based on PreGL https://github.com/deanm/pregl/ (c) Dean McNamee.1201 invert: function(dest) {1202 var m = Mat4.clone(dest);1203 return Mat4.$invert(m);1204 },1205 $invert: function(dest) {1206 var x0 = dest[0], x1 = dest[1], x2 = dest[2], x3 = dest[3],1207 x4 = dest[4], x5 = dest[5], x6 = dest[6], x7 = dest[7],1208 x8 = dest[8], x9 = dest[9], x10 = dest[10], x11 = dest[11],1209 x12 = dest[12], x13 = dest[13], x14 = dest[14], x15 = dest[15];1210 var a0 = x0*x5 - x1*x4,1211 a1 = x0*x6 - x2*x4,1212 a2 = x0*x7 - x3*x4,1213 a3 = x1*x6 - x2*x5,1214 a4 = x1*x7 - x3*x5,1215 a5 = x2*x7 - x3*x6,1216 b0 = x8*x13 - x9*x12,1217 b1 = x8*x14 - x10*x12,1218 b2 = x8*x15 - x11*x12,1219 b3 = x9*x14 - x10*x13,1220 b4 = x9*x15 - x11*x13,1221 b5 = x10*x15 - x11*x14;1222 var invdet = 1 / (a0*b5 - a1*b4 + a2*b3 + a3*b2 - a4*b1 + a5*b0);1223 dest[0 ] = (+ x5*b5 - x6*b4 + x7*b3) * invdet;1224 dest[1 ] = (- x1*b5 + x2*b4 - x3*b3) * invdet;1225 dest[2 ] = (+ x13*a5 - x14*a4 + x15*a3) * invdet;1226 dest[3 ] = (- x9*a5 + x10*a4 - x11*a3) * invdet;1227 dest[4 ] = (- x4*b5 + x6*b2 - x7*b1) * invdet;1228 dest[5 ] = (+ x0*b5 - x2*b2 + x3*b1) * invdet;1229 dest[6 ] = (- x12*a5 + x14*a2 - x15*a1) * invdet;1230 dest[7 ] = (+ x8*a5 - x10*a2 + x11*a1) * invdet;1231 dest[8 ] = (+ x4*b4 - x5*b2 + x7*b0) * invdet;1232 dest[9 ] = (- x0*b4 + x1*b2 - x3*b0) * invdet;1233 dest[10] = (+ x12*a4 - x13*a2 + x15*a0) * invdet;1234 dest[11] = (- x8*a4 + x9*a2 - x11*a0) * invdet;1235 dest[12] = (- x4*b3 + x5*b1 - x6*b0) * invdet;1236 dest[13] = (+ x0*b3 - x1*b1 + x2*b0) * invdet;1237 dest[14] = (- x12*a3 + x13*a1 - x14*a0) * invdet;1238 dest[15] = (+ x8*a3 - x9*a1 + x10*a0) * invdet;1239 return dest;1240 },1241 //TODO(nico) breaking convention here... 1242 //because I don't think it's useful to add1243 //two methods for each of these.1244 lookAt: function(dest, eye, center, up) {1245 var z = Vec3.sub(eye, center);1246 z.$unit();1247 var x = Vec3.cross(up, z);1248 x.$unit();1249 var y = Vec3.cross(z, x);1250 y.$unit();1251 return Mat4.set(dest, x[0], x[1], x[2], -x.dot(eye),1252 y[0], y[1], y[2], -y.dot(eye),1253 z[0], z[1], z[2], -z.dot(eye),1254 0, 0, 0, 1);1255 },1256 frustum: function(dest, left, right, bottom, top, near, far) {1257 var rl = right - left,1258 tb = top - bottom,1259 fn = far - near;1260 1261 dest[0] = (near * 2) / rl;1262 dest[1] = 0;1263 dest[2] = 0;1264 dest[3] = 0;1265 dest[4] = 0;1266 dest[5] = (near * 2) / tb;1267 dest[6] = 0;1268 dest[7] = 0;1269 dest[8] = (right + left) / rl;1270 dest[9] = (top + bottom) / tb;1271 dest[10] = -(far + near) / fn;1272 dest[11] = -1;1273 dest[12] = 0;1274 dest[13] = 0;1275 dest[14] = -(far * near * 2) / fn;1276 dest[15] = 0;1277 return dest;1278 },1279 perspective: function(dest, fov, aspect, near, far) {1280 var ymax = near * tan(fov * pi / 360),1281 ymin = -ymax,1282 xmin = ymin * aspect,1283 xmax = ymax * aspect;1284 return Mat4.frustum(dest, xmin, xmax, ymin, ymax, near, far);1285 },1286 ortho: function(dest, left, right, bottom, top, near, far) {1287 var rl = right - left,1288 tb = top - bottom,1289 fn = far - near;1290 dest[0] = 2 / rl;1291 dest[1] = 0;1292 dest[2] = 0;1293 dest[3] = 0;1294 dest[4] = 0;1295 dest[5] = 2 / tb;1296 dest[6] = 0;1297 dest[7] = 0;1298 dest[8] = 0;1299 dest[9] = 0;1300 dest[10] = -2 / fn;1301 dest[11] = 0;1302 dest[12] = -(left + right) / rl;1303 dest[13] = -(top + bottom) / tb;1304 dest[14] = -(far + near) / fn;1305 dest[15] = 1;1306 return dest;1307 },1308 toFloat32Array: function(dest) {1309 var ans = dest.typedContainer;1310 if (!ans) return dest;1311 1312 ans[0] = dest[0];1313 ans[1] = dest[1];1314 ans[2] = dest[2];1315 ans[3] = dest[3];1316 ans[4] = dest[4];1317 ans[5] = dest[5];1318 ans[6] = dest[6];1319 ans[7] = dest[7];1320 ans[8] = dest[8];1321 ans[9] = dest[9];1322 ans[10] = dest[10];1323 ans[11] = dest[11];1324 ans[12] = dest[12];1325 ans[13] = dest[13];1326 ans[14] = dest[14];1327 ans[15] = dest[15];1328 return ans;1329 }1330 };1331 1332 //add generics and instance methods1333 proto = Mat4.prototype;1334 for (method in generics) {1335 Mat4[method] = generics[method];1336 proto[method] = (function (m) {1337 return function() {1338 var args = slice.call(arguments);1339 1340 args.unshift(this);1341 return Mat4[m].apply(Mat4, args);1342 };1343 })(method);1344 }1345 //Quaternion class1346 var Quat = function(x, y, z, w) {1347 ArrayImpl.call(this, 4);1348 this[0] = x || 0;1349 this[1] = y || 0;1350 this[2] = z || 0;1351 this[3] = w || 0;1352 this.typedContainer = new typedArray(4);1353 };1354 Quat.create = function() {1355 return new typedArray(4);1356 };1357 generics = {1358 setQuat: function(dest, q) {1359 dest[0] = q[0];1360 dest[1] = q[1];1361 dest[2] = q[2];1362 dest[3] = q[3];1363 return dest;1364 },1365 set: function(dest, x, y, z, w) {1366 dest[0] = x || 0;1367 dest[1] = y || 0;1368 dest[2] = z || 0;1369 dest[3] = w || 0;1370 return dest;1371 },1372 1373 clone: function(dest) {1374 if (dest.$$family) {1375 return new Quat(dest[0], dest[1], dest[2], dest[3]);1376 } else {1377 return Quat.setQuat(new typedArray(4), dest);1378 }1379 },1380 neg: function(dest) {1381 return new Quat(-dest[0], -dest[1], -dest[2], -dest[3]);1382 },1383 $neg: function(dest) {1384 dest[0] = -dest[0];1385 dest[1] = -dest[1];1386 dest[2] = -dest[2];1387 dest[3] = -dest[3];1388 1389 return dest;1390 },1391 add: function(dest, q) {1392 return new Quat(dest[0] + q[0],1393 dest[1] + q[1],1394 dest[2] + q[2],1395 dest[3] + q[3]);1396 },1397 $add: function(dest, q) {1398 dest[0] += q[0];1399 dest[1] += q[1];1400 dest[2] += q[2];1401 dest[3] += q[3];1402 1403 return dest;1404 },1405 sub: function(dest, q) {1406 return new Quat(dest[0] - q[0],1407 dest[1] - q[1],1408 dest[2] - q[2],1409 dest[3] - q[3]);1410 },1411 $sub: function(dest, q) {1412 dest[0] -= q[0];1413 dest[1] -= q[1];1414 dest[2] -= q[2];1415 dest[3] -= q[3];1416 1417 return dest;1418 },1419 scale: function(dest, s) {1420 return new Quat(dest[0] * s,1421 dest[1] * s,1422 dest[2] * s,1423 dest[3] * s);1424 },1425 $scale: function(dest, s) {1426 dest[0] *= s;1427 dest[1] *= s;1428 dest[2] *= s;1429 dest[3] *= s;1430 1431 return dest;1432 },1433 mulQuat: function(dest, q) {1434 var aX = dest[0],1435 aY = dest[1],1436 aZ = dest[2],1437 aW = dest[3],1438 bX = q[0],1439 bY = q[1],1440 bZ = q[2],1441 bW = q[3];1442 return new Quat(aW * bX + aX * bW + aY * bZ - aZ * bY,1443 aW * bY + aY * bW + aZ * bX - aX * bZ,1444 aW * bZ + aZ * bW + aX * bY - aY * bX,1445 aW * bW - aX * bX - aY * bY - aZ * bZ);1446 },1447 $mulQuat: function(dest, q) {1448 var aX = dest[0],1449 aY = dest[1],1450 aZ = dest[2],1451 aW = dest[3],1452 bX = q[0],1453 bY = q[1],1454 bZ = q[2],1455 bW = q[3];1456 dest[0] = aW * bX + aX * bW + aY * bZ - aZ * bY;1457 dest[1] = aW * bY + aY * bW + aZ * bX - aX * bZ;1458 dest[2] = aW * bZ + aZ * bW + aX * bY - aY * bX;1459 dest[3] = aW * bW - aX * bX - aY * bY - aZ * bZ;1460 return dest;1461 },1462 divQuat: function(dest, q) {1463 var aX = dest[0],1464 aY = dest[1],1465 aZ = dest[2],1466 aW = dest[3],1467 bX = q[0],1468 bY = q[1],1469 bZ = q[2],1470 bW = q[3];1471 var d = 1 / (bW * bW + bX * bX + bY * bY + bZ * bZ);1472 1473 return new Quat((aX * bW - aW * bX - aY * bZ + aZ * bY) * d,1474 (aX * bZ - aW * bY + aY * bW - aZ * bX) * d,1475 (aY * bX + aZ * bW - aW * bZ - aX * bY) * d,1476 (aW * bW + aX * bX + aY * bY + aZ * bZ) * d);1477 },1478 $divQuat: function(dest, q) {1479 var aX = dest[0],1480 aY = dest[1],1481 aZ = dest[2],1482 aW = dest[3],1483 bX = q[0],1484 bY = q[1],1485 bZ = q[2],1486 bW = q[3];1487 var d = 1 / (bW * bW + bX * bX + bY * bY + bZ * bZ);1488 1489 dest[0] = (aX * bW - aW * bX - aY * bZ + aZ * bY) * d;1490 dest[1] = (aX * bZ - aW * bY + aY * bW - aZ * bX) * d;1491 dest[2] = (aY * bX + aZ * bW - aW * bZ - aX * bY) * d;1492 dest[3] = (aW * bW + aX * bX + aY * bY + aZ * bZ) * d;1493 return dest;1494 },1495 invert: function(dest) {1496 var q0 = dest[0],1497 q1 = dest[1],1498 q2 = dest[2],1499 q3 = dest[3];1500 var d = 1 / (q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);1501 1502 return new Quat(-q0 * d, -q1 * d, -q2 * d, q3 * d);1503 },1504 $invert: function(dest) {1505 var q0 = dest[0],1506 q1 = dest[1],1507 q2 = dest[2],1508 q3 = dest[3];1509 var d = 1 / (q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);1510 dest[0] = -q0 * d;1511 dest[1] = -q1 * d;1512 dest[2] = -q2 * d;1513 dest[3] = q3 * d;1514 1515 return dest;1516 },1517 norm: function(dest) {1518 var a = dest[0],1519 b = dest[1],1520 c = dest[2],1521 d = dest[3];1522 return sqrt(a * a + b * b + c * c + d * d);1523 },1524 normSq: function(dest) {1525 var a = dest[0],1526 b = dest[1],1527 c = dest[2],1528 d = dest[3];1529 return a * a + b * b + c * c + d * d;1530 },1531 unit: function(dest) {1532 return Quat.scale(dest, 1 / Quat.norm(dest));1533 },1534 $unit: function(dest) {1535 return Quat.$scale(dest, 1 / Quat.norm(dest));1536 },1537 conjugate: function(dest) {1538 return new Quat(-dest[0],1539 -dest[1],1540 -dest[2],1541 dest[3]);1542 },1543 $conjugate: function(dest) {1544 dest[0] = -dest[0];1545 dest[1] = -dest[1];1546 dest[2] = -dest[2];1547 1548 return dest;1549 }1550 };1551 //add generics and instance methods1552 proto = Quat.prototype = {};1553 for (method in generics) {1554 Quat[method] = generics[method];1555 proto[method] = (function (m) {1556 return function() {1557 var args = slice.call(arguments);1558 1559 args.unshift(this);1560 return Quat[m].apply(Quat, args);1561 };1562 })(method);1563 }1564 1565 //Add static methods1566 Vec3.fromQuat = function(q) {1567 return new Vec3(q[0], q[1], q[2]);1568 };1569 Quat.fromVec3 = function(v, r) {1570 return new Quat(v[0], v[1], v[2], r || 0);1571 };1572 Quat.fromMat4 = function(m) {1573 var u;1574 var v;1575 var w;1576 // Choose u, v, and w such that u is the index of the biggest diagonal entry1577 // of m, and u v w is an even permutation of 0 1 and 2.1578 if (m[0] > m[5] && m[0] > m[10]) {1579 u = 0;1580 v = 1;1581 w = 2;1582 } else if (m[5] > m[0] && m[5] > m[10]) {1583 u = 1;1584 v = 2;1585 w = 0;1586 } else {1587 u = 2;1588 v = 0;1589 w = 1;1590 }1591 var r = sqrt(1 + m[u * 5] - m[v * 5] - m[w * 5]);1592 var q = new Quat;1593 1594 q[u] = 0.5 * r;1595 q[v] = 0.5 * (m['n' + v + '' + u] + m['n' + u + '' + v]) / r;1596 q[w] = 0.5 * (m['n' + u + '' + w] + m['n' + w + '' + u]) / r;1597 q[3] = 0.5 * (m['n' + v + '' + w] - m['n' + w + '' + v]) / r;1598 return q;1599 };1600 1601 Quat.fromXRotation = function(angle) {1602 return new Quat(sin(angle / 2), 0, 0, cos(angle / 2));1603 };1604 Quat.fromYRotation = function(angle) {1605 return new Quat(0, sin(angle / 2), 0, cos(angle / 2));1606 };1607 Quat.fromZRotation = function(angle) {1608 return new Quat(0, 0, sin(angle / 2), cos(angle / 2));1609 };1610 Quat.fromAxisRotation = function(vec, angle) {1611 var x = vec[0],1612 y = vec[1],1613 z = vec[2],1614 d = 1 / sqrt(x * x + y * y + z * z),1615 s = sin(angle / 2),1616 c = cos(angle / 2);1617 return new Quat(s * x * d,1618 s * y * d,1619 s * z * d,1620 c);1621 };1622 1623 Mat4.fromQuat = function(q) {1624 var a = q[3],1625 b = q[0],1626 c = q[1],1627 d = q[2];1628 1629 return new Mat4(a * a + b * b - c * c - d * d, 2 * b * c - 2 * a * d, 2 * b * d + 2 * a * c, 0,1630 2 * b * c + 2 * a * d, a * a - b * b + c * c - d * d, 2 * c * d - 2 * a * b, 0,1631 2 * b * d - 2 * a * c, 2 * c * d + 2 * a * b, a * a - b * b - c * c + d * d, 0,1632 0, 0, 0, 1);1633 };1634 PhiloGL.Vec3 = Vec3;1635 PhiloGL.Mat4 = Mat4;1636 PhiloGL.Quat = Quat;1637})();1638//event.js1639//Handle keyboard/mouse/touch events in the Canvas1640(function() {1641 1642 //returns an O3D object or false otherwise.1643 function toO3D(n) {1644 return n !== true ? n : false;1645 }1646 1647 //Returns an element position1648 var getPos = function(elem) {1649 var bbox = elem.getBoundingClientRect();1650 return {1651 x: bbox.left,1652 y: bbox.top,1653 bbox: bbox1654 };1655 };1656 //event object wrapper1657 var event = {1658 get: function(e, win) {1659 win = win || window;1660 return e || win.event;1661 },1662 getWheel: function(e) {1663 return e.wheelDelta? e.wheelDelta / 120 : -(e.detail || 0) / 3;1664 },1665 getKey: function(e) {1666 var code = e.which || e.keyCode;1667 var key = keyOf(code);1668 //onkeydown1669 var fKey = code - 111;1670 if (fKey > 0 && fKey < 13) key = 'f' + fKey;1671 key = key || String.fromCharCode(code).toLowerCase();1672 1673 return {1674 code: code,1675 key: key,1676 shift: e.shiftKey,1677 control: e.ctrlKey,1678 alt: e.altKey,1679 meta: e.metaKey1680 };1681 },1682 isRightClick: function(e) {1683 return (e.which == 3 || e.button == 2);1684 },1685 getPos: function(e, win) {1686 // get mouse position1687 win = win || window;1688 e = e || win.event;1689 var doc = win.document;1690 doc = doc.documentElement || doc.body;1691 //TODO(nico): make touch event handling better1692 if(e.touches && e.touches.length) {1693 e = e.touches[0];1694 }1695 var page = {1696 x: e.pageX || (e.clientX + doc.scrollLeft),1697 y: e.pageY || (e.clientY + doc.scrollTop)1698 };1699 return page;1700 },1701 stop: function(e) {1702 if (e.stopPropagation) e.stopPropagation();1703 e.cancelBubble = true;1704 if (e.preventDefault) e.preventDefault();1705 else e.returnValue = false;1706 }1707 };1708 var EventsProxy = function(app, opt) {1709 var domElem = app.canvas;1710 this.scene = app.scene;1711 this.domElem = domElem;1712 this.pos = getPos(domElem);1713 this.opt = this.callbacks = opt;1714 this.size = {1715 width: domElem.width || domElem.offsetWidth,1716 height: domElem.height || domElem.offsetHeight1717 };1718 this.attachEvents();1719 };1720 1721 EventsProxy.prototype = {1722 hovered: false,1723 pressed: false,1724 touched: false,1725 touchMoved: false,1726 moved: false,1727 1728 attachEvents: function() {1729 var domElem = this.domElem,1730 opt = this.opt,1731 that = this;1732 1733 if (opt.disableContextMenu) {1734 domElem.oncontextmenu = function() { return false; };1735 }1736 1737 ['mouseup', 'mousedown', 'mousemove', 'mouseover', 'mouseout', 1738 'touchstart', 'touchmove', 'touchend'].forEach(function(action) {1739 domElem.addEventListener(action, function(e, win) {1740 that[action](that.eventInfo(action, e, win));1741 }, false);1742 });1743 1744 ['keydown', 'keyup'].forEach(function(action) {1745 document.addEventListener(action, function(e, win) {1746 that[action](that.eventInfo(action, e, win));1747 }, false);1748 });1749 //"well, this is embarrassing..."1750 var type = '';1751 if (!document.getBoxObjectFor && window.mozInnerScreenX == null) {1752 type = 'mousewheel';1753 } else {1754 type = 'DOMMouseScroll';1755 }1756 domElem.addEventListener(type, function(e, win) {1757 that['mousewheel'](that.eventInfo('mousewheel', e, win));1758 }, false);1759 },1760 1761 eventInfo: function(type, e, win) {1762 var domElem = this.domElem,1763 scene = this.scene,1764 opt = this.opt,1765 size = this.getSize(),1766 relative = opt.relative,1767 centerOrigin = opt.centerOrigin,1768 pos = opt.cachePosition && this.pos || getPos(domElem),1769 ge = event.get(e, win),1770 epos = event.getPos(e, win),1771 evt = {};1772 //get Position1773 var x = epos.x, y = epos.y;1774 if (relative) {1775 x -= pos.x; y-= pos.y;1776 if (centerOrigin) {1777 x -= size.width / 2;1778 y -= size.height / 2;1779 y *= -1; //y axis now points to the top of the screen1780 }1781 }1782 switch (type) {1783 case 'mousewheel':1784 evt.wheel = event.getWheel(ge);1785 break;1786 case 'keydown':1787 case 'keyup':1788 $.extend(evt, event.getKey(ge));1789 break;1790 case 'mouseup':1791 evt.isRightClick = event.isRightClick(ge);1792 break;1793 }1794 var cacheTarget;1795 1796 $.extend(evt, {1797 x: x,1798 y: y,1799 cache: false,1800 //stop event propagation1801 stop: function() {1802 event.stop(ge);1803 },1804 //get the target element of the event1805 getTarget: function() {1806 if (cacheTarget) return cacheTarget;1807 return (cacheTarget = !opt.picking || scene.pick(epos.x - pos.x, epos.y - pos.y, opt.lazyPicking) || true);1808 }1809 });1810 //wrap native event1811 evt.event = ge;1812 1813 return evt;1814 },1815 getSize: function() {1816 if (this.cacheSize) {1817 return this.size;1818 }1819 var domElem = this.domElem;1820 return {1821 width: domElem.width || domElem.offsetWidth,1822 height: domElem.height || domElem.offsetHeight1823 };1824 },1825 1826 mouseup: function(e) {1827 if(!this.moved) {1828 if(e.isRightClick) {1829 this.callbacks.onRightClick(e, this.hovered);1830 } else {1831 this.callbacks.onClick(e, toO3D(this.pressed));1832 }1833 }1834 if(this.pressed) {1835 if(this.moved) {1836 this.callbacks.onDragEnd(e, toO3D(this.pressed));1837 } else {1838 this.callbacks.onDragCancel(e, toO3D(this.pressed));1839 }1840 this.pressed = this.moved = false;1841 }1842 },1843 mouseout: function(e) {1844 //mouseout canvas1845 var rt = e.relatedTarget,1846 domElem = this.domElem;1847 while(rt && rt.parentNode) {1848 if(domElem == rt.parentNode) return;1849 rt = rt.parentNode;1850 }1851 if(this.hovered) {1852 this.callbacks.onMouseLeave(e, this.hovered);1853 this.hovered = false;1854 }1855 if (this.pressed && this.moved) {1856 this.callbacks.onDragEnd(e);1857 this.pressed = this.moved = false;1858 }1859 },1860 1861 mouseover: function(e) {},1862 1863 mousemove: function(e) {1864 if(this.pressed) {1865 this.moved = true;1866 this.callbacks.onDragMove(e, toO3D(this.pressed));1867 return;1868 }1869 if(this.hovered) {1870 var target = toO3D(e.getTarget());1871 if(!target || target.hash != this.hash) {1872 this.callbacks.onMouseLeave(e, this.hovered);1873 this.hovered = target;1874 this.hash = target;1875 if(target) {1876 this.hash = target.hash;1877 this.callbacks.onMouseEnter(e, this.hovered);1878 }1879 } else {1880 this.callbacks.onMouseMove(e, this.hovered);1881 }1882 } else {1883 this.hovered = toO3D(e.getTarget());1884 this.hash = this.hovered;1885 if(this.hovered) {1886 this.hash = this.hovered.hash;1887 this.callbacks.onMouseEnter(e, this.hovered);1888 }1889 }1890 if (!this.opt.picking) {1891 this.callbacks.onMouseMove(e);1892 }1893 },1894 1895 mousewheel: function(e) {1896 this.callbacks.onMouseWheel(e);1897 },1898 1899 mousedown: function(e) {1900 this.pressed = e.getTarget();1901 this.callbacks.onDragStart(e, toO3D(this.pressed));1902 },1903 1904 touchstart: function(e) {1905 this.touched = e.getTarget();1906 this.callbacks.onTouchStart(e, toO3D(this.touched));1907 },1908 1909 touchmove: function(e) {1910 if(this.touched) {1911 this.touchMoved = true;1912 this.callbacks.onTouchMove(e, toO3D(this.touched));1913 }1914 },1915 1916 touchend: function(e) {1917 if(this.touched) {1918 if(this.touchMoved) {1919 this.callbacks.onTouchEnd(e, toO3D(this.touched));1920 } else {1921 this.callbacks.onTouchCancel(e, toO3D(this.touched));1922 }1923 this.touched = this.touchMoved = false;1924 }1925 },1926 keydown: function(e) {1927 this.callbacks.onKeyDown(e);1928 },1929 keyup: function(e) {1930 this.callbacks.onKeyUp(e);1931 }1932 };1933 1934 var Events = {};1935 Events.create = function(app, opt) {1936 opt = $.extend({1937 cachePosition: true,1938 cacheSize: true,1939 relative: true,1940 centerOrigin: true,1941 disableContextMenu: true,1942 bind: false,1943 picking: false,1944 lazyPicking: false,1945 1946 onClick: $.empty,1947 onRightClick: $.empty,1948 onDragStart: $.empty,1949 onDragMove: $.empty,1950 onDragEnd: $.empty,1951 onDragCancel: $.empty,1952 onTouchStart: $.empty,1953 onTouchMove: $.empty,1954 onTouchEnd: $.empty,1955 onTouchCancel: $.empty,1956 onMouseMove: $.empty,1957 onMouseEnter: $.empty,1958 onMouseLeave: $.empty,1959 onMouseWheel: $.empty,1960 onKeyDown: $.empty,1961 onKeyUp: $.empty1962 1963 }, opt || {});1964 var bind = opt.bind;1965 if (bind) {1966 for (var name in opt) {1967 if (name.match(/^on[a-zA-Z0-9]+$/)) {1968 (function (name, fn) {1969 opt[name] = function() {1970 return fn.apply(bind, Array.prototype.slice.call(arguments));1971 };1972 })(name, opt[name]);1973 }1974 }1975 }1976 new EventsProxy(app, opt);1977 //assign event handler to app.1978 app.events = opt;1979 };1980 Events.Keys = {1981 'enter': 13,1982 'up': 38,1983 'down': 40,1984 'left': 37,1985 'right': 39,1986 'esc': 27,1987 'space': 32,1988 'backspace': 8,1989 'tab': 9,1990 'delete': 461991 };1992 function keyOf(code) {1993 var keyMap = Events.Keys;1994 for (var name in keyMap) {1995 if (keyMap[name] == code) {1996 return name;1997 }1998 }1999 }2000 PhiloGL.Events = Events;2001 2002})();2003//program.js2004//Creates programs out of shaders and provides convenient methods for loading2005//buffers attributes and uniforms2006(function() {2007 //First, some privates to handle compiling/linking shaders to programs.2008 2009 //Creates a shader from a string source.2010 var createShader = function(gl, shaderSource, shaderType) {2011 var shader = gl.createShader(shaderType);2012 if (shader == null) {2013 throw "Error creating the shader with shader type: " + shaderType;2014 //return false;2015 }2016 gl.shaderSource(shader, shaderSource);2017 gl.compileShader(shader);2018 var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);2019 if (!compiled) {2020 var info = gl.getShaderInfoLog(shader);2021 gl.deleteShader(shader);2022 throw "Error while compiling the shader " + info;2023 //return false;2024 }2025 return shader;2026 };2027 2028 //Creates a program from vertex and fragment shader sources.2029 var createProgram = function(gl, vertexShader, fragmentShader) {2030 var program = gl.createProgram();2031 gl.attachShader(2032 program,2033 createShader(gl, vertexShader, gl.VERTEX_SHADER));2034 gl.attachShader(2035 program,2036 createShader(gl, fragmentShader, gl.FRAGMENT_SHADER));2037 linkProgram(gl, program);2038 return program;2039 };2040 2041 var getpath = function(path) {2042 var last = path.lastIndexOf('/');2043 if (last == '/') {2044 return './';2045 } else {2046 return path.substr(0, last + 1);2047 }2048 };2049 // preprocess a source with `#include ""` support2050 // `duplist` records all the pending replacements2051 var preprocess = function(base, source, callback, callbackError, duplist) {2052 duplist = duplist || {};2053 var match;2054 if ((match = source.match(/#include "(.*?)"/))) {2055 var xhr = PhiloGL.IO.XHR,2056 url = getpath(base) + match[1];2057 if (duplist[url]) {2058 callbackError('Recursive include');2059 }2060 new xhr({2061 url: url,2062 noCache: true,2063 onError: function(code) {2064 callbackError('Load included file `' + url + '` failed: Code ' + code);2065 },2066 onSuccess: function(response) {2067 duplist[url] = true;2068 return preprocess(url, response, function(replacement) {2069 delete duplist[url];2070 source = source.replace(/#include ".*?"/, replacement);2071 source = source.replace(/\sHAS_EXTENSION\s*\(\s*([A-Za-z_\-0-9]+)\s*\)/g, function (all, ext) {2072 return gl.getExtension(ext) ? ' 1 ': ' 0 ';2073 });2074 return preprocess(url, source, callback, callbackError, duplist);2075 }, callbackError, duplist);2076 }2077 }).send();2078 return null;2079 } else {2080 return callback(source);2081 }2082 }; 2083 //Link a program.2084 var linkProgram = function(gl, program) {2085 gl.linkProgram(program);2086 var linked = gl.getProgramParameter(program, gl.LINK_STATUS);2087 if (!linked) {2088 throw "Error linking the shader: " + gl.getProgramInfoLog(program);2089 //return false;2090 }2091 return true;2092 };2093 //Returns a Magic Uniform Setter2094 var getUniformSetter = function(program, info, isArray) {2095 var name = info.name,2096 loc = gl.getUniformLocation(program, name),2097 type = info.type,2098 matrix = false,2099 vector = true,2100 glFunction, typedArray;2101 if (info.size > 1 && isArray) {2102 switch(type) {2103 case gl.FLOAT:2104 glFunction = gl.uniform1fv;2105 typedArray = Float32Array;2106 vector = false;2107 break;2108 case gl.INT: case gl.BOOL: case gl.SAMPLER_2D: case gl.SAMPLER_CUBE:2109 glFunction = gl.uniform1iv;2110 typedArray = Uint16Array;2111 vector = false;2112 break;2113 }2114 }2115 2116 if (vector) {2117 switch (type) {2118 case gl.FLOAT:2119 glFunction = gl.uniform1f;2120 break;2121 case gl.FLOAT_VEC2:2122 glFunction = gl.uniform2fv;2123 typedArray = isArray ? Float32Array : new Float32Array(2);2124 break;2125 case gl.FLOAT_VEC3:2126 glFunction = gl.uniform3fv;2127 typedArray = isArray ? Float32Array : new Float32Array(3);2128 break;2129 case gl.FLOAT_VEC4:2130 glFunction = gl.uniform4fv;2131 typedArray = isArray ? Float32Array : new Float32Array(4);2132 break;2133 case gl.INT: case gl.BOOL: case gl.SAMPLER_2D: case gl.SAMPLER_CUBE:2134 glFunction = gl.uniform1i;2135 break;2136 case gl.INT_VEC2: case gl.BOOL_VEC2:2137 glFunction = gl.uniform2iv;2138 typedArray = isArray ? Uint16Array : new Uint16Array(2);2139 break;2140 case gl.INT_VEC3: case gl.BOOL_VEC3:2141 glFunction = gl.uniform3iv;2142 typedArray = isArray ? Uint16Array : new Uint16Array(3);2143 break;2144 case gl.INT_VEC4: case gl.BOOL_VEC4:2145 glFunction = gl.uniform4iv;2146 typedArray = isArray ? Uint16Array : new Uint16Array(4);2147 break;2148 case gl.FLOAT_MAT2:2149 matrix = true;2150 glFunction = gl.uniformMatrix2fv;2151 break;2152 case gl.FLOAT_MAT3:2153 matrix = true;2154 glFunction = gl.uniformMatrix3fv;2155 break;2156 case gl.FLOAT_MAT4:2157 matrix = true;2158 glFunction = gl.uniformMatrix4fv;2159 break;2160 }2161 }2162 //TODO(nico): Safari 5.1 doesn't have Function.prototype.bind.2163 //remove this check when they implement it.2164 if (glFunction.bind) {2165 glFunction = glFunction.bind(gl);2166 } else {2167 var target = glFunction;2168 glFunction = function() { target.apply(gl, arguments); };2169 }2170 //Set a uniform array2171 if (isArray && typedArray) {2172 return function(val) {2173 glFunction(loc, new typedArray(val));2174 };2175 2176 //Set a matrix uniform2177 } else if (matrix) {2178 return function(val) {2179 glFunction(loc, false, val.toFloat32Array());2180 };2181 2182 //Set a vector/typed array uniform2183 } else if (typedArray) {2184 return function(val) {2185 typedArray.set(val.toFloat32Array ? val.toFloat32Array() : val);2186 glFunction(loc, typedArray);2187 };2188 2189 //Set a primitive-valued uniform2190 } else {2191 return function(val) {2192 glFunction(loc, val);2193 };2194 }2195 // FIXME: Unreachable code2196 throw "Unknown type: " + type;2197 };2198 //Program Class: Handles loading of programs and mapping of attributes and uniforms2199 var Program = function(vertexShader, fragmentShader) {2200 var program = createProgram(gl, vertexShader, fragmentShader);2201 if (!program) return false;2202 2203 var attributes = {},2204 attributeEnabled = {},2205 uniforms = {},2206 info, name, index;2207 2208 //fill attribute locations2209 var len = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);2210 for (var i = 0; i < len; i++) {2211 info = gl.getActiveAttrib(program, i);2212 name = info.name;2213 index = gl.getAttribLocation(program, info.name);2214 attributes[name] = index;2215 }2216 2217 //create uniform setters2218 len = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);2219 for (i = 0; i < len; i++) {2220 info = gl.getActiveUniform(program, i);2221 name = info.name;2222 //if array name then clean the array brackets2223 name = name[name.length -1] == ']' ? name.substr(0, name.length -3) : name;2224 uniforms[name] = getUniformSetter(program, info, info.name != name);2225 }2226 this.program = program;2227 //handle attributes and uniforms2228 this.attributes = attributes;2229 this.attributeEnabled = attributeEnabled;2230 this.uniforms = uniforms;2231 };2232 Program.prototype = {2233 2234 $$family: 'program',2235 setUniform: function(name, val) {2236 if (this.uniforms[name]) {2237 this.uniforms[name](val);2238 }2239 return this;2240 },2241 setUniforms: function(obj) {2242 for (var name in obj) {2243 this.setUniform(name, obj[name]);2244 }2245 return this;2246 }2247 };2248 ['setBuffer', 'setBuffers', 'use'].forEach(function(name) {2249 Program.prototype[name] = function() {2250 var args = Array.prototype.slice.call(arguments);2251 args.unshift(this);2252 app[name].apply(app, args);2253 return this;2254 };2255 });2256 ['setFrameBuffer', 'setFrameBuffers', 'setRenderBuffer', 2257 'setRenderBuffers', 'setTexture', 'setTextures'].forEach(function(name) {2258 Program.prototype[name] = function() {2259 app[name].apply(app, arguments);2260 return this;2261 };2262 });2263 //Get options in object or arguments2264 function getOptions(args, base) {2265 var opt;2266 if (args.length == 2) {2267 opt = {2268 vs: args[0],2269 fs: args[1]2270 };2271 } else {2272 opt = args[0] || {};2273 }2274 return $.merge(base || {}, opt);2275 }2276 //Create a program from vertex and fragment shader node ids2277 Program.fromShaderIds = function() {2278 var opt = getOptions(arguments),2279 vs = $(opt.vs),2280 fs = $(opt.fs);2281 return preprocess(opt.path, vs.innerHTML, function(vectexShader) {2282 return preprocess(opt.path, fs.innerHTML, function(fragmentShader) {2283 opt.onSuccess(new Program(vectexShader, fragmentShader), opt);2284 });2285 });2286 };2287 //Create a program from vs and fs sources2288 Program.fromShaderSources = function() {2289 var opt = getOptions(arguments, {path: './'});2290 return preprocess(opt.path, opt.vs, function(vectexShader) {2291 return preprocess(opt.path, opt.fs, function(fragmentShader) {2292 try {2293 var program = new Program(vectexShader, fragmentShader);2294 if(opt.onSuccess) {2295 opt.onSuccess(program, opt); 2296 } else {2297 return program;2298 }2299 } catch(e) {2300 if (opt.onError) {2301 opt.onError(e, opt);2302 } else {2303 throw e;2304 }2305 }2306 });2307 });2308 };2309 //Build program from default shaders (requires Shaders)2310 Program.fromDefaultShaders = function(opt) {2311 opt = opt || {};2312 var vs = opt.vs || 'Default',2313 fs = opt.fs || 'Default',2314 sh = PhiloGL.Shaders;2315 opt.vs = sh.Vertex[vs];2316 opt.fs = sh.Fragment[fs];2317 return PhiloGL.Program.fromShaderSources(opt);2318 };2319 //Implement Program.fromShaderURIs (requires IO)2320 Program.fromShaderURIs = function(opt) {2321 opt = $.merge({2322 path: '',2323 vs: '',2324 fs: '',2325 noCache: false,2326 onSuccess: $.empty,2327 onError: $.empty2328 }, opt || {});2329 var vertexShaderURI = opt.path + opt.vs,2330 fragmentShaderURI = opt.path + opt.fs,2331 XHR = PhiloGL.IO.XHR;2332 new XHR.Group({2333 urls: [vertexShaderURI, fragmentShaderURI],2334 noCache: opt.noCache,2335 onError: function(arg) {2336 opt.onError(arg);2337 },2338 onComplete: function(ans) {2339 try {2340 return preprocess(vertexShaderURI, ans[0], function(vectexShader) {2341 return preprocess(fragmentShaderURI, ans[1], function(fragmentShader) {2342 opt.vs = vectexShader;2343 opt.fs = fragmentShader;2344 return Program.fromShaderSources(opt);2345 }, opt.onError);2346 }, opt.onError);2347 } catch (e) {2348 opt.onError(e, opt);2349 }2350 }2351 }).send();2352 };2353 PhiloGL.Program = Program;2354})();2355//io.js2356//Provides loading of assets with XHR and JSONP methods.2357(function () {2358 var IO = {};2359 var XHR = function(opt) {2360 opt = $.merge({2361 url: 'http://philogljs.org/',2362 method: 'GET',2363 async: true,2364 noCache: false,2365 //body: null,2366 sendAsBinary: false,2367 responseType: false,2368 onProgress: $.empty,2369 onSuccess: $.empty,2370 onError: $.empty,2371 onAbort: $.empty,2372 onComplete: $.empty2373 }, opt || {});2374 this.opt = opt;2375 this.initXHR();2376 };2377 XHR.State = {};2378 ['UNINITIALIZED', 'LOADING', 'LOADED', 'INTERACTIVE', 'COMPLETED'].forEach(function(stateName, i) {2379 XHR.State[stateName] = i;2380 });2381 XHR.prototype = {2382 initXHR: function() {2383 var req = this.req = new XMLHttpRequest(),2384 that = this;2385 ['Progress', 'Error', 'Abort', 'Load'].forEach(function(event) {2386 if (req.addEventListener) {2387 req.addEventListener(event.toLowerCase(), function(e) {2388 that['handle' + event](e);2389 }, false);2390 } else {2391 req['on' + event.toLowerCase()] = function(e) {2392 that['handle' + event](e);2393 };2394 }2395 });2396 },2397 2398 send: function(body) {2399 var req = this.req,2400 opt = this.opt,2401 async = opt.async;2402 2403 if (opt.noCache) {2404 opt.url += (opt.url.indexOf('?') >= 0? '&' : '?') + $.uid();2405 }2406 req.open(opt.method, opt.url, async);2407 if (opt.responseType) {2408 req.responseType = opt.responseType;2409 }2410 2411 if (async) {2412 req.onreadystatechange = function(e) {2413 if (req.readyState == XHR.State.COMPLETED) {2414 if (req.status == 200) {2415 opt.onSuccess(req.responseType ? req.response : req.responseText);2416 } else {2417 opt.onError(req.status);2418 }2419 }2420 };2421 }2422 2423 if (opt.sendAsBinary) {2424 req.sendAsBinary(body || opt.body || null);2425 } else {2426 req.send(body || opt.body || null);2427 }2428 if (!async) {2429 if (req.status == 200) {2430 opt.onSuccess(req.responseType ? req.response : req.responseText);2431 } else {2432 opt.onError(req.status);2433 }2434 }2435 },2436 setRequestHeader: function(header, value) {2437 this.req.setRequestHeader(header, value);2438 return this;2439 },2440 handleProgress: function(e) {2441 if (e.lengthComputable) {2442 this.opt.onProgress(e, Math.round(e.loaded / e.total * 100));2443 } else {2444 this.opt.onProgress(e, -1);2445 }2446 },2447 handleError: function(e) {2448 this.opt.onError(e);2449 },2450 handleAbort: function() {2451 this.opt.onAbort(e);2452 },2453 handleLoad: function(e) {2454 this.opt.onComplete(e);2455 }2456 };2457 //Make parallel requests and group the responses.2458 XHR.Group = function(opt) {2459 opt = $.merge({2460 urls: [],2461 onError: $.empty,2462 onSuccess: $.empty,2463 onComplete: $.empty,2464 method: 'GET',2465 async: true,2466 noCache: false,2467 //body: null,2468 sendAsBinary: false,2469 responseType: false2470 }, opt || {});2471 var urls = $.splat(opt.urls),2472 len = urls.length,2473 ans = new Array(len),2474 reqs = urls.map(function(url, i) {2475 return new XHR({2476 url: url,2477 method: opt.method,2478 async: opt.async,2479 noCache: opt.noCache,2480 sendAsBinary: opt.sendAsBinary,2481 responseType: opt.responseType,2482 body: opt.body,2483 //add callbacks2484 onError: handleError(i),2485 onSuccess: handleSuccess(i)2486 });2487 });2488 function handleError(i) {2489 return function(e) {2490 --len;2491 opt.onError(e, i);2492 2493 if (!len) opt.onComplete(ans);2494 };2495 }2496 function handleSuccess(i) {2497 return function(response) {2498 --len;2499 ans[i] = response;2500 opt.onSuccess(response, i);2501 if (!len) opt.onComplete(ans);2502 };2503 }2504 this.reqs = reqs;2505 };2506 XHR.Group.prototype = {2507 send: function() {2508 for (var i = 0, reqs = this.reqs, l = reqs.length; i < l; ++i) {2509 reqs[i].send();2510 }2511 }2512 };2513 var JSONP = function(opt) {2514 opt = $.merge({2515 url: 'http://philogljs.org/',2516 data: {},2517 noCache: false,2518 onComplete: $.empty,2519 callbackKey: 'callback'2520 }, opt || {});2521 2522 var index = JSONP.counter++;2523 //create query string2524 var data = [];2525 for(var prop in opt.data) {2526 data.push(prop + '=' + opt.data[prop]);2527 }2528 data = data.join('&');2529 //append unique id for cache2530 if (opt.noCache) {2531 data += (data.indexOf('?') >= 0? '&' : '?') + $.uid();2532 }2533 //create source url2534 var src = opt.url + 2535 (opt.url.indexOf('?') > -1 ? '&' : '?') +2536 opt.callbackKey + '=PhiloGL.IO.JSONP.requests.request_' + index +2537 (data.length > 0 ? '&' + data : '');2538 //create script2539 var script = document.createElement('script');2540 script.type = 'text/javascript';2541 script.src = src;2542 //create callback2543 JSONP.requests['request_' + index] = function(json) {2544 opt.onComplete(json);2545 //remove script2546 if(script.parentNode) {2547 script.parentNode.removeChild(script);2548 }2549 if(script.clearAttributes) {2550 script.clearAttributes();2551 } 2552 };2553 //inject script2554 document.getElementsByTagName('head')[0].appendChild(script);2555 };2556 JSONP.counter = 0;2557 JSONP.requests = {};2558 //Load multiple Image assets async2559 var Images = function(opt) {2560 opt = $.merge({2561 src: [],2562 noCache: false,2563 onProgress: $.empty,2564 onComplete: $.empty2565 }, opt || {});2566 var count = 0, l = opt.src.length;2567 //Image onload handler2568 var load = function() {2569 opt.onProgress(Math.round(++count / l * 100));2570 if (count == l) {2571 opt.onComplete(images);2572 }2573 };2574 //Image error handler2575 var error = function() {2576 if (++count == l) {2577 opt.onComplete(images);2578 }2579 };2580 //uid for image sources2581 var noCache = opt.noCache,2582 uid = $.uid(),2583 getSuffix = function(s) { return (s.indexOf('?') >= 0? '&' : '?') + uid; };2584 //Create image array2585 var images = opt.src.map(function(src, i) {2586 var img = new Image();2587 img.index = i;2588 img.onload = load;2589 img.onerror = error;2590 img.src = src + (noCache? getSuffix(src) : '');2591 return img;2592 });2593 return images;2594 };2595 //Load multiple textures from images2596 var Textures = function(opt) {2597 opt = $.merge({2598 src: [],2599 noCache: false,2600 onComplete: $.empty2601 }, opt || {});2602 Images({2603 src: opt.src,2604 noCache: opt.noCache,2605 onComplete: function(images) {2606 var textures = {};2607 images.forEach(function(img, i) {2608 textures[opt.id && opt.id[i] || opt.src && opt.src[i]] = $.merge({2609 data: {2610 value: img2611 }2612 }, opt);2613 });2614 app.setTextures(textures);2615 opt.onComplete();2616 }2617 });2618 };2619 2620 IO.XHR = XHR;2621 IO.JSONP = JSONP;2622 IO.Images = Images;2623 IO.Textures = Textures;2624 PhiloGL.IO = IO;2625})();2626//camera.js2627//Provides a Camera with ModelView and Projection matrices2628(function () {2629 //Define some locals2630 var Vec3 = PhiloGL.Vec3,2631 Mat4 = PhiloGL.Mat4;2632 //Camera class2633 var Camera = function(fov, aspect, near, far, opt) {2634 opt = opt || {};2635 var pos = opt.position,2636 target = opt.target,2637 up = opt.up;2638 this.type = opt.type ? opt.type : 'perspective';2639 this.fov = fov;2640 this.near = near;2641 this.far = far;2642 this.aspect = aspect;2643 this.position = pos && new Vec3(pos.x, pos.y, pos.z) || new Vec3();2644 this.target = target && new Vec3(target.x, target.y, target.z) || new Vec3();2645 this.up = up && new Vec3(up.x, up.y, up.z) || new Vec3(0, 1, 0);2646 if (this.type == 'perspective') {2647 this.projection = new Mat4().perspective(fov, aspect, near, far);2648 } else {2649 var ymax = near * Math.tan(fov * Math.PI / 360),2650 ymin = -ymax,2651 xmin = ymin * aspect,2652 xmax = ymax * aspect;2653 this.projection = new Mat4().ortho(xmin, xmax, ymin, ymax, near, far);2654 }2655 this.view = new Mat4();2656 };2657 Camera.prototype = {2658 2659 update: function() {2660 if (this.type == 'perspective') {2661 this.projection = new Mat4().perspective(this.fov, this.aspect, this.near, this.far);2662 } else {2663 var ymax = this.near * Math.tan(this.fov * Math.PI / 360),2664 ymin = -ymax,2665 xmin = ymin * this.aspect,2666 xmax = ymax * this.aspect;2667 this.projection = new Mat4().ortho(xmin, xmax, ymin, ymax, this.near, this.far);2668 }2669 this.view.lookAt(this.position, this.target, this.up); 2670 },2671 //Set Camera view and projection matrix2672 setStatus: function (program) {2673 var camera = this,2674 pos = camera.position,2675 view = camera.view,2676 projection = camera.projection,2677 viewProjection = view.mulMat4(projection),2678 viewProjectionInverse = viewProjection.invert();2679 program.setUniforms({2680 cameraPosition: [pos.x, pos.y, pos.z],2681 projectionMatrix: projection,2682 viewMatrix: view,2683 viewProjectionMatrix: viewProjection,2684 viewInverseMatrix: view.invert(),2685 viewProjectionInverseMatrix: viewProjectionInverse2686 }); 2687 }2688 2689 };2690 PhiloGL.Camera = Camera;2691})();2692//o3d.js2693//Scene Objects2694(function () {2695 //Define some locals2696 var Vec3 = PhiloGL.Vec3,2697 Mat4 = PhiloGL.Mat4,2698 cos = Math.cos,2699 sin = Math.sin,2700 pi = Math.PI,2701 max = Math.max,2702 slice = Array.prototype.slice;2703 function normalizeColors(arr, len) {2704 if (arr && arr.length < len) {2705 var a0 = arr[0],2706 a1 = arr[1],2707 a2 = arr[2],2708 a3 = arr[3],2709 ans = [a0, a1, a2, a3],2710 times = len / arr.length,2711 index;2712 while (--times) {2713 index = times * 4;2714 ans[index ] = a0;2715 ans[index + 1] = a1;2716 ans[index + 2] = a2;2717 ans[index + 3] = a3;2718 }2719 return new Float32Array(ans);2720 } else {2721 return arr;2722 }2723 }2724 //Model repository2725 var O3D = {2726 //map attribute names to property names2727 //TODO(nico): textures are treated separately.2728 attributeMap: {2729 'position': 'vertices',2730 'normal': 'normals',2731 'pickingColor': 'pickingColors',2732 'colors': 'color'2733 }2734 };2735 //Model abstract O3D Class2736 O3D.Model = function(opt) {2737 opt = opt || {};2738 this.id = opt.id || $.uid();2739 //picking options2740 this.pickable = !!opt.pickable;2741 this.pick = opt.pick || function() { return false; };2742 this.vertices = opt.vertices;2743 this.normals = opt.normals;2744 this.textures = opt.textures && $.splat(opt.textures);2745 this.colors = opt.colors;2746 this.indices = opt.indices;2747 this.shininess = opt.shininess || 0;2748 this.reflection = opt.reflection || 0;2749 this.refraction = opt.refraction || 0;2750 if (opt.pickingColors) {2751 this.pickingColors = opt.pickingColors;2752 }2753 if (opt.texCoords) {2754 this.texCoords = opt.texCoords;2755 }2756 //extra uniforms2757 this.uniforms = opt.uniforms || {};2758 //extra attribute descriptors2759 this.attributes = opt.attributes || {};2760 //override the render method2761 this.render = opt.render;2762 //whether to render as triangles, lines, points, etc.2763 this.drawType = opt.drawType || 'TRIANGLES';2764 //whether to display the object at all2765 this.display = 'display' in opt? opt.display : true;2766 //before and after render callbacks2767 this.onBeforeRender = opt.onBeforeRender || $.empty;2768 this.onAfterRender = opt.onAfterRender || $.empty;2769 //set a custom program per o3d2770 if (opt.program) {2771 this.program = opt.program;2772 }2773 //model position, rotation, scale and all in all matrix2774 this.position = new Vec3;2775 this.rotation = new Vec3;2776 this.scale = new Vec3(1, 1, 1);2777 this.matrix = new Mat4;2778 if (opt.computeCentroids) {2779 this.computeCentroids();2780 }2781 if (opt.computeNormals) {2782 this.computeNormals();2783 }2784 };2785 //Buffer setter mixin2786 var Setters = {2787 setUniforms: function(program) {2788 program.setUniforms(this.uniforms);2789 },2790 setAttributes: function(program) {2791 var attributes = this.attributes;2792 for (var name in attributes) {2793 var descriptor = attributes[name],2794 bufferId = this.id + '-' + name;2795 if (!Object.keys(descriptor).length) {2796 program.setBuffer(bufferId, true);2797 } else {2798 descriptor.attribute = name;2799 program.setBuffer(bufferId, descriptor);2800 delete descriptor.value;2801 }2802 }2803 },2804 setVertices: function(program) {2805 if (!this.$vertices) return;2806 if (this.dynamic) {2807 program.setBuffer('position-' + this.id, {2808 attribute: 'position',2809 value: this.$vertices,2810 size: 32811 });2812 } else {2813 program.setBuffer('position-' + this.id);2814 }2815 },2816 setNormals: function(program) {2817 if (!this.$normals) return;2818 if (this.dynamic) {2819 program.setBuffer('normal-' + this.id, {2820 attribute: 'normal',2821 value: this.$normals,2822 size: 32823 });2824 } else {2825 program.setBuffer('normal-' + this.id);2826 }2827 },2828 setIndices: function(program) {2829 if (!this.$indices) return;2830 if (this.dynamic) {2831 program.setBuffer('indices-' + this.id, {2832 bufferType: gl.ELEMENT_ARRAY_BUFFER,2833 drawType: gl.STATIC_DRAW,2834 value: this.$indices,2835 size: 12836 });2837 } else {2838 program.setBuffer('indices-' + this.id);2839 }2840 },2841 setPickingColors: function(program) {2842 if (!this.$pickingColors) return;2843 if (this.dynamic) {2844 program.setBuffer('pickingColor-' + this.id, {2845 attribute: 'pickingColor',2846 value: this.$pickingColors,2847 size: 42848 });2849 } else {2850 program.setBuffer('pickingColor-' + this.id);2851 }2852 },2853 setColors: function(program) {2854 if (!this.$colors) return;2855 if (this.dynamic) {2856 program.setBuffer('color-' + this.id, {2857 attribute: 'color',2858 value: this.$colors,2859 size: 42860 });2861 } else {2862 program.setBuffer('color-' + this.id);2863 }2864 },2865 setTexCoords: function(program) {2866 if (!this.$texCoords) return;2867 var id = this.id,2868 i, txs, l, tex;2869 if (this.dynamic) {2870 //If is an object containing textureName -> textureCoordArray2871 //Set all textures, samplers and textureCoords.2872 if ($.type(this.$texCoords) == 'object') {2873 for (i = 0, txs = this.textures, l = txs.length; i < l; i++) {2874 tex = txs[i];2875 program.setBuffer('texCoord-' + i + '-' + id, {2876 attribute: 'texCoord' + (i + 1),2877 value: this.$texCoords[tex],2878 size: 22879 });2880 }2881 //An array of textureCoordinates2882 } else {2883 program.setBuffer('texCoord-' + id, {2884 attribute: 'texCoord1',2885 value: this.$texCoords,2886 size: 22887 });2888 }2889 } else {2890 if ($.type(this.$texCoords) == 'object') {2891 for (i = 0, txs = this.textures, l = txs.length; i < l; i++) {2892 program.setBuffer('texCoord-' + i + '-' + id);2893 }2894 } else {2895 program.setBuffer('texCoord-' + id);2896 }2897 }2898 },2899 setTextures: function(program, force) {2900 this.textures = this.textures? $.splat(this.textures) : [];2901 var dist = 5;2902 for (var i = 0, texs = this.textures, l = texs.length, mtexs = PhiloGL.Scene.MAX_TEXTURES; i < mtexs; i++) {2903 if (i < l) {2904 var isCube = app.textureMemo[texs[i]].isCube;2905 if (isCube) {2906 program.setUniform('hasTextureCube' + (i + 1), true);2907 program.setTexture(texs[i], gl['TEXTURE' + (i + dist)]);2908 } else {2909 program.setUniform('hasTexture' + (i + 1), true);2910 program.setTexture(texs[i], gl['TEXTURE' + i]);2911 }2912 } else {2913 program.setUniform('hasTextureCube' + (i + 1), false);2914 program.setUniform('hasTexture' + (i + 1), false);2915 }2916 program.setUniform('sampler' + (i + 1), i);2917 program.setUniform('samplerCube' + (i + 1), i + dist);2918 }2919 },2920 setState: function(program) {2921 this.setUniforms(program);2922 this.setAttributes(program);2923 this.setVertices(program);2924 this.setColors(program);2925 this.setPickingColors(program);2926 this.setNormals(program);2927 this.setTextures(program);2928 this.setTexCoords(program);2929 this.setIndices(program);2930 },2931 unsetState: function(program) {2932 var attributes = program.attributes;2933 //unbind the array and element buffers2934 gl.bindBuffer(gl.ARRAY_BUFFER, null);2935 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);2936 for (var name in attributes) {2937 gl.disableVertexAttribArray(attributes[name]);2938 }2939 }2940 };2941 //ensure known attributes use typed arrays2942 O3D.Model.prototype = Object.create(null, {2943 hash: {2944 get: function() {2945 return this.id + ' ' + this.$pickingIndex;2946 }2947 },2948 vertices: {2949 set: function(val) {2950 if (!val) {2951 delete this.$vertices;2952 delete this.$verticesLength;2953 return;2954 }2955 var vlen = val.length;2956 if (val.BYTES_PER_ELEMENT) {2957 this.$vertices = val;2958 } else {2959 if (this.$verticesLength == vlen) {2960 this.$vertices.set(val);2961 } else {2962 this.$vertices = new Float32Array(val);2963 }2964 }2965 this.$verticesLength = vlen;2966 },2967 get: function() {2968 return this.$vertices;2969 }2970 },2971 normals: {2972 set: function(val) {2973 if (!val) {2974 delete this.$normals;2975 delete this.$normalsLength;2976 return;2977 }2978 var vlen = val.length;2979 if (val.BYTES_PER_ELEMENT) {2980 this.$normals = val;2981 } else {2982 if (this.$normalsLength == vlen) {2983 this.$normals.set(val);2984 } else {2985 this.$normals = new Float32Array(val);2986 }2987 }2988 this.$normalsLength = vlen;2989 },2990 get: function() {2991 return this.$normals;2992 }2993 },2994 colors: {2995 set: function(val) {2996 if (!val) {2997 delete this.$colors;2998 delete this.$colorsLength;2999 return;3000 }3001 var vlen = val.length;3002 if (val.BYTES_PER_ELEMENT) {3003 this.$colors = val;3004 } else {3005 if (this.$colorsLength == vlen) {3006 this.$colors.set(val);3007 } else {3008 this.$colors = new Float32Array(val);3009 }3010 }3011 if (this.$vertices && this.$verticesLength / 3 * 4 != vlen) {3012 this.$colors = normalizeColors(slice.call(this.$colors), this.$verticesLength / 3 * 4);3013 }3014 this.$colorsLength = this.$colors.length;3015 },3016 get: function() {3017 return this.$colors;3018 }3019 },3020 pickingColors: {3021 set: function(val) {3022 if (!val) {3023 delete this.$pickingColors;3024 delete this.$pickingColorsLength;3025 return;3026 }3027 var vlen = val.length;3028 if (val.BYTES_PER_ELEMENT) {3029 this.$pickingColors = val;3030 } else {3031 if (this.$pickingColorsLength == vlen) {3032 this.$pickingColors.set(val);3033 } else {3034 this.$pickingColors = new Float32Array(val);3035 }3036 }3037 if (this.$vertices && this.$verticesLength / 3 * 4 != vlen) {3038 this.$pickingColors = normalizeColors(slice.call(this.$pickingColors), this.$verticesLength / 3 * 4);3039 }3040 this.$pickingColorsLength = this.$pickingColors.length;3041 },3042 get: function() {3043 return this.$pickingColors;3044 }3045 },3046 texCoords: {3047 set: function(val) {3048 if (!val) {3049 delete this.$texCoords;3050 delete this.$texCoordsLength;3051 return;3052 }3053 if ($.type(val) == 'object') {3054 var ans = {};3055 for (var prop in val) {3056 var texCoordArray = val[prop];3057 ans[prop] = texCoordArray.BYTES_PER_ELEMENT ? texCoordArray : new Float32Array(texCoordArray);3058 }3059 this.$texCoords = ans;3060 } else {3061 var vlen = val.length;3062 if (val.BYTES_PER_ELEMENT) {3063 this.$texCoords = val;3064 } else {3065 if (this.$texCoordsLength == vlen) {3066 this.$texCoords.set(val);3067 } else {3068 this.$texCoords = new Float32Array(val);3069 }3070 }3071 this.$texCoordsLength = vlen;3072 }3073 },3074 get: function() {3075 return this.$texCoords;3076 }3077 },3078 indices: {3079 set: function(val) {3080 if (!val) {3081 delete this.$indices;3082 delete this.$indicesLength;3083 return;3084 }3085 var vlen = val.length;3086 if (val.BYTES_PER_ELEMENT) {3087 this.$indices = val;3088 } else {3089 if (this.$indicesLength == vlen) {3090 this.$indices.set(val);3091 } else {3092 this.$indices = new Uint16Array(val);3093 }3094 }3095 this.$indicesLength = vlen;3096 },3097 get: function() {3098 return this.$indices;3099 }3100 }3101 });3102 $.extend(O3D.Model.prototype, {3103 $$family: 'model',3104 update: function() {3105 var matrix = this.matrix,3106 pos = this.position,3107 rot = this.rotation,3108 scale = this.scale;3109 matrix.id();3110 matrix.$translate(pos.x, pos.y, pos.z);3111 matrix.$rotateXYZ(rot.x, rot.y, rot.z);3112 matrix.$scale(scale.x, scale.y, scale.z);3113 },3114 computeCentroids: function() {3115 var faces = this.faces,3116 vertices = this.vertices,3117 centroids = [];3118 faces.forEach(function(face) {3119 var centroid = [0, 0, 0],3120 acum = 0;3121 face.forEach(function(idx) {3122 var vertex = vertices[idx];3123 centroid[0] += vertex[0];3124 centroid[1] += vertex[1];3125 centroid[2] += vertex[2];3126 acum++;3127 });3128 centroid[0] /= acum;3129 centroid[1] /= acum;3130 centroid[2] /= acum;3131 centroids.push(centroid);3132 });3133 this.centroids = centroids;3134 },3135 computeNormals: function() {3136 var faces = this.faces,3137 vertices = this.vertices,3138 normals = [];3139 faces.forEach(function(face) {3140 var v1 = vertices[face[0]],3141 v2 = vertices[face[1]],3142 v3 = vertices[face[2]],3143 dir1 = {3144 x: v3[0] - v2[0],3145 y: v3[1] - v2[1],3146 z: v3[1] - v2[2]3147 },3148 dir2 = {3149 x: v1[0] - v2[0],3150 y: v1[1] - v2[1],3151 z: v1[2] - v2[2]3152 };3153 Vec3.$cross(dir2, dir1);3154 if (Vec3.norm(dir2) > 1e-6) {3155 Vec3.unit(dir2);3156 }3157 normals.push([dir2.x, dir2.y, dir2.z]);3158 });3159 this.normals = normals;3160 }3161 });3162 //Apply our Setters mixin3163 $.extend(O3D.Model.prototype, Setters);3164 //Now some primitives, Cube, Sphere, Cone, Cylinder3165 //Cube3166 O3D.Cube = function(config) {3167 O3D.Model.call(this, $.extend({3168 vertices: [-1, -1, 1,3169 1, -1, 1,3170 1, 1, 1,3171 -1, 1, 1,3172 -1, -1, -1,3173 -1, 1, -1,3174 1, 1, -1,3175 1, -1, -1,3176 -1, 1, -1,3177 -1, 1, 1,3178 1, 1, 1,3179 1, 1, -1,3180 -1, -1, -1,3181 1, -1, -1,3182 1, -1, 1,3183 -1, -1, 1,3184 1, -1, -1,3185 1, 1, -1,3186 1, 1, 1,3187 1, -1, 1,3188 -1, -1, -1,3189 -1, -1, 1,3190 -1, 1, 1,3191 -1, 1, -1],3192 texCoords: [0.0, 0.0,3193 1.0, 0.0,3194 1.0, 1.0,3195 0.0, 1.0,3196 // Back face3197 1.0, 0.0,3198 1.0, 1.0,3199 0.0, 1.0,3200 0.0, 0.0,3201 // Top face3202 0.0, 1.0,3203 0.0, 0.0,3204 1.0, 0.0,3205 1.0, 1.0,3206 // Bottom face3207 1.0, 1.0,3208 0.0, 1.0,3209 0.0, 0.0,3210 1.0, 0.0,3211 // Right face3212 1.0, 0.0,3213 1.0, 1.0,3214 0.0, 1.0,3215 0.0, 0.0,3216 // Left face3217 0.0, 0.0,3218 1.0, 0.0,3219 1.0, 1.0,3220 0.0, 1.0],3221 normals: [3222 // Front face3223 0.0, 0.0, 1.0,3224 0.0, 0.0, 1.0,3225 0.0, 0.0, 1.0,3226 0.0, 0.0, 1.0,3227 // Back face3228 0.0, 0.0, -1.0,3229 0.0, 0.0, -1.0,3230 0.0, 0.0, -1.0,3231 0.0, 0.0, -1.0,3232 // Top face3233 0.0, 1.0, 0.0,3234 0.0, 1.0, 0.0,3235 0.0, 1.0, 0.0,3236 0.0, 1.0, 0.0,3237 // Bottom face3238 0.0, -1.0, 0.0,3239 0.0, -1.0, 0.0,3240 0.0, -1.0, 0.0,3241 0.0, -1.0, 0.0,3242 // Right face3243 1.0, 0.0, 0.0,3244 1.0, 0.0, 0.0,3245 1.0, 0.0, 0.0,3246 1.0, 0.0, 0.0,3247 // Left face3248 -1.0, 0.0, 0.0,3249 -1.0, 0.0, 0.0,3250 -1.0, 0.0, 0.0,3251 -1.0, 0.0, 0.03252 ],3253 indices: [0, 1, 2, 0, 2, 3,3254 4, 5, 6, 4, 6, 7,3255 8, 9, 10, 8, 10, 11,3256 12, 13, 14, 12, 14, 15,3257 16, 17, 18, 16, 18, 19,3258 20, 21, 22, 20, 22, 23]3259 }, config || {}));3260 };3261 O3D.Cube.prototype = Object.create(O3D.Model.prototype);3262 //Primitives constructors inspired by TDL http://code.google.com/p/webglsamples/,3263 //copyright 2011 Google Inc. new BSD License (http://www.opensource.org/licenses/bsd-license.php).3264 O3D.Sphere = function(opt) {3265 var nlat = opt.nlat || 10,3266 nlong = opt.nlong || 10,3267 radius = opt.radius || 1,3268 startLat = 0,3269 endLat = pi,3270 latRange = endLat - startLat,3271 startLong = 0,3272 endLong = 2 * pi,3273 longRange = endLong - startLong,3274 numVertices = (nlat + 1) * (nlong + 1),3275 vertices = new Float32Array(numVertices * 3),3276 normals = new Float32Array(numVertices * 3),3277 texCoords = new Float32Array(numVertices * 2),3278 indices = new Uint16Array(nlat * nlong * 6);3279 if (typeof radius == 'number') {3280 var value = radius;3281 radius = function(n1, n2, n3, u, v) {3282 return value;3283 };3284 }3285 //Create vertices, normals and texCoords3286 for (var y = 0; y <= nlat; y++) {3287 for (var x = 0; x <= nlong; x++) {3288 var u = x / nlong,3289 v = y / nlat,3290 theta = longRange * u,3291 phi = latRange * v,3292 sinTheta = sin(theta),3293 cosTheta = cos(theta),3294 sinPhi = sin(phi),3295 cosPhi = cos(phi),3296 ux = cosTheta * sinPhi,3297 uy = cosPhi,3298 uz = sinTheta * sinPhi,3299 r = radius(ux, uy, uz, u, v),3300 index = x + y * (nlong + 1),3301 i3 = index * 3,3302 i2 = index * 2;3303 vertices[i3 + 0] = r * ux;3304 vertices[i3 + 1] = r * uy;3305 vertices[i3 + 2] = r * uz;3306 normals[i3 + 0] = ux;3307 normals[i3 + 1] = uy;3308 normals[i3 + 2] = uz;3309 texCoords[i2 + 0] = u;3310 texCoords[i2 + 1] = v;3311 }3312 }3313 //Create indices3314 var numVertsAround = nlat + 1;3315 for (x = 0; x < nlat; x++) {3316 for (y = 0; y < nlong; y++) {3317 var index = (x * nlong + y) * 6;3318 indices[index + 0] = y * numVertsAround + x;3319 indices[index + 1] = y * numVertsAround + x + 1;3320 indices[index + 2] = (y + 1) * numVertsAround + x;3321 indices[index + 3] = (y + 1) * numVertsAround + x;3322 indices[index + 4] = y * numVertsAround + x + 1;3323 indices[index + 5] = (y + 1) * numVertsAround + x + 1;3324 }3325 }3326 O3D.Model.call(this, $.extend({3327 vertices: vertices,3328 indices: indices,3329 normals: normals,3330 texCoords: texCoords3331 }, opt || {}));3332 };3333 O3D.Sphere.prototype = Object.create(O3D.Model.prototype);3334 //Code based on http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html3335 O3D.IcoSphere = function(opt) {3336 var iterations = opt.iterations || 0,3337 vertices = [],3338 indices = [],3339 sqrt = Math.sqrt,3340 acos = Math.acos,3341 atan2 = Math.atan2,3342 pi = Math.PI,3343 pi2 = pi * 2;3344 //Add a callback for when a vertex is created3345 opt.onAddVertex = opt.onAddVertex || $.empty;3346 // and Icosahedron vertices3347 var t = (1 + sqrt(5)) / 2,3348 len = sqrt(1 + t * t);3349 vertices.push(-1 / len, t / len, 0,3350 1 / len, t / len, 0,3351 -1 / len, -t / len, 0,3352 1 / len, -t / len, 0,3353 0, -1 / len, t / len,3354 0, 1 / len, t / len,3355 0, -1 / len, -t / len,3356 0, 1 / len, -t / len,3357 t / len, 0, -1 / len,3358 t / len, 0, 1 / len,3359 -t / len, 0, -1 / len,3360 -t / len, 0, 1 / len);3361 indices.push(0, 11, 5,3362 0, 5, 1,3363 0, 1, 7,3364 0, 7, 10,3365 0, 10, 11,3366 1, 5, 9,3367 5, 11, 4,3368 11, 10, 2,3369 10, 7, 6,3370 7, 1, 8,3371 3, 9, 4,3372 3, 4, 2,3373 3, 2, 6,3374 3, 6, 8,3375 3, 8, 9,3376 4, 9, 5,3377 2, 4, 11,3378 6, 2, 10,3379 8, 6, 7,3380 9, 8, 1);3381 var getMiddlePoint = (function() {3382 var pointMemo = {};3383 return function(i1, i2) {3384 i1 *= 3;3385 i2 *= 3;3386 var mini = i1 < i2 ? i1 : i2,3387 maxi = i1 > i2 ? i1 : i2,3388 key = mini + '|' + maxi;3389 if (key in pointMemo) {3390 return pointMemo[key];3391 }3392 var x1 = vertices[i1 ],3393 y1 = vertices[i1 + 1],3394 z1 = vertices[i1 + 2],3395 x2 = vertices[i2 ],3396 y2 = vertices[i2 + 1],3397 z2 = vertices[i2 + 2],3398 xm = (x1 + x2) / 2,3399 ym = (y1 + y2) / 2,3400 zm = (z1 + z2) / 2,3401 len = sqrt(xm * xm + ym * ym + zm * zm);3402 xm /= len;3403 ym /= len;3404 zm /= len;3405 vertices.push(xm, ym, zm);3406 return (pointMemo[key] = (vertices.length / 3 - 1));3407 };3408 })();3409 for (var i = 0; i < iterations; i++) {3410 var indices2 = [];3411 for (var j = 0, l = indices.length; j < l; j += 3) {3412 var a = getMiddlePoint(indices[j ], indices[j + 1]),3413 b = getMiddlePoint(indices[j + 1], indices[j + 2]),3414 c = getMiddlePoint(indices[j + 2], indices[j ]);3415 indices2.push(indices[j], a, c,3416 indices[j + 1], b, a,3417 indices[j + 2], c, b,3418 a, b, c);3419 }3420 indices = indices2;3421 }3422 //Calculate texCoords and normals3423 var l = indices.length,3424 normals = new Float32Array(l * 3),3425 texCoords = new Float32Array(l * 2);3426 for (var i = 0; i < l; i += 3) {3427 var i1 = indices[i ],3428 i2 = indices[i + 1],3429 i3 = indices[i + 2],3430 in1 = i1 * 3,3431 in2 = i2 * 3,3432 in3 = i3 * 3,3433 iu1 = i1 * 2,3434 iu2 = i2 * 2,3435 iu3 = i3 * 2,3436 x1 = vertices[in1 ],3437 y1 = vertices[in1 + 1],3438 z1 = vertices[in1 + 2],3439 theta1 = acos(z1 / sqrt(x1 * x1 + y1 * y1 + z1 * z1)),3440 phi1 = atan2(y1, x1),3441 v1 = theta1 / pi,3442 u1 = 1 - phi1 / pi2,3443 x2 = vertices[in2 ],3444 y2 = vertices[in2 + 1],3445 z2 = vertices[in2 + 2],3446 theta2 = acos(z2 / sqrt(x2 * x2 + y2 * y2 + z2 * z2)),3447 phi2 = atan2(y2, x2),3448 v2 = theta2 / pi,3449 u2 = 1 - phi2 / pi2,3450 x3 = vertices[in3 ],3451 y3 = vertices[in3 + 1],3452 z3 = vertices[in3 + 2],3453 theta3 = acos(z3 / sqrt(x3 * x3 + y3 * y3 + z3 * z3)),3454 phi3 = atan2(y3, x3),3455 v3 = theta3 / pi,3456 u3 = 1 - phi3 / pi2,3457 vec1 = {3458 x: x3 - x2,3459 y: y3 - y2,3460 z: z3 - z23461 },3462 vec2 = {3463 x: x1 - x2,3464 y: y1 - y2,3465 z: z1 - z23466 },3467 normal = Vec3.cross(vec1, vec2).$unit();3468 normals[in1 ] = normals[in2 ] = normals[in3 ] = normal.x;3469 normals[in1 + 1] = normals[in2 + 1] = normals[in3 + 1] = normal.y;3470 normals[in1 + 2] = normals[in2 + 2] = normals[in3 + 2] = normal.z;3471 texCoords[iu1 ] = u1;3472 texCoords[iu1 + 1] = v1;3473 texCoords[iu2 ] = u2;3474 texCoords[iu2 + 1] = v2;3475 texCoords[iu3 ] = u3;3476 texCoords[iu3 + 1] = v3;3477 }3478 O3D.Model.call(this, $.extend({3479 vertices: vertices,3480 indices: indices,3481 normals: normals,3482 texCoords: texCoords3483 }, opt || {}));3484 };3485 O3D.IcoSphere.prototype = Object.create(O3D.Model.prototype);3486 O3D.TruncatedCone = function(config) {3487 var bottomRadius = config.bottomRadius || 0,3488 topRadius = config.topRadius || 0,3489 height = config.height || 1,3490 nradial = config.nradial || 10,3491 nvertical = config.nvertical || 10,3492 topCap = !!config.topCap,3493 bottomCap = !!config.bottomCap,3494 extra = (topCap? 2 : 0) + (bottomCap? 2 : 0),3495 numVertices = (nradial + 1) * (nvertical + 1 + extra),3496 vertices = new Float32Array(numVertices * 3),3497 normals = new Float32Array(numVertices * 3),3498 texCoords = new Float32Array(numVertices * 2),3499 indices = new Uint16Array(nradial * (nvertical + extra) * 6),3500 vertsAroundEdge = nradial + 1,3501 math = Math,3502 slant = math.atan2(bottomRadius - topRadius, height),3503 msin = math.sin,3504 mcos = math.cos,3505 mpi = math.PI,3506 cosSlant = mcos(slant),3507 sinSlant = msin(slant),3508 start = topCap? -2 : 0,3509 end = nvertical + (bottomCap? 2 : 0),3510 i3 = 0,3511 i2 = 0;3512 for (var i = start; i <= end; i++) {3513 var v = i / nvertical,3514 y = height * v,3515 ringRadius;3516 if (i < 0) {3517 y = 0;3518 v = 1;3519 ringRadius = bottomRadius;3520 } else if (i > nvertical) {3521 y = height;3522 v = 1;3523 ringRadius = topRadius;3524 } else {3525 ringRadius = bottomRadius +3526 (topRadius - bottomRadius) * (i / nvertical);3527 }3528 if (i == -2 || i == nvertical + 2) {3529 ringRadius = 0;3530 v = 0;3531 }3532 y -= height / 2;3533 for (var j = 0; j < vertsAroundEdge; j++) {3534 var sin = msin(j * mpi * 2 / nradial);3535 var cos = mcos(j * mpi * 2 / nradial);3536 vertices[i3 + 0] = sin * ringRadius;3537 vertices[i3 + 1] = y;3538 vertices[i3 + 2] = cos * ringRadius;3539 normals[i3 + 0] = (i < 0 || i > nvertical) ? 0 : (sin * cosSlant);3540 normals[i3 + 1] = (i < 0) ? -1 : (i > nvertical ? 1 : sinSlant);3541 normals[i3 + 2] = (i < 0 || i > nvertical) ? 0 : (cos * cosSlant);3542 texCoords[i2 + 0] = j / nradial;3543 texCoords[i2 + 1] = v;3544 i2 += 2;3545 i3 += 3;3546 }3547 }3548 for (i = 0; i < nvertical + extra; i++) {3549 for (j = 0; j < nradial; j++) {3550 var index = (i * nradial + j) * 6;3551 indices[index + 0] = vertsAroundEdge * (i + 0) + 0 + j;3552 indices[index + 1] = vertsAroundEdge * (i + 0) + 1 + j;3553 indices[index + 2] = vertsAroundEdge * (i + 1) + 1 + j;3554 indices[index + 3] = vertsAroundEdge * (i + 0) + 0 + j;3555 indices[index + 4] = vertsAroundEdge * (i + 1) + 1 + j;3556 indices[index + 5] = vertsAroundEdge * (i + 1) + 0 + j;3557 }3558 }3559 O3D.Model.call(this, $.extend({3560 vertices: vertices,3561 normals: normals,3562 texCoords: texCoords,3563 indices: indices3564 }, config || {}));3565 };3566 O3D.TruncatedCone.prototype = Object.create(O3D.Model.prototype);3567 O3D.Cone = function(config) {3568 config.topRadius = 0;3569 config.topCap = !!config.cap;3570 config.bottomCap = !!config.cap;3571 config.bottomRadius = config.radius || 3;3572 O3D.TruncatedCone.call(this, config);3573 };3574 O3D.Cone.prototype = Object.create(O3D.TruncatedCone.prototype);3575 O3D.Cylinder = function(config) {3576 config.bottomRadius = config.radius;3577 config.topRadius = config.radius;3578 O3D.TruncatedCone.call(this, config);3579 };3580 O3D.Cylinder.prototype = Object.create(O3D.TruncatedCone.prototype);3581 O3D.Plane = function(config) {3582 var type = config.type,3583 coords = type.split(','),3584 c1len = config[coords[0] + 'len'], //width3585 c2len = config[coords[1] + 'len'], //height3586 subdivisions1 = config['n' + coords[0]] || 1, //subdivisionsWidth3587 subdivisions2 = config['n' + coords[1]] || 1, //subdivisionsDepth3588 offset = config.offset,3589 flipCull = !!config.flipCull, 3590 numVertices = (subdivisions1 + 1) * (subdivisions2 + 1),3591 positions = new Float32Array(numVertices * 3),3592 normals = new Float32Array(numVertices * 3),3593 texCoords = new Float32Array(numVertices * 2),3594 i2 = 0, i3 = 0;3595 if (flipCull) {3596 c1len = - c1len;3597 }3598 3599 for (var z = 0; z <= subdivisions2; z++) {3600 for (var x = 0; x <= subdivisions1; x++) {3601 var u = x / subdivisions1,3602 v = z / subdivisions2;3603 if (flipCull) {3604 texCoords[i2 + 0] = 1 - u;3605 } else {3606 texCoords[i2 + 0] = u;3607 }3608 texCoords[i2 + 1] = v;3609 i2 += 2;3610 switch (type) {3611 case 'x,y':3612 positions[i3 + 0] = c1len * u - c1len * 0.5;3613 positions[i3 + 1] = c2len * v - c2len * 0.5;3614 positions[i3 + 2] = offset;3615 normals[i3 + 0] = 0;3616 normals[i3 + 1] = 0;3617 if (flipCull) {3618 normals[i3 + 2] = 1;3619 } else {3620 normals[i3 + 2] = -1;3621 }3622 break;3623 case 'x,z':3624 positions[i3 + 0] = c1len * u - c1len * 0.5;3625 positions[i3 + 1] = offset;3626 positions[i3 + 2] = c2len * v - c2len * 0.5;3627 normals[i3 + 0] = 0;3628 if (flipCull) {3629 normals[i3 + 1] = 1;3630 } else {3631 normals[i3 + 1] = -1;3632 }3633 normals[i3 + 2] = 0;3634 break;3635 case 'y,z':3636 positions[i3 + 0] = offset;3637 positions[i3 + 1] = c1len * u - c1len * 0.5;3638 positions[i3 + 2] = c2len * v - c2len * 0.5;3639 if (flipCull) {3640 normals[i3 + 0] = 1;3641 } else {3642 normals[i3 + 0] = -1;3643 }3644 normals[i3 + 1] = 0;3645 normals[i3 + 2] = 0;3646 break;3647 }3648 i3 += 3;3649 }3650 }3651 var numVertsAcross = subdivisions1 + 1,3652 indices = [];3653 for (z = 0; z < subdivisions2; z++) {3654 for (x = 0; x < subdivisions1; x++) {3655 var index = (z * subdivisions1 + x) * 6;3656 // Make triangle 1 of quad.3657 indices[index + 0] = (z + 0) * numVertsAcross + x;3658 indices[index + 1] = (z + 1) * numVertsAcross + x;3659 indices[index + 2] = (z + 0) * numVertsAcross + x + 1;3660 // Make triangle 2 of quad.3661 indices[index + 3] = (z + 1) * numVertsAcross + x;3662 indices[index + 4] = (z + 1) * numVertsAcross + x + 1;3663 indices[index + 5] = (z + 0) * numVertsAcross + x + 1;3664 }3665 }3666 O3D.Model.call(this, $.extend({3667 vertices: positions,3668 normals: normals,3669 texCoords: texCoords,3670 indices: indices3671 }, config));3672 };3673 O3D.Plane.prototype = Object.create(O3D.Model.prototype);3674 //unique id3675 O3D.id = $.time();3676 //Assign to namespace3677 PhiloGL.O3D = O3D;3678})();3679//shaders.js3680//Default Shaders3681(function() {3682 //Add default shaders3683 var Shaders = {3684 Vertex: {},3685 Fragment: {}3686 };3687 var VertexShaders = Shaders.Vertex,3688 FragmentShaders = Shaders.Fragment;3689 VertexShaders.Default = [3690 "#define LIGHT_MAX 4",3691 //object attributes3692 "attribute vec3 position;",3693 "attribute vec3 normal;",3694 "attribute vec4 color;",3695 "attribute vec4 pickingColor;",3696 "attribute vec2 texCoord1;",3697 //camera and object matrices3698 "uniform mat4 viewMatrix;",3699 "uniform mat4 viewInverseMatrix;",3700 "uniform mat4 projectionMatrix;",3701 "uniform mat4 viewProjectionMatrix;",3702 //objectMatrix * viewMatrix = worldMatrix3703 "uniform mat4 worldMatrix;",3704 "uniform mat4 worldInverseMatrix;",3705 "uniform mat4 worldInverseTransposeMatrix;",3706 "uniform mat4 objectMatrix;",3707 "uniform vec3 cameraPosition;",3708 //lighting configuration3709 "uniform bool enableLights;",3710 "uniform vec3 ambientColor;",3711 "uniform vec3 directionalColor;",3712 "uniform vec3 lightingDirection;",3713 //point lights configuration3714 "uniform vec3 pointLocation[LIGHT_MAX];",3715 "uniform vec3 pointColor[LIGHT_MAX];",3716 "uniform int numberPoints;",3717 //reflection / refraction configuration3718 "uniform bool useReflection;",3719 //varyings3720 "varying vec3 vReflection;",3721 "varying vec4 vColor;",3722 "varying vec4 vPickingColor;",3723 "varying vec2 vTexCoord;",3724 "varying vec4 vNormal;",3725 "varying vec3 lightWeighting;",3726 "void main(void) {",3727 "vec4 mvPosition = worldMatrix * vec4(position, 1.0);",3728 "vec4 transformedNormal = worldInverseTransposeMatrix * vec4(normal, 1.0);",3729 //lighting code3730 "if(!enableLights) {",3731 "lightWeighting = vec3(1.0, 1.0, 1.0);",3732 "} else {",3733 "vec3 plightDirection;",3734 "vec3 pointWeight = vec3(0.0, 0.0, 0.0);",3735 "float directionalLightWeighting = max(dot(transformedNormal.xyz, lightingDirection), 0.0);",3736 "for (int i = 0; i < LIGHT_MAX; i++) {",3737 "if (i < numberPoints) {",3738 "plightDirection = normalize((viewMatrix * vec4(pointLocation[i], 1.0)).xyz - mvPosition.xyz);",3739 "pointWeight += max(dot(transformedNormal.xyz, plightDirection), 0.0) * pointColor[i];",3740 "} else {",3741 "break;",3742 "}",3743 "}",3744 "lightWeighting = ambientColor + (directionalColor * directionalLightWeighting) + pointWeight;",3745 "}",3746 //refraction / reflection code3747 "if (useReflection) {",3748 "vReflection = (viewInverseMatrix[3] - (worldMatrix * vec4(position, 1.0))).xyz;",3749 "} else {",3750 "vReflection = vec3(1.0, 1.0, 1.0);",3751 "}",3752 //pass results to varyings3753 "vColor = color;",3754 "vPickingColor = pickingColor;",3755 "vTexCoord = texCoord1;",3756 "vNormal = transformedNormal;",3757 "gl_Position = projectionMatrix * worldMatrix * vec4(position, 1.0);",3758 "}"3759 ].join("\n");3760 FragmentShaders.Default = [3761 "#ifdef GL_ES",3762 "precision highp float;",3763 "#endif",3764 //varyings3765 "varying vec4 vColor;",3766 "varying vec4 vPickingColor;",3767 "varying vec2 vTexCoord;",3768 "varying vec3 lightWeighting;",3769 "varying vec3 vReflection;",3770 "varying vec4 vNormal;",3771 //texture configs3772 "uniform bool hasTexture1;",3773 "uniform sampler2D sampler1;",3774 "uniform bool hasTextureCube1;",3775 "uniform samplerCube samplerCube1;",3776 //picking configs3777 "uniform bool enablePicking;",3778 "uniform bool hasPickingColors;",3779 "uniform vec3 pickColor;",3780 //reflection / refraction configs3781 "uniform float reflection;",3782 "uniform float refraction;",3783 //fog configuration3784 "uniform bool hasFog;",3785 "uniform vec3 fogColor;",3786 "uniform float fogNear;",3787 "uniform float fogFar;",3788 "void main(){",3789 //set color from texture3790 "if (!hasTexture1) {",3791 "gl_FragColor = vec4(vColor.rgb * lightWeighting, vColor.a);",3792 "} else {",3793 "gl_FragColor = vec4(texture2D(sampler1, vec2(vTexCoord.s, vTexCoord.t)).rgb * lightWeighting, 1.0);",3794 "}",3795 //has cube texture then apply reflection3796 "if (hasTextureCube1) {",3797 "vec3 nReflection = normalize(vReflection);",3798 "vec3 reflectionValue;",3799 "if (refraction > 0.0) {",3800 "reflectionValue = refract(nReflection, vNormal.xyz, refraction);",3801 "} else {",3802 "reflectionValue = -reflect(nReflection, vNormal.xyz);",3803 "}",3804 //TODO(nico): check whether this is right.3805 "vec4 cubeColor = textureCube(samplerCube1, vec3(-reflectionValue.x, -reflectionValue.y, reflectionValue.z));",3806 "gl_FragColor = vec4(mix(gl_FragColor.xyz, cubeColor.xyz, reflection), 1.0);",3807 "}",3808 //set picking3809 "if (enablePicking) {",3810 "if (hasPickingColors) {",3811 "gl_FragColor = vPickingColor;",3812 "} else {",3813 "gl_FragColor = vec4(pickColor, 1.0);",3814 "}",3815 "}",3816 //handle fog3817 "if (hasFog) {",3818 "float depth = gl_FragCoord.z / gl_FragCoord.w;",3819 "float fogFactor = smoothstep(fogNear, fogFar, depth);",3820 "gl_FragColor = mix(gl_FragColor, vec4(fogColor, gl_FragColor.w), fogFactor);",3821 "}",3822 "}"3823 ].join("\n");3824 PhiloGL.Shaders = Shaders;3825})();3826//scene.js3827//Scene Object management and rendering3828(function() {3829 //Define some locals3830 var Vec3 = PhiloGL.Vec3,3831 Mat4 = PhiloGL.Mat4;3832 //Scene class3833 var Scene = function(program, camera, opt) {3834 opt = $.merge({3835 lights: {3836 enable: false,3837 //ambient light3838 ambient: {3839 r: 0.2,3840 g: 0.2,3841 b: 0.23842 },3843 //directional light3844 directional: {3845 direction: {3846 x: 1,3847 y: 1,3848 z: 13849 },3850 color: {3851 r: 0,3852 g: 0,3853 b: 03854 }3855 }3856 //point light3857 //points: []3858 },3859 effects: {3860 fog: false3861 // { near, far, color }3862 }3863 }, opt || {});3864 this.program = opt.program ? program[opt.program] : program;3865 this.camera = camera;3866 this.models = [];3867 this.config = opt;3868 };3869 Scene.prototype = {3870 add: function() {3871 for (var i = 0, models = this.models, l = arguments.length; i < l; i++) {3872 var model = arguments[i];3873 //Generate unique id for model3874 model.id = model.id || $.uid();3875 models.push(model);3876 //Create and load Buffers3877 this.defineBuffers(model);3878 }3879 },3880 remove: function(model) {3881 var models = this.models,3882 indexOf = models.indexOf(model);3883 if (indexOf > -1) {3884 models.splice(indexOf, 1);3885 }3886 },3887 getProgram: function(obj) {3888 var program = this.program;3889 if (program.$$family != 'program' && obj && obj.program) {3890 program = program[obj.program];3891 program.use();3892 return program;3893 }3894 return program;3895 },3896 defineBuffers: function(obj) {3897 var program = this.getProgram(obj),3898 prevDynamic = obj.dynamic;3899 obj.dynamic = true;3900 obj.setState(program);3901 obj.dynamic = prevDynamic;3902 obj.unsetState(program);3903 },3904 beforeRender: function(program) {3905 //Setup lighting and scene effects like fog, etc.3906 this.setupLighting(program);3907 this.setupEffects(program);3908 if (this.camera) {3909 this.camera.setStatus(program);3910 }3911 },3912 //Setup the lighting system: ambient, directional, point lights.3913 setupLighting: function(program) {3914 //Setup Lighting3915 var abs = Math.abs,3916 camera = this.camera,3917 cpos = camera.position,3918 light = this.config.lights,3919 ambient = light.ambient,3920 directional = light.directional,3921 dcolor = directional.color,3922 dir = directional.direction,3923 enable = light.enable,3924 points = light.points && $.splat(light.points) || [],3925 numberPoints = points.length,3926 pointLocations = [],3927 pointColors = [],3928 enableSpecular = [],3929 pointSpecularColors = [];3930 //Normalize lighting direction vector3931 dir = new Vec3(dir.x, dir.y, dir.z).$unit().$scale(-1);3932 //Set light uniforms. Ambient and directional lights.3933 program.setUniform('enableLights', enable);3934 if (!enable) return;3935 program.setUniform('ambientColor', [ambient.r, ambient.g, ambient.b]);3936 program.setUniform('directionalColor', [dcolor.r, dcolor.g, dcolor.b]);3937 program.setUniform('lightingDirection', [dir.x, dir.y, dir.z]);3938 //Set point lights3939 program.setUniform('numberPoints', numberPoints);3940 for (var i = 0, l = numberPoints; i < l; i++) {3941 var point = points[i],3942 position = point.position,3943 color = point.color || point.diffuse,3944 spec = point.specular;3945 pointLocations.push(position.x, position.y, position.z);3946 pointColors.push(color.r, color.g, color.b);3947 //Add specular color3948 enableSpecular.push(+!!spec);3949 if (spec) {3950 pointSpecularColors.push(spec.r, spec.g, spec.b);3951 } else {3952 pointSpecularColors.push(0, 0, 0);3953 }3954 }3955 program.setUniforms({3956 'pointLocation': pointLocations,3957 'pointColor': pointColors3958 });3959 program.setUniforms({3960 'enableSpecular': enableSpecular,3961 'pointSpecularColor': pointSpecularColors3962 });3963 },3964 //Setup effects like fog, etc.3965 setupEffects: function(program) {3966 var config = this.config.effects,3967 fog = config.fog,3968 color = fog.color || { r: 0.5, g: 0.5, b: 0.5 };3969 if (fog) {3970 program.setUniforms({3971 'hasFog': true,3972 'fogNear': fog.near,3973 'fogFar': fog.far,3974 'fogColor': [color.r, color.g, color.b]3975 });3976 } else {3977 program.setUniform('hasFog', false);3978 }3979 },3980 //Renders all objects in the scene.3981 render: function(opt) {3982 opt = opt || {};3983 var camera = this.camera,3984 program = this.program,3985 renderProgram = opt.renderProgram,3986 pType = $.type(program),3987 multiplePrograms = !renderProgram && pType == 'object',3988 options = $.extend({3989 onBeforeRender: $.empty,3990 onAfterRender: $.empty3991 }, opt || {});3992 //If we're just using one program then3993 //execute the beforeRender method once.3994 !multiplePrograms && this.beforeRender(renderProgram || program);3995 //Go through each model and render it.3996 for (var i = 0, models = this.models, l = models.length; i < l; ++i) {3997 var elem = models[i];3998 if (elem.display) {3999 var program = renderProgram || this.getProgram(elem);4000 //Setup the beforeRender method for each object4001 //when there are multiple programs to be used.4002 multiplePrograms && this.beforeRender(program);4003 elem.onBeforeRender(program, camera);4004 options.onBeforeRender(elem, i);4005 this.renderObject(elem, program);4006 options.onAfterRender(elem, i);4007 elem.onAfterRender(program, camera);4008 }4009 }4010 },4011 renderToTexture: function(name, opt) {4012 opt = opt || {};4013 var texture = app.textures[name + '-texture'],4014 texMemo = app.textureMemo[name + '-texture'];4015 this.render(opt);4016 gl.bindTexture(texMemo.textureType, texture);4017 //gl.generateMipmap(texMemo.textureType);4018 //gl.bindTexture(texMemo.textureType, null);4019 },4020 renderObject: function(obj, program) {4021 var camera = this.camera,4022 view = camera.view,4023 projection = camera.projection,4024 object = obj.matrix,4025 world = view.mulMat4(object),4026 worldInverse = world.invert(),4027 worldInverseTranspose = worldInverse.transpose();4028 obj.setState(program);4029 //Now set view and normal matrices4030 program.setUniforms({4031 objectMatrix: object,4032 worldMatrix: world,4033 worldInverseMatrix: worldInverse,4034 worldInverseTransposeMatrix: worldInverseTranspose4035// worldViewProjection: view.mulMat4(object).$mulMat4(view.mulMat4(projection))4036 });4037 //Draw4038 //TODO(nico): move this into O3D, but, somehow, abstract the gl.draw* methods inside that object.4039 if (obj.render) {4040 obj.render(gl, program, camera);4041 } else {4042 if (obj.$indicesLength) {4043 gl.drawElements((obj.drawType !== undefined) ? gl.get(obj.drawType) : gl.TRIANGLES, obj.$indicesLength, gl.UNSIGNED_SHORT, 0);4044 } else {4045 gl.drawArrays((obj.drawType !== undefined) ? gl.get(obj.drawType) : gl.TRIANGLES, 0, obj.$verticesLength / 3);4046 }4047 }4048 obj.unsetState(program);4049 },4050 //setup picking framebuffer4051 setupPicking: function() {4052 //create picking program4053 var program = PhiloGL.Program.fromDefaultShaders(),4054 floor = Math.floor;4055 //create framebuffer4056 app.setFrameBuffer('$picking', {4057 width: 5,4058 height: 1,4059 bindToTexture: {4060 parameters: [{4061 name: 'TEXTURE_ MAG_FILTER',4062 value: 'LINEAR'4063 }, {4064 name: 'TEXTURE_MIN_FILTER',4065 value: 'LINEAR',4066 generateMipmap: false4067 }]4068 },4069 bindToRenderBuffer: true4070 });4071 app.setFrameBuffer('$picking', false);4072 this.pickingProgram = program;4073 },4074 //returns an element at the given position4075 pick: function(x, y, lazy) {4076 //setup the picking program if this is4077 //the first time we enter the method.4078 if (!this.pickingProgram) {4079 this.setupPicking();4080 }4081 var o3dHash = {},4082 o3dList = [],4083 program = app.usedProgram,4084 pickingProgram = this.pickingProgram,4085 camera = this.camera,4086 oldtarget = camera.target,4087 oldaspect = camera.aspect,4088 config = this.config,4089 memoLightEnable = config.lights.enable,4090 memoFog = config.effects.fog,4091 width = gl.canvas.width,4092 height = gl.canvas.height,4093 floor = Math.floor,4094 pickingRes = Scene.PICKING_RES,4095 resWidth = 5,4096 resHeight = 1,4097 ndcx = x * 2 / width - 1,4098 ndcy = 1 - y * 2 / height,4099 target = this.unproject([ndcx, ndcy, 1.0], camera),4100 hash = [],4101 pixel = new Uint8Array(1 * 1 * 4),4102 index = 0,4103 backgroundColor, capture, pindex;4104 this.camera.target = target;4105 this.camera.update ();4106 //setup the scene for picking4107 config.lights.enable = false;4108 config.effects.fog = false;4109 //enable picking and render to texture4110 app.setFrameBuffer('$picking', true);4111 pickingProgram.use();4112 pickingProgram.setUniform('enablePicking', true);4113 //render the scene to a texture4114 gl.disable(gl.BLEND);4115 gl.viewport(0, 0, resWidth, resHeight);4116 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);4117 //read the background color so we don't step on it4118 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);4119 backgroundColor = pixel[0] + pixel[1] * 256 + pixel[2] * 256 * 256;4120 //render picking scene4121 this.renderPickingScene({4122 background: backgroundColor,4123 o3dHash: o3dHash,4124 o3dList: o3dList,4125 hash: hash4126 });4127 // the target point is in the center of the screen,4128 // so it should be the center point.4129 gl.readPixels(2, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);4130 var stringColor = [pixel[0], pixel[1], pixel[2]].join(),4131 elem = o3dHash[stringColor],4132 pick;4133 if (!elem) {4134 for (var i = 0, l = o3dList.length; i < l; i++) {4135 elem = o3dList[i];4136 pick = elem.pick(pixel);4137 if (pick !== false) {4138 elem.$pickingIndex = pick;4139 } else {4140 elem = false;4141 }4142 }4143 }4144 //restore all values and unbind buffers4145 app.setFrameBuffer('$picking', false);4146 app.setTexture('$picking-texture', false);4147 pickingProgram.setUniform('enablePicking', false);4148 config.lights.enable = memoLightEnable;4149 config.effects.fog = memoFog;4150 //restore previous program4151 if (program) program.use();4152 //restore the viewport size to original size4153 gl.viewport(0, 0, width, height);4154 //restore camera properties4155 camera.target = oldtarget;4156 camera.aspect = oldaspect;4157 camera.update();4158 //store model hash and pixel array4159 this.o3dHash = o3dHash;4160 this.o3dList = o3dList;4161 this.pixel = pixel;4162 this.capture = capture;4163 return elem && elem.pickable && elem;4164 },4165 unproject: function(pt, camera) {4166 return camera.view.invert().mulMat4(camera.projection.invert()).mulVec3(pt);4167 },4168 renderPickingScene: function(opt) {4169 //if set through the config, render a custom scene.4170 if (this.config.renderPickingScene) {4171 this.config.renderPickingScene.call(this, opt);4172 return;4173 }4174 var pickingProgram = this.pickingProgram,4175 o3dHash = opt.o3dHash,4176 o3dList = opt.o3dList,4177 background = opt.background,4178 hash = opt.hash,4179 index = 0;4180 //render to texture4181 this.renderToTexture('$picking', {4182 renderProgram: pickingProgram,4183 onBeforeRender: function(elem, i) {4184 if (i == background) {4185 index = 1;4186 }4187 var suc = i + index,4188 hasPickingColors = !!elem.pickingColors;4189 pickingProgram.setUniform('hasPickingColors', hasPickingColors);4190 if (!hasPickingColors) {4191 hash[0] = suc % 256;4192 hash[1] = ((suc / 256) >> 0) % 256;4193 hash[2] = ((suc / (256 * 256)) >> 0) % 256;4194 pickingProgram.setUniform('pickColor', [hash[0] / 255, hash[1] / 255, hash[2] / 255]);4195 o3dHash[hash.join()] = elem;4196 } else {4197 o3dList.push(elem);4198 }4199 }4200 });4201 },4202 resetPicking: $.empty4203 };4204 Scene.MAX_TEXTURES = 10;4205 Scene.MAX_POINT_LIGHTS = 4;4206 Scene.PICKING_RES = 4;4207 PhiloGL.Scene = Scene;4208})();4209//workers.js4210//4211(function () {4212 function WorkerGroup(fileName, n) {4213 var workers = this.workers = [];4214 while (n--) {4215 workers.push(new Worker(fileName));4216 }4217 }4218 WorkerGroup.prototype = {4219 map: function(callback) {4220 var workers = this.workers;4221 var configs = this.configs = [];4222 for (var i = 0, l = workers.length; i < l; i++) {4223 configs.push(callback && callback(i));4224 }4225 return this;4226 },4227 reduce: function(opt) {4228 var fn = opt.reduceFn,4229 workers = this.workers,4230 configs = this.configs,4231 l = workers.length,4232 acum = opt.initialValue,4233 message = function (e) {4234 l--;4235 if (acum === undefined) {4236 acum = e.data;4237 } else {4238 acum = fn(acum, e.data);4239 }4240 if (l == 0) {4241 opt.onComplete(acum);4242 }4243 };4244 for (var i = 0, ln = l; i < ln; i++) {4245 var w = workers[i];4246 w.onmessage = message;4247 w.postMessage(configs[i]);4248 }4249 return this;4250 }4251 };4252 PhiloGL.WorkerGroup = WorkerGroup;4253})();4254(function() {4255 //Timer based animation4256 var Fx = function(options) {4257 this.opt = $.merge({4258 delay: 0,4259 duration: 1000,4260 transition: function(x) { return x; },4261 onCompute: $.empty,4262 onComplete: $.empty4263 }, options || {});4264 };4265 var Queue = Fx.Queue = [];4266 Fx.prototype = {4267 time:null,4268 4269 start: function(options) {4270 this.opt = $.merge(this.opt, options || {});4271 this.time = $.time();4272 this.animating = true;4273 Queue.push(this);4274 },4275 //perform a step in the animation4276 step: function() {4277 //if not animating, then return4278 if (!this.animating) return;4279 var currentTime = $.time(), 4280 time = this.time,4281 opt = this.opt,4282 delay = opt.delay,4283 duration = opt.duration,4284 delta = 0;4285 //hold animation for the delay4286 if (currentTime < time + delay) {4287 opt.onCompute.call(this, delta);4288 return;4289 }4290 //if in our time window, then execute animation4291 if (currentTime < time + delay + duration) {4292 delta = opt.transition((currentTime - time - delay) / duration);4293 opt.onCompute.call(this, delta);4294 } else {4295 this.animating = false;4296 opt.onCompute.call(this, 1);4297 opt.onComplete.call(this);4298 }4299 }4300 };4301 4302 Fx.compute = function(from, to, delta) {4303 return from + (to - from) * delta;4304 };4305 //Easing equations4306 Fx.Transition = {4307 linear: function(p){4308 return p;4309 }4310 };4311 var Trans = Fx.Transition;4312 (function(){4313 var makeTrans = function(transition, params){4314 params = $.splat(params);4315 return $.extend(transition, {4316 easeIn: function(pos){4317 return transition(pos, params);4318 },4319 easeOut: function(pos){4320 return 1 - transition(1 - pos, params);4321 },4322 easeInOut: function(pos){4323 return (pos <= 0.5)? transition(2 * pos, params) / 2 : (2 - transition(4324 2 * (1 - pos), params)) / 2;4325 }4326 });4327 };4328 var transitions = {4329 Pow: function(p, x){4330 return Math.pow(p, x[0] || 6);4331 },4332 Expo: function(p){4333 return Math.pow(2, 8 * (p - 1));4334 },4335 Circ: function(p){4336 return 1 - Math.sin(Math.acos(p));4337 },4338 Sine: function(p){4339 return 1 - Math.sin((1 - p) * Math.PI / 2);4340 },4341 Back: function(p, x){4342 x = x[0] || 1.618;4343 return Math.pow(p, 2) * ((x + 1) * p - x);4344 },4345 Bounce: function(p){4346 var value;4347 for ( var a = 0, b = 1; 1; a += b, b /= 2) {4348 if (p >= (7 - 4 * a) / 11) {4349 value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);4350 break;4351 }4352 }4353 return value;4354 },4355 Elastic: function(p, x){4356 return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);4357 }4358 };4359 for (var t in transitions) {4360 Trans[t] = makeTrans(transitions[t]);4361 }4362 ['Quad', 'Cubic', 'Quart', 'Quint'].forEach(function(elem, i){4363 Trans[elem] = makeTrans(function(p){4364 return Math.pow(p, [4365 i + 24366 ]);4367 });4368 });4369 })();4370 //animationTime - function branching4371 var global = self || window,4372 checkFxQueue = function() {4373 var newQueue = [];4374 if (Queue.length) {4375 for (var i = 0, l = Queue.length, fx; i < l; i++) {4376 fx = Queue[i];4377 fx.step();4378 if (fx.animating) {4379 newQueue.push(fx);4380 }4381 }4382 Fx.Queue = Queue = newQueue;4383 }4384 };4385 if (global) {4386 var found = false;4387 ['webkitAnimationTime', 'mozAnimationTime', 'animationTime',4388 'webkitAnimationStartTime', 'mozAnimationStartTime', 'animationStartTime'].forEach(function(impl) {4389 if (impl in global) {4390 Fx.animationTime = function() {4391 return global[impl];4392 };4393 found = true;4394 }4395 });4396 if (!found) {4397 Fx.animationTime = $.time;4398 }4399 //requestAnimationFrame - function branching4400 found = false;4401 ['webkitRequestAnimationFrame', 'mozRequestAnimationFrame', 'requestAnimationFrame'].forEach(function(impl) {4402 if (impl in global) {4403 Fx.requestAnimationFrame = function(callback) {4404 global[impl](function() {4405 checkFxQueue();4406 callback();4407 });4408 };4409 found = true;4410 }4411 });4412 if (!found) {4413 Fx.requestAnimationFrame = function(callback) {4414 setTimeout(function() {4415 checkFxQueue();4416 callback();4417 }, 1000 / 60);4418 };4419 }4420 }4421 4422 PhiloGL.Fx = Fx;4423})();4424//media.js4425//media has utility functions for image, video and audio manipulation (and4426//maybe others like device, etc).4427(function() {4428 var Media = {};4429 var Image = function() {};4430 //post process an image by setting it to a texture with a specified fragment4431 //and vertex shader.4432 Image.postProcess = (function() {4433 var plane = new PhiloGL.O3D.Plane({4434 type: 'x,y',4435 xlen: 1,4436 ylen: 1,4437 offset: 04438 }), camera = new PhiloGL.Camera(45, 1, 0.1, 500, {4439 position: { x: 0, y: 0, z: 1.205 }4440 }), scene = new PhiloGL.Scene({}, camera);4441 return function(opt) {4442 var program = app.program.$$family ? app.program : app.program[opt.program],4443 textures = opt.fromTexture ? $.splat(opt.fromTexture) : [],4444 framebuffer = opt.toFrameBuffer,4445 screen = !!opt.toScreen,4446 width = opt.width || app.canvas.width,4447 height = opt.height || app.canvas.height;4448 camera.aspect = opt.aspectRatio ? opt.aspectRatio : Math.max(height / width, width / height);4449 camera.update();4450 scene.program = program;4451 plane.textures = textures;4452 plane.program = program;4453 if(!scene.models.length) {4454 scene.add(plane);4455 }4456 if (framebuffer) {4457 //create framebuffer4458 if (!(framebuffer in app.frameBufferMemo)) {4459 app.setFrameBuffer(framebuffer, {4460 width: width,4461 height: height,4462 bindToTexture: {4463 parameters: [{4464 name: 'TEXTURE_MAG_FILTER',4465 value: 'LINEAR'4466 }, {4467 name: 'TEXTURE_MIN_FILTER',4468 value: 'LINEAR',4469 generateMipmap: false4470 }]4471 },4472 bindToRenderBuffer: false4473 });4474 }4475 program.use();4476 app.setFrameBuffer(framebuffer, true);4477 gl.viewport(0, 0, width, height);4478 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);4479 program.setUniforms(opt.uniforms || {});4480 scene.renderToTexture(framebuffer);4481 app.setFrameBuffer(framebuffer, false);4482 }4483 if (screen) {4484 program.use();4485 gl.viewport(0, 0, width, height);4486 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);4487 program.setUniforms(opt.uniforms || {});4488 scene.render();4489 }4490 return this;4491 };4492 })();4493 Media.Image = Image;4494 PhiloGL.Media = Media;4495})();...
git.py
Source:git.py
1"""Functions for interacting with hg"""2import os3import subprocess4import urlparse5import urllib6import re7from util.commands import run_cmd, remove_path, run_quiet_cmd8from util.file import safe_unlink9import logging10log = logging.getLogger(__name__)11class DefaultShareBase:12 pass13DefaultShareBase = DefaultShareBase()14def _make_absolute(repo):15 if repo.startswith("file://"):16 # Make file:// urls absolute17 path = repo[len("file://"):]18 repo = "file://%s" % os.path.abspath(path)19 elif "://" not in repo:20 repo = os.path.abspath(repo)21 return repo22def get_repo_name(repo):23 bits = urlparse.urlsplit(repo)24 host = urllib.quote(bits.netloc, "")25 path = urllib.quote(bits.path.lstrip("/"), "")26 return os.path.join(host, path)27def has_revision(dest, revision):28 """Returns True if revision exists in dest"""29 try:30 run_quiet_cmd(['git', 'log', '--oneline', '-n1', revision], cwd=dest)31 return True32 except subprocess.CalledProcessError:33 return False34def has_ref(dest, refname):35 """Returns True if refname exists in dest.36 refname can be a branch or tag name."""37 try:38 run_quiet_cmd(['git', 'show-ref', '-d', refname], cwd=dest)39 return True40 except subprocess.CalledProcessError:41 return False42def init(dest, bare=False):43 """Initializes an empty repository at dest. If dest exists and isn't empty, it will be removed.44 If `bare` is True, then a bare repo will be created."""45 if not os.path.isdir(dest):46 log.info("removing %s", dest)47 safe_unlink(dest)48 else:49 for f in os.listdir(dest):50 f = os.path.join(dest, f)51 log.info("removing %s", f)52 if os.path.isdir(f):53 remove_path(f)54 else:55 safe_unlink(f)56 # Git will freak out if it tries to create intermediate directories for57 # dest, and then they exist. We can hit this when pulling in multiple repos58 # in parallel to shared repo paths that contain common parent directories59 # Let's create all the directories first60 try:61 os.makedirs(dest)62 except OSError, e:63 if e.errno == 20:64 # Not a directory error...one of the parents of dest isn't a65 # directory66 raise67 if bare:68 cmd = ['git', 'init', '--bare', '-q', dest]69 else:70 cmd = ['git', 'init', '-q', dest]71 log.info(" ".join(cmd))72 run_quiet_cmd(cmd)73def is_git_repo(dest):74 """Returns True if dest is a valid git repo"""75 if not os.path.isdir(dest):76 return False77 try:78 proc = subprocess.Popen(["git", "rev-parse", "--git-dir"], cwd=dest, stdout=subprocess.PIPE)79 if proc.wait() != 0:80 return False81 output = proc.stdout.read().strip()82 git_dir = os.path.normpath(os.path.join(dest, output))83 retval = (git_dir == dest or git_dir == os.path.join(dest, ".git"))84 return retval85 except subprocess.CalledProcessError:86 return False87def get_git_dir(dest):88 """Returns the path to the git directory for dest. For bare repos this is89 dest itself, for regular repos this is dest/.git"""90 assert is_git_repo(dest)91 cmd = ['git', 'config', '--bool', '--get', 'core.bare']92 proc = subprocess.Popen(cmd, cwd=dest, stdout=subprocess.PIPE)93 proc.wait()94 is_bare = proc.stdout.read().strip()95 if is_bare == "false":96 d = os.path.join(dest, ".git")97 else:98 d = dest99 assert os.path.exists(d)100 return d101def set_share(repo, share):102 alternates = os.path.join(get_git_dir(repo), 'objects', 'info', 'alternates')103 share_objects = os.path.join(get_git_dir(share), 'objects')104 with open(alternates, 'w') as f:105 f.write("%s\n" % share_objects)106def clean(repo):107 # Two '-f's means "clean submodules", which is what we want so far.108 run_cmd(['git', 'clean', '-f', '-f', '-d', '-x'], cwd=repo, stdout=subprocess.PIPE)109def add_remote(repo, remote_name, remote_repo):110 """Adds a remote named `remote_name` to the local git repo in `repo`111 pointing to `remote_repo`"""112 run_cmd(['git', 'remote', 'add', remote_name, remote_repo], cwd=repo)113def set_remote_url(repo, remote_name, remote_repo):114 """Sets the url for a remote"""115 run_cmd(['git', 'remote', 'set-url', remote_name, remote_repo], cwd=repo)116def get_remote(repo, remote_name):117 """Returns the url for the given remote, or None if the remote doesn't118 exist"""119 cmd = ['git', 'remote', '-v']120 proc = subprocess.Popen(cmd, cwd=repo, stdout=subprocess.PIPE)121 proc.wait()122 for line in proc.stdout.readlines():123 m = re.match(r"%s\s+(\S+) \(fetch\)$" % re.escape(remote_name), line)124 if m:125 return m.group(1)126def set_remote(repo, remote_name, remote_repo):127 """Sets remote named `remote_name` to `remote_repo`"""128 log.debug("%s: getting remotes", repo)129 my_remote = get_remote(repo, remote_name)130 if my_remote == remote_repo:131 return132 if my_remote is not None:133 log.info("%s: setting remote %s to %s (was %s)", repo, remote_name, remote_repo, my_remote)134 set_remote_url(repo, remote_name, remote_repo)135 else:136 log.info("%s: adding remote %s %s", repo, remote_name, remote_repo)137 add_remote(repo, remote_name, remote_repo)138def git(repo, dest, refname=None, revision=None, update_dest=True,139 shareBase=DefaultShareBase, mirrors=None, clean_dest=False):140 """Makes sure that `dest` is has `revision` or `refname` checked out from141 `repo`.142 Do what it takes to make that happen, including possibly clobbering143 dest.144 If `mirrors` is set, will try and use the mirrors before `repo`.145 """146 if shareBase is DefaultShareBase:147 shareBase = os.environ.get("GIT_SHARE_BASE_DIR", None)148 if shareBase is not None:149 repo_name = get_repo_name(repo)150 share_dir = os.path.join(shareBase, repo_name)151 else:152 share_dir = None153 if share_dir is not None and not is_git_repo(share_dir):154 log.info("creating bare repo %s", share_dir)155 try:156 init(share_dir, bare=True)157 os.utime(share_dir, None)158 except Exception:159 log.warning("couldn't create shared repo %s; disabling sharing", share_dir, exc_info=True)160 shareBase = None161 share_dir = None162 dest = os.path.abspath(dest)163 log.info("Checking dest %s", dest)164 if not is_git_repo(dest):165 if os.path.exists(dest):166 log.warning("%s doesn't appear to be a valid git directory; clobbering", dest)167 remove_path(dest)168 if share_dir is not None:169 # Initialize the repo and set up the share170 init(dest)171 set_share(dest, share_dir)172 else:173 # Otherwise clone into dest174 clone(repo, dest, refname=refname, mirrors=mirrors, update_dest=False)175 # Make sure our share is pointing to the right place176 if share_dir is not None:177 lock_file = os.path.join(get_git_dir(share_dir), "index.lock")178 if os.path.exists(lock_file):179 log.info("removing %s", lock_file)180 safe_unlink(lock_file)181 set_share(dest, share_dir)182 # If we're supposed to be updating to a revision, check if we183 # have that revision already. If so, then there's no need to184 # fetch anything.185 do_fetch = False186 if revision is None:187 # we don't have a revision specified, so pull in everything188 do_fetch = True189 elif has_ref(dest, revision):190 # revision is actually a ref name, so we need to run fetch191 # to make sure we update the ref192 do_fetch = True193 elif not has_revision(dest, revision):194 # we don't have this revision, so need to fetch it195 do_fetch = True196 if do_fetch:197 if share_dir:198 # Fetch our refs into our share199 try:200 # TODO: Handle fetching refnames like refs/tags/XXXX201 if refname is None:202 fetch(repo, share_dir, mirrors=mirrors)203 else:204 fetch(repo, share_dir, mirrors=mirrors, refname=refname)205 except subprocess.CalledProcessError:206 # Something went wrong!207 # Clobber share_dir and re-raise208 log.info("error fetching into %s - clobbering", share_dir)209 remove_path(share_dir)210 raise211 try:212 if refname is None:213 fetch(share_dir, dest, fetch_remote="origin")214 else:215 fetch(share_dir, dest, fetch_remote="origin", refname=refname)216 except subprocess.CalledProcessError:217 log.info("clobbering %s", share_dir)218 remove_path(share_dir)219 log.info("error fetching into %s - clobbering", dest)220 remove_path(dest)221 raise222 else:223 try:224 fetch(repo, dest, mirrors=mirrors, refname=refname)225 except Exception:226 log.info("error fetching into %s - clobbering", dest)227 remove_path(dest)228 raise229 # Set our remote230 set_remote(dest, 'origin', repo)231 if update_dest:232 log.info("Updating local copy refname: %s; revision: %s", refname, revision)233 # Sometimes refname is passed in as a revision234 if revision:235 if not has_revision(dest, revision) and has_ref(dest, 'origin/%s' % revision):236 log.info("Using %s as ref name instead of revision", revision)237 refname = revision238 revision = None239 rev = update(dest, refname=refname, revision=revision)240 if clean_dest:241 clean(dest)242 return rev243 if clean_dest:244 clean(dest)245def clone(repo, dest, refname=None, mirrors=None, shared=False, update_dest=True):246 """Clones git repo and places it at `dest`, replacing whatever else is247 there. The working copy will be empty.248 If `mirrors` is set, will try and clone from the mirrors before249 cloning from `repo`.250 If `shared` is True, then git shared repos will be used251 If `update_dest` is False, then no working copy will be created252 """253 if os.path.exists(dest):254 remove_path(dest)255 if mirrors:256 log.info("Attempting to clone from mirrors")257 for mirror in mirrors:258 log.info("Cloning from %s", mirror)259 try:260 retval = clone(mirror, dest, refname, update_dest=update_dest)261 return retval262 except KeyboardInterrupt:263 raise264 except Exception:265 log.exception("Problem cloning from mirror %s", mirror)266 continue267 else:268 log.info("Pulling from mirrors failed; falling back to %s", repo)269 cmd = ['git', 'clone', '-q']270 if not update_dest:271 # TODO: Use --bare/--mirror here?272 cmd.append('--no-checkout')273 if refname:274 cmd.extend(['--branch', refname])275 if shared:276 cmd.append('--shared')277 cmd.extend([repo, dest])278 run_cmd(cmd)279 if update_dest:280 return get_revision(dest)281def update(dest, refname=None, revision=None, remote_name="origin"):282 """Updates working copy `dest` to `refname` or `revision`. If neither is283 set then the working copy will be updated to the latest revision on the284 current refname. Local changes will be discarded."""285 # If we have a revision, switch to that286 # We use revision^0 (and refname^0 below) to force the names to be287 # dereferenced into commit ids, which makes git check them out in a288 # detached state. This is equivalent to 'git checkout --detach', except is289 # supported by older versions of git290 if revision is not None:291 cmd = ['git', 'checkout', '-q', '-f', revision + '^0']292 run_cmd(cmd, cwd=dest)293 else:294 if not refname:295 refname = '%s/master' % remote_name296 else:297 refname = '%s/%s' % (remote_name, refname)298 cmd = ['git', 'checkout', '-q', '-f', refname + '^0']299 run_cmd(cmd, cwd=dest)300 return get_revision(dest)301def fetch(repo, dest, refname=None, remote_name="origin", fetch_remote=None, mirrors=None, fetch_tags=True):302 """Fetches changes from git repo and places it in `dest`.303 If `mirrors` is set, will try and fetch from the mirrors first before304 `repo`."""305 if mirrors:306 for mirror in mirrors:307 try:308 return fetch(mirror, dest, refname=refname)309 except KeyboardInterrupt:310 raise311 except Exception:312 log.exception("Problem fetching from mirror %s", mirror)313 continue314 else:315 log.info("Pulling from mirrors failed; falling back to %s", repo)316 # Convert repo to an absolute path if it's a local repository317 repo = _make_absolute(repo)318 cmd = ['git', 'fetch', '-q', repo]319 if not fetch_tags:320 # Don't fetch tags into our local tags/ refs since we have no way to321 # associate those with this remote and can't purge it later.322 cmd.append('--no-tags')323 if refname:324 if fetch_remote:325 cmd.append("+refs/remotes/{fetch_remote}/{refname}:refs/remotes/{remote_name}/{refname}".format(refname=refname, remote_name=remote_name, fetch_remote=fetch_remote))326 else:327 cmd.append("+refs/heads/{refname}:refs/remotes/{remote_name}/{refname}".format(refname=refname, remote_name=remote_name))328 else:329 if fetch_remote:330 cmd.append("+refs/remotes/{fetch_remote}/*:refs/remotes/{remote_name}/*".format(remote_name=remote_name, fetch_remote=fetch_remote))331 else:332 cmd.append("+refs/heads/*:refs/remotes/{remote_name}/*".format(remote_name=remote_name))333 run_cmd(cmd, cwd=dest)334def get_revision(path):335 """Returns which revision directory `path` currently has checked out."""336 proc = subprocess.Popen(['git', 'rev-parse', 'HEAD'], cwd=path, stdout=subprocess.PIPE)337 proc.wait()...
studio2FieldDD.js
Source:studio2FieldDD.js
1/**2 *3 * SugarCRM Community Edition is a customer relationship management program developed by4 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.5 *6 * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.7 * Copyright (C) 2011 - 2018 SalesAgility Ltd.8 *9 * This program is free software; you can redistribute it and/or modify it under10 * the terms of the GNU Affero General Public License version 3 as published by the11 * Free Software Foundation with the addition of the following permission added12 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK13 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY14 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.15 *16 * This program is distributed in the hope that it will be useful, but WITHOUT17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS18 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more19 * details.20 *21 * You should have received a copy of the GNU Affero General Public License along with22 * this program; if not, see http://www.gnu.org/licenses or write to the Free23 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA24 * 02110-1301 USA.25 *26 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,27 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.28 *29 * The interactive user interfaces in modified source and object code versions30 * of this program must display Appropriate Legal Notices, as required under31 * Section 5 of the GNU Affero General Public License version 3.32 *33 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,34 * these Appropriate Legal Notices must retain the display of the "Powered by35 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not36 * reasonably feasible for technical reasons, the Appropriate Legal Notices must37 * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".38 */39Studio2.FieldDD = function(id, sGroup) {40 Studio2.FieldDD.superclass.constructor.call(this, id, sGroup);41};42YAHOO.extend(Studio2.FieldDD, YAHOO.util.DDProxy, {43 startDrag: function(x, y) {44 // make the proxy look like the source element45 var dragEl = this.getDragEl();46 var clickEl = this.getEl();47 dragEl.innerHTML = clickEl.innerHTML;48 dragEl.className = clickEl.className;49 Studio2.copyId = null;50 this.showAnimation = true;51 if (Studio2.isSpecial(clickEl) && (Studio2.establishLocation(clickEl) == 'toolbox')) {52 var copy = Studio2.copyElement(clickEl);53 Studio2.setCopy(copy);54 clickEl.parentNode.insertBefore(copy,clickEl.nextSibling);55 YAHOO.util.Dom.setStyle(clickEl, "display", "none"); // don't want it to take up any space56 } else {57 YAHOO.util.Dom.setStyle(clickEl, "visibility", "hidden"); // want a empty space as we're dragging it away from this place58 }59 Studio2.setScrollObj(this);60 },61 endDrag: function(e) {62 Studio2.clearScrollObj();63 ModuleBuilder.state.isDirty=true;64 var srcEl = this.getEl();65 var proxy = this.getDragEl();66 var proxyid = proxy.id;67 var thisid = this.id;68 if (YAHOO.util.Dom.get(srcEl)) { // if we have a valid srcEl still...hasn't been deleted earlier69 // Show the proxy element and animate it to the src element's location70 YAHOO.util.Dom.setStyle(proxy, "visibility", "");71 YAHOO.util.Dom.setStyle(srcEl, "display", ""); // display!=none for getXY to work72 //YAHOO.util.Dom.setStyle(proxy).alignTo(srcEl, 'tl', null, {73 //callback: function(){74 YAHOO.util.Dom.setStyle(proxyid, "visibility", "hidden");75 if(typeof(YAHOO.util.Dom.get(thisid)) != 'undefined' && YAHOO.util.Dom.get(thisid)!=null) 76 YAHOO.util.Dom.setStyle(thisid, "visibility", "");77 }78 if (Studio2.isSpecial(srcEl) && Studio2.copy()) {79 Studio2.activateCopy(); // activateCopy makes it active, and removes the flag that says there is a copy80 } 81 82 proxy.innerHTML = "";83 },84 onInvalidDrop: function(e) {85 Studio2.clearScrollObj();86 var dragEl = this.getDragEl();87 dragEl.innerHTML = '';88 Studio2.removeCopy();89 YAHOO.util.Dom.setStyle(this.getEl(), "display", "block");90 },91 onDrag: Studio2.onDrag,92 93 onDragDrop: function(e, id) {94 var srcEl = this.getEl();95 var destEl = YAHOO.util.Dom.get(id); // where this element is being dropped96 var srcLocation = Studio2.establishLocation(srcEl);97 var destLocation = Studio2.establishLocation(destEl);98 // CASE1: Trying to delete an item from the toolbox or move fields within the toolbox - don't allow99 if ( ((srcLocation == 'toolbox') && (destLocation == 'delete')) ||100 ((srcLocation == 'toolbox') && (destLocation == 'toolbox'))) {101 Studio2.removeCopy();102 YAHOO.util.Dom.setStyle(srcEl, "display", "block"); // make it visible again - we made special elements invisible in startDrag103 return;104 }105 // CASE2: Delete a panel element106 // if source was in a panel (not toolbox) and destination is delete then remove this element107 if ((srcLocation == 'panels') && (destLocation == 'delete')) {108 if(Studio2.isSpecial(srcEl)) //nsingh- Bug 23057 Disallow deleting a (filler) as it does not make sense to do so.109 return;110 var parent = srcEl.parentNode;111 var sibling = srcEl.previousSibling;112 while(sibling != null) {113 if (sibling.className && (sibling.className.indexOf('le_field') != -1)) {114 break;115 }116 sibling = sibling.previousSibling;117 }118 if (sibling == null) {119 sibling = srcEl.nextSibling;120 while(sibling != null) {121 if (sibling.className && (sibling.className.indexOf('le_field') != -1)) {122 break;123 }124 sibling = sibling.nextSibling;125 }126 }127 Studio2.removeElement(srcEl);128 Studio2.unregisterExpandableField( srcEl );129// this.showAnimation = false; // can't show animation as the source no longer exists130 if (sibling == null) {131 // If we've just deleted the last field from a panel then we need to tidy up132 Studio2.tidyFields(parent);133 } else {134 Studio2.registerExpandableField(sibling);135 }136 return;137 } // end delete138 // CASE3: Simple field swap139 // Either neither one is special, or they're both special and both in panels140 if (( ! Studio2.isSpecial(srcEl) && ! Studio2.isSpecial(destEl)) ||141 ( Studio2.isSpecial(srcEl) && Studio2.isSpecial(destEl) && (srcLocation == 'panels') && (destLocation == 'panels')) ) {142 Studio2.swapElements(srcEl, destEl);143 this.runSpecialCode(srcEl, destEl);144 return;145 }146 // CASE4: swapping a special field from the toolbox with a field in a panel147 if (Studio2.copy() && (destLocation == 'panels')) {148 // CASE: split a field149 //Disallow (filler) on (filler)150 if( Studio2.isSpecial(destEl) ) {Studio2.removeCopy(); return }151 var destSibling = Studio2.nextField( destEl ) || Studio2.prevField( destEl );152 if( Studio2.isExpandable( destEl ) && destEl.getAttribute("state") == 'expanded' ){153 Studio2.removeCopy(); return;154 }155 if( Studio2.isExpandable( destEl ) && destEl.getAttribute("state") == 'reduced' ){ Studio2.unregisterExpandableField( destEl ); }156 var copy = Studio2.copyElement(srcEl);157 Studio2.activateElement(copy);158 YAHOO.util.Dom.setStyle(copy, "display", "");159 Studio2.swapElements( Studio2.copy(),destEl );160 YAHOO.util.Dom.setStyle(srcEl, "display", "");161 Studio2.registerExpandableField (destSibling );162 return;163 }164 // CASE5: moving a plain field from the panel to a special field in the toolbox - just copy165 if ( ! Studio2.isSpecial(srcEl) && Studio2.isSpecial(destEl) && (destLocation == 'toolbox')) {166 // make a copy of the destination167 if(Studio2.isExpandable (srcEl ) && Studio2.isExpanded( srcEl)) {168 Studio2.toggleFieldWidth(srcEl.id); //bring back the old filler.169 Studio2.unregisterExpandableField ( srcEl );170 }171 //check if srcSibling needs to expand172// var srcSibling = ;173 var copy = Studio2.copyElement(destEl);174 var destination = document.getElementById('availablefields');175 destination.appendChild(copy);176 Studio2.swapElements(copy,srcEl);177 YAHOO.util.Dom.setStyle(srcEl, "display", "");178 Studio2.activateElement(copy);179 //if src is expanded, reduce it then unregister180 //After Swap Only.181 Studio2.registerExpandableField( Studio2.nextField( srcEl ) || Studio2.prevField( srcEl ) );182 return;183 }184 //CASE6: (filler) droppped on a expandable field.185 if(Studio2.isSpecial(srcEl) && destLocation == srcLocation ){186 //Disallow Swap if dropping on a expanded field.187 if( Studio2.isExpandable( destEl ) && Studio2.isExpanded( destEl )) {return; }188 var srcSibling = Studio2.prevField( srcEl ) || Studio2.nextField( srcEl );189 var destSibling = Studio2.prevField( destEl ) || Studio2.nextField( destEl );190 Studio2.swapElements(srcEl, destEl); //don't change order.191 if ( !Studio2.isExpandable( destSibling ) && Studio2.isExpandable(srcSibling) && Studio2.isReduced(srcSibling) && !(srcSibling.id == destEl.id && srcEl.id == destSibling.id)) {192 Studio2.unregisterExpandableField( srcSibling );193 Studio2.registerExpandableField (destSibling );194 Studio2.unregisterExpandableField( destEl );195 }196 if ( !Studio2.isExpandable( destEl ) && Studio2.isSpecial( destSibling )) {197 Studio2.registerExpandableField (destEl );198 }199 if(!Studio2.isSpecial(destSibling)) {Studio2.registerExpandableField (destSibling )}200 return;201 }202 //CASE 7: A special field swapped with a regular field. Source is not-special, destination is special.203 if(!Studio2.isSpecial(srcEl) && Studio2.isSpecial(destEl) && destLocation == srcLocation) {204 /**205 if destination's left sibling is expandable.206 unregister left sibling from expandable.207 if src field's left sibling is not special208 register left sibling to expandable.209 */210 var srcSibling = Studio2.prevField(srcEl) || Studio2.nextField( srcEl ) ;211 var destSibling = Studio2.prevField(destEl) || Studio2.nextField( destEl );212 var sameRow = (srcSibling!=null && destSibling!=null) ? (srcSibling.id == destEl.id && destSibling.id == srcEl.id) : false;213 if (Studio2.isExpandable( srcEl ) && Studio2.isExpanded( srcEl )) {return;} //disallow dropping expanded fields onto fillers.214 if (Studio2.isExpandable ( srcEl ) && Studio2.isReduced( srcEl ) && !sameRow) {Studio2.unregisterExpandableField( srcEl );}215 if (Studio2.isExpandable (destSibling) && !sameRow ){Studio2.unregisterExpandableField( destSibling )}216 //expand src sibling217 if( srcEl.id == destSibling.id && srcSibling.id == destEl.id ) {Studio2.registerExpandableField ( srcEl ) }218 Studio2.swapElements(srcEl, destEl);219 if (Studio2.isSpecial(destSibling)) {Studio2.registerExpandableField(srcEl)}220 Studio2.registerExpandableField( srcSibling );221 return;222 }223 if( !Studio2.isSpecial( srcEl ) && Studio2.isSpecial( destEl) && destLocation == 'panels' && srcLocation =='toolbox'){224 var destSibling = Studio2.nextField( destEl ) || Studio2.prevField ( destEl );225 Studio2.unregisterExpandableField( destSibling );226 Studio2.swapElements( srcEl,destEl );227 Studio2.removeElement( destEl ) ;228 return;229 }230 Studio2.swapElements( srcEl,destEl );231 this.runSpecialCode(srcEl,destEl);232 if ((srcLocation != destLocation)) {233 if (Studio2.isSpecial(srcEl) && ! Studio2.isSpecial(destEl)) {234 Studio2.removeElement(srcEl);235// this.showAnimation = false;236 return;237 }238 if (Studio2.isSpecial(destEl) && ! Studio2.isSpecial(srcEl)) {239 Studio2.removeElement(destEl);240// this.showAnimation = false;241 return;242 }243 }244 },245 runSpecialCode: function(srcEl, destEl){246 var srcLeftSibling = Studio2.prevField(srcEl);247 var srcRightSibling = Studio2.nextField(srcEl);248 var destRightSibling = Studio2.nextField(destEl);249 var destLeftSibling = Studio2.prevField(destEl);250 //For every affected element unexpand if needed.251 //registration vs Transformation.252 if ( Studio2.isExpandable (srcEl ) && Studio2.isExpandable( destEl) ){253 //src is dest now. copy dest's properties to src.254 Studio2.swapStates( srcEl, destEl );255 //srcEl.setAttribute("state", destEl.getAttribute("state"));256 }257 var registerSrc = !Studio2.isExpandable( srcEl );258 var destExpandable = !Studio2.isSpecial(destEl) && ((null==destRightSibling && null==destLeftSibling)259 || (null !== destRightSibling) && Studio2.isSpecial(destRightSibling));260 var srcUnexpandable = !Studio2.isSpecial(srcEl) && ((null!==srcLeftSibling && !Studio2.isSpecial(srcLeftSibling))261 || ((null !== srcRightSibling) && !Studio2.isSpecial(srcRightSibling)));262 var destUnexpandable = !Studio2.isSpecial(destEl) && ((null!==destLeftSibling && !Studio2.isSpecial(destLeftSibling))263 || ((null!== destRightSibling) && !Studio2.isSpecial(destRightSibling)));264 if( registerSrc ){265 Studio2.registerExpandableField( srcEl );266 }267 if(srcUnexpandable){268 Studio2.unregisterExpandableField( srcEl );269 }270 if(destExpandable){271 Studio2.registerExpandableField(destEl);272 }273 if(destUnexpandable){274 Studio2.unregisterExpandableField( destEl );275 }276 if(srcLeftSibling!==null && !Studio2.isSpecial(srcLeftSibling) && !Studio2.isSpecial(srcEl))277 Studio2.unregisterExpandableField( srcLeftSibling );278 return;279 }...
copy.js
Source:copy.js
1module.exports = {2 less: {3 files: [{4 expand: true,5 dot: true,6 filter: 'isFile',7 flatten: true,8 cwd: 'scss/temp/',9 dest: 'scss/',10 src: ['{,*/}*.scss'],11 rename: function(dest, src) {12 if (src !== 'material-design-iconic-font.scss') {13 src = "_" + src;14 }15 return dest + src;16 }17 }]18 },19 action: {20 files: [{21 expand: true,22 dot: true,23 filter: 'isFile',24 flatten: true,25 cwd: 'node_modules/material-design-icons/action/svg/production/',26 dest: 'svg/google/action/',27 src: ['{,*/}*_24px.svg'],28 rename: function(dest, src) {29 src = src.replace('ic_','');30 src = src.replace('_24px','');31 return dest + src.replace(/[_ ]/g,'-');32 }33 }]34 },35 alert: {36 files: [{37 expand: true,38 dot: true,39 filter: 'isFile',40 flatten: true,41 cwd: 'node_modules/material-design-icons/alert/svg/production/',42 dest: 'svg/google/alert/',43 src: ['{,*/}*_24px.svg'],44 rename: function(dest, src) {45 src = src.replace('ic_','');46 src = src.replace('_24px','');47 return dest + src.replace(/[_ ]/g,'-');48 }49 }]50 },51 av: {52 files: [{53 expand: true,54 dot: true,55 filter: 'isFile',56 flatten: true,57 cwd: 'node_modules/material-design-icons/av/svg/production/',58 dest: 'svg/google/av/',59 src: ['{,*/}*_24px.svg'],60 rename: function(dest, src) {61 src = src.replace('ic_','');62 src = src.replace('_24px','');63 return dest + src.replace(/[_ ]/g,'-');64 }65 }]66 },67 communication: {68 files: [{69 expand: true,70 dot: true,71 filter: 'isFile',72 flatten: true,73 cwd: 'node_modules/material-design-icons/communication/svg/production/',74 dest: 'svg/google/communication/',75 src: ['{,*/}*_24px.svg'],76 rename: function(dest, src) {77 src = src.replace('ic_','');78 src = src.replace('_24px','');79 return dest + src.replace(/[_ ]/g,'-');80 }81 }]82 },83 content: {84 files: [{85 expand: true,86 dot: true,87 filter: 'isFile',88 flatten: true,89 cwd: 'node_modules/material-design-icons/content/svg/production/',90 dest: 'svg/google/content/',91 src: ['{,*/}*_24px.svg'],92 rename: function(dest, src) {93 src = src.replace('ic_','');94 src = src.replace('_24px','');95 return dest + src.replace(/[_ ]/g,'-');96 }97 }]98 },99 device: {100 files: [{101 expand: true,102 dot: true,103 filter: 'isFile',104 flatten: true,105 cwd: 'node_modules/material-design-icons/device/svg/production/',106 dest: 'svg/google/device/',107 src: ['{,*/}*_24px.svg'],108 rename: function(dest, src) {109 src = src.replace('ic_','');110 src = src.replace('_24px','');111 return dest + src.replace(/[_ ]/g,'-');112 }113 }]114 },115 editor: {116 files: [{117 expand: true,118 dot: true,119 filter: 'isFile',120 flatten: true,121 cwd: 'node_modules/material-design-icons/editor/svg/production/',122 dest: 'svg/google/editor/',123 src: ['{,*/}*_24px.svg'],124 rename: function(dest, src) {125 src = src.replace('ic_','');126 src = src.replace('_24px','');127 return dest + src.replace(/[_ ]/g,'-');128 }129 }]130 },131 file: {132 files: [{133 expand: true,134 dot: true,135 filter: 'isFile',136 flatten: true,137 cwd: 'node_modules/material-design-icons/file/svg/production/',138 dest: 'svg/google/file/',139 src: ['{,*/}*_24px.svg'],140 rename: function(dest, src) {141 src = src.replace('ic_','');142 src = src.replace('_24px','');143 return dest + src.replace(/[_ ]/g,'-');144 }145 }]146 },147 hardware: {148 files: [{149 expand: true,150 dot: true,151 filter: 'isFile',152 flatten: true,153 cwd: 'node_modules/material-design-icons/hardware/svg/production/',154 dest: 'svg/google/hardware/',155 src: ['{,*/}*_24px.svg'],156 rename: function(dest, src) {157 src = src.replace('ic_','');158 src = src.replace('_24px','');159 return dest + src.replace(/[_ ]/g,'-');160 }161 }]162 },163 image: {164 files: [{165 expand: true,166 dot: true,167 filter: 'isFile',168 flatten: true,169 cwd: 'node_modules/material-design-icons/image/svg/production/',170 dest: 'svg/google/image/',171 src: ['{,*/}*_24px.svg'],172 rename: function(dest, src) {173 src = src.replace('ic_','');174 src = src.replace('_24px','');175 return dest + src.replace(/[_ ]/g,'-');176 }177 }]178 },179 maps: {180 files: [{181 expand: true,182 dot: true,183 filter: 'isFile',184 flatten: true,185 cwd: 'node_modules/material-design-icons/maps/svg/production/',186 dest: 'svg/google/maps/',187 src: ['{,*/}*_24px.svg'],188 rename: function(dest, src) {189 src = src.replace('ic_','');190 src = src.replace('_24px','');191 return dest + src.replace(/[_ ]/g,'-');192 }193 }]194 },195 navigation: {196 files: [{197 expand: true,198 dot: true,199 filter: 'isFile',200 flatten: true,201 cwd: 'node_modules/material-design-icons/navigation/svg/production/',202 dest: 'svg/google/navigation/',203 src: ['{,*/}*_24px.svg'],204 rename: function(dest, src) {205 src = src.replace('ic_','');206 src = src.replace('_24px','');207 return dest + src.replace(/[_ ]/g,'-');208 }209 }]210 },211 notification: {212 files: [{213 expand: true,214 dot: true,215 filter: 'isFile',216 flatten: true,217 cwd: 'node_modules/material-design-icons/notification/svg/production/',218 dest: 'svg/google/notification/',219 src: ['{,*/}*_24px.svg'],220 rename: function(dest, src) {221 src = src.replace('ic_','');222 src = src.replace('_24px','');223 return dest + src.replace(/[_ ]/g,'-');224 }225 }]226 },227 social: {228 files: [{229 expand: true,230 dot: true,231 filter: 'isFile',232 flatten: true,233 cwd: 'node_modules/material-design-icons/social/svg/production/',234 dest: 'svg/google/social/',235 src: ['{,*/}*_24px.svg'],236 rename: function(dest, src) {237 src = src.replace('ic_','');238 src = src.replace('_24px','');239 return dest + src.replace(/[_ ]/g,'-');240 }241 }]242 },243 toggle: {244 files: [{245 expand: true,246 dot: true,247 filter: 'isFile',248 flatten: true,249 cwd: 'node_modules/material-design-icons/toggle/svg/production/',250 dest: 'svg/google/toggle/',251 src: ['{,*/}*_24px.svg'],252 rename: function(dest, src) {253 src = src.replace('ic_','');254 src = src.replace('_24px','');255 return dest + src.replace(/[_ ]/g,'-');256 }257 }]258 }...
install_custom_python.py
Source:install_custom_python.py
1""" Copies the build output of a custom python interpreter to a directory2 structure that mirrors that of an official Python distribution.3 --------------------------------------------------------------------------4 File: install_custom_python.py5 Overview: Most users build LLDB by linking against the standard6 Python distribution installed on their system. Occasionally7 a user may want to build their own version of Python, and on8 platforms such as Windows this is a hard requirement. This9 script will take the build output of a custom interpreter and10 install it into a canonical structure that mirrors that of an11 official Python distribution, thus allowing PYTHONHOME to be12 set appropriately.13 Gotchas: None.14 Copyright: None.15 --------------------------------------------------------------------------16"""17import argparse18import itertools19import os20import shutil21import sys22def copy_one_file(dest_dir, source_dir, filename):23 source_path = os.path.join(source_dir, filename)24 dest_path = os.path.join(dest_dir, filename)25 print 'Copying file %s ==> %s...' % (source_path, dest_path)26 shutil.copyfile(source_path, dest_path)27def copy_named_files(28 dest_dir,29 source_dir,30 files,31 extensions,32 copy_debug_suffix_also):33 for (file, ext) in itertools.product(files, extensions):34 copy_one_file(dest_dir, source_dir, file + '.' + ext)35 if copy_debug_suffix_also:36 copy_one_file(dest_dir, source_dir, file + '_d.' + ext)37def copy_subdirectory(dest_dir, source_dir, subdir):38 dest_dir = os.path.join(dest_dir, subdir)39 source_dir = os.path.join(source_dir, subdir)40 print 'Copying directory %s ==> %s...' % (source_dir, dest_dir)41 shutil.copytree(source_dir, dest_dir)42def copy_distro(dest_dir, dest_subdir, source_dir, source_prefix):43 dest_dir = os.path.join(dest_dir, dest_subdir)44 print 'Copying distribution %s ==> %s' % (source_dir, dest_dir)45 os.mkdir(dest_dir)46 PCbuild_dir = os.path.join(source_dir, 'PCbuild')47 if source_prefix:48 PCbuild_dir = os.path.join(PCbuild_dir, source_prefix)49 # First copy the files that go into the root of the new distribution. This50 # includes the Python executables, python27(_d).dll, and relevant PDB51 # files.52 print 'Copying Python executables...'53 copy_named_files(54 dest_dir, PCbuild_dir, ['w9xpopen'], [55 'exe', 'pdb'], False)56 copy_named_files(57 dest_dir, PCbuild_dir, [58 'python_d', 'pythonw_d'], ['exe'], False)59 copy_named_files(60 dest_dir, PCbuild_dir, [61 'python', 'pythonw'], [62 'exe', 'pdb'], False)63 copy_named_files(dest_dir, PCbuild_dir, ['python27'], ['dll', 'pdb'], True)64 # Next copy everything in the Include directory.65 print 'Copying Python include directory'66 copy_subdirectory(dest_dir, source_dir, 'Include')67 # Copy Lib folder (builtin Python modules)68 print 'Copying Python Lib directory'69 copy_subdirectory(dest_dir, source_dir, 'Lib')70 # Copy tools folder. These are probably not necessary, but we copy them anyway to71 # match an official distribution as closely as possible. Note that we don't just copy72 # the subdirectory recursively. The source distribution ships with many more tools73 # than what you get by installing python regularly. We only copy the tools that appear74 # in an installed distribution.75 tools_dest_dir = os.path.join(dest_dir, 'Tools')76 tools_source_dir = os.path.join(source_dir, 'Tools')77 os.mkdir(tools_dest_dir)78 copy_subdirectory(tools_dest_dir, tools_source_dir, 'i18n')79 copy_subdirectory(tools_dest_dir, tools_source_dir, 'pynche')80 copy_subdirectory(tools_dest_dir, tools_source_dir, 'scripts')81 copy_subdirectory(tools_dest_dir, tools_source_dir, 'versioncheck')82 copy_subdirectory(tools_dest_dir, tools_source_dir, 'webchecker')83 pyd_names = [84 '_ctypes',85 '_ctypes_test',86 '_elementtree',87 '_multiprocessing',88 '_socket',89 '_testcapi',90 'pyexpat',91 'select',92 'unicodedata',93 'winsound']94 # Copy builtin extension modules (pyd files)95 dlls_dir = os.path.join(dest_dir, 'DLLs')96 os.mkdir(dlls_dir)97 print 'Copying DLLs directory'98 copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ['pyd', 'pdb'], True)99 # Copy libs folder (implibs for the pyd files)100 libs_dir = os.path.join(dest_dir, 'libs')101 os.mkdir(libs_dir)102 print 'Copying libs directory'103 copy_named_files(libs_dir, PCbuild_dir, pyd_names, ['lib'], False)104 copy_named_files(libs_dir, PCbuild_dir, ['python27'], ['lib'], True)105parser = argparse.ArgumentParser(106 description='Install a custom Python distribution')107parser.add_argument(108 '--source',109 required=True,110 help='The root of the source tree where Python is built.')111parser.add_argument(112 '--dest',113 required=True,114 help='The location to install the Python distributions.')115parser.add_argument(116 '--overwrite',117 default=False,118 action='store_true',119 help='If the destination directory already exists, destroys its contents first.')120parser.add_argument(121 '--silent',122 default=False,123 action='store_true',124 help='If --overwite was specified, suppress confirmation before deleting a directory tree.')125args = parser.parse_args()126args.source = os.path.normpath(args.source)127args.dest = os.path.normpath(args.dest)128if not os.path.exists(args.source):129 print 'The source directory %s does not exist. Exiting...'130 sys.exit(1)131if os.path.exists(args.dest):132 if not args.overwrite:133 print 'The destination directory \'%s\' already exists and --overwrite was not specified. Exiting...' % args.dest134 sys.exit(1)135 while not args.silent:136 print 'Ok to recursively delete \'%s\' and all contents (Y/N)? Choosing Y will permanently delete the contents.' % args.dest137 result = str.upper(sys.stdin.read(1))138 if result == 'N':139 print 'Unable to copy files to the destination. The destination already exists.'140 sys.exit(1)141 elif result == 'Y':142 break143 shutil.rmtree(args.dest)144os.mkdir(args.dest)145copy_distro(args.dest, 'x86', args.source, None)...
Using AI Code Generation
1var wptools = require('wptools');2var options = {3};4var page = wptools.page('Barack Obama', options);5page.get(function(err, resp) {6 if (err) {7 console.log(err);8 } else {9 console.log(resp);10 }11});
Using AI Code Generation
1const fs = require('fs');2const path = require('path');3const wpt = require('webpagetest');4const util = require('util');5const exec = util.promisify(require('child_process').exec);6const { promisify } = require('util');7const writeFile = promisify(fs.writeFile);8const readFile = promisify(fs.readFile);9const options = {10 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/18.1b12038 Mobile/16B92 Safari/605.1.15',11 lighthouseConfig: {12 settings: {13 },14 },
Using AI Code Generation
1var WPTS = require('wpts');2var wpts = new WPTS();3wpts.dest('dest');4### wpts.src()5var WPTS = require('wpts');6var wpts = new WPTS();7wpts.src('src');8### wpts.watch()9var WPTS = require('wpts');10var wpts = new WPTS();11wpts.watch('watch');12### wpts.watch()13var WPTS = require('wpts');14var wpts = new WPTS();15wpts.watch('watch');16### wpts.watch()17var WPTS = require('wpts');18var wpts = new WPTS();19wpts.watch('watch');20### wpts.watch()21var WPTS = require('wpts');22var wpts = new WPTS();23wpts.watch('watch');24### wpts.watch()25var WPTS = require('wpts');26var wpts = new WPTS();27wpts.watch('watch');28### wpts.watch()29var WPTS = require('wpts');30var wpts = new WPTS();31wpts.watch('watch');32### wpts.watch()33var WPTS = require('wpts');34var wpts = new WPTS();35wpts.watch('watch');36### wpts.watch()37var WPTS = require('wpts');38var wpts = new WPTS();39wpts.watch('watch');40### wpts.task()41var WPTS = require('wpts
Using AI Code Generation
1var fs = require('fs');2var readable = fs.createReadStream(__dirname + '/greet.txt', {encoding: 'utf8', highWaterMark: 16 * 1024});3var writable = fs.createWriteStream(__dirname + '/greetcopy.txt');4readable.on('data', function(chunk){5 console.log(chunk.length);6 writable.write(chunk);7});
Using AI Code Generation
1var wpt = require('webpagetest');2var options = {3};4var test = wpt(options);5var dest = 'test.json';6test.runTest(url, function(err, data) {7 if (err) return console.error(err);8 console.log('Test submitted. Polling for results.');9 test.getTestResults(data.data.testId, function(err, data) {10 if (err) return console.error(err);11 console.log('Test completed.');12 console.log('First View: ' + data.data.average.firstView.loadTime + 'ms');13 console.log('Repeat View: ' + data.data.average.repeatView.loadTime + 'ms');14 test.getTestResults(data.data.testId, function(err, data) {15 if (err) return console.error(err);16 console.log('Test completed.');17 console.log('First View: ' + data.data.average.firstView.loadTime + 'ms');18 console.log('Repeat View: ' + data.data.average.repeatView.loadTime + 'ms');19 test.getTestResults(data.data.testId, function(err, data) {20 if (err) return console.error(err);21 console.log('Test completed.');22 console.log('First View: ' + data.data.average.firstView.loadTime + 'ms');23 console.log('Repeat View: ' + data.data.average.repeatView.loadTime + 'ms');24 test.getTestResults(data.data.testId, function(err, data) {25 if (err) return console.error(err);26 console.log('Test completed.');27 console.log('First View: ' + data.data.average.firstView.loadTime + 'ms');28 console.log('Repeat View: ' + data.data.average.repeatView.loadTime + 'ms');29 test.getTestResults(data.data.testId, function(err, data) {30 if (err)
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!