diff --git a/Release/XSeen.0.4.5+23_75edebb.js b/Release/XSeen.0.4.5+23_75edebb.js new file mode 100644 index 0000000..a8cc914 --- /dev/null +++ b/Release/XSeen.0.4.5+23_75edebb.js @@ -0,0 +1,4103 @@ +/* + * XSeen V0.4.5+23_75edebb + * Built Mon Jul 10 20:41:35 2017 + * + +Dual licensed under the MIT and GPL licenses. + +==[MIT]==================================================================== +Copyright (c) 2017, Daly Realism + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +==[GPL]==================================================================== + +XSeen - Declarative 3D for HTML + +Copyright (C) 2017, Daly Realism + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + + +=== COPYRIGHT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Copyright (C) 2017, Daly Realism for XSeen +Copyright, Fraunhofer for X3DOM +Copyright, Mozilla for A-Frame +Copyright, THREE and Khronos for various parts of THREE.js +Copyright (C) 2017, John Carlson for JSON->XML converter (JSONParser.js) + +=== +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + */ +// File: utils/JSONParser.js +"use strict"; + +var JSONParser = function(scene) +{ +} + +JSONParser.prototype.constructor = JSONParser; + + /** + * Load X3D JSON into an element. + * jsobj - the JavaScript object to convert to DOM. + */ +JSONParser.prototype.parseJavaScript = function(jsobj) { + var child = this.CreateElement('scene'); + this.ConvertToX3DOM(jsobj, "", child); + // console.log(jsobj, child); + return child; + }; + + // 'http://www.web3d.org/specifications/x3d-namespace' + + // Load X3D JavaScript object into XML or DOM + + /** + * Yet another way to set an attribute on an element. does not allow you to + * set JSON schema or encoding. + */ +JSONParser.prototype.elementSetAttribute = function(element, key, value) { + if (key === 'SON schema') { + // JSON Schema + } else if (key === 'ncoding') { + // encoding, UTF-8, UTF-16 or UTF-32 + } else { + if (typeof element.setAttribute === 'function') { + element.setAttribute(key, value); + } + } + }; + + /** + * converts children of object to DOM. + */ +JSONParser.prototype.ConvertChildren = function(parentkey, object, element) { + var key; + + for (key in object) { + if (typeof object[key] === 'object') { + if (isNaN(parseInt(key))) { + this.ConvertObject(key, object, element, parentkey.substr(1)); + } else { + this.ConvertToX3DOM(object[key], key, element, parentkey.substr(1)); + } + } + } + }; + + /** + * a method to create and element with tagnam key to DOM in a namespace. If + * containerField is set, then the containerField is set in the elemetn. + */ +JSONParser.prototype.CreateElement = function(key, containerField) { + var child = document.createElement(key); + if (typeof containerField !== 'undefined') { + this.elementSetAttribute(child, 'containerField', containerField); + } + return child; + }; + + /** + * a way to create a CDATA function or script in HTML, by using a DOM parser. + */ +JSONParser.prototype.CDATACreateFunction = function(document, element, str) { + var y = str.replace(/\\"/g, "\\\"") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/&/g, "&"); + do { + str = y; + y = str.replace(/'([^'\r\n]*)\n([^']*)'/g, "'$1\\n$2'"); + if (str !== y) { + console.log("CDATA Replacing",str,"with",y); + } + } while (y != str); + var domParser = new DOMParser(); + var cdataStr = ''; // has to be wrapped into an element + var scriptDoc = domParser .parseFromString (cdataStr, 'application/xml'); + var cdata = scriptDoc .children[0] .childNodes[1]; // space after script is childNode[0] + element .appendChild(cdata); + }; + + /** + * convert the object at object[key] to DOM. + */ +JSONParser.prototype.ConvertObject = function(key, object, element, containerField) { + var child; + if (object !== null && typeof object[key] === 'object') { + if (key.substr(0,1) === '@') { + this.ConvertToX3DOM(object[key], key, element); + } else if (key.substr(0,1) === '-') { + this.ConvertChildren(key, object[key], element); + } else if (key === '#comment') { + for (var c in object[key]) { + child = document.createComment(this.CommentStringToXML(object[key][c])); + element.appendChild(child); + } + } else if (key === '#text') { + child = document.createTextNode(object[key].join("")); + element.appendChild(child); + } else if (key === '#sourceText') { + this.CDATACreateFunction(document, element, object[key].join("\r\n")+"\r\n"); + } else { + if (key === 'connect' || key === 'fieldValue' || key === 'field' || key === 'meta' || key === 'component') { + for (var childkey in object[key]) { // for each field + if (typeof object[key][childkey] === 'object') { + child = this.CreateElement(key, containerField); + this.ConvertToX3DOM(object[key][childkey], childkey, child); + element.appendChild(child); + element.appendChild(document.createTextNode("\n")); + } + } + } else { + child = this.CreateElement(key, containerField); + this.ConvertToX3DOM(object[key], key, child); + element.appendChild(child); + element.appendChild(document.createTextNode("\n")); + } + } + } + }; + + /** + * convert a comment string in JavaScript to XML. Pass the string + */ +JSONParser.prototype.CommentStringToXML = function(str) { + var y = str; + str = str.replace(/\\\\/g, '\\'); + if (y !== str) { + console.log("X3DJSONLD replacing", y, "with", str); + } + return str; + }; + + /** + * convert an SFString to XML. + */ +JSONParser.prototype.SFStringToXML = function(str) { + var y = str; + /* + str = (""+str).replace(/\\\\/g, '\\\\'); + str = str.replace(/\\\\\\\\/g, '\\\\'); + str = str.replace(/(\\+)"/g, '\\"'); + */ + str = str.replace(/\\/g, '\\\\'); + str = str.replace(/"/g, '\\\"'); + if (y !== str) { + console.log("X3DJSONLD [] replacing", y, "with", str); + } + return str; + }; + + /** + * convert a JSON String to XML. + */ +JSONParser.prototype.JSONStringToXML = function(str) { + var y = str; + str = str.replace(/\\/g, '\\\\'); + str = str.replace(/\n/g, '\\n'); + if (y !== str) { + console.log("X3DJSONLD replacing", y, "with", str); + } + return str; + }; + + /** + * main routine for converting a JavaScript object to DOM. + * object is the object to convert. + * parentkey is the key of the object in the parent. + * element is the parent element. + * containerField is a possible containerField. + */ +JSONParser.prototype.ConvertToX3DOM = function(object, parentkey, element, containerField) { + var key; + var localArray = []; + var isArray = false; + var arrayOfStrings = false; + for (key in object) { + if (isNaN(parseInt(key))) { + isArray = false; + } else { + isArray = true; + } + if (isArray) { + if (typeof object[key] === 'number') { + localArray.push(object[key]); + } else if (typeof object[key] === 'string') { + localArray.push(object[key]); + arrayOfStrings = true; + } else if (typeof object[key] === 'boolean') { + localArray.push(object[key]); + } else if (typeof object[key] === 'object') { + /* + if (object[key] != null && typeof object[key].join === 'function') { + localArray.push(object[key].join(" ")); + } + */ + this.ConvertToX3DOM(object[key], key, element); + } else if (typeof object[key] === 'undefined') { + } else { + console.error("Unknown type found in array "+typeof object[key]); + } + } else if (typeof object[key] === 'object') { + // This is where the whole thing starts + if (key === 'scene') { + this.ConvertToX3DOM(object[key], key, element); + } else { + this.ConvertObject(key, object, element); + } + } else if (typeof object[key] === 'number') { + this.elementSetAttribute(element, key.substr(1),object[key]); + } else if (typeof object[key] === 'string') { + if (key === '#comment') { + var child = document.createComment(this.CommentStringToXML(object[key])); + element.appendChild(child); + } else if (key === '#text') { + var child = document.createTextNode(object[key]); + element.appendChild(child); + } else { + // ordinary string attributes + this.elementSetAttribute(element, key.substr(1), this.JSONStringToXML(object[key])); + } + } else if (typeof object[key] === 'boolean') { + this.elementSetAttribute(element, key.substr(1),object[key]); + } else if (typeof object[key] === 'undefined') { + } else { + console.error("Unknown type found in object "+typeof object[key]); + console.error(object); + } + } + if (isArray) { + if (parentkey.substr(0,1) === '@') { + if (arrayOfStrings) { + arrayOfStrings = false; + for (var str in localArray) { + localArray[str] = this.SFStringToXML(localArray[str]); + } + this.elementSetAttribute(element, parentkey.substr(1),'"'+localArray.join('" "')+'"'); + } else { + // if non string array + this.elementSetAttribute(element, parentkey.substr(1),localArray.join(" ")); + } + } + isArray = false; + } + return element; + }; +// File: utils/LoadManager.js +/* + * For use with XSeen JavaScript Library + * http://tools.realism.com/... + * + * Licensed under MIT or GNU in the same manner as XSeen + * + * (C)2017 Daly Realiusm, Los Angeles + * + */ + +/* + * Manages all download requests. + * Requests are queued up and processed to the maximum limit (.MaxRequests) + * Use this for processing text (X3D, XML, JSON, HTML) files. + * Not really setup for binary files (.jpg, png, etc.) + * + * Requires jQuery -- should work on removing that... + * + */ + +function LoadManager () { + this.urlQueue = []; + this.urlNext = -1; + this.MaxRequests = 3; + this.totalRequests = 0; + this.totalResponses = 0; + this.requestCount = 0; + var lmThat = this; + + this.load = function (url, success, progress, failed, userdata) { + this.urlQueue.push( {'url':url, 'type':'', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); + this.loadNextUrl(); + } + + this.loadText = function (url, success, progress, failed, userdata) { + this.urlQueue.push( {'url':url, 'type':'text', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); + this.loadNextUrl(); + } + + this.loadHtml = function (url, success, progress, failed, userdata) { + this.urlQueue.push( {'url':url, 'type':'html', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); + this.loadNextUrl(); + } + + this.loadXml = function (url, success, progress, failed, userdata) { + this.urlQueue.push( {'url':url, 'type':'xml', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); + this.loadNextUrl(); + } + + this.loadJson = function (url, success, progress, failed, userdata) { + this.urlQueue.push( {'url':url, 'type':'json', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); + this.loadNextUrl(); + } + + this.loadImage = function (url, success, progress, failed, userdata) { + this.urlQueue.push( {'url':url, 'type':'image', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); + this.loadNextUrl(); + } + + this.success = function (response, string, xhr) { + if (typeof(xhr._loadManager.success) !== undefined) { + xhr._loadManager.success (response, xhr._loadManager.userdata, xhr); + } + } + + this.failure = function (xhr, errorCode, errorText) { + if (typeof(xhr._loadManager.failure) !== undefined) { + xhr._loadManager.failure (xhr, xhr._loadManager.userdata, errorCode, errorText); + } + } + + this.requestComplete = function (event, xhr, settings) { + lmThat.requestCount --; + lmThat.totalResponses++; + lmThat.loadNextUrl(); + } + + this.loadNextUrl = function () { + if (this.requestCount >= this.MaxRequests) {return; } + if (this.urlNext >= this.urlQueue.length || this.urlNext < 0) { + this.urlNext = -1; + for (var i=0; i ' + obj.type + ' (' + obj.name + ')'); + for (var i=0; i + var validParams = xseen.array_to_object([ + 'showLog', + 'showStat', + 'showProgress', + 'PrimitiveQuality', + 'components', + 'loadpath', + 'disableDoubleClick', + 'backend', + 'altImg', + 'runtimeEnabled', + 'keysEnabled', + 'showTouchpoints', + 'disableTouch', + 'maxActiveDownloads' + ]); + var components, prefix; + var showLoggingConsole = false; + + // for each XSeens element + for (var i=0; i < xseens.length; i++) { + + // default parameters + settings.setProperty("showLog", xseens[i].getAttribute("showLog") || 'false'); + settings.setProperty("showLog", xseens[i].getAttribute("showLog") || 'true'); + settings.setProperty("showStat", xseens[i].getAttribute("showStat") || 'false'); + settings.setProperty("showProgress", xseens[i].getAttribute("showProgress") || 'true'); + settings.setProperty("PrimitiveQuality", xseens[i].getAttribute("PrimitiveQuality") || 'High'); + + // for each param element inside the X3D element + // add settings to properties object + params = xseens[i].getElementsByTagName('PARAM'); + for (var j=0; j < params.length; j++) { + if (params[j].getAttribute('name') in validParams) { + settings.setProperty(params[j].getAttribute('name'), params[j].getAttribute('value')); + } else { + //xseen.debug.logError("Unknown parameter: " + params[j].getAttribute('name')); + } + } + + // enable log + if (settings.getProperty('showLog') === 'true') { + showLoggingConsole = true; + } + + if (typeof X3DOM_SECURITY_OFF != 'undefined' && X3DOM_SECURITY_OFF === true) { + // load components from params or default to x3d attribute + components = settings.getProperty('components', xseens[i].getAttribute("components")); + if (components) { + prefix = settings.getProperty('loadpath', xseens[i].getAttribute("loadpath")); + components = components.trim().split(','); + for (j=0; j < components.length; j++) { + xseen.loadJS(components[j] + ".js", prefix); + } + } + + // src=foo.x3d adding inline node, not a good idea, but... + if (xseens[i].getAttribute("src")) { + var _scene = document.createElement("scene"); + var _inl = document.createElement("Inline"); + _inl.setAttribute("url", xseens[i].getAttribute("src")); + _scene.appendChild(_inl); + xseens[i].appendChild(_scene); + } + } + } + // }}} + + if (showLoggingConsole == true) { + xseen.debug.activate(true); + } else { + xseen.debug.activate(false); + } + + // Convert the collection into a simple array (is this necessary?) +/* Don't think so -- commented out + xseens = Array.map(xseens, function (n) { + n.hasRuntime = true; + return n; + }); + */ + + if (xseen.versionInfo !== undefined) { + xseen.debug.logInfo("XSeen version " + xseen.versionInfo.version + ", " + + "Date " + xseen.versionInfo.date); + xseen.debug.logInfo(xseen.versionInfo.splashText); + } + + //xseen.debug.logInfo("Found " + xseen.length + " XSeen nodes"); + + + // Create a HTML canvas for every XSeen scene and wrap it with + // an X3D canvas and load the content + var x_element; + var x_canvas; + var altDiv, altP, aLnk, altImg; + var t0, t1; + + for (var i=0; i < xseens.length; i++) + { + x_element = xseens[i]; // The XSeen DOM element + + x_canvas = new THREE.Scene(); // May need addtl info if multiple: xseen.X3DCanvas(x_element, xseen.canvases.length); + xseen.canvases.push(x_canvas); // TODO: Need to handle failure to initialize? + t0 = new Date().getTime(); + +/* + * Handle opening tag attributes + * divHeight + * divWidth + * turntable Indicates if view automatically rotates (independent of navigation) + */ + + var divWidth = x_element.getAttribute('width'); + var divHeight = x_element.getAttribute('height'); + if (divHeight + divWidth < 100) { + divHeight = 450; + divWidth = 800; + } else if (divHeight < 50) { + divHeight = Math.floor(divWidth/2) + 50; + } else if (divWidth < 50) { + divWidth = divHeight * 2 - 100; + } + var turntable = (x_element.getAttribute('turntable') || '').toLowerCase(); + if (turntable == 'on' || turntable == 'yes' || turntable == 'y' || turntable == '1') { + turntable = true; + } else { + turntable = false; + } + turntable = false; +/* + * Removed because camera is stored in the Scene node (x_element._xseen.renderer.camera + * Leave variable definition so other code works... + var x_camera = new THREE.PerspectiveCamera( 75, divWidth / divHeight, 0.1, 1000 ); + x_camera.position.x = 0; + x_camera.position.z = 10; + */ + var x_camera = {}; + var x_renderer = new THREE.WebGLRenderer(); + x_renderer.setSize (divWidth, divHeight); + //x_element.appendChild (x_renderer.domElement); + + // Stereo camera effect + // from http://charliegerard.github.io/blog/Virtual-Reality-ThreeJs/ + var x_effect = new THREE.StereoEffect(x_renderer); + x_renderer.controls = {'update' : function() {return;}}; + +/* + * Add event handler to XSeen tag (x_element) + * These handle all mouse/cursor/button controls when the cursor is + * in the XSeen region of the page + */ + + x_element.addEventListener ('dblclick', xseen.Events.canvasHandler, true); + x_element.addEventListener ('click', xseen.Events.canvasHandler, true); + x_element.addEventListener ('mousedown', xseen.Events.canvasHandler, true); + x_element.addEventListener ('mousemove', xseen.Events.canvasHandler, true); + x_element.addEventListener ('mouseup', xseen.Events.canvasHandler, true); + x_element.addEventListener ('xseen', xseen.Events.XSeenHandler); // Last chance for XSeen handling of event + x_element.addEventListener ('change', xseen.Events.XSeenDebugHandler, true); // Early catch of 'change' event +/* + x_element.addEventListener ('mousedown', xseen.Events.XSeenDebugHandler, true); // Early catch of 'change' event + x_element.addEventListener ('mouseup', xseen.Events.XSeenDebugHandler, true); // Early catch of 'change' event + x_element.addEventListener ('mousemove', xseen.Events.XSeenDebugHandler, true); // Early catch of 'change' event + */ + xseen.sceneInfo.push ({ + 'size' : {'width':divWidth, 'height':divHeight}, + 'scene' : x_canvas, + 'renderer' : x_renderer, + 'effect' : x_effect, + 'camera' : [x_camera], + 'turntable' : turntable, + 'mixers' : [], + 'clock' : new THREE.Clock(), + 'element' : x_element, + 'selectable': [], + 'stacks' : [], + 'tmp' : {activeViewpoint:false}, + 'xseen' : xseen, + }); + x_element._xseen = {}; + x_element._xseen.children = []; + x_element._xseen.sceneInfo = xseen.sceneInfo[xseen.sceneInfo.length-1]; + + t1 = new Date().getTime() - t0; + xseen.debug.logInfo("Time for setup and init of GL element no. " + i + ": " + t1 + " ms."); + } + + var ready = (function(eventType) { + var evt = null; + + if (document.createEvent) { + evt = document.createEvent("Events"); + evt.initEvent(eventType, true, true); + document.dispatchEvent(evt); + } else if (document.createEventObject) { + evt = document.createEventObject(); + // http://stackoverflow.com/questions/1874866/how-to-fire-onload-event-on-document-in-ie + document.body.fireEvent('on' + eventType, evt); + } + })('load'); + + // for each X-Scene tag, parse and load the contents + var t=[]; + for (var i=0; i root element that was added after document load. */ + xseen.reload = function() { + onload(); + }; + + /* FIX PROBLEM IN CHROME - HACK - searching for better solution !!! */ + if (navigator.userAgent.indexOf("Chrome") != -1) { + document.__getElementsByTagName = document.getElementsByTagName; + + document.getElementsByTagName = function(tag) { + var obj = []; + var elems = this.__getElementsByTagName("*"); + + if(tag =="*"){ + obj = elems; + } else { + tag = tag.toUpperCase(); + for (var i = 0; i < elems.length; i++) { + var tagName = elems[i].tagName.toUpperCase(); + if (tagName === tag) { + obj.push(elems[i]); + } + } + } + + return obj; + }; + + document.__getElementById = document.getElementById; + document.getElementById = function(id) { + var obj = this.__getElementById(id); + + if (!obj) { + var elems = this.__getElementsByTagName("*"); + for (var i=0; i + * MODE_NAVIGATION events are 'captured' (not bubbled) and drive the camera position + * + * In MODE_SELECT + * mousedown sets redispatch to TRUE + * click Activates + * dblclick ?? + * mouseup terminates select + * mousemove sets redispatch to FALSE + * In all cases, recreate event as type='xseen' and dispatch from geometry when + * redispatch is TRUE. + */ + canvasHandler: function (ev) + { + //console.log ('Primary canvas event handler for event type: ' + ev.type); + var sceneInfo = ev.currentTarget._xseen.sceneInfo; + var localXseen = sceneInfo.xseen; + var lEvents = localXseen.Events; + var type = ev.type; + if (type == 'mousedown') { + lEvents.redispatch = true; + lEvents.mode = lEvents.MODE_SELECT; + lEvents.mouse.x = (ev.clientX / 800) * 2 -1; // TODO: Use real XSeen display sizes + lEvents.mouse.y = (ev.clientY / 450) * 2 -1; + // + lEvents.raycaster.setFromCamera(lEvents.mouse, sceneInfo.element._xseen.renderer.activeCamera); + var hitGeometryList = lEvents.raycaster.intersectObjects (sceneInfo.selectable, true); + if (hitGeometryList.length != 0) { + lEvents.object = hitGeometryList[0]; + } else { + lEvents.object = {}; + lEvents.redispatch = false; + lEvents.mode = lEvents.MODE_NAVIGATION; + } + } + if ((lEvents.redispatch || type == 'click' || type == 'dblclick') && typeof(lEvents.object.object) !== 'undefined') { + // Generate an XSeen (Custom)Event of the same type and dispatch it + var newEv = lEvents.createEvent (ev, lEvents.object); + lEvents.object.object.userData.dispatchEvent(newEv); + ev.stopPropagation(); // No propagation beyond this tag + } else { + //console.log ('Navigation mode...'); + } + if (type == 'mouseup') { + lEvents.redispatch = false; + lEvents.mode = lEvents.MODE_NAVIGATION; + } + }, + + createEvent: function (ev, selectedObject) + { + var properties = { + 'detail': { // This object contains all of the XSeen data + 'type': ev.type, + 'originalType': ev.type, + 'originator': selectedObject.object.userData, + 'position': { + 'x': selectedObject.point.x, + 'y': selectedObject.point.y, + 'z': selectedObject.point.z, + }, + 'normal': { + 'x': 0, + 'y': 0, + 'z': 0, + }, + 'uv': { + 'x': selectedObject.uv.x, + 'y': selectedObject.uv.y, + }, + 'screenX': ev.screenX, + 'screenY': ev.screenY, + 'clientX': ev.clientX, + 'clientY': ev.clientY, + 'ctrlKey': ev.ctrlKey, + 'shiftKey': ev.shiftKey, + 'altKey': ev.altKey, + 'metaKey': ev.metaKey, + 'button': ev.button, + 'buttons': ev.buttons, + }, + 'bubbles': ev.bubbles, + 'cancelable': ev.cancelable, + 'composed': ev.composed, + }; + + var newEvent = new CustomEvent('xseen', properties); + return newEvent; + }, + // Uses method described in https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener + // to change 'this' for the handler method. Want 'this' to refer to the target node. + addHandler: function (route, source, eventName, destination, field) + { + var handler = {}; + handler.route = route; // Route element + handler.source = source; // Source element + handler.type = eventName; // Event type + handler.destination = destination; // Destination element + handler.field = field; // Destination field structure + handler.handler = destination._xseen.handlers[field.handlerName]; + this.routes.push (handler); + if (typeof(source._xseen) === 'undefined') { // DOM event + source.addEventListener (eventName, function(ev) { + handler.handler(ev) + }); + } else { // XSeen event + source.addEventListener ('xseen', function(ev) { + //console.log ('New event of original type: |'+ev.detail.originalType+'|; Desired type: |'+handler.type+'|'); + if (ev.detail.originalType == handler.type) { + handler.handler(ev) + } + }); + } + }, + + // Generic notification handler for XSeen's canvas + XSeenHandler: function (ev) + { + //console.log ('XSeen DEBUG Event Bubble handler ('+ev.type+'/'+ev.eventPhase+').'); + }, + XSeenDebugHandler : function (ev) + { + console.log ('XSeen DEBUG Event Capture handler ('+ev.type+'/'+ev.eventPhase+').'); + }, + }; + + this.debug = { + INFO: "INFO", + WARNING: "WARNING", + ERROR: "ERROR", + EXCEPTION: "EXCEPTION", + + // determines whether debugging/logging is active. If set to "false" + // no debugging messages will be logged. + isActive: false, + + // stores if firebug is available + isFirebugAvailable: false, + + // stores if the xseen.debug object is initialized already + isSetup: false, + + // stores if xseen.debug object is append already (Need for IE integration) + isAppend: false, + + // stores the number of lines logged + numLinesLogged: 0, + + // the maximum number of lines to log in order to prevent + // the browser to slow down + maxLinesToLog: 10000, + + // the container div for the logging messages + logContainer: null, + + /** @brief Setup the xseen.debug object. + + Checks for firebug and creates the container div for the logging + messages. + */ + setup: function() { + // If debugging is already setup simply return + if (xseen.debug.isSetup) { return; } + + // Check for firebug console + try { + if (window.console.firebug !== undefined) { + xseen.debug.isFirebugAvailable = true; + } + } + catch (err) { + xseen.debug.isFirebugAvailable = false; + } + + xseen.debug.setupLogContainer(); + + // setup should be setup only once, thus store if we done that already + xseen.debug.isSetup = true; + }, + + /** @brief Activates the log + */ + activate: function(visible) { + xseen.debug.isActive = true; + + //var aDiv = document.createElement("div"); + //aDiv.style.clear = "both"; + //aDiv.appendChild(document.createTextNode("\r\n")); + //aDiv.style.display = (visible) ? "block" : "none"; + xseen.debug.logContainer.style.display = (visible) ? "block" : "none"; + + //Need this HACK for IE/Flash integration. IE don't have a document.body at this time when starting Flash-Backend + if(!xseen.debug.isAppend) { + if(navigator.appName == "Microsoft Internet Explorer") { + //document.documentElement.appendChild(aDiv); + xseen.debug.logContainer.style.marginLeft = "8px"; + document.documentElement.appendChild(xseen.debug.logContainer); + }else{ + //document.body.appendChild(aDiv); + document.body.appendChild(xseen.debug.logContainer); + } + xseen.debug.isAppend = true; + } + }, + + /** @brief Inserts a container div for the logging messages into the HTML page + */ + setupLogContainer: function() { + xseen.debug.logContainer = document.createElement("div"); + xseen.debug.logContainer.id = "xseen_logdiv"; + xseen.debug.logContainer.setAttribute("class", "xseen-logContainer"); + xseen.debug.logContainer.style.clear = "both"; + //document.body.appendChild(xseen.debug.logContainer); + }, + + /** @brief Generic logging function which does all the work. + + @param msg the log message + @param logType the type of the log message. One of INFO, WARNING, ERROR + or EXCEPTION. + */ + doLog: function(msg, logType) { + + // If logging is deactivated do nothing and simply return + if (!xseen.debug.isActive) { return; } + + // If we have reached the maximum number of logged lines output + // a warning message + if (xseen.debug.numLinesLogged === xseen.debug.maxLinesToLog) { + msg = "Maximum number of log lines (=" + xseen.debug.maxLinesToLog + ") reached. Deactivating logging..."; + } + + // If the maximum number of log lines is exceeded do not log anything + // but simply return + if (xseen.debug.numLinesLogged > xseen.debug.maxLinesToLog) { return; } + + // Output a log line to the HTML page + var node = document.createElement("p"); + node.style.margin = 0; + switch (logType) { + case xseen.debug.INFO: + node.style.color = "#009900"; + break; + case xseen.debug.WARNING: + node.style.color = "#cd853f"; + break; + case xseen.debug.ERROR: + node.style.color = "#ff4500"; + break; + case xseen.debug.EXCEPTION: + node.style.color = "#ffff00"; + break; + default: + node.style.color = "#009900"; + break; + } + + // not sure if try/catch solves problem http://sourceforge.net/apps/trac/x3dom/ticket/52 + // but due to no avail of ATI gfxcard can't test + try { + node.innerHTML = logType + ": " + msg; + xseen.debug.logContainer.insertBefore(node, xseen.debug.logContainer.firstChild); + } catch (err) { + if (window.console.firebug !== undefined) { + window.console.warn(msg); + } + } + + // Use firebug's console if available + if (xseen.debug.isFirebugAvailable) { + switch (logType) { + case xseen.debug.INFO: + window.console.info(msg); + break; + case xseen.debug.WARNING: + window.console.warn(msg); + break; + case xseen.debug.ERROR: + window.console.error(msg); + break; + case xseen.debug.EXCEPTION: + window.console.debug(msg); + break; + default: + break; + } + } + + xseen.debug.numLinesLogged++; + }, + + /** Log an info message. */ + logInfo: function(msg) { + xseen.debug.doLog(msg, xseen.debug.INFO); + }, + + /** Log a warning message. */ + logWarning: function(msg) { + xseen.debug.doLog(msg, xseen.debug.WARNING); + }, + + /** Log an error message. */ + logError: function(msg) { + xseen.debug.doLog(msg, xseen.debug.ERROR); + }, + + /** Log an exception message. */ + logException: function(msg) { + xseen.debug.doLog(msg, xseen.debug.EXCEPTION); + }, + + /** Log an assertion. */ + assert: function(c, msg) { + if (!c) { + xseen.debug.doLog("Assertion failed in " + xseen.debug.assert.caller.name + ': ' + msg, xseen.debug.ERROR); + } + }, + + /** + Checks the type of a given object. + + @param obj the object to check. + @returns one of; "boolean", "number", "string", "object", + "function", or "null". + */ + typeOf: function (obj) { + var type = typeof obj; + return type === "object" && !obj ? "null" : type; + }, + + /** + Checks if a property of a specified object has the given type. + + @param obj the object to check. + @param name the property name. + @param type the property type (optional, default is "function"). + @returns true if the property exists and has the specified type, + otherwise false. + */ + exists: function (obj, name, type) { + type = type || "function"; + return (obj ? this.typeOf(obj[name]) : "null") === type; + }, + + /** + Dumps all members of the given object. + */ + dumpFields: function (node) { + var str = ""; + for (var fName in node) { + str += (fName + ", "); + } + str += '\n'; + xseen.debug.logInfo(str); + return str; + } + }; +// Call the setup function to... umm, well, setup xseen.debug + this.debug.setup(); + + }; +// File: ./Nav-Viewpoint.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * This is all new code. + * Portions of XSeen extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * Dual licensed under the MIT and GPL + */ + + +/* + * xseen.Navigation.(label); + * Computes the new viewing location for the specific mode. + * + * Each Navigation method takes the following parameters: + * speed Floating point value indicating motion speed. + * Units are distance per milli-second for linear motion or + * revolutions (2*pi) per milli-second for angular motion + * deltaT Time since last update in milli-seconds + * TODO: This is not true for the Turntable class of camera motion -- which isn't really Navigation anyway + * scene The 'sceneInfo' object for this HTML instance + * camera The current (active) camera (aka scene.element._xseen.renderer.activeCamera) + * + * Navigation is the user-controlled process of moving in the 3D world. + * + */ + +xseen.Navigation = { + 'TwoPi' : 2 * Math.PI, + 'none' : function () {}, // Does not allow user-controlled navigation + + 'turntable' : function (speed, deltaT, scene, camera) + { + var T, radians, radius, vp; + T = (new Date()).getTime() - xseen.timeStart; + radians = T * speed * this.TwoPi; + vp = scene.stacks.Viewpoints.getActive(); // Convienence declaration + radius = vp.fields._radius0; + camera.position.x = radius * Math.sin(radians) + camera.position.y = vp.fields.position[1] * Math.cos(1.5*radians); + camera.position.z = radius * Math.cos(radians); + camera.lookAt(scene.ORIGIN); + }, + + 'tilt' : function (speed, deltaT, scene, camera) + { + var T, radians, vp; + T = (new Date()).getTime() - xseen.timeStart; + radians = T * speed * this.TwoPi; + vp = scene.stacks.Viewpoints.getActive(); // Convienence declaration + camera.position.y = vp.fields.position[1] * Math.cos(1.5*radians); + camera.lookAt(scene.ORIGIN); + }, + + 'setup' : { + 'none' : function () {return null;}, + + 'orbit' : function (camera, renderer) + { + var controls; + controls = new THREE.OrbitControls( camera, renderer.domElement ); + //controls.addEventListener( 'change', render ); // remove when using animation loop + // enable animation loop when using damping or autorotation + //controls.enableDamping = true; + //controls.dampingFactor = 0.25; + controls.enableZoom = false; + controls.enableZoom = true; + return controls; + }, + + 'trackball' : function (camera, renderer) + { + var controls; + controls = new THREE.TrackballControls(camera, renderer.domElement); + + // These are from the example code at https://github.com/mrdoob/three.js/blob/master/examples/misc_controls_trackball.html + controls.rotateSpeed = 1.0; + controls.zoomSpeed = 1.2; + controls.panSpeed = 0.8; + controls.noZoom = false; + controls.noPan = false; + controls.staticMoving = true; + controls.dynamicDampingFactor = 0.3; + controls.keys = [ 65, 83, 68 ]; + + // Render function is 'xseen.renderFrame' + // remove when using animation loop + //controls.addEventListener( 'change', xseen.renderFrame ); + return controls; + }, + }, +}; +// File: ./NodeDefinitions.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * portions extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + */ + + +/* + * xseen.nodes. is the definition of + * All internal variables are stored in ._internal. All functions start with '_' + * + * This is a bare-bones setup. There is no error checking - missing arguments or + * methods that do not exist (e.g., .init) + * + * These are intended to be development support routines. It is anticipated that in + * production systems the array dump (_dumpTable) would be loaded. As a result, it is necessary + * to have a routine that dumps out the Object so it can be captured and saved. A routine + * or documentation on how to load the Object would also be good. + * + * Fields are added with the .addField method. It takes its values from the argument list + * or an object passed as the first argument. The properties of the argument are: + * name - the name of the field. This is converted to lowercase before use + * datatype - the datatype of the field. There must be a method in xseen.types by this name + * defaultValue - the default value of the field to be used if the field is not present or incorrectly defined. + * If this argument is an array, then it is the set of allowed values. The first element is the default. + * enumerated - the list of allowed values when the datatype only allows specific values for this field (optional) + * animatable - Flag (T/F) indicating if the field is animatable. Generally speaking, enumerated fieles are not animatable + */ + +xseen.nodes = { + '_defineNode' : function(nodeName, nodeComponent, nodeMethod) { + //methodBase = 'xseen.node.'; + var methodBase = ''; + node = { + 'tag' : nodeName, + 'taglc' : nodeName.toLowerCase(), + 'component' : nodeComponent, + 'method' : methodBase + nodeMethod, + 'fields' : [], + 'fieldIndex': [], + 'addField' : function (fieldObj, datatype, defaultValue) { + var fieldName, namelc, enumerated, animatable; + if (typeof(fieldObj) === 'object') { + fieldName = fieldObj.name; + datatype = fieldObj.datatype; + defaultValue = fieldObj.defaultValue; + enumerated = (typeof(fieldObj.enumerated) === 'undefined') ? [] : fieldObj.enumerated; + animatable = (typeof(fieldObj.animatable) === 'undefined') ? false : fieldObj.animatable; + } else { + fieldName = fieldObj; + animatable = false; + if (typeof(defaultValue) == 'array') { + enumerated = defaultValue; + defaultValue = enumerated[0]; + } else { + enumerated = []; + } + } + namelc = fieldName.toLowerCase(); + this.fields.push ({ + 'field' : fieldName, + 'fieldlc' : namelc, + 'type' : datatype, + 'default' : defaultValue, + 'enumeration' : enumerated, + 'animatable' : animatable, + 'clone' : this.cloneField, + 'setFieldName' : this.setFieldName, + }); + this.fieldIndex[namelc] = this.fields.length-1; + return this; + }, + 'addNode' : function () { + xseen.parseTable[this.taglc] = this; + }, + 'cloneField' : function () { + var newFieldObject = { + 'field' : this.field, + 'fieldlc' : this.fieldlc, + 'type' : this.type, + 'default' : 0, + 'enumeration' : [], + 'animatable' : this.animatable, + 'clone' : this.clone, + 'setFieldName' : this.setFieldName, + }; + for (var i=0; i xseen.node[xseen.nodeDefinitions[nodeName].method].endParse (element, parent); + } + //xseen.debug.logInfo(" reached bottom, heading back up from |" + nodeName + "|"); +} +// File: ./Properties.js +/* + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + * + * Based on code originally provided by + * Philip Taylor: http://philip.html5.org + */ + + +xseen.Properties = function() { + this.properties = {}; +}; + +xseen.Properties.prototype.setProperty = function(name, value) { + xseen.debug.logInfo("Properties: Setting property '"+ name + "' to value '" + value + "'"); + this.properties[name] = value; +}; + +xseen.Properties.prototype.getProperty = function(name, def) { + if (this.properties[name]) { + return this.properties[name] + } else { + return def; + } +}; + +xseen.Properties.prototype.merge = function(other) { + for (var attrname in other.properties) { + this.properties[attrname] = other.properties[attrname]; + } +}; + +xseen.Properties.prototype.toString = function() { + var str = ""; + for (var name in this.properties) { + str += "Name: " + name + " Value: " + this.properties[name] + "\n"; + } + return str; +}; +// File: ./StackHandler.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * This is all new code. + * Portions of XSeen extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * Dual licensed under the MIT and GPL + */ + + +/* + * xseen.utlis.StackHandler(label); + * Creates a new stack that is managed by this class + * + * Note that the Push-Down stack (aka FILO) is implemented as a reverse list + * so that the Array methods .push and .pop can be used. The end of the array + * is the "top-most" element in the stack. + */ + +xseen.utils.StackHandler = function (label) { + this._internals = {}; // Internal class storage + this._internals.label = label; // Unique user-supplied name for this stack + this._internals.stack = []; // Maintains the stack. Last entry on stack is active + this._internals.active = -1; // Index of currently active list element + this._internals.activeNode = {}; // Entry of currently active list element + this._internals.defaultNode = {}; // The default entry to be active if nothing else is + + this._setActiveNode = function() { // Sets the entry specified by nodeId as active + this._internals.active = this._internals.stack.length-1; + if (this._internals.active >= 0) { + this._internals.activeNode = this._internals.stack[this._internals.active]; + } else { + this._internals.activeNode = this._internals.defaultNode; + } + } + + this.init = function() { // Clears existing stack + this._internals.stack = []; + } + + this.pushDown = function(node) { // Push new node onto stack and make active + this._internals.stack.push (node); + this._setActiveNode(); + } + + this.popOff = function() { // Pop node off stack and make next one active + this._internals.stack.pop(); + this._setActiveNode(); + } + + this.getActive = function() { + return this._internals.activeNode; + } + + this.setDefault = function(node) { + this._internals.defaultNode = node; + if (Object.keys(this._internals.activeNode).length === 0) { + this._internals.activeNode = this._internals.defaultNode; + } + } +} +// File: ./Types.js +/* + * xseen.types contains the datatype and conversion utilities. These convert one format to another. + * Any method ending in 'toX' where 'X' is some datatype is a conversion to that type + * Other methods convert from string with space-spearated values + */ +xseen.types = { + 'Deg2Rad' : Math.PI / 180, + + 'SFFloat' : function (value, def) + { + if (value === null) {return def;} + if (Number.isNaN(value)) {return def}; + return value; + }, + + 'SFInt' : function (value, def) + { + if (value === null) {return def;} + if (Number.isNaN(value)) {return def}; + return Math.round(value); + }, + + 'SFBool' : function (value, def) + { + if (value === null) {return def;} + if (value) {return true;} + if (!value) {return false;} + return def; + }, + + 'SFTime' : function (value, def) + { + if (value === null) {return def;} + if (Number.isNaN(value)) {return def}; + return value; + }, + + 'SFVec3f' : function (value, def) + { + if (value === null) {return def;} + var v3 = value.split(' '); + if (v3.length < 3 || Number.isNaN(v3[0]) || Number.isNaN(v3[1]) || Number.isNaN(v3[2])) { + return def; + } + return [v3[0]-0, v3[1]-0, v3[2]-0]; + }, + + 'SFVec2f' : function (value, def) + { + if (value === null) {return def;} + var v2 = value.split(' '); + if (v2.length != 2 || Number.isNaN(v2[0]) || Number.isNaN(v2[1])) { + return def; + } + return [v2[0]-0, v2[1]-0]; + }, + + 'SFRotation' : function (value, def) + { + if (value === null) {return def;} + var v4 = value.split(' '); + if (v4.length != 4 || Number.isNaN(v4[0]) || Number.isNaN(v4[1]) || Number.isNaN(v4[2]) || Number.isNaN(v4[3])) { + return def; + } + var result = { + 'vector' : [v4[0], v4[1], v4[2], v4[3]], + 'axis_angle' : [{'x': v4[0], 'y': v4[1], 'z': v4[2]}, v4[3]], + }; + return result; + }, + + 'SFColor' : function (value, defaultString) + { + var v3 = this.SFVec3f(value, defaultString); + v3[0] = Math.min(Math.max(v3[0], 0.0), 1.0); + v3[1] = Math.min(Math.max(v3[1], 0.0), 1.0); + v3[2] = Math.min(Math.max(v3[2], 0.0), 1.0); + return v3; + }, + + 'SFString' : function (value, def) + { + if (value === null) {value = def;} + return value; + }, + +// For MF* types, a default of '' means to return an empty array on parsing error + 'MFFloat' : function (value, def) + { + var defReturn = (def == '') ? [] : def; + if (value === null) {return defReturn;} + var mi = value.split(' '); + var rv = []; + for (var i=0; iDocumentation."]; +/* + * All X3D and A-Frame pre-defined solids, fixed camera, directional light, Material texture only, glTF model loader with animations, Assets and reuse, Viewpoint, Background, Lighting, Image Texture, [Indexed]TriangleSet, IndexedFaceSet, [Indexed]QuadSet
\nNext work
  • Event Model/Animation
  • Extrusion
  • Navigation
", + * + * All of the following are ALPHA releases for V0.4.x + * V0.4.0+13 Feature -- events (from HTML to XSeen) + * V0.4.1+14 Fix - minor text correction in xseen.node.geometry__TriangulateFix (nodes-x3d_Geometry.js) + * V0.4.1+15 Modified build.pl to increase compression by removing block comments + * V0.4.1+16 Feature -- XSeen events (from XSeen to HTML) + * V0.4.2+17 Feature -- XSeen internals events (from XSeen to XSeen) with changes to fix previous event handling + * V0.4.2+18 Feature -- Split screen VR display + * V0.4.3+19 Rebuild and fix loading caused by new Stereo library + * V0.4.3+20 Feature -- Navigation (orbit), including Stack update for Viewpoint and restructuring the rendering loop + * V0.4.3+21 Feature -- Changed handling of Viewpoint to include camera motion + * V0.4.4+22 Fix -- Internal event handling in passing on events of the proper type + * V0.4.5+23 Feature -- Navigation (trackball) + * V0.4.5+24 Fix -- when there is no navigation + * + * In progress + */ + var version = { + major : Major, + minor : Minor, + patch : Patch, + preRelease : PreRelease, + release : Release, + version : '', + date : RDate, + splashText : SplashText + }; +// Using the scheme at http://semver.org/ + version.version = version.major + '.' + version.minor + '.' + version.patch; + version.version += (version.preRelease != '') ? '-' + version.preRelease : ''; + version.version += (version.release != '') ? '+' + version.release : ''; + return version; +} +// File: nodes/nodes-af.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * portions extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + */ + + // Node definition code for A-Frame nodes + + +xseen.node.core_NOOP = { + 'init' : function (e,p) {}, + 'fin' : function (e,p) {} +}; +xseen.node.parsing = function (s, e) { + xseen.debug.logInfo ('Parsing init details stub for ' + s); +} + +xseen.node.af_Entity = { + 'init' : function (e,p) + { + xseen.node.parsing('A-Frame Entity'); + }, + 'fin' : function (e,p) {} +}; +xseen.node.af_Assets = { + 'init' : function (e,p) {}, + 'fin' : function (e,p) {} +}; +xseen.node.af_AssetItem = { + 'init' : function (e,p) // Only field is SRC. + { + }, + 'fin' : function (e,p) {} +}; +xseen.node.af_Mixin = { + 'init' : function (e,p) // Lots of fields -- all nebelous until used + { + }, + 'fin' : function (e,p) {} +}; + + + +xseen.node.af_Appearance = function (e) { + var parameters = { + 'aoMap' : e._xseen.fields['ambient-occlusion-map'], + 'aoMapIntensity' : e._xseen.fields['ambient-occlusion-map-intensity'], + 'color' : e._xseen.fields['color'], + 'displacementMap' : e._xseen.fields['displacement-map'], + 'displacementScale' : e._xseen.fields['displacement-scale'], + 'displacementBias' : e._xseen.fields['displacement-bias'], + 'envMap' : e._xseen.fields['env-map'], + 'normalMap' : e._xseen.fields['normal-map'], + 'normalScale' : e._xseen.fields['normal-scale'], + 'wireframe' : e._xseen.fields['wireframe'], + 'wireframeLinewidth' : e._xseen.fields['wireframe-linewidth'], + }; + var material = new THREE.MeshPhongMaterial(parameters); + return material; +/* + * === All Entries === +.aoMap +.aoMapIntensity +.color + .combine +.displacementMap +.displacementScale +.displacementBias + .emissive + .emissiveMap + .emissiveIntensity +.envMap + .lightMap + .lightMapIntensity + .map + .morphNormals + .morphTargets +.normalMap +.normalScale + .reflectivity + .refractionRatio + .shininess + .skinning + .specular + .specularMap +.wireframe + .wireframeLinecap + .wireframeLinejoin +.wireframeLinewidth +/////////////////////////////////////////////////////////////////////////////// +e._xseen.fields['ambient-occlusion-map'] +e._xseen.fields['ambient-occlusion-map-intensity'] + e._xseen.fields['ambient-occlusion-texture-offset'] + e._xseen.fields['ambient-occlusion-texture-repeat'] +e._xseen.fields['color'] +e._xseen.fields['displacement-bias'] +e._xseen.fields['displacement-map'] +e._xseen.fields['displacement-scale'] + e._xseen.fields['displacement-texture-offset'] + e._xseen.fields['displacement-texture-repeat'] +e._xseen.fields['env-map'] + e._xseen.fields['fog'] + e._xseen.fields['metalness'] +e._xseen.fields['normal-map'] +e._xseen.fields['normal-scale'] + e._xseen.fields['normal-texture-offset'] + e._xseen.fields['normal-texture-repeat'] + e._xseen.fields['repeat'] + e._xseen.fields['roughness'] + e._xseen.fields['spherical-env-map'] + e._xseen.fields['src'] +e._xseen.fields['wireframe'] +e._xseen.fields['wireframe-linewidth'] + + * === Unused Entries === + .combine + .emissive + .emissiveMap + .emissiveIntensity + .lightMap + .lightMapIntensity + .map + .morphNormals + .morphTargets + .reflectivity + .refractionRatio + .shininess + .skinning + .specular + .specularMap + .wireframeLinecap + .wireframeLinejoin +/////////////////////////////////////////////////////////////////////////////// + e._xseen.fields['ambient-occlusion-texture-offset'] + e._xseen.fields['ambient-occlusion-texture-repeat'] + e._xseen.fields['displacement-texture-offset'] + e._xseen.fields['displacement-texture-repeat'] + e._xseen.fields['fog'] + e._xseen.fields['metalness'] + e._xseen.fields['normal-texture-offset'] + e._xseen.fields['normal-texture-repeat'] + e._xseen.fields['repeat'] + e._xseen.fields['roughness'] + e._xseen.fields['spherical-env-map'] + e._xseen.fields['src'] + */ +} + +xseen.node.af_Box = { + 'init' : function (e,p) + { + var geometry = new THREE.BoxGeometry( + e._xseen.fields.width, + e._xseen.fields.height, + e._xseen.fields.depth, + e._xseen.fields['segments-width'], + e._xseen.fields['segments-height'], + e._xseen.fields['segments-depth'] + ); + var appearance = xseen.node.af_Appearance (e); + var mesh = new THREE.Mesh (geometry, appearance); + mesh.userData = e; + p._xseen.sceneInfo.selectable.push(mesh); + var group = new THREE.Group(); + group.add (mesh); + if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + p._xseen.children.push(group); + }, + 'fin' : function (e,p) {} +}; + +xseen.node.af_Cone = { + 'init' : function (e,p) + { + var geometry = new THREE.ConeGeometry( + e._xseen.fields.radius, + e._xseen.fields.height, + e._xseen.fields['segments-radial'], + e._xseen.fields['segments-height'], + e._xseen.fields['open-ended'], + e._xseen.fields['theta-start'] * xseen.types.Deg2Rad, + e._xseen.fields['theta-length'] * xseen.types.Deg2Rad + ); + var appearance = xseen.node.af_Appearance (e); + var mesh = new THREE.Mesh (geometry, appearance); + mesh.userData = e; + p._xseen.sceneInfo.selectable.push(mesh); + var group = new THREE.Group(); + group.add (mesh); + if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + p._xseen.children.push(group); + }, + 'fin' : function (e,p) {} +}; + +xseen.node.af_Cylinder = { + 'init' : function (e,p) + { + var geometry = new THREE.CylinderGeometry( + e._xseen.fields['radius-top'], + e._xseen.fields['radius-bottom'], + e._xseen.fields.height, + e._xseen.fields['segments-radial'], + e._xseen.fields['segments-height'], + e._xseen.fields['open-ended'], + e._xseen.fields['theta-start'] * xseen.types.Deg2Rad, + e._xseen.fields['theta-length'] * xseen.types.Deg2Rad + ); + var appearance = xseen.node.af_Appearance (e); + var mesh = new THREE.Mesh (geometry, appearance); + mesh.userData = e; + p._xseen.sceneInfo.selectable.push(mesh); + var group = new THREE.Group(); + group.add (mesh); + if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + p._xseen.children.push(group); + }, + 'fin' : function (e,p) {} +}; + +xseen.node.af_Dodecahedron = { + 'init' : function (e,p) + { + var geometry = new THREE.DodecahedronGeometry( + e._xseen.fields.radius, + e._xseen.fields.detail + ); + var appearance = xseen.node.af_Appearance (e); + var mesh = new THREE.Mesh (geometry, appearance); + mesh.userData = e; + p._xseen.sceneInfo.selectable.push(mesh); + var group = new THREE.Group(); + group.add (mesh); + if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + p._xseen.children.push(group); + }, + 'fin' : function (e,p) {} +}; + +xseen.node.af_Icosahedron = { + 'init' : function (e,p) + { + var geometry = new THREE.IcosahedronGeometry( + e._xseen.fields.radius, + e._xseen.fields.detail + ); + var appearance = xseen.node.af_Appearance (e); + var mesh = new THREE.Mesh (geometry, appearance); + mesh.userData = e; + p._xseen.sceneInfo.selectable.push(mesh); + var group = new THREE.Group(); + group.add (mesh); + if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + p._xseen.children.push(group); + }, + 'fin' : function (e,p) {} +}; + +xseen.node.af_Octahedron = { + 'init' : function (e,p) + { + var geometry = new THREE.OctahedronGeometry( + e._xseen.fields.radius, + e._xseen.fields.detail + ); + var appearance = xseen.node.af_Appearance (e); + var mesh = new THREE.Mesh (geometry, appearance); + mesh.userData = e; + p._xseen.sceneInfo.selectable.push(mesh); + var group = new THREE.Group(); + group.add (mesh); + if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + p._xseen.children.push(group); + }, + 'fin' : function (e,p) {} +}; + +xseen.node.af_Sphere = { + 'init' : function (e,p) + { + var geometry = new THREE.SphereGeometry( + e._xseen.fields.radius, + e._xseen.fields['segments-width'], + e._xseen.fields['segments-height'], + e._xseen.fields['phi-start'] * xseen.types.Deg2Rad, + e._xseen.fields['phi-length'] * xseen.types.Deg2Rad, + e._xseen.fields['theta-start'] * xseen.types.Deg2Rad, + e._xseen.fields['theta-length'] * xseen.types.Deg2Rad + ); + var appearance = xseen.node.af_Appearance (e); + var mesh = new THREE.Mesh (geometry, appearance); + mesh.userData = e; + p._xseen.sceneInfo.selectable.push(mesh); + var group = new THREE.Group(); + group.add (mesh); + if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + p._xseen.children.push(group); + }, + 'fin' : function (e,p) {} +}; + +xseen.node.af_Tetrahedron = { + 'init' : function (e,p) + { + var geometry = new THREE.TetrahedronGeometry( + e._xseen.fields.radius, + e._xseen.fields.detail + ); + var appearance = xseen.node.af_Appearance (e); + var mesh = new THREE.Mesh (geometry, appearance); + mesh.userData = e; + p._xseen.sceneInfo.selectable.push(mesh); + var group = new THREE.Group(); + group.add (mesh); + if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + p._xseen.children.push(group); + }, + 'fin' : function (e,p) {} +}; + +xseen.node.af_Torus = { + 'init' : function (e,p) + { + var geometry = new THREE.TorusGeometry( + e._xseen.fields.radius, + e._xseen.fields.tube, + e._xseen.fields['segments-radial'], + e._xseen.fields['segments-tubular'], + e._xseen.fields.arc * xseen.types.Deg2Rad + ); + var appearance = xseen.node.af_Appearance (e); + var mesh = new THREE.Mesh (geometry, appearance); + mesh.userData = e; + p._xseen.sceneInfo.selectable.push(mesh); + var group = new THREE.Group(); + group.add (mesh); + if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + p._xseen.children.push(group); + }, + 'fin' : function (e,p) {} +}; +// File: nodes/nodes-Viewing.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * portions extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + */ + + // Control Node definitions + + +xseen.node.unk_Viewpoint = { + 'init' : function (e,p) + { // This should really go in a separate push-down list for Viewpoints + e._xseen.fields._radius0 = Math.sqrt( e._xseen.fields.position[0]*e._xseen.fields.position[0] + + e._xseen.fields.position[1]*e._xseen.fields.position[1] + + e._xseen.fields.position[2]*e._xseen.fields.position[2]); + e._xseen.domNode = e; // Back-link to node if needed later on + e._xseen.position = new THREE.Vector3(e._xseen.fields.position[0], e._xseen.fields.position[1], e._xseen.fields.position[2]); + e._xseen.type = e._xseen.fields.cameratype; + e._xseen.motion = e._xseen.fields.motion; + e._xseen.motionspeed = e._xseen.fields.motionspeed * 1000; + if (e._xseen.motion == 'turntable' || e._xseen.motion == 'tilt') {e._xseen.motionspeed = 1.0/e._xseen.motionspeed;} + + if (!e._xseen.sceneInfo.tmp.activeViewpoint) { + e._xseen.sceneInfo.stacks.Viewpoints.pushDown(e._xseen); + e._xseen.sceneInfo.tmp.activeViewpoint = true; + } + + e._xseen.handlers = {}; + e._xseen.handlers.setactive = this.setactive; + }, + 'fin' : function (e,p) {}, + + 'setactive' : function (ev) + { + var xseenNode = this.destination._xseen; + xseenNode.sceneInfo.stacks.Viewpoints.pushDown(xseenNode); // TODO: This is probably not the right way to change VP in the stack + xseenNode.sceneInfo.element._xseen.renderer.activeCamera = + xseenNode.sceneInfo.element._xseen.renderer.cameras[xseenNode.fields.type]; + xseenNode.sceneInfo.element._xseen.renderer.activeRender = + xseenNode.sceneInfo.element._xseen.renderer.renderEffects[xseenNode.fields.type]; + if (xseenNode.fields.type != 'stereo') { + xseenNode.sceneInfo.element._xseen.renderer.activeRender.setViewport( 0, 0, xseenNode.sceneInfo.size.width, this.destination._xseen.sceneInfo.size.height); + } + }, +}; + +xseen.node.controls_Navigation = { + 'init' : function (e,p) + { // This should really go in a separate push-down list for Viewpoints + + e._xseen.domNode = e; // Back-link to node if needed later on + e._xseen.speed = e._xseen.fields.speed; + if (e._xseen.setup == 'examine') {e._xseen.setup == 'trackball';} + //e._xseen.type = e._xseen.fields.type; + e._xseen.type = 'none'; + e._xseen.setup = e._xseen.fields.type; + if (!(e._xseen.setup == 'orbit' || e._xseen.setup == 'trackball')) {e._xseen.setup = 'none';} + + if (!e._xseen.sceneInfo.tmp.activeNavigation) { + e._xseen.sceneInfo.stacks.Navigation.pushDown(e._xseen); + e._xseen.sceneInfo.tmp.activeNavigation = true; + } + + e._xseen.handlers = {}; + e._xseen.handlers.setactive = this.setactive; + }, + 'fin' : function (e,p) {}, + + 'setactive' : function (ev) + { +/* + this.destination._xseen.sceneInfo.stacks.Viewpoints.pushDown(this.destination); // TODO: This is probably not the right way to change VP in the stack + this.destination._xseen.sceneInfo.element._xseen.renderer.activeCamera = + this.destination._xseen.sceneInfo.element._xseen.renderer.cameras[this.destination._xseen.fields.type]; + this.destination._xseen.sceneInfo.element._xseen.renderer.activeRender = + this.destination._xseen.sceneInfo.element._xseen.renderer.renderEffects[this.destination._xseen.fields.type]; + if (this.destination._xseen.fields.type != 'stereo') { + this.destination._xseen.sceneInfo.element._xseen.renderer.activeRender.setViewport( 0, 0, this.destination._xseen.sceneInfo.size.width, this.destination._xseen.sceneInfo.size.height); + } + */ + }, +}; + +xseen.node.lighting_Light = { + 'init' : function (e,p) + { + var color = xseen.types.Color3toInt (e._xseen.fields.color); + var intensity = e._xseen.fields.intensity - 0; + var lamp, type=e._xseen.fields.type.toLowerCase(); +/* + if (typeof(p._xseen.children) == 'undefined') { + console.log('Parent of Light does not have children...'); + p._xseen.children = []; + } + */ + + if (type == 'point') { + // Ignored field -- e._xseen.fields.location + lamp = new THREE.PointLight (color, intensity); + lamp.distance = Math.max(0.0, e._xseen.fields.radius - 0); + lamp.decay = Math.max (.1, e._xseen.fields.attenuation[1]/2 + e._xseen.fields.attenuation[2]); + + } else if (type == 'spot') { + lamp = new THREE.SpotLight (color, intensity); + lamp.position.set(0-e._xseen.fields.direction[0], 0-e._xseen.fields.direction[1], 0-e._xseen.fields.direction[2]); + lamp.distance = Math.max(0.0, e._xseen.fields.radius - 0); + lamp.decay = Math.max (.1, e._xseen.fields.attenuation[1]/2 + e._xseen.fields.attenuation[2]); + lamp.angle = Math.max(0.0, Math.min(1.5707963267948966192313216916398, e._xseen.fields.cutoffangle)); + lamp.penumbra = 1 - Math.max(0.0, Math.min(lamp.angle, e._xseen.fields.beamwidth)) / lamp.angle; + + } else { // DirectionalLight (by default) + lamp = new THREE.DirectionalLight (color, intensity); + lamp.position.x = 0-e._xseen.fields.direction[0]; + lamp.position.y = 0-e._xseen.fields.direction[1]; + lamp.position.z = 0-e._xseen.fields.direction[2]; + } + p._xseen.children.push(lamp); + lamp = null; + } + , + 'fin' : function (e,p) + { + } +}; +// File: nodes/nodes-x3d_Appearance.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * portions extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + */ + + // Node definition code (just stubs right now...) + + +xseen.node.appearance_Material = { + 'init' : function (e,p) + { + var transparency = e._xseen.fields.transparency - 0; + var shininess = e._xseen.fields.shininess - 0; + var colorDiffuse = xseen.types.Color3toInt (e._xseen.fields.diffusecolor); + var colorEmissive = xseen.types.Color3toInt (e._xseen.fields.emissivecolor); + var colorSpecular = xseen.types.Color3toInt (e._xseen.fields.specularcolor); + p._xseen.material = new THREE.MeshPhongMaterial( { +// p._xseen.material = new THREE.MeshBasicMaterial( { + 'color' : colorDiffuse, + 'emissive' : colorEmissive, + 'specular' : colorSpecular, + 'shininess' : shininess, + 'opacity' : 1.0-transparency, + 'transparent' : (transparency > 0.0) ? true : false + } ); + e._xseen.animate['diffusecolor'] = p._xseen.material.color; + e._xseen.animate['emissivecolor'] = p._xseen.material.emissive; + e._xseen.animate['specularcolor'] = p._xseen.material.specular; + e._xseen.animate['transparency'] = p._xseen.material.opacity; + e._xseen.animate['shininess'] = p._xseen.material.shininess; + }, + 'fin' : function (e,p) {} +}; + +xseen.node.appearance_ImageTexture = { + 'init' : function (e,p) + { + p._xseen.texture = xseen.loader.ImageLoader.load(e._xseen.fields.url); + p._xseen.texture.wrapS = (e._xseen.fields.repeats) ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; + p._xseen.texture.wrapT = (e._xseen.fields.repeatt) ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; + }, + 'fin' : function (e,p) {} +}; + +xseen.node.appearance_Appearance = { + 'init' : function (e,p) {}, + + 'fin' : function (e,p) + { + if (typeof(e._xseen.texture) !== 'undefined' && e._xseen.texture !== null) { + e._xseen.material.map = e._xseen.texture; + } + p._xseen.appearance = e._xseen.material; + } +}; +// File: nodes/nodes-x3d_Geometry.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * portions extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + */ + + // Node definition code (just stubs right now...) + + +xseen.node.geometry_Coordinate = { + 'init' : function (e,p) + { + var vertices = []; + for (var i=0; i= 0 where each triple defines a triangle face. It is assumed that the + * indices define the face in counter-clockwise order when looking at the face. + * vertices - an array of THREE.Vector3 points + */ +xseen.node.geometry__Indexed3 = function (indices, vertices, normals=[], color=[]) { + var i, face, normal=[], faceCount=0, n; + var useNormals = (normals.length > 0) ? true : false; + var useColor = (color.length > 0) ? true : false; + var maxIndex = Math.max.apply(null, indices); + var minIndex = Math.min.apply(null, indices); + if (maxIndex >= vertices.length) { + console.log ('Maximum index ('+maxIndex+') exceeds vertex count ('+vertices.length+'). No geometry is created'); + return; + } + if (useNormals && maxIndex >= normals.length) { + console.log ('Maximum index ('+maxIndex+') exceeds normal count ('+normals.length+'). No geometry is created'); + return; + } + if (useColor && maxIndex >= color.length) { + console.log ('Maximum index ('+maxIndex+') exceeds color count ('+color.length+'). No geometry is created'); + return; + } + if (minIndex < 0) { + console.log ('Minimum index ('+minIndex+') less than zero. No geometry is created'); + return; + } + if (indices.length % 3 != 0) { + console.log ('Number of indices ('+indices.length+') not divisible by 3. No geometry is created'); + return; + } + + var geometry = new THREE.Geometry(); + var normal_pz = new THREE.Vector3 (0, 0, 1); + var normal_mz = new THREE.Vector3 (0, 0, -1); + for (var i=0; i 0) {clip.duration = e._xseen.fields.duration;} + e._xseen.mixer.clipAction( clip ).play(); + } ); + } else { // Play a specific animation + var clip = THREE.AnimationClip.findByName(response.animations, e._xseen.fields.playonload); + var action = e._xseen.mixer.clipAction (clip); + action.play(); + } + } + } + } +}; + + +xseen.node.x_Route = { + 'init' : function (e,p) + { + var dest = e._xseen.fields.destination; + var hand = e._xseen.fields.handler; + var externalHandler = false; + + // Make sure sufficient data is provided + if (e._xseen.fields.source == '' || + typeof(window[hand]) !== 'function' && + (dest == '' || e._xseen.fields.event == '' || e._xseen.fields.field == '')) { + xseen.debug.logError ('Route node missing field. No route setup. Source: '+e._xseen.fields.source+'.'+e._xseen.fields.event+'; Destination: '+dest+'.'+e._xseen.fields.field+'; Handler: '+hand); + return; + } else if (typeof(window[hand]) === 'function') { + externalHandler = true; + } + + // For toNode routing, check existence of source and destination elements + var eSource = document.getElementById (e._xseen.fields.source); + if (! externalHandler) { + var eDestination = document.getElementById (dest); + if (typeof(eSource) === 'undefined' || typeof(eDestination) === 'undefined') { + xseen.debug.logError ('Source or Destination node does not exist. No route setup'); + return; + } + // Get field information -- perhaps there is some use in the Animate node? + var fField = xseen.nodes._getFieldInfo (eDestination.nodeName, e._xseen.fields.field); + if (typeof(fField) === 'undefined' || !fField.good) { + xseen.debug.logError ('Destination field does not exist or incorrectly specified. No route setup'); + return; + } + // Set up listener on source node for specified event. The listener code is the 'set' method for the + // node. It is passed the DOM 'event' data structure. Since there may be more than one node of the type + // specified by 'destination', the event handler is attached to the node in e._xseen.handlers. This is done + // when the node is parsed + xseen.Events.addHandler (e, eSource, e._xseen.fields.event, eDestination, fField); + +/* + * External (to XSeen) event handler + * TODO: limit the events to those requested if e._xseen.fields.event != 'xseen' + * This probably requires an intermediatiary event handler + */ + } else { + var handler = window[hand]; + eSource.addEventListener ('xseen', handler); + } + }, + + 'fin' : function (e,p) + { + }, + 'evHandler' : function (u) + { + var de = u.e; + var df = u.f; + return de._xseen.handlers[df.handlerName]; + }, +}; +// File: nodes/nodes.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * portions extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + */ + + // Node definition code (just stubs right now...) + + +xseen.node.core_NOOP = { + 'init' : function (e,p) {}, + 'fin' : function (e,p) {} +}; +xseen.node.core_WorldInfo = { + 'init' : function (e,p) {parsing('WorldInfo', e)}, + 'fin' : function (e,p) {} +}; + +function parsing (s, e) { + xseen.debug.logInfo ('Parsing init details stub for ' + s); +} + + +xseen.node.unk_Shape = { + 'init' : function (e,p) {}, + 'fin' : function (e,p) + { +// if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + if (typeof(e._xseen.materialProperty) !== 'undefined') { + e._xseen.appearance.vertexColors = THREE.VertexColors; + //e._xseen.appearance.vertexColors = THREE.FaceColors; + e._xseen.appearance._needsUpdate = true; + e._xseen.appearance.needsUpdate = true; + } + var mesh = new THREE.Mesh (e._xseen.geometry, e._xseen.appearance); + mesh.userData = e; + p._xseen.children.push(mesh); + p._xseen.sceneInfo.selectable.push(mesh); + mesh = null; + } +}; + +xseen.node.grouping_Transform = { + 'init' : function (e,p) + { + var group = new THREE.Group(); + if (e.nodeName == "TRANSFORM") { + var rotation = xseen.types.Rotation2Quat(e._xseen.fields.rotation); + group.name = 'Transform children [' + e.id + ']'; + group.position.x = e._xseen.fields.translation[0]; + group.position.y = e._xseen.fields.translation[1]; + group.position.z = e._xseen.fields.translation[2]; + group.scale.x = e._xseen.fields.scale[0]; + group.scale.y = e._xseen.fields.scale[1]; + group.scale.z = e._xseen.fields.scale[2]; + group.quaternion.x = rotation.x; + group.quaternion.y = rotation.y; + group.quaternion.z = rotation.z; + group.quaternion.w = rotation.w; + + e._xseen.animate['translation'] = group.position; + e._xseen.animate['rotation'] = group.quaternion; + e._xseen.animate['scale'] = group.scale; + } + e._xseen.sceneNode = group; + }, + 'fin' : function (e,p) + { + // Apply transform to all objects in e._xseen.children + e._xseen.children.forEach (function (child, ndx, wholeThing) + { + e._xseen.sceneNode.add(child); + }); + p._xseen.children.push(e._xseen.sceneNode); + } +}; + +xseen.node.networking_Inline = { + 'init' : function (e,p) + { + if (typeof(e._xseen.processedUrl) === 'undefined' || !e._xseen.requestedUrl) { + var uri = xseen.parseUrl (e._xseen.fields.url); + var type = uri.extension; + e._xseen.loadGroup = new THREE.Group(); + e._xseen.loadGroup.name = 'Inline content [' + e.id + ']'; + console.log ('Created Inline Group with UUID ' + e._xseen.loadGroup.uuid); + var userdata = {'requestType':'x3d', 'e':e, 'p':p} + if (type.toLowerCase() == 'json') { + userdata.requestType = 'json'; + xseen.loadMgr.loadJson (e._xseen.fields.url, this.loadSuccess, xseen.loadProgress, xseen.loadError, userdata); + } else { + xseen.loadMgr.loadXml (e._xseen.fields.url, this.loadSuccess, xseen.loadProgress, xseen.loadError, userdata); + } + e._xseen.requestedUrl = true; + } + //if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} + p._xseen.children.push(e._xseen.loadGroup); + console.log ('Using Inline Group with UUID ' + e._xseen.loadGroup.uuid); + }, + 'fin' : function (e,p) + { + }, + + 'loadSuccess' : + function (response, userdata, xhr) { + userdata.e._xseen.processedUrl = true; + userdata.e._xseen.loadResponse = response; + console.log("download successful for "+userdata.e.id); + if (userdata.requestType == 'json') { + var tmp = {'scene': response}; + response = null; + response = (new JSONParser()).parseJavaScript(tmp); + } + var start = {'_xseen':0}; + var findSceneTag = function (fragment) { + if (typeof(fragment._xseen) === 'undefined') {fragment._xseen = {'childCount': -1};} + if (fragment.nodeName.toLowerCase() == 'scene') { + start = fragment; + return; + } else if (fragment.children.length > 0) { + for (fragment._xseen.childCount=0; fragment._xseen.childCount 0) { + userdata.e.appendChild(start.children[0]); + } + xseen.Parse(userdata.e, userdata.p, userdata.p._xseen.sceneInfo); + userdata.e._xseen.children.forEach (function (child, ndx, wholeThing) + { + userdata.e._xseen.loadGroup.add(child); +console.log ('...Adding ' + child.type + ' (' + child.name + ') to Inline Group? with UUID ' + userdata.e._xseen.loadGroup.uuid + ' (' + userdata.e._xseen.loadGroup.name + ')'); + }); + userdata.p._xseen.sceneInfo.scene.updateMatrixWorld(); + //xseen.debug.logInfo("Complete work on Inline..."); + } else { + console.log("Found illegal X3D file -- no 'scene' tag"); + } + // Parse (start, userdata.p)... + } +}; + +/* + * Most of this stuff is only done once per XSeen element. Loading of Inline contents should not + * repeat the definitions and canvas creation + */ +xseen.node.core_Scene = { + 'DEFAULT' : { + 'Viewpoint' : { + 'Position' : new THREE.Vector3 (0, 0, 10), + 'Orientation' : '0 1 0 0', // TODO: fix (and below) when handling orientation + 'Type' : 'perpsective', + 'Motion' : 'none', + 'MotionSpeed' : 1.0, + }, + 'Navigation' : { + 'Speed' : 1.0, // 16 spr (1 revolution per 16 seconds), in mseconds. + 'Type' : 'none', + 'Setup' : 'none', + } + }, + 'init' : function (e,p) + { + // Create default Viewpoint and Navigation + xseen.sceneInfo[0].stacks.Viewpoints.setDefault( + { + 'position' : this.DEFAULT.Viewpoint.Position, + 'type' : this.DEFAULT.Viewpoint.Type, + 'motion' : this.DEFAULT.Viewpoint.Motion, + 'motionspeed': this.DEFAULT.Viewpoint.MotionSpeed / 1000, + 'domNode' : e, + 'fields' : {}, + } + ); + xseen.sceneInfo[0].stacks.Navigation.setDefault( + { + 'speed' : this.DEFAULT.Navigation.Speed / 1000, + 'type' : this.DEFAULT.Navigation.Type, + 'setup' : this.DEFAULT.Navigation.Setup, + 'domNode' : e, + 'fields' : {}, + } + ); + + var width = e._xseen.sceneInfo.size.width; + var height = e._xseen.sceneInfo.size.height; + var x_renderer = new THREE.WebGLRenderer(); + x_renderer.setSize (width, height); + var perspectiveCamera = new THREE.PerspectiveCamera( 75, width / height, 0.1, 1000 ); + var orthoCamera = new THREE.OrthographicCamera( 75, width / height, 0.1, 1000 ); + //perspectiveCamera.translateX(this.DEFAULT.Viewpoint.Position.x).translateY(this.DEFAULT.Viewpoint.Position.y).translateZ(this.DEFAULT.Viewpoint.Position.z); // Default position + //orthoCamera.translateX(this.DEFAULT.Viewpoint.Position.x).translateY(this.DEFAULT.Viewpoint.Position.y).translateZ(this.DEFAULT.Viewpoint.Position.z); // Default position + perspectiveCamera.position.x = this.DEFAULT.Viewpoint.Position.x; // Default position + perspectiveCamera.position.y = this.DEFAULT.Viewpoint.Position.y; // Default position + perspectiveCamera.position.z = this.DEFAULT.Viewpoint.Position.z; // Default position + orthoCamera.position.x = this.DEFAULT.Viewpoint.Position.x; // Default position + orthoCamera.position.y = this.DEFAULT.Viewpoint.Position.y; // Default position + orthoCamera.position.z = this.DEFAULT.Viewpoint.Position.z; // Default position + + // Stereo viewing effect + // from http://charliegerard.github.io/blog/Virtual-Reality-ThreeJs/ + var x_effect = new THREE.StereoEffect(x_renderer); + + e.appendChild (x_renderer.domElement); + e._xseen.renderer = { + 'canvas' : e._xseen.sceneInfo.scene, + 'width' : width, + 'height' : height, + 'cameras' : { + 'perspective' : perspectiveCamera, + 'ortho' : orthoCamera, + 'stereo' : perspectiveCamera, + }, // Removed .sceneInfo camera because this node defines the camera + 'effects' : x_effect, + 'renderEffects' : { + 'normal' : x_renderer, + 'perspective' : x_renderer, + 'ortho' : x_renderer, + 'stereo' : x_effect, + }, + 'activeRender' : {}, + 'activeCamera' : {}, + 'controls' : {}, // Used for navigation + }; + e._xseen.renderer.activeRender = e._xseen.renderer.renderEffects.normal; + e._xseen.renderer.activeCamera = e._xseen.renderer.cameras.perspective; + }, + +/* + * This appears now to be working!!! + * + * Late loading content is not getting inserted into the scene graph for rendering. Need to read + * THREE docs about how to do that. + * Camera will need to be redone. Existing camera is treated as a special child. A separate camera + * should be established and Viewpoint nodes define "photostops" rather than a camera. The camera is + * in effect, parented to the "photostop". This probably needs to list of Viewpoints discussed in the + * X3D specification. + */ + 'fin' : function (e,p) + { + // Render all Children + //xseen.renderNewChildren (e._xseen.children, e._xseen.renderer.canvas); + e._xseen.children.forEach (function (child, ndx, wholeThing) + { + console.log('Adding child of type ' + child.type + ' (' + child.name + ')'); + e._xseen.renderer.canvas.add(child); + }); + xseen.dumpSceneGraph (); +// e._xseen.renderer.renderer.render( e._xseen.renderer.canvas, e._xseen.renderer.camera ); +// xseen.debug.logInfo("Rendered all elements -- Starting animation"); +/* + * TODO: Need to get current top-of-stack for all stack-bound nodes and set them as active. + * This only happens the initial time for each XSeen tag in the main HTML file + * + * At this time, only Viewpoint is stack-bound. Probably need to stack just the ._xseen object. + * Also, .fields.position is the initial specified location; not the navigated/animated one + */ + var vp = xseen.sceneInfo[0].stacks.Viewpoints.getActive(); + var nav = xseen.sceneInfo[0].stacks.Navigation.getActive(); + var currentCamera = e._xseen.renderer.activeCamera; + var currentRenderer = e._xseen.renderer.activeRender; + currentCamera.position.x = vp.position.x; + currentCamera.position.y = vp.position.y; + currentCamera.position.z = vp.position.z; + e._xseen.renderer.controls = xseen.Navigation.setup[nav.setup] (currentCamera, currentRenderer); + xseen.debug.logInfo("Ready to kick off rendering loop"); + xseen.renderFrame(); + }, + +}; + +xseen.node.env_Background = { + 'init' : function (e,p) + { + var color = new THREE.Color(e._xseen.fields.skycolor[0], e._xseen.fields.skycolor[1], e._xseen.fields.skycolor[2]); + var textureCube = new THREE.CubeTextureLoader() + .load ([e._xseen.fields.srcright, + e._xseen.fields.srcleft, + e._xseen.fields.srctop, + e._xseen.fields.srcbottom, + e._xseen.fields.srcfront, + e._xseen.fields.srcback], + this.loadSuccess({'e':e, 'p':p}) + ); + e._xseen.sceneInfo.scene.background = color; +/* + var material = new THREE.MeshBasicMaterial( { color: 0xffffff, envMap: textureCube } ); + var size = 1; + //var geometry = new THREE.BoxGeometry(200, 200, 2); + var geometry = new THREE.Geometry(); + geometry.vertices.push ( + new THREE.Vector3(-size, -size, size), + new THREE.Vector3( size, -size, size), + new THREE.Vector3( size, -size, -size), + new THREE.Vector3(-size, -size, -size), + new THREE.Vector3(-size, size, size), + new THREE.Vector3( size, size, size), + new THREE.Vector3( size, size, -size), + new THREE.Vector3(-size, size, -size) + ); + + geometry.faces.push ( // external facing geometry + new THREE.Face3(0, 1, 5), + new THREE.Face3(0, 5, 4), + new THREE.Face3(1, 2, 6), + new THREE.Face3(1, 6, 5), + new THREE.Face3(2, 3, 7), + new THREE.Face3(2, 7, 6), + new THREE.Face3(3, 0, 4), + new THREE.Face3(3, 4, 7), + new THREE.Face3(4, 5, 6), + new THREE.Face3(4, 6, 7), + new THREE.Face3(0, 2, 1), + new THREE.Face3(0, 3, 2), + ); + geometry.computeBoundingSphere(); + var mesh = new THREE.Mesh (geometry, material); + e._xseen.sceneInfo.element._xseen.renderer.canvas.add(mesh); +*/ + }, + + 'fin' : function (e,p) + { + p._xseen.appearance = e._xseen.material; + }, + + 'loadSuccess' : function (userdata) + { + var e = userdata.e; + var p = userdata.p; + return function (textureCube) + { + e._xseen.processedUrl = true; + e._xseen.loadTexture = textureCube; + e._xseen.sceneInfo.scene.background = textureCube; + } + }, + +}; +// File: nodes/nodes_Animate.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * portions extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + */ + + // Node definition code (just stubs right now...) + + +xseen.node.x_Animate = { + 'init' : function (e,p) + { + var delay = e._xseen.fields.delay * 1000; // Convert to milliseconds + var duration = e._xseen.fields.duration * 1000; // Convert to milliseconds + var repeat = (e._xseen.fields.repeat < 0) ? Infinity : e._xseen.fields.repeat; + var interpolator = e._xseen.fields.interpolator; + var easing = e._xseen.fields.easing; + + var fields = xseen.parseTable[p.localName.toLowerCase()].fields; + var fieldIndex = xseen.parseTable[p.localName.toLowerCase()].fieldIndex; + var toField = e._xseen.fields.field; + var toFieldIndex = fieldIndex[toField]; + if (typeof(fields[toFieldIndex]) === 'undefined') { + xseen.debug.logInfo("Field '" + toField + "' not found in parent (" + p.localName.toLowerCase() + "). No animation performed."); + return; + } + var fieldObject = fields[toFieldIndex].clone().setFieldName('to'); // Parse table entry for 'toField' + var to = xseen.nodes._parseField(fieldObject, e); // Parsed data -- need to convert to THREE format + +// Convert 'to' to the datatype of 'field' and set interpolation type. + var interpolation; + if (fieldObject.type == 'SFVec3f') { + interpolation = TWEEN.Interpolation.Linear; + to = xseen.types.Vector3(to); + xseen.debug.logInfo("Interpolating field '" + toField + "' as 3-space."); + + } else if (fieldObject.type == 'SFColor') { + interpolation = this.Interpolator.color; + to = new THREE.Color (xseen.types.Color3toInt(to)); + xseen.debug.logInfo("Interpolation field '" + toField + "' as color."); + + } else if (fieldObject.type == 'SFRotation') { + interpolation = this.Interpolator.slerp; + to = xseen.types.Rotation2Quat(to); + xseen.debug.logInfo("Interpolation field '" + toField + "' as rotation."); + + } else { + xseen.debug.logInfo("Field '" + toField + "' not converted to THREE format. No animation performed."); + return; + } + var fieldTHREE = p._xseen.animate[toField]; // THREE field for animation + + var tween = new TWEEN.Tween(fieldTHREE) + .to(to, duration) + .delay(delay) + .repeat(repeat) + .interpolation(interpolation); + var easingType = e._xseen.fields.easingtype; + easingType = easingType.charAt(0).toUpperCase() + easingType.slice(1); + easing = (easingType != 'Linear' && easing == '') ? 'inout' : easing; + if (easing != '') { + easing = easing.replace('in', 'In').replace('out', 'Out'); + easingType = (easingType == 'Linear') ? 'Quadratic' : easingType; + e._xseen.fields.easing = easing; + e._xseen.fields.easingtype = easingType; + tween.easing(TWEEN.Easing[easingType][easing]); + } + +/* + * Put animation-specific data in node (e._xseen) so it can be accessed on events (through 'this') + * This includes initial value and field + * All handlers (goes into .handlers) + * TWEEN object + */ + e._xseen.initialValue = fieldTHREE.clone(); + e._xseen.animatingField = fieldTHREE; + e._xseen.handlers = {}; + e._xseen.handlers.setstart = this.setstart; + e._xseen.handlers.setstop = this.setstop; + e._xseen.handlers.setpause = this.setpause; + e._xseen.handlers.setresetstart = this.setresetstart; + e._xseen.animating = tween; + p._xseen.animation.push (tween); + tween.start(); + }, + 'fin' : function (e,p) {}, + 'setstart' : function (ev) + { + console.log ('Starting animation'); + this.destination._xseen.animating.start(); + }, + 'setstop' : function (ev) + { + console.log ('Stopping animation'); + this.destination._xseen.animating.stop(); + }, +/* + * TODO: Update TWEEN to support real pause & resume. + * Pause needs to hold current position + * Resume needs to restart the timer to current time so there is no "jump" + */ + 'setpause' : function (ev) + { + console.log ('Pausing (really stopping) animation'); + this.destination._xseen.animating.stop(); + }, + 'setresetstart' : function (ev) // TODO: Create seperate 'reset' method + { + console.log ('Reset and start animation'); + this.destination._xseen.animatingField = this.destination._xseen.initialValue; + this.destination._xseen.animating.start(); + }, + +/* + * Various interpolator functions for use with different data types + * All are designed to be used within TWEEN and take two arguments + * v A vector of way points (key values) that define the interpolated path + * k The interpolating factor that defines how far along the path for the current result + * + * Functions + * slerp - Linear in quaterian space (though not yet) + * color - Linear in color space (currently HSL as used by THREE) + * + */ + 'Interpolator' : { + 'slerp' : function (v,k) + { + var m = v.length - 1; + var f = m * k; + var i = Math.floor(f); + + if (k < 0) { + return v[0].slerp(v[1], f); + } + + if (k > 1) { + return v[m].slerp(v[m-1], m-f); + } + + return v[i].slerp (v[i + 1 > m ? m : i + 1], f-i); + }, + 'color' : function (v,k) + { + var m = v.length - 1; + var f = m * k; + var i = Math.floor(f); + var fn = this.slerpCompute; + + if (k < 0) { + return v[0].lerp(v[1], f); + } + if (k > 1) { + return v[m].lerp(v[m-1], m-f); + } + return v[i].lerp (v[i + 1 > m ? m : i + 1], f - i); + }, + }, +}; +// File: nodes/_Definitions-aframe.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * portions extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + */ + + +/* + * These are intended to be development support routines. It is anticipated that in + * production systems the array dump would be loaded. As a result, it is necessary + * to have a routine that dumps out the Object (_dumpTable) so it can be captured and saved. A routine + * or documentation on how to load the Object would also be good. + * + */ + +xseen._addAframeAppearance = function (node) { + node + .addField('ambient-occlusion-map', 'SFString', '') + .addField('ambient-occlusion-map-intensity', 'SFFloat', 1) + .addField('ambient-occlusion-texture-offset', 'SFVec2f', '0 0') + .addField('ambient-occlusion-texture-repeat', 'SFVec2f', '1 1') + .addField('color', 'Color', '#FFF') + .addField('displacement-bias', 'SFFloat', 0.5) + .addField('displacement-map', 'SFString', '') + .addField('displacement-scale', 'SFFloat', 1) + .addField('displacement-texture-offset', 'SFVec2f', '0 0') + .addField('displacement-texture-repeat', 'SFVec2f', '1 1') + .addField('env-map', 'SFString', '') + .addField('fog', 'SFBool', true) + .addField('metalness', 'SFFloat', 0) + .addField('normal-map', 'SFString', '') + .addField('normal-scale', 'SFVec2f', '1 1') + .addField('normal-texture-offset', 'SFVec2f', '0 0') + .addField('normal-texture-repeat', 'SFVec2f', '1 1') + .addField('repeat', 'SFVec2f', '1 1') + .addField('roughness', 'SFFloat', 0.5) + .addField('spherical-env-map', 'SFString', '') + .addField('src', 'SFString', '') + .addField('wireframe', 'SFBool', false) + .addField('wireframe-linewidth', 'SFInt', 2) + .addNode(); +} + +xseen.nodes._defineNode('a-entity', 'A-Frame', 'af_Entity') + .addField('geometry', 'SFString', '') + .addField('material', 'SFString', '') + .addField('light', 'SFString', '') + .addNode(); + +var node; +node = xseen.nodes._defineNode('a-box', 'A-Frame', 'af_Box') + .addField('depth', 'SFFloat', 1) + .addField('height', 'SFFloat', 1) + .addField('width', 'SFFloat', 512) + .addField('segments-depth', 'SFInt', 1) + .addField('segments-height', 'SFInt', 1) + .addField('segments-width', 'SFInt', 1); +xseen._addAframeAppearance (node); + +node = xseen.nodes._defineNode('a-cone', 'A-Frame', 'af_Cone') + .addField('height', 'SFFloat', 1) + .addField('radius', 'SFFloat', 1) + .addField('open-ended', 'SFBool', false) + .addField('theta-start', 'SFFloat', 0) + .addField('theta-length', 'SFFloat', 360) + .addField('segments-height', 'SFInt', 1) + .addField('segments-radial', 'SFInt', 8); +xseen._addAframeAppearance (node); + +node = xseen.nodes._defineNode('a-cylinder', 'A-Frame', 'af_Cylinder') + .addField('height', 'SFFloat', 1) + .addField('open-ended', 'SFBool', false) + .addField('radius-bottom', 'SFFloat', 1) + .addField('radius-top', 'SFFloat', 1) + .addField('theta-start', 'SFFloat', 0) + .addField('theta-length', 'SFFloat', 360) + .addField('segments-height', 'SFInt', 1) + .addField('segments-radial', 'SFInt', 8); +xseen._addAframeAppearance (node); + +node = xseen.nodes._defineNode('a-dodecahedron', 'A-Frame', 'af_Dodecahedron') + .addField('radius', 'SFFloat', 1) + .addField('detail', 'SFFloat', 0); +xseen._addAframeAppearance (node); + +node = xseen.nodes._defineNode('a-icosahedron', 'A-Frame', 'af_Icosahedron') + .addField('radius', 'SFFloat', 1) + .addField('detail', 'SFFloat', 0); +xseen._addAframeAppearance (node); + +node = xseen.nodes._defineNode('a-octahedron', 'A-Frame', 'af_Octahedron') + .addField('radius', 'SFFloat', 1) + .addField('detail', 'SFFloat', 0); +xseen._addAframeAppearance (node); + +node = xseen.nodes._defineNode('a-sphere', 'A-Frame', 'af_Sphere') + .addField('radius', 'SFFloat', 1) + .addField('theta-start', 'SFFloat', 0) + .addField('theta-length', 'SFFloat', 180) + .addField('phi-start', 'SFFloat', 0) + .addField('phi-length', 'SFFloat', 360) + .addField('segments-height', 'SFInt', 18) + .addField('segments-width', 'SFInt', 36); +xseen._addAframeAppearance (node); + +node = xseen.nodes._defineNode('a-tetrahedron', 'A-Frame', 'af_Tetrahedron') + .addField('radius', 'SFFloat', 1) + .addField('detail', 'SFFloat', 0); +xseen._addAframeAppearance (node); + +node = xseen.nodes._defineNode('a-torus', 'A-Frame', 'af_Torus') + .addField('radius', 'SFFloat', 2) + .addField('tube', 'SFFloat', 1) + .addField('arc', 'SFFloat', 360) + .addField('segments-radial', 'SFInt', 8) + .addField('segments-tubular', 'SFInt', 6); +xseen._addAframeAppearance (node); + +/* + * Asset management system nodes + */ +xseen.nodes._defineNode('a-assets', 'A-Frame', 'af_Assets') + .addNode(); +xseen.nodes._defineNode('a-asset-item', 'A-Frame', 'af_AssetItem') + .addField('src', 'SFString', '') + .addNode(); +xseen.nodes._defineNode('a-mixin', 'A-Frame', 'af_Mixin') + .addField('*', 'SFString', '') + .addNode(); +// File: nodes/_Definitions-x3d.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * portions extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + */ + + +/* + * These are intended to be development support routines. It is anticipated that in + * production systems the array dump would be loaded. As a result, it is necessary + * to have a routine that dumps out the Object (_dumpTable) so it can be captured and saved. A routine + * or documentation on how to load the Object would also be good. + * + */ + +xseen.nodes._defineNode('Cone', 'Geometry3D', 'geometry3D_Cone') + .addField('bottomRadius', 'SFFloat', 1) + .addField('height', 'SFFloat', 2) + .addField('bottom', 'SFBool', true) + .addField('side', 'SFBool', true) + .addNode(); + +xseen.nodes._defineNode('Box', 'Geometry3D', 'geometry3D_Box') + .addField('size', 'SFVec3f', [1,1,1]) + .addNode(); + +xseen.nodes._defineNode('Sphere', 'Geometry3D', 'geometry3D_Sphere') + .addField('radius', 'SFFloat', '1') + .addNode(); + +xseen.nodes._defineNode('Cylinder', 'Geometry3D', 'geometry3D_Cylinder') + .addField('radius', 'SFFloat', 1) + .addField('height', 'SFFloat', 2) + .addField('bottom', 'SFBool', true) + .addField('side', 'SFBool', true) + .addField('top', 'SFBool', true) + .addNode(); + +xseen.nodes._defineNode ('Material', 'Appearance', 'appearance_Material') + .addField({name:'diffuseColor', datatype:'SFColor', defaultValue:[.8,.8,.8], animatable:true}) + .addField({name:'emissiveColor',datatype: 'SFColor', defaultValue:[0,0,0], animatable:true}) + .addField({name:'specularColor', datatype:'SFColor', defaultValue:[0,0,0], animatable:true}) + .addField({name:'transparency', datatype:'SFFloat', defaultValue:'0', animatable:true}) + .addField({name:'shininess', datatype:'SFFloat', defaultValue:'0', animatable:true}) + .addNode(); + +xseen.nodes._defineNode ('Transform', 'Grouping', 'grouping_Transform') + .addField({name:'translation', datatype:'SFVec3f', defaultValue:[0,0,0], animatable:true}) + .addField({name:'scale', datatype:'SFVec3f', defaultValue:[1,1,1], animatable:true}) + .addField({name:'rotation', datatype:'SFRotation', defaultValue:xseen.types.SFRotation('0 1 0 0',''), animatable:true}) + .addNode(); +xseen.nodes._defineNode ('Group', 'Grouping', 'grouping_Transform') + .addNode(); + +xseen.nodes._defineNode ('Light', 'Lighting', 'lighting_Light') + .addField('direction', 'SFVec3f', [0,0,-1]) // DirectionalLight + .addField('location', 'SFVec3f', [0,0,0]) // PointLight & SpotLight + .addField('radius', 'SFFloat', '100') // PointLight & SpotLight + .addField('attenuation', 'SFVec3f', [1,0,0]) // PointLight & SpotLight + .addField('beamWidth', 'SFFloat', '0.78539816339744830961566084581988') // SpotLight + .addField('cutOffAngle', 'SFFloat', '1.5707963267948966192313216916398') // SpotLight + .addField('color', 'SFColor', [1,1,1]) // General + .addField('intensity', 'SFFloat', '1') // General + .addField({name:'type', datatype:'EnumerateString', defaultValue:'Directional', enumerated:['Directional', 'Spot', 'Point'], animatable:true}) + .addNode(); +xseen.nodes._defineNode ('DirectionalLight', 'Lighting', 'lighting_Light') + .addField('direction', 'SFVec3f', [0,0,-1]) + .addField('color', 'SFColor', [1,1,1]) + .addField('intensity', 'SFFloat', '1') + .addField('type', 'SFString', 'Directional') + .addNode(); +xseen.nodes._defineNode ('PointLight', 'Lighting', 'lighting_Light') + .addField('location', 'SFVec3f', [0,0,0]) + .addField('radius', 'SFFloat', '100') + .addField('attenuation', 'SFVec3f', [1,0,0]) + .addField('color', 'SFColor', [1,1,1]) + .addField('intensity', 'SFFloat', '1') + .addField('type', 'SFString', 'Point') + .addNode(); +xseen.nodes._defineNode ('SpotLight', 'Lighting', 'lighting_Light') + .addField('direction', 'SFVec3f', [0,0,-1]) + .addField('radius', 'SFFloat', '100') + .addField('attenuation', 'SFVec3f', [1,0,0]) + .addField('beamWidth', 'SFFloat', '0.78539816339744830961566084581988') // pi/4 + .addField('cutOffAngle', 'SFFloat', '1.5707963267948966192313216916398') // pi/2 + .addField('color', 'SFColor', [1,1,1]) + .addField('intensity', 'SFFloat', '1') + .addField('type', 'SFString', 'Spot') + .addNode(); + +xseen.nodes._defineNode ('Viewpoint', 'Controls', 'unk_Viewpoint') + .addField('position', 'SFVec3f', '0 0 10') + .addField('orientation', 'SFRotation', xseen.types.SFRotation('0 1 0 0','')) + .addField('description', 'SFString', '') + .addField({name:'cameratype', datatype:'EnumerateString', defaultValue:'perspective', enumerated:['perspective', 'stereo', 'orthographic'], animatable:false}) + .addField({name:'type', datatype:'EnumerateString', defaultValue:'perspective', enumerated:['perspective', 'stereo', 'orthographic'], animatable:false}) + .addField({name:'motion', datatype:'EnumerateString', defaultValue:'none', enumerated:['none', 'turntable', 'tilt'], animatable:false}) + .addField('motionspeed', 'SFFloat', 16) + .addField('active', 'SFBool', true) // incoming event + .addNode(); +xseen.nodes._defineNode ('NavigationMode', 'Controls', 'controls_Navigation') + .addField('speed', 'SFFloat', 1.) + .addField({name:'type', datatype:'EnumerateString', defaultValue:'none', enumerated:['none', 'orbit', 'fly', 'examine', 'trackball'], animatable:false}) + .addNode(); +xseen.nodes._defineNode ('Camera', 'Controls', 'unk_Viewpoint') + .addField('position', 'SFVec3f', [0,0,10]) + .addField('orientation', 'SFRotation', xseen.types.SFRotation('0 1 0 0','')) + .addNode(); + +xseen.nodes._defineNode ('Inline', 'Networking', 'networking_Inline') + .addField('url', 'SFString', '') + .addNode(); + +xseen.nodes._defineNode ('scene', 'Core', 'core_Scene') + .addNode(); +xseen.nodes._defineNode ('canvas', 'Core', 'core_NOOP') + .addNode(); +xseen.nodes._defineNode ('WorldInfo', 'Core', 'core_WorldInfo') + .addNode(); +xseen.nodes._defineNode ('Appearance', 'Appearance', 'appearance_Appearance') + .addNode(); +xseen.nodes._defineNode ('ImageTexture', 'Appearance', 'appearance_ImageTexture') + .addField('url', 'SFString', '') + .addField('repeatS', 'SFBool', true) + .addField('repeatT', 'SFBool', true) + .addNode(); + +xseen.nodes._defineNode ('Shape', 'Shape', 'unk_Shape') + .addNode(); +xseen.nodes._defineNode('Background', 'Environmental', 'env_Background') + .addField('skyColor', 'SFColor', [0,0,0]) + .addField('srcFront', 'SFString', '') + .addField('srcBack', 'SFString', '') + .addField('srcTop', 'SFString', '') + .addField('srcBottom', 'SFString', '') + .addField('srcLeft', 'SFString', '') + .addField('srcRight', 'SFString', '') + .addField('backgroundIsCube', 'SFBool', 'true') + .addNode(); + +xseen.nodes._defineNode('TriangleSet', 'Geometry', 'geometry_TriangleSet') + .addField('ccw', 'SFBool', 'true') + .addField('colorPerVertex', 'SFBool', 'true') + .addField('solid', 'SFBool', 'true') + .addNode(); +xseen.nodes._defineNode('IndexedTriangleSet', 'Geometry', 'geometry_IndexedTriangleSet') + .addField('ccw', 'SFBool', true) + .addField('colorPerVertex', 'SFBool', true) + .addField('solid', 'SFBool', true) + .addField('index', 'MFInt', '') + .addNode(); +xseen.nodes._defineNode('Coordinate', 'Geometry', 'geometry_Coordinate') + .addField('point', 'MFVec3f', []) + .addNode(); +xseen.nodes._defineNode('Normal', 'Geometry', 'geometry_Normal') + .addField('vector', 'MFVec3f', []) + .addNode(); +xseen.nodes._defineNode('Color', 'Geometry', 'geometry_Color') + .addField('color', 'MFColor', []) + .addNode(); +xseen.nodes._defineNode('IndexedFaceSet', 'Geometry', 'geometry_IndexedFaceSet') + .addField('ccw', 'SFBool', true) + .addField('colorPerVertex', 'SFBool', true) + .addField('solid', 'SFBool', true) + .addField('coordIndex', 'MFInt', '') + .addNode(); +xseen.nodes._defineNode('IndexedQuadSet', 'Geometry', 'geometry_IndexedQuadSet') + .addField('ccw', 'SFBool', true) + .addField('colorPerVertex', 'SFBool', true) + .addField('solid', 'SFBool', true) + .addField('index', 'MFInt', '') + .addNode(); +xseen.nodes._defineNode('QuadSet', 'Geometry', 'geometry_QuadSet') + .addField('ccw', 'SFBool', true) + .addField('colorPerVertex', 'SFBool', true) + .addField('solid', 'SFBool', true) + .addNode(); + +//xseen.nodes._dumpTable(); +// File: nodes/_Definitions-xseen.js +/* + * XSeen JavaScript library + * + * (c)2017, Daly Realism, Los Angeles + * + * portions extracted from or inspired by + * X3DOM JavaScript Library + * http://www.x3dom.org + * + * (C)2009 Fraunhofer IGD, Darmstadt, Germany + * Dual licensed under the MIT and GPL + */ + + +/* + * These are intended to be development support routines. It is anticipated that in + * production systems the array dump would be loaded. As a result, it is necessary + * to have a routine that dumps out the Object (_dumpTable) so it can be captured and saved. A routine + * or documentation on how to load the Object would also be good. + * + */ + +xseen.nodes._defineNode('model', 'XSeen', 'x_Model') + .addField('src', 'SFString', '') + .addField('playonload', 'SFString', '') + .addField('duration', 'SFFloat', '-1') + .addNode(); + +xseen.nodes._defineNode('animate', 'XSeen', 'x_Animate') + .addField('field', 'SFString', '') + .addField('to', 'MFFloat', '') // Needs to be 'field' datatype. That is not known until node-parse. For now insist on numeric array + .addField('delay', 'SFTime', 0) + .addField('duration', 'SFTime', 0) + .addField('repeat', 'SFInt', 0) + .addField({name:'interpolator', datatype:'EnumerateString', defaultValue:'position', enumerated:['position', 'rotation', 'color'], animatable:false}) + .addField({name:'Easing', datatype:'EnumerateString', defaultValue:'', enumerated:['', 'in', 'out', 'inout'], animatable:false}) + .addField({name:'EasingType', datatype:'EnumerateString', defaultValue:'linear', enumerated:['linear', 'quadratic', 'sinusoidal', 'exponential', 'elastic', 'bounce'], animatable:false}) + .addField('start', 'SFBool', true) // incoming event, need to set timer trigger + .addField('stop', 'SFBool', true) // incoming event, need to set timer trigger + .addField('resetstart', 'SFBool', true) // incoming event, need to set timer trigger + .addField('pause', 'SFBool', true) // incoming event, need to set timer trigger + .addNode(); + +xseen.nodes._defineNode('route', 'XSeen', 'x_Route') + .addField('source', 'SFString', '') + .addField('event', 'SFString', '') + .addField('destination', 'SFString', '') + .addField('field', 'SFString', '') + .addField('handler', 'SFString', '') + .addNode(); + + +// Dump parse table +//xseen.nodes._dumpTable(); \ No newline at end of file diff --git a/Release/XSeen.0.4.5+23_75edebb.min.js b/Release/XSeen.0.4.5+23_75edebb.min.js new file mode 100644 index 0000000..24ce2f2 --- /dev/null +++ b/Release/XSeen.0.4.5+23_75edebb.min.js @@ -0,0 +1,2818 @@ +/* + * XSeen V0.4.5+23_75edebb + * Built Mon Jul 10 20:41:35 2017 + * + +Dual licensed under the MIT and GPL licenses. + +==[MIT]==================================================================== +Copyright (c) 2017, Daly Realism + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +==[GPL]==================================================================== + +XSeen - Declarative 3D for HTML + +Copyright (C) 2017, Daly Realism + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + + +=== COPYRIGHT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Copyright (C) 2017, Daly Realism for XSeen +Copyright, Fraunhofer for X3DOM +Copyright, Mozilla for A-Frame +Copyright, THREE and Khronos for various parts of THREE.js +Copyright (C) 2017, John Carlson for JSON->XML converter (JSONParser.js) + +=== +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + */ +"use strict"; +var JSONParser = function(scene) +{ +} +JSONParser.prototype.constructor = JSONParser; +JSONParser.prototype.parseJavaScript = function(jsobj) { +var child = this.CreateElement('scene'); +this.ConvertToX3DOM(jsobj, "", child); +return child; +}; +JSONParser.prototype.elementSetAttribute = function(element, key, value) { +if (key === 'SON schema') { +} else if (key === 'ncoding') { +} else { +if (typeof element.setAttribute === 'function') { +element.setAttribute(key, value); +} +} +}; +JSONParser.prototype.ConvertChildren = function(parentkey, object, element) { +var key; +for (key in object) { +if (typeof object[key] === 'object') { +if (isNaN(parseInt(key))) { +this.ConvertObject(key, object, element, parentkey.substr(1)); +} else { +this.ConvertToX3DOM(object[key], key, element, parentkey.substr(1)); +} +} +} +}; +JSONParser.prototype.CreateElement = function(key, containerField) { +var child = document.createElement(key); +if (typeof containerField !== 'undefined') { +this.elementSetAttribute(child, 'containerField', containerField); +} +return child; +}; +JSONParser.prototype.CDATACreateFunction = function(document, element, str) { +var y = str.replace(/\\"/g, "\\\"") +.replace(/</g, "<") +.replace(/>/g, ">") +.replace(/&/g, "&"); +do { +str = y; +y = str.replace(/'([^'\r\n]*)\n([^']*)'/g, "'$1\\n$2'"); +if (str !== y) { +console.log("CDATA Replacing",str,"with",y); +} +} while (y != str); +var domParser = new DOMParser(); +var cdataStr = ''; // has to be wrapped into an element +var scriptDoc = domParser .parseFromString (cdataStr, 'application/xml'); +var cdata = scriptDoc .children[0] .childNodes[1]; // space after script is childNode[0] +element .appendChild(cdata); +}; +JSONParser.prototype.ConvertObject = function(key, object, element, containerField) { +var child; +if (object !== null && typeof object[key] === 'object') { +if (key.substr(0,1) === '@') { +this.ConvertToX3DOM(object[key], key, element); +} else if (key.substr(0,1) === '-') { +this.ConvertChildren(key, object[key], element); +} else if (key === '#comment') { +for (var c in object[key]) { +child = document.createComment(this.CommentStringToXML(object[key][c])); +element.appendChild(child); +} +} else if (key === '#text') { +child = document.createTextNode(object[key].join("")); +element.appendChild(child); +} else if (key === '#sourceText') { +this.CDATACreateFunction(document, element, object[key].join("\r\n")+"\r\n"); +} else { +if (key === 'connect' || key === 'fieldValue' || key === 'field' || key === 'meta' || key === 'component') { +for (var childkey in object[key]) { // for each field +if (typeof object[key][childkey] === 'object') { +child = this.CreateElement(key, containerField); +this.ConvertToX3DOM(object[key][childkey], childkey, child); +element.appendChild(child); +element.appendChild(document.createTextNode("\n")); +} +} +} else { +child = this.CreateElement(key, containerField); +this.ConvertToX3DOM(object[key], key, child); +element.appendChild(child); +element.appendChild(document.createTextNode("\n")); +} +} +} +}; +JSONParser.prototype.CommentStringToXML = function(str) { +var y = str; +str = str.replace(/\\\\/g, '\\'); +if (y !== str) { +console.log("X3DJSONLD replacing", y, "with", str); +} +return str; +}; +JSONParser.prototype.SFStringToXML = function(str) { +var y = str; +str = str.replace(/\\/g, '\\\\'); +str = str.replace(/"/g, '\\\"'); +if (y !== str) { +console.log("X3DJSONLD [] replacing", y, "with", str); +} +return str; +}; +JSONParser.prototype.JSONStringToXML = function(str) { +var y = str; +str = str.replace(/\\/g, '\\\\'); +str = str.replace(/\n/g, '\\n'); +if (y !== str) { +console.log("X3DJSONLD replacing", y, "with", str); +} +return str; +}; +JSONParser.prototype.ConvertToX3DOM = function(object, parentkey, element, containerField) { +var key; +var localArray = []; +var isArray = false; +var arrayOfStrings = false; +for (key in object) { +if (isNaN(parseInt(key))) { +isArray = false; +} else { +isArray = true; +} +if (isArray) { +if (typeof object[key] === 'number') { +localArray.push(object[key]); +} else if (typeof object[key] === 'string') { +localArray.push(object[key]); +arrayOfStrings = true; +} else if (typeof object[key] === 'boolean') { +localArray.push(object[key]); +} else if (typeof object[key] === 'object') { +this.ConvertToX3DOM(object[key], key, element); +} else if (typeof object[key] === 'undefined') { +} else { +console.error("Unknown type found in array "+typeof object[key]); +} +} else if (typeof object[key] === 'object') { +if (key === 'scene') { +this.ConvertToX3DOM(object[key], key, element); +} else { +this.ConvertObject(key, object, element); +} +} else if (typeof object[key] === 'number') { +this.elementSetAttribute(element, key.substr(1),object[key]); +} else if (typeof object[key] === 'string') { +if (key === '#comment') { +var child = document.createComment(this.CommentStringToXML(object[key])); +element.appendChild(child); +} else if (key === '#text') { +var child = document.createTextNode(object[key]); +element.appendChild(child); +} else { +this.elementSetAttribute(element, key.substr(1), this.JSONStringToXML(object[key])); +} +} else if (typeof object[key] === 'boolean') { +this.elementSetAttribute(element, key.substr(1),object[key]); +} else if (typeof object[key] === 'undefined') { +} else { +console.error("Unknown type found in object "+typeof object[key]); +console.error(object); +} +} +if (isArray) { +if (parentkey.substr(0,1) === '@') { +if (arrayOfStrings) { +arrayOfStrings = false; +for (var str in localArray) { +localArray[str] = this.SFStringToXML(localArray[str]); +} +this.elementSetAttribute(element, parentkey.substr(1),'"'+localArray.join('" "')+'"'); +} else { +this.elementSetAttribute(element, parentkey.substr(1),localArray.join(" ")); +} +} +isArray = false; +} +return element; +}; +function LoadManager () { +this.urlQueue = []; +this.urlNext = -1; +this.MaxRequests = 3; +this.totalRequests = 0; +this.totalResponses = 0; +this.requestCount = 0; +var lmThat = this; +this.load = function (url, success, progress, failed, userdata) { +this.urlQueue.push( {'url':url, 'type':'', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); +this.loadNextUrl(); +} +this.loadText = function (url, success, progress, failed, userdata) { +this.urlQueue.push( {'url':url, 'type':'text', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); +this.loadNextUrl(); +} +this.loadHtml = function (url, success, progress, failed, userdata) { +this.urlQueue.push( {'url':url, 'type':'html', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); +this.loadNextUrl(); +} +this.loadXml = function (url, success, progress, failed, userdata) { +this.urlQueue.push( {'url':url, 'type':'xml', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); +this.loadNextUrl(); +} +this.loadJson = function (url, success, progress, failed, userdata) { +this.urlQueue.push( {'url':url, 'type':'json', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); +this.loadNextUrl(); +} +this.loadImage = function (url, success, progress, failed, userdata) { +this.urlQueue.push( {'url':url, 'type':'image', 'userdata':userdata, 'success':success, 'failure':failed, 'progress':progress} ); +this.loadNextUrl(); +} +this.success = function (response, string, xhr) { +if (typeof(xhr._loadManager.success) !== undefined) { +xhr._loadManager.success (response, xhr._loadManager.userdata, xhr); +} +} +this.failure = function (xhr, errorCode, errorText) { +if (typeof(xhr._loadManager.failure) !== undefined) { +xhr._loadManager.failure (xhr, xhr._loadManager.userdata, errorCode, errorText); +} +} +this.requestComplete = function (event, xhr, settings) { +lmThat.requestCount --; +lmThat.totalResponses++; +lmThat.loadNextUrl(); +} +this.loadNextUrl = function () { +if (this.requestCount >= this.MaxRequests) {return; } +if (this.urlNext >= this.urlQueue.length || this.urlNext < 0) { +this.urlNext = -1; +for (var i=0; i ' + obj.type + ' (' + obj.name + ')'); +for (var i=0; i +var validParams = xseen.array_to_object([ +'showLog', +'showStat', +'showProgress', +'PrimitiveQuality', +'components', +'loadpath', +'disableDoubleClick', +'backend', +'altImg', +'runtimeEnabled', +'keysEnabled', +'showTouchpoints', +'disableTouch', +'maxActiveDownloads' +]); +var components, prefix; +var showLoggingConsole = false; +for (var i=0; i < xseens.length; i++) { +settings.setProperty("showLog", xseens[i].getAttribute("showLog") || 'false'); +settings.setProperty("showLog", xseens[i].getAttribute("showLog") || 'true'); +settings.setProperty("showStat", xseens[i].getAttribute("showStat") || 'false'); +settings.setProperty("showProgress", xseens[i].getAttribute("showProgress") || 'true'); +settings.setProperty("PrimitiveQuality", xseens[i].getAttribute("PrimitiveQuality") || 'High'); +params = xseens[i].getElementsByTagName('PARAM'); +for (var j=0; j < params.length; j++) { +if (params[j].getAttribute('name') in validParams) { +settings.setProperty(params[j].getAttribute('name'), params[j].getAttribute('value')); +} else { +} +} +if (settings.getProperty('showLog') === 'true') { +showLoggingConsole = true; +} +if (typeof X3DOM_SECURITY_OFF != 'undefined' && X3DOM_SECURITY_OFF === true) { +components = settings.getProperty('components', xseens[i].getAttribute("components")); +if (components) { +prefix = settings.getProperty('loadpath', xseens[i].getAttribute("loadpath")); +components = components.trim().split(','); +for (j=0; j < components.length; j++) { +xseen.loadJS(components[j] + ".js", prefix); +} +} +if (xseens[i].getAttribute("src")) { +var _scene = document.createElement("scene"); +var _inl = document.createElement("Inline"); +_inl.setAttribute("url", xseens[i].getAttribute("src")); +_scene.appendChild(_inl); +xseens[i].appendChild(_scene); +} +} +} +if (showLoggingConsole == true) { +xseen.debug.activate(true); +} else { +xseen.debug.activate(false); +} +if (xseen.versionInfo !== undefined) { +xseen.debug.logInfo("XSeen version " + xseen.versionInfo.version + ", " + +"Date " + xseen.versionInfo.date); +xseen.debug.logInfo(xseen.versionInfo.splashText); +} +var x_element; +var x_canvas; +var altDiv, altP, aLnk, altImg; +var t0, t1; +for (var i=0; i < xseens.length; i++) +{ +x_element = xseens[i]; // The XSeen DOM element +x_canvas = new THREE.Scene(); // May need addtl info if multiple: xseen.X3DCanvas(x_element, xseen.canvases.length); +xseen.canvases.push(x_canvas); // TODO: Need to handle failure to initialize? +t0 = new Date().getTime(); +var divWidth = x_element.getAttribute('width'); +var divHeight = x_element.getAttribute('height'); +if (divHeight + divWidth < 100) { +divHeight = 450; +divWidth = 800; +} else if (divHeight < 50) { +divHeight = Math.floor(divWidth/2) + 50; +} else if (divWidth < 50) { +divWidth = divHeight * 2 - 100; +} +var turntable = (x_element.getAttribute('turntable') || '').toLowerCase(); +if (turntable == 'on' || turntable == 'yes' || turntable == 'y' || turntable == '1') { +turntable = true; +} else { +turntable = false; +} +turntable = false; +var x_camera = {}; +var x_renderer = new THREE.WebGLRenderer(); +x_renderer.setSize (divWidth, divHeight); +var x_effect = new THREE.StereoEffect(x_renderer); +x_renderer.controls = {'update' : function() {return;}}; +x_element.addEventListener ('dblclick', xseen.Events.canvasHandler, true); +x_element.addEventListener ('click', xseen.Events.canvasHandler, true); +x_element.addEventListener ('mousedown', xseen.Events.canvasHandler, true); +x_element.addEventListener ('mousemove', xseen.Events.canvasHandler, true); +x_element.addEventListener ('mouseup', xseen.Events.canvasHandler, true); +x_element.addEventListener ('xseen', xseen.Events.XSeenHandler); // Last chance for XSeen handling of event +x_element.addEventListener ('change', xseen.Events.XSeenDebugHandler, true); // Early catch of 'change' event +xseen.sceneInfo.push ({ +'size' : {'width':divWidth, 'height':divHeight}, +'scene' : x_canvas, +'renderer' : x_renderer, +'effect' : x_effect, +'camera' : [x_camera], +'turntable' : turntable, +'mixers' : [], +'clock' : new THREE.Clock(), +'element' : x_element, +'selectable': [], +'stacks' : [], +'tmp' : {activeViewpoint:false}, +'xseen' : xseen, +}); +x_element._xseen = {}; +x_element._xseen.children = []; +x_element._xseen.sceneInfo = xseen.sceneInfo[xseen.sceneInfo.length-1]; +t1 = new Date().getTime() - t0; +xseen.debug.logInfo("Time for setup and init of GL element no. " + i + ": " + t1 + " ms."); +} +var ready = (function(eventType) { +var evt = null; +if (document.createEvent) { +evt = document.createEvent("Events"); +evt.initEvent(eventType, true, true); +document.dispatchEvent(evt); +} else if (document.createEventObject) { +evt = document.createEventObject(); +document.body.fireEvent('on' + eventType, evt); +} +})('load'); +var t=[]; +for (var i=0; i xseen.debug.maxLinesToLog) { return; } +var node = document.createElement("p"); +node.style.margin = 0; +switch (logType) { +case xseen.debug.INFO: +node.style.color = "#009900"; +break; +case xseen.debug.WARNING: +node.style.color = "#cd853f"; +break; +case xseen.debug.ERROR: +node.style.color = "#ff4500"; +break; +case xseen.debug.EXCEPTION: +node.style.color = "#ffff00"; +break; +default: +node.style.color = "#009900"; +break; +} +try { +node.innerHTML = logType + ": " + msg; +xseen.debug.logContainer.insertBefore(node, xseen.debug.logContainer.firstChild); +} catch (err) { +if (window.console.firebug !== undefined) { +window.console.warn(msg); +} +} +if (xseen.debug.isFirebugAvailable) { +switch (logType) { +case xseen.debug.INFO: +window.console.info(msg); +break; +case xseen.debug.WARNING: +window.console.warn(msg); +break; +case xseen.debug.ERROR: +window.console.error(msg); +break; +case xseen.debug.EXCEPTION: +window.console.debug(msg); +break; +default: +break; +} +} +xseen.debug.numLinesLogged++; +}, +logInfo: function(msg) { +xseen.debug.doLog(msg, xseen.debug.INFO); +}, +logWarning: function(msg) { +xseen.debug.doLog(msg, xseen.debug.WARNING); +}, +logError: function(msg) { +xseen.debug.doLog(msg, xseen.debug.ERROR); +}, +logException: function(msg) { +xseen.debug.doLog(msg, xseen.debug.EXCEPTION); +}, +assert: function(c, msg) { +if (!c) { +xseen.debug.doLog("Assertion failed in " + xseen.debug.assert.caller.name + ': ' + msg, xseen.debug.ERROR); +} +}, +typeOf: function (obj) { +var type = typeof obj; +return type === "object" && !obj ? "null" : type; +}, +exists: function (obj, name, type) { +type = type || "function"; +return (obj ? this.typeOf(obj[name]) : "null") === type; +}, +dumpFields: function (node) { +var str = ""; +for (var fName in node) { +str += (fName + ", "); +} +str += '\n'; +xseen.debug.logInfo(str); +return str; +} +}; +this.debug.setup(); +}; +xseen.Navigation = { +'TwoPi' : 2 * Math.PI, +'none' : function () {}, // Does not allow user-controlled navigation +'turntable' : function (speed, deltaT, scene, camera) +{ +var T, radians, radius, vp; +T = (new Date()).getTime() - xseen.timeStart; +radians = T * speed * this.TwoPi; +vp = scene.stacks.Viewpoints.getActive(); // Convienence declaration +radius = vp.fields._radius0; +camera.position.x = radius * Math.sin(radians) +camera.position.y = vp.fields.position[1] * Math.cos(1.5*radians); +camera.position.z = radius * Math.cos(radians); +camera.lookAt(scene.ORIGIN); +}, +'tilt' : function (speed, deltaT, scene, camera) +{ +var T, radians, vp; +T = (new Date()).getTime() - xseen.timeStart; +radians = T * speed * this.TwoPi; +vp = scene.stacks.Viewpoints.getActive(); // Convienence declaration +camera.position.y = vp.fields.position[1] * Math.cos(1.5*radians); +camera.lookAt(scene.ORIGIN); +}, +'setup' : { +'none' : function () {return null;}, +'orbit' : function (camera, renderer) +{ +var controls; +controls = new THREE.OrbitControls( camera, renderer.domElement ); +controls.enableZoom = false; +controls.enableZoom = true; +return controls; +}, +'trackball' : function (camera, renderer) +{ +var controls; +controls = new THREE.TrackballControls(camera, renderer.domElement); +controls.rotateSpeed = 1.0; +controls.zoomSpeed = 1.2; +controls.panSpeed = 0.8; +controls.noZoom = false; +controls.noPan = false; +controls.staticMoving = true; +controls.dynamicDampingFactor = 0.3; +controls.keys = [ 65, 83, 68 ]; +return controls; +}, +}, +}; +xseen.nodes = { +'_defineNode' : function(nodeName, nodeComponent, nodeMethod) { +var methodBase = ''; +node = { +'tag' : nodeName, +'taglc' : nodeName.toLowerCase(), +'component' : nodeComponent, +'method' : methodBase + nodeMethod, +'fields' : [], +'fieldIndex': [], +'addField' : function (fieldObj, datatype, defaultValue) { +var fieldName, namelc, enumerated, animatable; +if (typeof(fieldObj) === 'object') { +fieldName = fieldObj.name; +datatype = fieldObj.datatype; +defaultValue = fieldObj.defaultValue; +enumerated = (typeof(fieldObj.enumerated) === 'undefined') ? [] : fieldObj.enumerated; +animatable = (typeof(fieldObj.animatable) === 'undefined') ? false : fieldObj.animatable; +} else { +fieldName = fieldObj; +animatable = false; +if (typeof(defaultValue) == 'array') { +enumerated = defaultValue; +defaultValue = enumerated[0]; +} else { +enumerated = []; +} +} +namelc = fieldName.toLowerCase(); +this.fields.push ({ +'field' : fieldName, +'fieldlc' : namelc, +'type' : datatype, +'default' : defaultValue, +'enumeration' : enumerated, +'animatable' : animatable, +'clone' : this.cloneField, +'setFieldName' : this.setFieldName, +}); +this.fieldIndex[namelc] = this.fields.length-1; +return this; +}, +'addNode' : function () { +xseen.parseTable[this.taglc] = this; +}, +'cloneField' : function () { +var newFieldObject = { +'field' : this.field, +'fieldlc' : this.fieldlc, +'type' : this.type, +'default' : 0, +'enumeration' : [], +'animatable' : this.animatable, +'clone' : this.clone, +'setFieldName' : this.setFieldName, +}; +for (var i=0; i= 0) { +this._internals.activeNode = this._internals.stack[this._internals.active]; +} else { +this._internals.activeNode = this._internals.defaultNode; +} +} +this.init = function() { // Clears existing stack +this._internals.stack = []; +} +this.pushDown = function(node) { // Push new node onto stack and make active +this._internals.stack.push (node); +this._setActiveNode(); +} +this.popOff = function() { // Pop node off stack and make next one active +this._internals.stack.pop(); +this._setActiveNode(); +} +this.getActive = function() { +return this._internals.activeNode; +} +this.setDefault = function(node) { +this._internals.defaultNode = node; +if (Object.keys(this._internals.activeNode).length === 0) { +this._internals.activeNode = this._internals.defaultNode; +} +} +} +xseen.types = { +'Deg2Rad' : Math.PI / 180, +'SFFloat' : function (value, def) +{ +if (value === null) {return def;} +if (Number.isNaN(value)) {return def}; +return value; +}, +'SFInt' : function (value, def) +{ +if (value === null) {return def;} +if (Number.isNaN(value)) {return def}; +return Math.round(value); +}, +'SFBool' : function (value, def) +{ +if (value === null) {return def;} +if (value) {return true;} +if (!value) {return false;} +return def; +}, +'SFTime' : function (value, def) +{ +if (value === null) {return def;} +if (Number.isNaN(value)) {return def}; +return value; +}, +'SFVec3f' : function (value, def) +{ +if (value === null) {return def;} +var v3 = value.split(' '); +if (v3.length < 3 || Number.isNaN(v3[0]) || Number.isNaN(v3[1]) || Number.isNaN(v3[2])) { +return def; +} +return [v3[0]-0, v3[1]-0, v3[2]-0]; +}, +'SFVec2f' : function (value, def) +{ +if (value === null) {return def;} +var v2 = value.split(' '); +if (v2.length != 2 || Number.isNaN(v2[0]) || Number.isNaN(v2[1])) { +return def; +} +return [v2[0]-0, v2[1]-0]; +}, +'SFRotation' : function (value, def) +{ +if (value === null) {return def;} +var v4 = value.split(' '); +if (v4.length != 4 || Number.isNaN(v4[0]) || Number.isNaN(v4[1]) || Number.isNaN(v4[2]) || Number.isNaN(v4[3])) { +return def; +} +var result = { +'vector' : [v4[0], v4[1], v4[2], v4[3]], +'axis_angle' : [{'x': v4[0], 'y': v4[1], 'z': v4[2]}, v4[3]], +}; +return result; +}, +'SFColor' : function (value, defaultString) +{ +var v3 = this.SFVec3f(value, defaultString); +v3[0] = Math.min(Math.max(v3[0], 0.0), 1.0); +v3[1] = Math.min(Math.max(v3[1], 0.0), 1.0); +v3[2] = Math.min(Math.max(v3[2], 0.0), 1.0); +return v3; +}, +'SFString' : function (value, def) +{ +if (value === null) {value = def;} +return value; +}, +'MFFloat' : function (value, def) +{ +var defReturn = (def == '') ? [] : def; +if (value === null) {return defReturn;} +var mi = value.split(' '); +var rv = []; +for (var i=0; iDocumentation."]; +var version = { +major : Major, +minor : Minor, +patch : Patch, +preRelease : PreRelease, +release : Release, +version : '', +date : RDate, +splashText : SplashText +}; +version.version = version.major + '.' + version.minor + '.' + version.patch; +version.version += (version.preRelease != '') ? '-' + version.preRelease : ''; +version.version += (version.release != '') ? '+' + version.release : ''; +return version; +} +xseen.node.core_NOOP = { +'init' : function (e,p) {}, +'fin' : function (e,p) {} +}; +xseen.node.parsing = function (s, e) { +xseen.debug.logInfo ('Parsing init details stub for ' + s); +} +xseen.node.af_Entity = { +'init' : function (e,p) +{ +xseen.node.parsing('A-Frame Entity'); +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Assets = { +'init' : function (e,p) {}, +'fin' : function (e,p) {} +}; +xseen.node.af_AssetItem = { +'init' : function (e,p) // Only field is SRC. +{ +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Mixin = { +'init' : function (e,p) // Lots of fields -- all nebelous until used +{ +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Appearance = function (e) { +var parameters = { +'aoMap' : e._xseen.fields['ambient-occlusion-map'], +'aoMapIntensity' : e._xseen.fields['ambient-occlusion-map-intensity'], +'color' : e._xseen.fields['color'], +'displacementMap' : e._xseen.fields['displacement-map'], +'displacementScale' : e._xseen.fields['displacement-scale'], +'displacementBias' : e._xseen.fields['displacement-bias'], +'envMap' : e._xseen.fields['env-map'], +'normalMap' : e._xseen.fields['normal-map'], +'normalScale' : e._xseen.fields['normal-scale'], +'wireframe' : e._xseen.fields['wireframe'], +'wireframeLinewidth' : e._xseen.fields['wireframe-linewidth'], +}; +var material = new THREE.MeshPhongMaterial(parameters); +return material; +} +xseen.node.af_Box = { +'init' : function (e,p) +{ +var geometry = new THREE.BoxGeometry( +e._xseen.fields.width, +e._xseen.fields.height, +e._xseen.fields.depth, +e._xseen.fields['segments-width'], +e._xseen.fields['segments-height'], +e._xseen.fields['segments-depth'] +); +var appearance = xseen.node.af_Appearance (e); +var mesh = new THREE.Mesh (geometry, appearance); +mesh.userData = e; +p._xseen.sceneInfo.selectable.push(mesh); +var group = new THREE.Group(); +group.add (mesh); +if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} +p._xseen.children.push(group); +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Cone = { +'init' : function (e,p) +{ +var geometry = new THREE.ConeGeometry( +e._xseen.fields.radius, +e._xseen.fields.height, +e._xseen.fields['segments-radial'], +e._xseen.fields['segments-height'], +e._xseen.fields['open-ended'], +e._xseen.fields['theta-start'] * xseen.types.Deg2Rad, +e._xseen.fields['theta-length'] * xseen.types.Deg2Rad +); +var appearance = xseen.node.af_Appearance (e); +var mesh = new THREE.Mesh (geometry, appearance); +mesh.userData = e; +p._xseen.sceneInfo.selectable.push(mesh); +var group = new THREE.Group(); +group.add (mesh); +if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} +p._xseen.children.push(group); +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Cylinder = { +'init' : function (e,p) +{ +var geometry = new THREE.CylinderGeometry( +e._xseen.fields['radius-top'], +e._xseen.fields['radius-bottom'], +e._xseen.fields.height, +e._xseen.fields['segments-radial'], +e._xseen.fields['segments-height'], +e._xseen.fields['open-ended'], +e._xseen.fields['theta-start'] * xseen.types.Deg2Rad, +e._xseen.fields['theta-length'] * xseen.types.Deg2Rad +); +var appearance = xseen.node.af_Appearance (e); +var mesh = new THREE.Mesh (geometry, appearance); +mesh.userData = e; +p._xseen.sceneInfo.selectable.push(mesh); +var group = new THREE.Group(); +group.add (mesh); +if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} +p._xseen.children.push(group); +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Dodecahedron = { +'init' : function (e,p) +{ +var geometry = new THREE.DodecahedronGeometry( +e._xseen.fields.radius, +e._xseen.fields.detail +); +var appearance = xseen.node.af_Appearance (e); +var mesh = new THREE.Mesh (geometry, appearance); +mesh.userData = e; +p._xseen.sceneInfo.selectable.push(mesh); +var group = new THREE.Group(); +group.add (mesh); +if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} +p._xseen.children.push(group); +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Icosahedron = { +'init' : function (e,p) +{ +var geometry = new THREE.IcosahedronGeometry( +e._xseen.fields.radius, +e._xseen.fields.detail +); +var appearance = xseen.node.af_Appearance (e); +var mesh = new THREE.Mesh (geometry, appearance); +mesh.userData = e; +p._xseen.sceneInfo.selectable.push(mesh); +var group = new THREE.Group(); +group.add (mesh); +if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} +p._xseen.children.push(group); +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Octahedron = { +'init' : function (e,p) +{ +var geometry = new THREE.OctahedronGeometry( +e._xseen.fields.radius, +e._xseen.fields.detail +); +var appearance = xseen.node.af_Appearance (e); +var mesh = new THREE.Mesh (geometry, appearance); +mesh.userData = e; +p._xseen.sceneInfo.selectable.push(mesh); +var group = new THREE.Group(); +group.add (mesh); +if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} +p._xseen.children.push(group); +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Sphere = { +'init' : function (e,p) +{ +var geometry = new THREE.SphereGeometry( +e._xseen.fields.radius, +e._xseen.fields['segments-width'], +e._xseen.fields['segments-height'], +e._xseen.fields['phi-start'] * xseen.types.Deg2Rad, +e._xseen.fields['phi-length'] * xseen.types.Deg2Rad, +e._xseen.fields['theta-start'] * xseen.types.Deg2Rad, +e._xseen.fields['theta-length'] * xseen.types.Deg2Rad +); +var appearance = xseen.node.af_Appearance (e); +var mesh = new THREE.Mesh (geometry, appearance); +mesh.userData = e; +p._xseen.sceneInfo.selectable.push(mesh); +var group = new THREE.Group(); +group.add (mesh); +if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} +p._xseen.children.push(group); +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Tetrahedron = { +'init' : function (e,p) +{ +var geometry = new THREE.TetrahedronGeometry( +e._xseen.fields.radius, +e._xseen.fields.detail +); +var appearance = xseen.node.af_Appearance (e); +var mesh = new THREE.Mesh (geometry, appearance); +mesh.userData = e; +p._xseen.sceneInfo.selectable.push(mesh); +var group = new THREE.Group(); +group.add (mesh); +if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} +p._xseen.children.push(group); +}, +'fin' : function (e,p) {} +}; +xseen.node.af_Torus = { +'init' : function (e,p) +{ +var geometry = new THREE.TorusGeometry( +e._xseen.fields.radius, +e._xseen.fields.tube, +e._xseen.fields['segments-radial'], +e._xseen.fields['segments-tubular'], +e._xseen.fields.arc * xseen.types.Deg2Rad +); +var appearance = xseen.node.af_Appearance (e); +var mesh = new THREE.Mesh (geometry, appearance); +mesh.userData = e; +p._xseen.sceneInfo.selectable.push(mesh); +var group = new THREE.Group(); +group.add (mesh); +if (typeof(p._xseen.children) == 'undefined') {p._xseen.children = [];} +p._xseen.children.push(group); +}, +'fin' : function (e,p) {} +}; +xseen.node.unk_Viewpoint = { +'init' : function (e,p) +{ // This should really go in a separate push-down list for Viewpoints +e._xseen.fields._radius0 = Math.sqrt( e._xseen.fields.position[0]*e._xseen.fields.position[0] + +e._xseen.fields.position[1]*e._xseen.fields.position[1] + +e._xseen.fields.position[2]*e._xseen.fields.position[2]); +e._xseen.domNode = e; // Back-link to node if needed later on +e._xseen.position = new THREE.Vector3(e._xseen.fields.position[0], e._xseen.fields.position[1], e._xseen.fields.position[2]); +e._xseen.type = e._xseen.fields.cameratype; +e._xseen.motion = e._xseen.fields.motion; +e._xseen.motionspeed = e._xseen.fields.motionspeed * 1000; +if (e._xseen.motion == 'turntable' || e._xseen.motion == 'tilt') {e._xseen.motionspeed = 1.0/e._xseen.motionspeed;} +if (!e._xseen.sceneInfo.tmp.activeViewpoint) { +e._xseen.sceneInfo.stacks.Viewpoints.pushDown(e._xseen); +e._xseen.sceneInfo.tmp.activeViewpoint = true; +} +e._xseen.handlers = {}; +e._xseen.handlers.setactive = this.setactive; +}, +'fin' : function (e,p) {}, +'setactive' : function (ev) +{ +var xseenNode = this.destination._xseen; +xseenNode.sceneInfo.stacks.Viewpoints.pushDown(xseenNode); // TODO: This is probably not the right way to change VP in the stack +xseenNode.sceneInfo.element._xseen.renderer.activeCamera = +xseenNode.sceneInfo.element._xseen.renderer.cameras[xseenNode.fields.type]; +xseenNode.sceneInfo.element._xseen.renderer.activeRender = +xseenNode.sceneInfo.element._xseen.renderer.renderEffects[xseenNode.fields.type]; +if (xseenNode.fields.type != 'stereo') { +xseenNode.sceneInfo.element._xseen.renderer.activeRender.setViewport( 0, 0, xseenNode.sceneInfo.size.width, this.destination._xseen.sceneInfo.size.height); +} +}, +}; +xseen.node.controls_Navigation = { +'init' : function (e,p) +{ // This should really go in a separate push-down list for Viewpoints +e._xseen.domNode = e; // Back-link to node if needed later on +e._xseen.speed = e._xseen.fields.speed; +if (e._xseen.setup == 'examine') {e._xseen.setup == 'trackball';} +e._xseen.type = 'none'; +e._xseen.setup = e._xseen.fields.type; +if (!(e._xseen.setup == 'orbit' || e._xseen.setup == 'trackball')) {e._xseen.setup = 'none';} +if (!e._xseen.sceneInfo.tmp.activeNavigation) { +e._xseen.sceneInfo.stacks.Navigation.pushDown(e._xseen); +e._xseen.sceneInfo.tmp.activeNavigation = true; +} +e._xseen.handlers = {}; +e._xseen.handlers.setactive = this.setactive; +}, +'fin' : function (e,p) {}, +'setactive' : function (ev) +{ +}, +}; +xseen.node.lighting_Light = { +'init' : function (e,p) +{ +var color = xseen.types.Color3toInt (e._xseen.fields.color); +var intensity = e._xseen.fields.intensity - 0; +var lamp, type=e._xseen.fields.type.toLowerCase(); +if (type == 'point') { +lamp = new THREE.PointLight (color, intensity); +lamp.distance = Math.max(0.0, e._xseen.fields.radius - 0); +lamp.decay = Math.max (.1, e._xseen.fields.attenuation[1]/2 + e._xseen.fields.attenuation[2]); +} else if (type == 'spot') { +lamp = new THREE.SpotLight (color, intensity); +lamp.position.set(0-e._xseen.fields.direction[0], 0-e._xseen.fields.direction[1], 0-e._xseen.fields.direction[2]); +lamp.distance = Math.max(0.0, e._xseen.fields.radius - 0); +lamp.decay = Math.max (.1, e._xseen.fields.attenuation[1]/2 + e._xseen.fields.attenuation[2]); +lamp.angle = Math.max(0.0, Math.min(1.5707963267948966192313216916398, e._xseen.fields.cutoffangle)); +lamp.penumbra = 1 - Math.max(0.0, Math.min(lamp.angle, e._xseen.fields.beamwidth)) / lamp.angle; +} else { // DirectionalLight (by default) +lamp = new THREE.DirectionalLight (color, intensity); +lamp.position.x = 0-e._xseen.fields.direction[0]; +lamp.position.y = 0-e._xseen.fields.direction[1]; +lamp.position.z = 0-e._xseen.fields.direction[2]; +} +p._xseen.children.push(lamp); +lamp = null; +} +, +'fin' : function (e,p) +{ +} +}; +xseen.node.appearance_Material = { +'init' : function (e,p) +{ +var transparency = e._xseen.fields.transparency - 0; +var shininess = e._xseen.fields.shininess - 0; +var colorDiffuse = xseen.types.Color3toInt (e._xseen.fields.diffusecolor); +var colorEmissive = xseen.types.Color3toInt (e._xseen.fields.emissivecolor); +var colorSpecular = xseen.types.Color3toInt (e._xseen.fields.specularcolor); +p._xseen.material = new THREE.MeshPhongMaterial( { +'color' : colorDiffuse, +'emissive' : colorEmissive, +'specular' : colorSpecular, +'shininess' : shininess, +'opacity' : 1.0-transparency, +'transparent' : (transparency > 0.0) ? true : false +} ); +e._xseen.animate['diffusecolor'] = p._xseen.material.color; +e._xseen.animate['emissivecolor'] = p._xseen.material.emissive; +e._xseen.animate['specularcolor'] = p._xseen.material.specular; +e._xseen.animate['transparency'] = p._xseen.material.opacity; +e._xseen.animate['shininess'] = p._xseen.material.shininess; +}, +'fin' : function (e,p) {} +}; +xseen.node.appearance_ImageTexture = { +'init' : function (e,p) +{ +p._xseen.texture = xseen.loader.ImageLoader.load(e._xseen.fields.url); +p._xseen.texture.wrapS = (e._xseen.fields.repeats) ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; +p._xseen.texture.wrapT = (e._xseen.fields.repeatt) ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; +}, +'fin' : function (e,p) {} +}; +xseen.node.appearance_Appearance = { +'init' : function (e,p) {}, +'fin' : function (e,p) +{ +if (typeof(e._xseen.texture) !== 'undefined' && e._xseen.texture !== null) { +e._xseen.material.map = e._xseen.texture; +} +p._xseen.appearance = e._xseen.material; +} +}; +xseen.node.geometry_Coordinate = { +'init' : function (e,p) +{ +var vertices = []; +for (var i=0; i 0) ? true : false; +var useColor = (color.length > 0) ? true : false; +var maxIndex = Math.max.apply(null, indices); +var minIndex = Math.min.apply(null, indices); +if (maxIndex >= vertices.length) { +console.log ('Maximum index ('+maxIndex+') exceeds vertex count ('+vertices.length+'). No geometry is created'); +return; +} +if (useNormals && maxIndex >= normals.length) { +console.log ('Maximum index ('+maxIndex+') exceeds normal count ('+normals.length+'). No geometry is created'); +return; +} +if (useColor && maxIndex >= color.length) { +console.log ('Maximum index ('+maxIndex+') exceeds color count ('+color.length+'). No geometry is created'); +return; +} +if (minIndex < 0) { +console.log ('Minimum index ('+minIndex+') less than zero. No geometry is created'); +return; +} +if (indices.length % 3 != 0) { +console.log ('Number of indices ('+indices.length+') not divisible by 3. No geometry is created'); +return; +} +var geometry = new THREE.Geometry(); +var normal_pz = new THREE.Vector3 (0, 0, 1); +var normal_mz = new THREE.Vector3 (0, 0, -1); +for (var i=0; i 0) {clip.duration = e._xseen.fields.duration;} +e._xseen.mixer.clipAction( clip ).play(); +} ); +} else { // Play a specific animation +var clip = THREE.AnimationClip.findByName(response.animations, e._xseen.fields.playonload); +var action = e._xseen.mixer.clipAction (clip); +action.play(); +} +} +} +} +}; +xseen.node.x_Route = { +'init' : function (e,p) +{ +var dest = e._xseen.fields.destination; +var hand = e._xseen.fields.handler; +var externalHandler = false; +if (e._xseen.fields.source == '' || +typeof(window[hand]) !== 'function' && +(dest == '' || e._xseen.fields.event == '' || e._xseen.fields.field == '')) { +xseen.debug.logError ('Route node missing field. No route setup. Source: '+e._xseen.fields.source+'.'+e._xseen.fields.event+'; Destination: '+dest+'.'+e._xseen.fields.field+'; Handler: '+hand); +return; +} else if (typeof(window[hand]) === 'function') { +externalHandler = true; +} +var eSource = document.getElementById (e._xseen.fields.source); +if (! externalHandler) { +var eDestination = document.getElementById (dest); +if (typeof(eSource) === 'undefined' || typeof(eDestination) === 'undefined') { +xseen.debug.logError ('Source or Destination node does not exist. No route setup'); +return; +} +var fField = xseen.nodes._getFieldInfo (eDestination.nodeName, e._xseen.fields.field); +if (typeof(fField) === 'undefined' || !fField.good) { +xseen.debug.logError ('Destination field does not exist or incorrectly specified. No route setup'); +return; +} +xseen.Events.addHandler (e, eSource, e._xseen.fields.event, eDestination, fField); +} else { +var handler = window[hand]; +eSource.addEventListener ('xseen', handler); +} +}, +'fin' : function (e,p) +{ +}, +'evHandler' : function (u) +{ +var de = u.e; +var df = u.f; +return de._xseen.handlers[df.handlerName]; +}, +}; +xseen.node.core_NOOP = { +'init' : function (e,p) {}, +'fin' : function (e,p) {} +}; +xseen.node.core_WorldInfo = { +'init' : function (e,p) {parsing('WorldInfo', e)}, +'fin' : function (e,p) {} +}; +function parsing (s, e) { +xseen.debug.logInfo ('Parsing init details stub for ' + s); +} +xseen.node.unk_Shape = { +'init' : function (e,p) {}, +'fin' : function (e,p) +{ +if (typeof(e._xseen.materialProperty) !== 'undefined') { +e._xseen.appearance.vertexColors = THREE.VertexColors; +e._xseen.appearance._needsUpdate = true; +e._xseen.appearance.needsUpdate = true; +} +var mesh = new THREE.Mesh (e._xseen.geometry, e._xseen.appearance); +mesh.userData = e; +p._xseen.children.push(mesh); +p._xseen.sceneInfo.selectable.push(mesh); +mesh = null; +} +}; +xseen.node.grouping_Transform = { +'init' : function (e,p) +{ +var group = new THREE.Group(); +if (e.nodeName == "TRANSFORM") { +var rotation = xseen.types.Rotation2Quat(e._xseen.fields.rotation); +group.name = 'Transform children [' + e.id + ']'; +group.position.x = e._xseen.fields.translation[0]; +group.position.y = e._xseen.fields.translation[1]; +group.position.z = e._xseen.fields.translation[2]; +group.scale.x = e._xseen.fields.scale[0]; +group.scale.y = e._xseen.fields.scale[1]; +group.scale.z = e._xseen.fields.scale[2]; +group.quaternion.x = rotation.x; +group.quaternion.y = rotation.y; +group.quaternion.z = rotation.z; +group.quaternion.w = rotation.w; +e._xseen.animate['translation'] = group.position; +e._xseen.animate['rotation'] = group.quaternion; +e._xseen.animate['scale'] = group.scale; +} +e._xseen.sceneNode = group; +}, +'fin' : function (e,p) +{ +e._xseen.children.forEach (function (child, ndx, wholeThing) +{ +e._xseen.sceneNode.add(child); +}); +p._xseen.children.push(e._xseen.sceneNode); +} +}; +xseen.node.networking_Inline = { +'init' : function (e,p) +{ +if (typeof(e._xseen.processedUrl) === 'undefined' || !e._xseen.requestedUrl) { +var uri = xseen.parseUrl (e._xseen.fields.url); +var type = uri.extension; +e._xseen.loadGroup = new THREE.Group(); +e._xseen.loadGroup.name = 'Inline content [' + e.id + ']'; +console.log ('Created Inline Group with UUID ' + e._xseen.loadGroup.uuid); +var userdata = {'requestType':'x3d', 'e':e, 'p':p} +if (type.toLowerCase() == 'json') { +userdata.requestType = 'json'; +xseen.loadMgr.loadJson (e._xseen.fields.url, this.loadSuccess, xseen.loadProgress, xseen.loadError, userdata); +} else { +xseen.loadMgr.loadXml (e._xseen.fields.url, this.loadSuccess, xseen.loadProgress, xseen.loadError, userdata); +} +e._xseen.requestedUrl = true; +} +p._xseen.children.push(e._xseen.loadGroup); +console.log ('Using Inline Group with UUID ' + e._xseen.loadGroup.uuid); +}, +'fin' : function (e,p) +{ +}, +'loadSuccess' : +function (response, userdata, xhr) { +userdata.e._xseen.processedUrl = true; +userdata.e._xseen.loadResponse = response; +console.log("download successful for "+userdata.e.id); +if (userdata.requestType == 'json') { +var tmp = {'scene': response}; +response = null; +response = (new JSONParser()).parseJavaScript(tmp); +} +var start = {'_xseen':0}; +var findSceneTag = function (fragment) { +if (typeof(fragment._xseen) === 'undefined') {fragment._xseen = {'childCount': -1};} +if (fragment.nodeName.toLowerCase() == 'scene') { +start = fragment; +return; +} else if (fragment.children.length > 0) { +for (fragment._xseen.childCount=0; fragment._xseen.childCount 0) { +userdata.e.appendChild(start.children[0]); +} +xseen.Parse(userdata.e, userdata.p, userdata.p._xseen.sceneInfo); +userdata.e._xseen.children.forEach (function (child, ndx, wholeThing) +{ +userdata.e._xseen.loadGroup.add(child); +console.log ('...Adding ' + child.type + ' (' + child.name + ') to Inline Group? with UUID ' + userdata.e._xseen.loadGroup.uuid + ' (' + userdata.e._xseen.loadGroup.name + ')'); +}); +userdata.p._xseen.sceneInfo.scene.updateMatrixWorld(); +} else { +console.log("Found illegal X3D file -- no 'scene' tag"); +} +} +}; +xseen.node.core_Scene = { +'DEFAULT' : { +'Viewpoint' : { +'Position' : new THREE.Vector3 (0, 0, 10), +'Orientation' : '0 1 0 0', // TODO: fix (and below) when handling orientation +'Type' : 'perpsective', +'Motion' : 'none', +'MotionSpeed' : 1.0, +}, +'Navigation' : { +'Speed' : 1.0, // 16 spr (1 revolution per 16 seconds), in mseconds. +'Type' : 'none', +'Setup' : 'none', +} +}, +'init' : function (e,p) +{ +xseen.sceneInfo[0].stacks.Viewpoints.setDefault( +{ +'position' : this.DEFAULT.Viewpoint.Position, +'type' : this.DEFAULT.Viewpoint.Type, +'motion' : this.DEFAULT.Viewpoint.Motion, +'motionspeed': this.DEFAULT.Viewpoint.MotionSpeed / 1000, +'domNode' : e, +'fields' : {}, +} +); +xseen.sceneInfo[0].stacks.Navigation.setDefault( +{ +'speed' : this.DEFAULT.Navigation.Speed / 1000, +'type' : this.DEFAULT.Navigation.Type, +'setup' : this.DEFAULT.Navigation.Setup, +'domNode' : e, +'fields' : {}, +} +); +var width = e._xseen.sceneInfo.size.width; +var height = e._xseen.sceneInfo.size.height; +var x_renderer = new THREE.WebGLRenderer(); +x_renderer.setSize (width, height); +var perspectiveCamera = new THREE.PerspectiveCamera( 75, width / height, 0.1, 1000 ); +var orthoCamera = new THREE.OrthographicCamera( 75, width / height, 0.1, 1000 ); +perspectiveCamera.position.x = this.DEFAULT.Viewpoint.Position.x; // Default position +perspectiveCamera.position.y = this.DEFAULT.Viewpoint.Position.y; // Default position +perspectiveCamera.position.z = this.DEFAULT.Viewpoint.Position.z; // Default position +orthoCamera.position.x = this.DEFAULT.Viewpoint.Position.x; // Default position +orthoCamera.position.y = this.DEFAULT.Viewpoint.Position.y; // Default position +orthoCamera.position.z = this.DEFAULT.Viewpoint.Position.z; // Default position +var x_effect = new THREE.StereoEffect(x_renderer); +e.appendChild (x_renderer.domElement); +e._xseen.renderer = { +'canvas' : e._xseen.sceneInfo.scene, +'width' : width, +'height' : height, +'cameras' : { +'perspective' : perspectiveCamera, +'ortho' : orthoCamera, +'stereo' : perspectiveCamera, +}, // Removed .sceneInfo camera because this node defines the camera +'effects' : x_effect, +'renderEffects' : { +'normal' : x_renderer, +'perspective' : x_renderer, +'ortho' : x_renderer, +'stereo' : x_effect, +}, +'activeRender' : {}, +'activeCamera' : {}, +'controls' : {}, // Used for navigation +}; +e._xseen.renderer.activeRender = e._xseen.renderer.renderEffects.normal; +e._xseen.renderer.activeCamera = e._xseen.renderer.cameras.perspective; +}, +'fin' : function (e,p) +{ +e._xseen.children.forEach (function (child, ndx, wholeThing) +{ +console.log('Adding child of type ' + child.type + ' (' + child.name + ')'); +e._xseen.renderer.canvas.add(child); +}); +xseen.dumpSceneGraph (); +var vp = xseen.sceneInfo[0].stacks.Viewpoints.getActive(); +var nav = xseen.sceneInfo[0].stacks.Navigation.getActive(); +var currentCamera = e._xseen.renderer.activeCamera; +var currentRenderer = e._xseen.renderer.activeRender; +currentCamera.position.x = vp.position.x; +currentCamera.position.y = vp.position.y; +currentCamera.position.z = vp.position.z; +e._xseen.renderer.controls = xseen.Navigation.setup[nav.setup] (currentCamera, currentRenderer); +xseen.debug.logInfo("Ready to kick off rendering loop"); +xseen.renderFrame(); +}, +}; +xseen.node.env_Background = { +'init' : function (e,p) +{ +var color = new THREE.Color(e._xseen.fields.skycolor[0], e._xseen.fields.skycolor[1], e._xseen.fields.skycolor[2]); +var textureCube = new THREE.CubeTextureLoader() +.load ([e._xseen.fields.srcright, +e._xseen.fields.srcleft, +e._xseen.fields.srctop, +e._xseen.fields.srcbottom, +e._xseen.fields.srcfront, +e._xseen.fields.srcback], +this.loadSuccess({'e':e, 'p':p}) +); +e._xseen.sceneInfo.scene.background = color; +}, +'fin' : function (e,p) +{ +p._xseen.appearance = e._xseen.material; +}, +'loadSuccess' : function (userdata) +{ +var e = userdata.e; +var p = userdata.p; +return function (textureCube) +{ +e._xseen.processedUrl = true; +e._xseen.loadTexture = textureCube; +e._xseen.sceneInfo.scene.background = textureCube; +} +}, +}; +xseen.node.x_Animate = { +'init' : function (e,p) +{ +var delay = e._xseen.fields.delay * 1000; // Convert to milliseconds +var duration = e._xseen.fields.duration * 1000; // Convert to milliseconds +var repeat = (e._xseen.fields.repeat < 0) ? Infinity : e._xseen.fields.repeat; +var interpolator = e._xseen.fields.interpolator; +var easing = e._xseen.fields.easing; +var fields = xseen.parseTable[p.localName.toLowerCase()].fields; +var fieldIndex = xseen.parseTable[p.localName.toLowerCase()].fieldIndex; +var toField = e._xseen.fields.field; +var toFieldIndex = fieldIndex[toField]; +if (typeof(fields[toFieldIndex]) === 'undefined') { +xseen.debug.logInfo("Field '" + toField + "' not found in parent (" + p.localName.toLowerCase() + "). No animation performed."); +return; +} +var fieldObject = fields[toFieldIndex].clone().setFieldName('to'); // Parse table entry for 'toField' +var to = xseen.nodes._parseField(fieldObject, e); // Parsed data -- need to convert to THREE format +var interpolation; +if (fieldObject.type == 'SFVec3f') { +interpolation = TWEEN.Interpolation.Linear; +to = xseen.types.Vector3(to); +xseen.debug.logInfo("Interpolating field '" + toField + "' as 3-space."); +} else if (fieldObject.type == 'SFColor') { +interpolation = this.Interpolator.color; +to = new THREE.Color (xseen.types.Color3toInt(to)); +xseen.debug.logInfo("Interpolation field '" + toField + "' as color."); +} else if (fieldObject.type == 'SFRotation') { +interpolation = this.Interpolator.slerp; +to = xseen.types.Rotation2Quat(to); +xseen.debug.logInfo("Interpolation field '" + toField + "' as rotation."); +} else { +xseen.debug.logInfo("Field '" + toField + "' not converted to THREE format. No animation performed."); +return; +} +var fieldTHREE = p._xseen.animate[toField]; // THREE field for animation +var tween = new TWEEN.Tween(fieldTHREE) +.to(to, duration) +.delay(delay) +.repeat(repeat) +.interpolation(interpolation); +var easingType = e._xseen.fields.easingtype; +easingType = easingType.charAt(0).toUpperCase() + easingType.slice(1); +easing = (easingType != 'Linear' && easing == '') ? 'inout' : easing; +if (easing != '') { +easing = easing.replace('in', 'In').replace('out', 'Out'); +easingType = (easingType == 'Linear') ? 'Quadratic' : easingType; +e._xseen.fields.easing = easing; +e._xseen.fields.easingtype = easingType; +tween.easing(TWEEN.Easing[easingType][easing]); +} +e._xseen.initialValue = fieldTHREE.clone(); +e._xseen.animatingField = fieldTHREE; +e._xseen.handlers = {}; +e._xseen.handlers.setstart = this.setstart; +e._xseen.handlers.setstop = this.setstop; +e._xseen.handlers.setpause = this.setpause; +e._xseen.handlers.setresetstart = this.setresetstart; +e._xseen.animating = tween; +p._xseen.animation.push (tween); +tween.start(); +}, +'fin' : function (e,p) {}, +'setstart' : function (ev) +{ +console.log ('Starting animation'); +this.destination._xseen.animating.start(); +}, +'setstop' : function (ev) +{ +console.log ('Stopping animation'); +this.destination._xseen.animating.stop(); +}, +'setpause' : function (ev) +{ +console.log ('Pausing (really stopping) animation'); +this.destination._xseen.animating.stop(); +}, +'setresetstart' : function (ev) // TODO: Create seperate 'reset' method +{ +console.log ('Reset and start animation'); +this.destination._xseen.animatingField = this.destination._xseen.initialValue; +this.destination._xseen.animating.start(); +}, +'Interpolator' : { +'slerp' : function (v,k) +{ +var m = v.length - 1; +var f = m * k; +var i = Math.floor(f); +if (k < 0) { +return v[0].slerp(v[1], f); +} +if (k > 1) { +return v[m].slerp(v[m-1], m-f); +} +return v[i].slerp (v[i + 1 > m ? m : i + 1], f-i); +}, +'color' : function (v,k) +{ +var m = v.length - 1; +var f = m * k; +var i = Math.floor(f); +var fn = this.slerpCompute; +if (k < 0) { +return v[0].lerp(v[1], f); +} +if (k > 1) { +return v[m].lerp(v[m-1], m-f); +} +return v[i].lerp (v[i + 1 > m ? m : i + 1], f - i); +}, +}, +}; +xseen._addAframeAppearance = function (node) { +node +.addField('ambient-occlusion-map', 'SFString', '') +.addField('ambient-occlusion-map-intensity', 'SFFloat', 1) +.addField('ambient-occlusion-texture-offset', 'SFVec2f', '0 0') +.addField('ambient-occlusion-texture-repeat', 'SFVec2f', '1 1') +.addField('color', 'Color', '#FFF') +.addField('displacement-bias', 'SFFloat', 0.5) +.addField('displacement-map', 'SFString', '') +.addField('displacement-scale', 'SFFloat', 1) +.addField('displacement-texture-offset', 'SFVec2f', '0 0') +.addField('displacement-texture-repeat', 'SFVec2f', '1 1') +.addField('env-map', 'SFString', '') +.addField('fog', 'SFBool', true) +.addField('metalness', 'SFFloat', 0) +.addField('normal-map', 'SFString', '') +.addField('normal-scale', 'SFVec2f', '1 1') +.addField('normal-texture-offset', 'SFVec2f', '0 0') +.addField('normal-texture-repeat', 'SFVec2f', '1 1') +.addField('repeat', 'SFVec2f', '1 1') +.addField('roughness', 'SFFloat', 0.5) +.addField('spherical-env-map', 'SFString', '') +.addField('src', 'SFString', '') +.addField('wireframe', 'SFBool', false) +.addField('wireframe-linewidth', 'SFInt', 2) +.addNode(); +} +xseen.nodes._defineNode('a-entity', 'A-Frame', 'af_Entity') +.addField('geometry', 'SFString', '') +.addField('material', 'SFString', '') +.addField('light', 'SFString', '') +.addNode(); +var node; +node = xseen.nodes._defineNode('a-box', 'A-Frame', 'af_Box') +.addField('depth', 'SFFloat', 1) +.addField('height', 'SFFloat', 1) +.addField('width', 'SFFloat', 512) +.addField('segments-depth', 'SFInt', 1) +.addField('segments-height', 'SFInt', 1) +.addField('segments-width', 'SFInt', 1); +xseen._addAframeAppearance (node); +node = xseen.nodes._defineNode('a-cone', 'A-Frame', 'af_Cone') +.addField('height', 'SFFloat', 1) +.addField('radius', 'SFFloat', 1) +.addField('open-ended', 'SFBool', false) +.addField('theta-start', 'SFFloat', 0) +.addField('theta-length', 'SFFloat', 360) +.addField('segments-height', 'SFInt', 1) +.addField('segments-radial', 'SFInt', 8); +xseen._addAframeAppearance (node); +node = xseen.nodes._defineNode('a-cylinder', 'A-Frame', 'af_Cylinder') +.addField('height', 'SFFloat', 1) +.addField('open-ended', 'SFBool', false) +.addField('radius-bottom', 'SFFloat', 1) +.addField('radius-top', 'SFFloat', 1) +.addField('theta-start', 'SFFloat', 0) +.addField('theta-length', 'SFFloat', 360) +.addField('segments-height', 'SFInt', 1) +.addField('segments-radial', 'SFInt', 8); +xseen._addAframeAppearance (node); +node = xseen.nodes._defineNode('a-dodecahedron', 'A-Frame', 'af_Dodecahedron') +.addField('radius', 'SFFloat', 1) +.addField('detail', 'SFFloat', 0); +xseen._addAframeAppearance (node); +node = xseen.nodes._defineNode('a-icosahedron', 'A-Frame', 'af_Icosahedron') +.addField('radius', 'SFFloat', 1) +.addField('detail', 'SFFloat', 0); +xseen._addAframeAppearance (node); +node = xseen.nodes._defineNode('a-octahedron', 'A-Frame', 'af_Octahedron') +.addField('radius', 'SFFloat', 1) +.addField('detail', 'SFFloat', 0); +xseen._addAframeAppearance (node); +node = xseen.nodes._defineNode('a-sphere', 'A-Frame', 'af_Sphere') +.addField('radius', 'SFFloat', 1) +.addField('theta-start', 'SFFloat', 0) +.addField('theta-length', 'SFFloat', 180) +.addField('phi-start', 'SFFloat', 0) +.addField('phi-length', 'SFFloat', 360) +.addField('segments-height', 'SFInt', 18) +.addField('segments-width', 'SFInt', 36); +xseen._addAframeAppearance (node); +node = xseen.nodes._defineNode('a-tetrahedron', 'A-Frame', 'af_Tetrahedron') +.addField('radius', 'SFFloat', 1) +.addField('detail', 'SFFloat', 0); +xseen._addAframeAppearance (node); +node = xseen.nodes._defineNode('a-torus', 'A-Frame', 'af_Torus') +.addField('radius', 'SFFloat', 2) +.addField('tube', 'SFFloat', 1) +.addField('arc', 'SFFloat', 360) +.addField('segments-radial', 'SFInt', 8) +.addField('segments-tubular', 'SFInt', 6); +xseen._addAframeAppearance (node); +xseen.nodes._defineNode('a-assets', 'A-Frame', 'af_Assets') +.addNode(); +xseen.nodes._defineNode('a-asset-item', 'A-Frame', 'af_AssetItem') +.addField('src', 'SFString', '') +.addNode(); +xseen.nodes._defineNode('a-mixin', 'A-Frame', 'af_Mixin') +.addField('*', 'SFString', '') +.addNode(); +xseen.nodes._defineNode('Cone', 'Geometry3D', 'geometry3D_Cone') +.addField('bottomRadius', 'SFFloat', 1) +.addField('height', 'SFFloat', 2) +.addField('bottom', 'SFBool', true) +.addField('side', 'SFBool', true) +.addNode(); +xseen.nodes._defineNode('Box', 'Geometry3D', 'geometry3D_Box') +.addField('size', 'SFVec3f', [1,1,1]) +.addNode(); +xseen.nodes._defineNode('Sphere', 'Geometry3D', 'geometry3D_Sphere') +.addField('radius', 'SFFloat', '1') +.addNode(); +xseen.nodes._defineNode('Cylinder', 'Geometry3D', 'geometry3D_Cylinder') +.addField('radius', 'SFFloat', 1) +.addField('height', 'SFFloat', 2) +.addField('bottom', 'SFBool', true) +.addField('side', 'SFBool', true) +.addField('top', 'SFBool', true) +.addNode(); +xseen.nodes._defineNode ('Material', 'Appearance', 'appearance_Material') +.addField({name:'diffuseColor', datatype:'SFColor', defaultValue:[.8,.8,.8], animatable:true}) +.addField({name:'emissiveColor',datatype: 'SFColor', defaultValue:[0,0,0], animatable:true}) +.addField({name:'specularColor', datatype:'SFColor', defaultValue:[0,0,0], animatable:true}) +.addField({name:'transparency', datatype:'SFFloat', defaultValue:'0', animatable:true}) +.addField({name:'shininess', datatype:'SFFloat', defaultValue:'0', animatable:true}) +.addNode(); +xseen.nodes._defineNode ('Transform', 'Grouping', 'grouping_Transform') +.addField({name:'translation', datatype:'SFVec3f', defaultValue:[0,0,0], animatable:true}) +.addField({name:'scale', datatype:'SFVec3f', defaultValue:[1,1,1], animatable:true}) +.addField({name:'rotation', datatype:'SFRotation', defaultValue:xseen.types.SFRotation('0 1 0 0',''), animatable:true}) +.addNode(); +xseen.nodes._defineNode ('Group', 'Grouping', 'grouping_Transform') +.addNode(); +xseen.nodes._defineNode ('Light', 'Lighting', 'lighting_Light') +.addField('direction', 'SFVec3f', [0,0,-1]) // DirectionalLight +.addField('location', 'SFVec3f', [0,0,0]) // PointLight & SpotLight +.addField('radius', 'SFFloat', '100') // PointLight & SpotLight +.addField('attenuation', 'SFVec3f', [1,0,0]) // PointLight & SpotLight +.addField('beamWidth', 'SFFloat', '0.78539816339744830961566084581988') // SpotLight +.addField('cutOffAngle', 'SFFloat', '1.5707963267948966192313216916398') // SpotLight +.addField('color', 'SFColor', [1,1,1]) // General +.addField('intensity', 'SFFloat', '1') // General +.addField({name:'type', datatype:'EnumerateString', defaultValue:'Directional', enumerated:['Directional', 'Spot', 'Point'], animatable:true}) +.addNode(); +xseen.nodes._defineNode ('DirectionalLight', 'Lighting', 'lighting_Light') +.addField('direction', 'SFVec3f', [0,0,-1]) +.addField('color', 'SFColor', [1,1,1]) +.addField('intensity', 'SFFloat', '1') +.addField('type', 'SFString', 'Directional') +.addNode(); +xseen.nodes._defineNode ('PointLight', 'Lighting', 'lighting_Light') +.addField('location', 'SFVec3f', [0,0,0]) +.addField('radius', 'SFFloat', '100') +.addField('attenuation', 'SFVec3f', [1,0,0]) +.addField('color', 'SFColor', [1,1,1]) +.addField('intensity', 'SFFloat', '1') +.addField('type', 'SFString', 'Point') +.addNode(); +xseen.nodes._defineNode ('SpotLight', 'Lighting', 'lighting_Light') +.addField('direction', 'SFVec3f', [0,0,-1]) +.addField('radius', 'SFFloat', '100') +.addField('attenuation', 'SFVec3f', [1,0,0]) +.addField('beamWidth', 'SFFloat', '0.78539816339744830961566084581988') // pi/4 +.addField('cutOffAngle', 'SFFloat', '1.5707963267948966192313216916398') // pi/2 +.addField('color', 'SFColor', [1,1,1]) +.addField('intensity', 'SFFloat', '1') +.addField('type', 'SFString', 'Spot') +.addNode(); +xseen.nodes._defineNode ('Viewpoint', 'Controls', 'unk_Viewpoint') +.addField('position', 'SFVec3f', '0 0 10') +.addField('orientation', 'SFRotation', xseen.types.SFRotation('0 1 0 0','')) +.addField('description', 'SFString', '') +.addField({name:'cameratype', datatype:'EnumerateString', defaultValue:'perspective', enumerated:['perspective', 'stereo', 'orthographic'], animatable:false}) +.addField({name:'type', datatype:'EnumerateString', defaultValue:'perspective', enumerated:['perspective', 'stereo', 'orthographic'], animatable:false}) +.addField({name:'motion', datatype:'EnumerateString', defaultValue:'none', enumerated:['none', 'turntable', 'tilt'], animatable:false}) +.addField('motionspeed', 'SFFloat', 16) +.addField('active', 'SFBool', true) // incoming event +.addNode(); +xseen.nodes._defineNode ('NavigationMode', 'Controls', 'controls_Navigation') +.addField('speed', 'SFFloat', 1.) +.addField({name:'type', datatype:'EnumerateString', defaultValue:'none', enumerated:['none', 'orbit', 'fly', 'examine', 'trackball'], animatable:false}) +.addNode(); +xseen.nodes._defineNode ('Camera', 'Controls', 'unk_Viewpoint') +.addField('position', 'SFVec3f', [0,0,10]) +.addField('orientation', 'SFRotation', xseen.types.SFRotation('0 1 0 0','')) +.addNode(); +xseen.nodes._defineNode ('Inline', 'Networking', 'networking_Inline') +.addField('url', 'SFString', '') +.addNode(); +xseen.nodes._defineNode ('scene', 'Core', 'core_Scene') +.addNode(); +xseen.nodes._defineNode ('canvas', 'Core', 'core_NOOP') +.addNode(); +xseen.nodes._defineNode ('WorldInfo', 'Core', 'core_WorldInfo') +.addNode(); +xseen.nodes._defineNode ('Appearance', 'Appearance', 'appearance_Appearance') +.addNode(); +xseen.nodes._defineNode ('ImageTexture', 'Appearance', 'appearance_ImageTexture') +.addField('url', 'SFString', '') +.addField('repeatS', 'SFBool', true) +.addField('repeatT', 'SFBool', true) +.addNode(); +xseen.nodes._defineNode ('Shape', 'Shape', 'unk_Shape') +.addNode(); +xseen.nodes._defineNode('Background', 'Environmental', 'env_Background') +.addField('skyColor', 'SFColor', [0,0,0]) +.addField('srcFront', 'SFString', '') +.addField('srcBack', 'SFString', '') +.addField('srcTop', 'SFString', '') +.addField('srcBottom', 'SFString', '') +.addField('srcLeft', 'SFString', '') +.addField('srcRight', 'SFString', '') +.addField('backgroundIsCube', 'SFBool', 'true') +.addNode(); +xseen.nodes._defineNode('TriangleSet', 'Geometry', 'geometry_TriangleSet') +.addField('ccw', 'SFBool', 'true') +.addField('colorPerVertex', 'SFBool', 'true') +.addField('solid', 'SFBool', 'true') +.addNode(); +xseen.nodes._defineNode('IndexedTriangleSet', 'Geometry', 'geometry_IndexedTriangleSet') +.addField('ccw', 'SFBool', true) +.addField('colorPerVertex', 'SFBool', true) +.addField('solid', 'SFBool', true) +.addField('index', 'MFInt', '') +.addNode(); +xseen.nodes._defineNode('Coordinate', 'Geometry', 'geometry_Coordinate') +.addField('point', 'MFVec3f', []) +.addNode(); +xseen.nodes._defineNode('Normal', 'Geometry', 'geometry_Normal') +.addField('vector', 'MFVec3f', []) +.addNode(); +xseen.nodes._defineNode('Color', 'Geometry', 'geometry_Color') +.addField('color', 'MFColor', []) +.addNode(); +xseen.nodes._defineNode('IndexedFaceSet', 'Geometry', 'geometry_IndexedFaceSet') +.addField('ccw', 'SFBool', true) +.addField('colorPerVertex', 'SFBool', true) +.addField('solid', 'SFBool', true) +.addField('coordIndex', 'MFInt', '') +.addNode(); +xseen.nodes._defineNode('IndexedQuadSet', 'Geometry', 'geometry_IndexedQuadSet') +.addField('ccw', 'SFBool', true) +.addField('colorPerVertex', 'SFBool', true) +.addField('solid', 'SFBool', true) +.addField('index', 'MFInt', '') +.addNode(); +xseen.nodes._defineNode('QuadSet', 'Geometry', 'geometry_QuadSet') +.addField('ccw', 'SFBool', true) +.addField('colorPerVertex', 'SFBool', true) +.addField('solid', 'SFBool', true) +.addNode(); +xseen.nodes._defineNode('model', 'XSeen', 'x_Model') +.addField('src', 'SFString', '') +.addField('playonload', 'SFString', '') +.addField('duration', 'SFFloat', '-1') +.addNode(); +xseen.nodes._defineNode('animate', 'XSeen', 'x_Animate') +.addField('field', 'SFString', '') +.addField('to', 'MFFloat', '') // Needs to be 'field' datatype. That is not known until node-parse. For now insist on numeric array +.addField('delay', 'SFTime', 0) +.addField('duration', 'SFTime', 0) +.addField('repeat', 'SFInt', 0) +.addField({name:'interpolator', datatype:'EnumerateString', defaultValue:'position', enumerated:['position', 'rotation', 'color'], animatable:false}) +.addField({name:'Easing', datatype:'EnumerateString', defaultValue:'', enumerated:['', 'in', 'out', 'inout'], animatable:false}) +.addField({name:'EasingType', datatype:'EnumerateString', defaultValue:'linear', enumerated:['linear', 'quadratic', 'sinusoidal', 'exponential', 'elastic', 'bounce'], animatable:false}) +.addField('start', 'SFBool', true) // incoming event, need to set timer trigger +.addField('stop', 'SFBool', true) // incoming event, need to set timer trigger +.addField('resetstart', 'SFBool', true) // incoming event, need to set timer trigger +.addField('pause', 'SFBool', true) // incoming event, need to set timer trigger +.addNode(); +xseen.nodes._defineNode('route', 'XSeen', 'x_Route') +.addField('source', 'SFString', '') +.addField('event', 'SFString', '') +.addField('destination', 'SFString', '') +.addField('field', 'SFString', '') +.addField('handler', 'SFString', '') +.addNode(); \ No newline at end of file diff --git a/Release/XSeen.js b/Release/XSeen.js index ea0ebaa..a8cc914 100644 --- a/Release/XSeen.js +++ b/Release/XSeen.js @@ -1,6 +1,6 @@ /* - * XSeen V0.4.4+21_7f7c55e - * Built Mon Jul 10 19:58:37 2017 + * XSeen V0.4.5+23_75edebb + * Built Mon Jul 10 20:41:35 2017 * Dual licensed under the MIT and GPL licenses. @@ -739,6 +739,7 @@ xseen.rerouteSetAttribute = function(node, browser) { // Stereo camera effect // from http://charliegerard.github.io/blog/Virtual-Reality-ThreeJs/ var x_effect = new THREE.StereoEffect(x_renderer); + x_renderer.controls = {'update' : function() {return;}}; /* * Add event handler to XSeen tag (x_element) @@ -833,34 +834,8 @@ xseen.rerouteSetAttribute = function(node, browser) { xseen.updateCamera (xseen.sceneInfo[0]); var renderObj = xseen.sceneInfo[0].element._xseen.renderer; - renderObj.controls.update(); + if (renderObj.controls !== null) {renderObj.controls.update();} -/* - * Existing code moved to updateAnimation & updateCamera to better handle navigation - * - var deltaT, radians, x, y, z, P, radius, vp; - var nodeAframe = document.getElementById ('aframe_nodes'); - P = 16000; - deltaT = xseen.sceneInfo[0].clock.getDelta(); - for (var i=0; iDocumentation."]; /* * All X3D and A-Frame pre-defined solids, fixed camera, directional light, Material texture only, glTF model loader with animations, Assets and reuse, Viewpoint, Background, Lighting, Image Texture, [Indexed]TriangleSet, IndexedFaceSet, [Indexed]QuadSet
\nNext work
  • Event Model/Animation
  • Extrusion
  • Navigation
", @@ -2162,9 +2137,11 @@ xseen.generateVersion = function () { * V0.4.2+17 Feature -- XSeen internals events (from XSeen to XSeen) with changes to fix previous event handling * V0.4.2+18 Feature -- Split screen VR display * V0.4.3+19 Rebuild and fix loading caused by new Stereo library - * V0.4.3+20 Feature -- Navigation (rotate), including Stack update for Viewpoint and restructuring the rendering loop + * V0.4.3+20 Feature -- Navigation (orbit), including Stack update for Viewpoint and restructuring the rendering loop * V0.4.3+21 Feature -- Changed handling of Viewpoint to include camera motion * V0.4.4+22 Fix -- Internal event handling in passing on events of the proper type + * V0.4.5+23 Feature -- Navigation (trackball) + * V0.4.5+24 Fix -- when there is no navigation * * In progress */ @@ -3187,13 +3164,13 @@ xseen.node.x_Route = { // For toNode routing, check existence of source and destination elements var eSource = document.getElementById (e._xseen.fields.source); if (! externalHandler) { - eDestination = document.getElementById (dest); + var eDestination = document.getElementById (dest); if (typeof(eSource) === 'undefined' || typeof(eDestination) === 'undefined') { xseen.debug.logError ('Source or Destination node does not exist. No route setup'); return; } // Get field information -- perhaps there is some use in the Animate node? - fField = xseen.nodes._getFieldInfo (eDestination.nodeName, e._xseen.fields.field); + var fField = xseen.nodes._getFieldInfo (eDestination.nodeName, e._xseen.fields.field); if (typeof(fField) === 'undefined' || !fField.good) { xseen.debug.logError ('Destination field does not exist or incorrectly specified. No route setup'); return; diff --git a/Release/XSeen.min.js b/Release/XSeen.min.js index 5355ab7..24ce2f2 100644 --- a/Release/XSeen.min.js +++ b/Release/XSeen.min.js @@ -1,6 +1,6 @@ /* - * XSeen V0.4.4+21_7f7c55e - * Built Mon Jul 10 19:58:37 2017 + * XSeen V0.4.5+23_75edebb + * Built Mon Jul 10 20:41:35 2017 * Dual licensed under the MIT and GPL licenses. @@ -514,6 +514,7 @@ var x_camera = {}; var x_renderer = new THREE.WebGLRenderer(); x_renderer.setSize (divWidth, divHeight); var x_effect = new THREE.StereoEffect(x_renderer); +x_renderer.controls = {'update' : function() {return;}}; x_element.addEventListener ('dblclick', xseen.Events.canvasHandler, true); x_element.addEventListener ('click', xseen.Events.canvasHandler, true); x_element.addEventListener ('mousedown', xseen.Events.canvasHandler, true); @@ -573,7 +574,7 @@ TWEEN.update(); xseen.updateAnimation (xseen.sceneInfo[0]); xseen.updateCamera (xseen.sceneInfo[0]); var renderObj = xseen.sceneInfo[0].element._xseen.renderer; -renderObj.controls.update(); +if (renderObj.controls !== null) {renderObj.controls.update();} var activeRender = renderObj.activeRender; var currentCamera = renderObj.activeCamera; activeRender.render (xseen.sceneInfo[0].scene, currentCamera); @@ -1410,11 +1411,11 @@ xseen.generateVersion = function () { var Major, Minor, Patch, PreRelease, Release, Version, RDate, SplashText; Major = 0; Minor = 4; -Patch = 4; +Patch = 5; PreRelease = ''; -Release = 21; +Release = 23; Version = ''; -RDate = '2017-07-09'; +RDate = '2017-07-10'; SplashText = ["XSeen 3D Language parser.", "XSeen Documentation."]; var version = { major : Major, @@ -2148,12 +2149,12 @@ externalHandler = true; } var eSource = document.getElementById (e._xseen.fields.source); if (! externalHandler) { -eDestination = document.getElementById (dest); +var eDestination = document.getElementById (dest); if (typeof(eSource) === 'undefined' || typeof(eDestination) === 'undefined') { xseen.debug.logError ('Source or Destination node does not exist. No route setup'); return; } -fField = xseen.nodes._getFieldInfo (eDestination.nodeName, e._xseen.fields.field); +var fField = xseen.nodes._getFieldInfo (eDestination.nodeName, e._xseen.fields.field); if (typeof(fField) === 'undefined' || !fField.good) { xseen.debug.logError ('Destination field does not exist or incorrectly specified. No route setup'); return; diff --git a/test/StereoNormals.html b/test/StereoNormals.html index 5cf1d89..848f683 100644 --- a/test/StereoNormals.html +++ b/test/StereoNormals.html @@ -59,20 +59,15 @@ canvas { width: 67%; height: 67% } #xscene {width:800px; height:450px; border:1px red dashed; } - - - - + - - - - + +