diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/samples/vrml/viewer-webgl.js | 1167 | ||||
-rw-r--r-- | apps/samples/vrml/viewer.html | 17 | ||||
-rw-r--r-- | apps/samples/vrml/vrml-server.caching.scxml (renamed from apps/samples/vrml/vrml-server.scxml.old) | 0 | ||||
-rw-r--r-- | apps/samples/vrml/vrml-server.pre-osgjs.scxml | 333 | ||||
-rw-r--r-- | apps/samples/vrml/vrml-server.scxml | 32 |
5 files changed, 1529 insertions, 20 deletions
diff --git a/apps/samples/vrml/viewer-webgl.js b/apps/samples/vrml/viewer-webgl.js new file mode 100644 index 0000000..5f8a4e8 --- /dev/null +++ b/apps/samples/vrml/viewer-webgl.js @@ -0,0 +1,1167 @@ +function VRMLViewer(element, params) { + + // private attributes + var self = this; + var batchChanges = false; + var webGLManipulatorsSetup = false; + + // private instanceId + if (!VRMLViewer.instances) + VRMLViewer.instances = 0; + this.instanceId = VRMLViewer.instances++; + + // public attribute defaults + this.width = 450; + this.height = 350; + + { + var pose = { + pitch: 0, + roll: 0, + yaw: 0, + zoom: 1, + x: 0, + y: 0, + z: 0, + width: this.width, + height: this.height, + autorotate: false, + } + this.pose = pose; + } + + this.enableMovies = true; + this.enableDND = true; + this.enableWebGL = false; + this.enableSceneshots = true; + this.enableDraggables = true; + this.treeNavigationStyle = true; + this.listNavigationStyle = true; + this.listDirectory = ""; + + this.serverURL = "localhost:8080"; + this.imagePath = ""; + this.imageFormat = ".png"; + this.resRoot = ""; + + // copy over values from constructor arguments + if (params) { + for (var param in params) { + if (self.hasOwnProperty(param)) { + self[param] = params[param]; + } else { + console.log("Unknown paramter " + param); + } + } + } + + // normalize parameters + var normalizeParams = function() { + // make sure server url begins with protocol and does *not* ends in / + if (!self.serverURL.substring(0, 7) == "http://" && + !self.serverURL.substring(0, 8) == "https://") + self.serverURL = "http://" + self.serverURL; + if (!self.serverURL.lastIndexOf("/") === self.serverURL.length) + self.serverURL += self.serverURL.substring(0, self.serverURL - 1); + + // make sure we have a listDirectory with navigation style list ending in / + if (self.modelNavigationStyle === "list" && !self.listDirectory && self.imagePath) + self.listDirectory = self.imagePath.substring(0, self.imagePath.lastIndexOf("/")); + if (!self.listDirectory.indexOf("/", self.listDirectory.length - 1) !== -1) + self.listDirectory += "/"; + + // use latest image if none given + if (!self.imagePath) + self.imagePath = self.listDirectory + "latest"; + + if (!self.imageFormat.substring(0, 1) != ".") + self.imageFormat = "." + self.imageFormat; + } + normalizeParams(); + + var getWebGLModel = function(url) { + var defer = osgDB.Promise.defer(); + var node = new osg.MatrixTransform(); + //node.setMatrix(osg.Matrix.makeRotate(-Math.PI/2, 1,0,0, [])); + var loadModel = function(url) { + osg.log("loading " + url); + var req = new XMLHttpRequest(); + req.open('GET', url, true); + req.onreadystatechange = function(aEvt) { + if (req.readyState == 4) { + if(req.status == 200) { + osgDB.Promise.when(osgDB.parseSceneGraph(JSON.parse(req.responseText))).then(function(child) { + node.setMatrix(osg.Matrix.makeRotate(Math.PI/2.0, 1,0,0,[])); + node.addChild(child); + defer.resolve(node); + osg.log("success " + url); + }); + } else { + osg.log("error " + url); + } + } + }; + req.send(null); + }; + loadModel(url); + return defer.promise; + } + + var urlSuffixForPose = function(pose) { + var queryString = + '?width=' + pose.width + + '&height=' + pose.height + + '&pitch=' + pose.pitch + + '&roll=' + pose.roll + + '&yaw=' + pose.yaw + + '&x=' + pose.x + + '&y=' + pose.y + + '&z=' + pose.z + + '&zoom=' + pose.zoom + + '&autorotate=' + (pose.autorotate ? '1' : '0'); + return queryString; + }; + + var moverRelativeTo = function(mover, container) { + var containerPos = absolutePosition(container); + return { + x: mover.x - containerPos.x, + y: mover.y - containerPos.y + }; + }; + + // see http://stackoverflow.com/questions/288699/get-the-position-of-a-div-span-tag + var absolutePosition = function(el) { + for (var lx=0, ly=0; el != null; lx += el.offsetLeft, ly += el.offsetTop, el = el.offsetParent); + return {x: lx,y: ly}; + }; + + // update the scene + this.updateScene = function() { + if (self.serverURL && self.imagePath && !self.batchChanges) { + console.log(self.serverURL + self.imagePath + self.imageFormat + urlSuffixForPose(self.pose)); + if (self.enableWebGL) { + osgDB.Promise.when(getWebGLModel(self.serverURL + self.imagePath + '.osgjs')).then(function(model) { + self.webGLViewer.setSceneData(model); + if (!webGLManipulatorsSetup) { + self.webGLViewer.setupManipulator(); + self.webGLViewer.getManipulator().computeHomePosition(); + } + webGLManipulatorsSetup = true; + }); + } + if (self.enableSceneshots) { + self.imgElem.src = self.serverURL + self.imagePath + self.imageFormat + urlSuffixForPose(self.pose); + if (self.enableMovies) { + // we are showing an image, activate movie controls + self.movieAddButton.domNode.style.display = ""; + self.movieDropDown.domNode.style.display = ""; + } + } + } + }; + + // get list of supported ffmpeg codecs from server + this.populateMovieCodecs = function(server, selectElem) { + self.xhr.get({ + // The URL to request + url: server, + handleAs:"json", + headers:{"X-Requested-With":null}, + load: function(result) { + for (var codec in result.video) { + if (codec !== "mpeg1video" && + codec !== "mpeg2video" && + codec !== "mpeg4" && + codec !== "h264" && + codec !== "ayuv" && + codec !== "flashsv" && + codec !== "flashsv2" && + codec !== "flv" && + codec !== "rv40" && + codec !== "theora" && + codec !== "v210" && + codec !== "v308" && + codec !== "v408" && + codec !== "v410" && + codec !== "wmv3" && + codec !== "y41p" && + codec !== "yuv4") + continue; + //console.log(codec); + selectElem.options.push({ label: result.video[codec].longName, value: codec }); + if (codec === "mpeg4") + selectElem.options[selectElem.options.length - 1].selected = true; + } + } + }); + } + + // update list of vrml files from server + this.refreshServer = function(server, params) { + self.serverURL = server; + if (!params) + params = {}; + if (self.fileStandby) { self.fileStandby.show(); } + + self.xhr.get({ + // The URL to request + url: server, + handleAs:"json", + headers:{"X-Requested-With":null}, + error: function(result) { + + if (self.browseButton) { self.browseButton.setAttribute('label', 'Browse'); } + if (self.fileStandby) { self.fileStandby.hide(); } + + if (!params.skipTree) { + if (self.fileTreeStore) { + var allItems = self.fileTreeStore.query(); + for (var i = 0; i < allItems.total; i++) { + self.fileTreeStore.remove(allItems[i].id); + } + } + } + if (!params.skipList) { + if (self.fileListStore) { + var allItems = self.fileListStore.query(); + for (var i = 0; i < allItems.total; i++) { + self.fileListStore.remove(allItems[i].id); + } + } + } + }, + load: function(result) { +// self.localStorage.put("vrmlServer", self.serverURL, null); + if (self.browseButton) { self.browseButton.setAttribute('label', 'Refresh'); } + if (self.fileStandby) { self.fileStandby.hide(); } + + if (self.treeNavigationStyle && !params.skipTree) { + // empty store + var allItems = self.fileTreeStore.query(); + for (var i = 0; i < allItems.total; i++) { + self.fileTreeStore.remove(allItems[i].id); + } + + // parse result as tree + (function fillstore(tree, parentId) { + // todo: respect navigation style + for (key in tree) { + if ('url' in tree[key]) { + self.fileTreeStore.add({id:parentId+key, name:key, url:tree[key].path, parent:parentId}); + } else { + self.fileTreeStore.add({id:parentId+key, name:key, parent:parentId}); + fillstore(tree[key], parentId+key); + } + } + } (result.models, "root", "")); + } + if (self.listNavigationStyle && !params.skipList) { + + // empty store + var allItems = self.fileListStore.query(); + for (var i = 0; i < allItems.total; i++) { + self.fileListStore.remove(allItems[i].id); + } + + // parse result as list + if (!self.listDirectory) + console.log("Requested modelNavigationStyle === list but provided no listDirectory"); + var dirs = self.listDirectory.split("/"); + var models = result.models; + for (var dir in dirs) { + if (!dirs[dir].length) + continue; + if (dirs[dir] in models) { + models = models[dirs[dir]]; + } else { + console.log("No " + dirs[dir] + " in " + models); + } + } + for (var key in models) { + var url = self.serverURL + models[key].path; + self.fileListStore.add({id:key, value:models[key].path, label:key, name:key, url:url}); + } + self.fileListSelect.startup(); + } + //self.updateScene(); + } + }); + }; + + this.setPose = function(imagePath, imageFormat, pose, serverURL) { + if (serverURL && serverURL != self.serverURL) { + self.refreshServer(serverURL); + } + self.imagePath = imagePath; + self.imageFormat = imageFormat; + self.pose = pose; + + var pitch = (pose.pitch % (2 * 3.14159) + 0.5) * 100; + var roll = (pose.roll % (2 * 3.14159) + 0.5) * 100; + var yaw = (pose.yaw % (2 * 3.14159) + 0.5) * 100; + + var x = ((pose.x / 100) + 0.5) * 100; + var y = ((pose.y / 100) + 0.5) * 100; + + var zoom = (((pose.zoom - 1) / 3) + 0.5) * 100; + + self.pitchRollHandlerElem.parentNode.style.right = pitch + "%"; + self.pitchRollHandlerElem.parentNode.style.top = roll + "%"; + self.yawZoomHandlerElem.parentNode.style.right = yaw + "%"; + self.yawZoomHandlerElem.parentNode.style.top = zoom + "%"; + self.xyHandlerElem.parentNode.style.right = x + "%"; + self.xyHandlerElem.parentNode.style.top = y + "%"; + + self.updateScene(); + }; + + require(["dojo/dom-construct", + "dojo/_base/xhr", + "dojo/dom", + "dojo/on", + "dojo/_base/array", + "dojox/storage", + "dojo/store/Memory", + "dojo/store/Observable", + "dijit/tree/ObjectStoreModel", + "dojo/data/ObjectStore", + "dijit/Tree", + "dijit/form/TextBox", + "dijit/form/Button", + "dojox/widget/Standby", + "dijit/form/DropDownButton", + "dijit/TooltipDialog", + "dojo/dnd/Moveable", + "dojo/ready", + "dojo/dnd/Source", + "dijit/form/HorizontalSlider", + "dijit/form/Select", + "dijit/form/NumberSpinner"], + function(domConst, + xhr, + dom, + on, + array, + storage, + Memory, + Observable, + ObjectStoreModel, + ObjectStore, + Tree, + TextBox, + Button, + Standby, + DropDownButton, + TooltipDialog, + Moveable, + ready, + Source, + HorizontalSlider, + Selector, + NumberSpinner) { + + ready(function() { + + if (typeof(element) === 'string') { + element = dom.byId(element); + } + element.style.height = self.pose.height; + element.style.width = self.pose.width; + + self.element = element; + self.xhr = xhr; + + // establish our dom + element.appendChild(domConst.toDom('\ + <table>\ + <tr>\ + <td valign="top">\ + <div style="position: relative; padding: 0px; width: ' + self.pose.width + 'px; height: ' + self.pose.height + 'px">\ + <div class="screenShot" style="position: absolute; width: ' + self.pose.width + 'px; height: ' + self.pose.height + 'px">\ + <img class="screenShot" style="width: ' + self.pose.width + 'px; height: ' + self.pose.height + 'px"></img>\ + </div>\ + <div class="webGL" style="position: absolute; width: ' + self.pose.width + 'px; height: ' + self.pose.height + 'px">\ + <canvas class="webGL" style="width: ' + self.pose.width + 'px; height: ' + self.pose.height + 'px"></canvas>\ + </div>\ + <div style="z-index: -1; position: absolute; right: 45%; top: 45%">\ + <div class="progress"></div>\ + </div>\ + <div style="position: absolute; left: 10px; top: 10px">\ + <table></tr>\ + <td class="treeNavigation filesDropDown" style="vertical-align: middle"></td>\ + <td class="movieControls">\ + <div class="movieDropDown" style="display: inline"></div>\ + <button type="button" class="movieAddButton"></button>\ + </td>\ + <td align="right"><button type="button" class="resetButton"></button></td>\ + <td class="dndHandler" style="vertical-align: middle; padding-top: 4px;"></td>\ + </tr></table>\ + </div>\ + <div style="position: absolute; right: 10px; top: 15%; height: 50%">\ + <div class="zoomSlide"></div>\ + </div>\ + <div class="draggable" style="position: absolute; right: 50%; top: 50%">\ + <div class="pitchRollHandler" style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px;">\ + <table>\ + <tr>\ + <td><img class="pitchRollHandlerImg" src="' + self.resRoot + 'img/pitchRoll-handle.png" height="20px" style="padding: 2px 0px 0px 4px;" /></td>\ + <td><div class="pitchLabel"></div><div class="rollLabel"></div></td>\ + </tr>\ + </table>\ + </div>\ + </div>\ + <div class="draggable"style="position: absolute; right: 50%; top: 50%">\ + <div class="yawZoomHandler">\ + <div style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px; position: absolute; left: -34px;">\ + <table>\ + <tr>\ + <td><img class="yawZoomHandlerImg" src="' + self.resRoot + 'img/yawZoom-handle.png" height="20px" style="padding: 2px 0px 0px 4px;" /></td>\ + <td><div class="yawLabel"></div><div class="zoomLabel"></div></td>\ + </tr>\ + </table>\ + </div>\ + </div>\ + </div>\ + <div class="draggable"style="position: absolute; right: 50%; top: 50%">\ + <div class="xyHandler" style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px;">\ + <table>\ + <tr>\ + <td><img class="xyHandlerImg" src="' + self.resRoot + 'img/xy-handle.png" width="20px" style="padding: 2px 0px 0px 4px;" /></td>\ + <td><div class="xLabel"></div><div class="yLabel"></div></td>\ + </tr>\ + </table>\ + </div>\ + </div>\ + <div class="listNavigation" style="position: absolute; left: 10px; bottom: 10px">\ + <table></tr>\ + <td style="vertical-align: middle"><button class="prevButton" type="button" /></td>\ + <td style="vertical-align: middle"><div class="fileList" /></td>\ + <td style="vertical-align: middle"><button class="nextButton" type="button" /></td>\ + </tr></table>\ + </div>\ + </div>\ + </td>\ + <td valign="top" height="100%">\ + </td>\ + </tr>\ + <tr>\ + <td colspan="2"><div class="messages"></div></td>\ + </tr>\ + </table>\ + ')); + + // fetch special dom nodes for content + self.messageBox = dojo.query("div.messages", element)[0]; + self.imgElem = dojo.query("img.screenShot", element)[0]; + + /** + * === WebGL ==================== + */ + var activateWebGL = function(enable) { + if (enable) { + self.canvasElem = dojo.query("canvas.webGL", element)[0]; + self.canvasElem.style.width = self.width; + self.canvasElem.style.height = self.height; + self.canvasElem.width = self.width; + self.canvasElem.height = self.height; + + // osgDB.Promise.when(getWebGLModel('http://localhost:8081/vrml/cranehook/cranehook_bad_convergence/HARD_MP_VAL_013.osgjs')).then(function(model) { + // self.webGLViewer = new osgViewer.Viewer(self.canvasElem, {antialias : true, alpha: true }); + // self.webGLViewer.init(); + // self.webGLViewer.getCamera().setClearColor([0.0, 0.0, 0.0, 0.0]); + // self.webGLViewer.setSceneData(model); + // self.webGLViewer.setupManipulator(); + // self.webGLViewer.getManipulator().computeHomePosition(); + // self.webGLViewer.run(); + // }); + + if (self.webGLViewer === undefined) { + self.webGLViewer = new osgViewer.Viewer(self.canvasElem, {antialias : true, alpha: true }); + self.webGLViewer.init(); + self.webGLViewer.getCamera().setClearColor([0.0, 0.0, 0.0, 0.0]); + self.webGLViewer.setupManipulator(); + self.webGLViewer.run(); + } + + // show elements + array.forEach(dojo.query(".webGL", element), function(entry, i) { + entry.style.display = "inline"; + }) + } else { + if (self.webGLViewer) { + self.webGLViewer.stop(); + } + // hide elements + array.forEach(dojo.query(".webGL", element), function(entry, i) { + entry.style.display = "none"; + }) + } + } + activateWebGL(self.enableWebGL); + + var activateScreenshot = function(enable) { + if (enable) { + array.forEach(dojo.query(".screenShot", element), function(entry, i) { + entry.style.display = "inline"; + }); + } else { + array.forEach(dojo.query(".screenShot", element), function(entry, i) { + entry.style.display = "none"; + }); + } + } + activateScreenshot(self.enableSceneshots); + + /** + * === POSE MANIPULATION AND RESET ==================== + */ + + self.resetButtonElem = dojo.query("button.resetButton", element)[0]; + self.resetButton = new Button({ + label: "Reset", + onClick: function() { + if (self.webGLViewer) { + self.webGLViewer.setupManipulator(); + self.webGLViewer.getManipulator().computeHomePosition(); + } + self.pose.x = 0; + self.pose.y = 0; + self.pose.pitch = 0; + self.pose.roll = 0; + self.pose.yaw = 0; + self.pose.zoom = 1; + + self.xyHandler.node.style.left = 0; + self.xyHandler.node.style.top = 0; + self.pitchRollHandler.node.style.left = 0; + self.pitchRollHandler.node.style.top = 0; + self.yawZoomHandler.node.style.left = 0; + self.yawZoomHandler.node.style.top = 0; + + self.updateScene(); + } + }, self.resetButtonElem); + + var activateDraggables = function(enable) { + if (enable) { + if (self.pitchRollHandler == undefined) { + self.progressElem = dojo.query("div.progress", element)[0]; + + self.pitchRollHandlerElem = dojo.query(".pitchRollHandler", element)[0]; + self.yawZoomHandlerElem = dojo.query(".yawZoomHandler", element)[0]; + self.xyHandlerElem = dojo.query(".xyHandler", element)[0]; + + self.pitchRollHandler = new Moveable(self.pitchRollHandlerElem); + self.pitchRollHandler.onMoveStop = function(mover) { + var handlerImg = dojo.query("img.pitchRollHandlerImg", mover.node)[0]; + var pitchLabel = dojo.query("div.pitchLabel", mover.node)[0]; + var rollLabel = dojo.query("div.rollLabel", mover.node)[0]; + pitchLabel.innerHTML = ''; + rollLabel.innerHTML = ''; + self.updateScene(); + }; + self.pitchRollHandler.onMoving = function(mover) { + var handlerImg = dojo.query(".pitchRollHandlerImg", mover.node)[0]; + var pitchLabel = dojo.query(".pitchLabel", mover.node)[0]; + var rollLabel = dojo.query(".rollLabel", mover.node)[0]; + var offset = moverRelativeTo(handlerImg, self.element); + + offset.x += 30; + offset.y += 20; + + self.xyHandlerElem.style.zIndex = 1; + self.yawZoomHandlerElem.style.zIndex = 1; + self.pitchRollHandlerElem.style.zIndex = 2; + + self.pose.roll = offset.x / self.pose.width - 0.5; + self.pose.pitch = offset.y / self.pose.height - 0.5; + self.pose.pitch *= -1; + self.pose.roll *= 2 * 3.14159; + self.pose.pitch *= 2 * 3.14159; + self.pose.roll = Math.ceil((self.pose.roll) * 10) / 10; + self.pose.pitch = Math.ceil((self.pose.pitch) * 10) / 10; + pitchLabel.innerHTML = 'Pitch:' + self.pose.pitch; + rollLabel.innerHTML = 'Roll:' + self.pose.roll; + }; + + self.yawZoomHandler = new Moveable(self.yawZoomHandlerElem); + self.yawZoomHandler.onMoveStop = function(mover) { + var handlerImg = dojo.query("img.yawZoomHandlerImg", mover.node)[0]; + var yawLabel = dojo.query("div.yawLabel", mover.node)[0]; + var zoomLabel = dojo.query("div.zoomLabel", mover.node)[0]; + yawLabel.innerHTML = ''; + zoomLabel.innerHTML = ''; + self.updateScene(); + }; + self.yawZoomHandler.onMoving = function(mover) { + var handlerImg = dojo.query("img.yawZoomHandlerImg", mover.node)[0]; + var yawLabel = dojo.query("div.yawLabel", mover.node)[0]; + var zoomLabel = dojo.query("div.zoomLabel", mover.node)[0]; + var offset = moverRelativeTo(handlerImg, self.element); + + offset.x += 7; + offset.y += 9; + + self.xyHandlerElem.style.zIndex = 1; + self.yawZoomHandlerElem.style.zIndex = 2; + self.pitchRollHandlerElem.style.zIndex = 1; + + // self.pose.pitch = self.pose.pitch % (2 * 3.14159); + // self.pose.roll = self.pose.roll % (2 * 3.14159); + self.pose.yaw = (self.pose.width - offset.x) / self.pose.width - 0.5; + self.pose.zoom = offset.y / self.pose.height - 0.5; + self.pose.yaw *= 2 * 3.14159; + self.pose.zoom = self.pose.zoom * 3 + 1; + self.pose.zoom = Math.ceil((self.pose.zoom) * 10) / 10; + self.pose.yaw = Math.ceil((self.pose.yaw) * 10) / 10; + yawLabel.innerHTML = 'Yaw:' + self.pose.yaw; + zoomLabel.innerHTML = 'Zoom:' + self.pose.zoom; + }; + + self.xyHandler = new Moveable(self.xyHandlerElem); + self.xyHandler.onMoveStop = function(mover) { + var handlerImg = dojo.query("img.xyHandlerImg", mover.node)[0]; + var xLabel = dojo.query("div.xLabel", mover.node)[0]; + var yLabel = dojo.query("div.yLabel", mover.node)[0]; + + xLabel.innerHTML = ''; + yLabel.innerHTML = ''; + + self.updateScene(); + }; + self.xyHandler.onMoving = function(mover) { + var handlerImg = dojo.query("img.xyHandlerImg", mover.node)[0]; + var xLabel = dojo.query("div.xLabel", mover.node)[0]; + var yLabel = dojo.query("div.yLabel", mover.node)[0]; + var offset = moverRelativeTo(handlerImg, self.element); + + offset.x += 3; + offset.y += 13; + + self.xyHandlerElem.style.zIndex = 2; + self.yawZoomHandlerElem.style.zIndex = 1; + self.pitchRollHandlerElem.style.zIndex = 1; + + self.pose.x = offset.x / self.pose.width - 0.5; + self.pose.y = offset.y / self.pose.height - 0.5; + self.pose.x *= 100; + self.pose.y *= 100; + self.pose.y = Math.ceil((self.pose.y) * 10) / 10; + self.pose.x = Math.ceil((self.pose.x) * 10) / 10; + xLabel.innerHTML = 'X:' + self.pose.x; + yLabel.innerHTML = 'Y:' + self.pose.y; + }; + } + + // show all draggables + array.forEach(dojo.query(".draggable", element), function(entry, i) { + entry.style.display = "inline"; + }) + + } else { + // show all draggables + array.forEach(dojo.query(".draggable", element), function(entry, i) { + entry.style.display = "none"; + }) + } + } + activateDraggables(self.enableDraggables); + + /** + * === DRAG HANDLER ==================== + */ + var activateDND = function(enable) { + if (enable) { + self.createAvatar = function(item, mode) { + if (mode == 'avatar') { + // create your avatar if you want + var avatar = dojo.create( 'div', { innerHTML: item.data }); + var avatarPose = dojo.clone(self.pose); + avatarPose.width=60; + avatarPose.height=60; + var avatarImgUrl = urlSuffixForPose(avatarPose); + avatar.innerHTML = '<img src=' + self.imagePath + self.imageFormat + avatarImgUrl + ' /> '; + item.srcEcc = "VRMLViewer"; + item.iconPoseUrl = self.imagePath + self.imageFormat + avatarImgUrl; + item.imagePath = self.imagePath; + item.imageFormat = self.imageFormat; + item.serverURL = self.serverURL; + item.pose = avatarPose; + return {node: avatar, data: item, type: item.type}; + } + var handler = dojo.create( 'div', { innerHTML: '<img src="' + self.resRoot + 'img/drag.png" width="20px" />' }); + return {node: handler, data: item, type: item.type}; + }; + + self.dndHandler = new Source(dojo.query("td.dndHandler", element)[0], {copyOnly: true, creator: self.createAvatar}); + self.dndHandler.insertNodes(false, [ { } ]); + + array.forEach(dojo.query(".dndHandler", element), function(entry, i) { + entry.style.display = "inline"; + }) + + } else { + array.forEach(dojo.query(".dndHandler", element), function(entry, i) { + entry.style.display = "none"; + }) + + } + } + activateDND(self.enableDND); + + /** + * === FILE NAVIGATION ==================== + */ + + var activateListNavigation = function(enable) { + if (enable) { + array.forEach(dojo.query(".listNavigation", element), function(entry, i) { + entry.style.display = "inline"; + }); + + if (!self.fileListStore) { + // setup fileStore + self.fileListStore = new Observable(new Memory({ + data: [], + })); + + self.prevButtonElem = dojo.query("button.prevButton", element)[0]; + self.nextButtonElem = dojo.query("button.nextButton", element)[0]; + self.fileListElem = dojo.query("div.fileList", element)[0]; + + self.fileListSelect = new Selector({ + store: new ObjectStore({ objectStore: self.fileListStore }), + onChange: function(name) { + var item = self.fileListStore.query({ id: name })[0]; + self.imagePath = self.listDirectory + item.name; + self.updateScene(); + } + }, self.fileListElem); + + self.prevButton = new Button({ + label: "<", + onClick: function() { + var allItems = self.fileListStore.query(); + var foundAt = 0; + for (var i = 0; i < allItems.total; i++) { + //console.log(self.serverURL + self.imagePath + " === " + allItems[i].url); + if (self.serverURL + self.imagePath + self.imageFormat === allItems[i].url) { + foundAt = i; + break; + } + } + + if (foundAt > 0) { + self.imagePath = self.listDirectory + allItems[foundAt - 1].name; + self.fileListSelect.attr( 'value', allItems[foundAt - 1].id ); + if (self.serverURL + self.imagePath !== allItems[foundAt - 1].url) + console.log(self.serverURL + self.imagePath + " !== " + allItems[foundAt - 1].url); + self.updateScene(); + } + } + }, self.prevButtonElem); + + self.nextButton = new Button({ + label: ">", + onClick: function() { + var allItems = self.fileListStore.query(); + var foundAt = 0; + for (var i = 0; i < allItems.total; i++) { + //console.log(self.serverURL + self.imagePath + " === " + allItems[i].url); + if (self.serverURL + self.imagePath === allItems[i].url) { + foundAt = i; + break + } + } + if (foundAt + 1 < allItems.total) { + self.imagePath = self.listDirectory + allItems[foundAt + 1].name + ".png"; + self.fileListSelect.attr( 'value', allItems[foundAt + 1].id ); + if (self.serverURL + self.imagePath !== allItems[foundAt + 1].url) + console.log(self.serverURL + self.imagePath + " !== " + allItems[foundAt + 1].url); + self.updateScene(); + } + } + }, self.nextButtonElem); + } + } else { + array.forEach(dojo.query(".listNavigation", element), function(entry, i) { + entry.style.display = "none"; + }); + } + } + activateListNavigation(self.listNavigationStyle); + + var activateTreeNavigation = function(enable) { + if (enable) { + + array.forEach(dojo.query(".treeNavigation", element), function(entry, i) { + entry.style.display = "inline"; + }); + + if (!self.fileTreeStore) { + // setup fileStore + self.fileTreeStore = new Observable(new Memory({ + data: [ { id: 'root', name:'3D Models'} ], + getChildren: function(object){ + return this.query({parent: object.id}); + } + })); + + self.fileTreeModel = new ObjectStoreModel({ + store: self.fileTreeStore, + query: { id: "root" } + }); + + // setup actual tree dijit + self.fileTree = new dijit.Tree({ + id: "fileTree" + self.instanceId, + model: self.fileTreeModel, + persist: false, + showRoot: false, + style: "height: 300px;", + onClick: function(item){ + if ('url' in item) { + self.imagePath = item.url; + var newListDir = self.imagePath.substring(0, self.imagePath.lastIndexOf("/")); + if (newListDir.length > 0) + newListDir += '/'; + if (newListDir !== self.listDirectory) { + self.listDirectory = newListDir; + self.refreshServer(self.serverURL, { skipTree: true }); + } + self.updateScene(); + } + }, + getIconClass: function(item, opened) { + return (!item || !('url' in item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "dijitLeaf"; + }, + getIconStyle: function(item, opened){ + if('url' in item) { + return { backgroundImage: "url('" + self.serverURL + item.url + self.imageFormat + "?width=16&height=16')"}; + } + } + //return {backgroundImage: "url('" + item.url + "?width=16&height=16')"}; + }); + + self.filesDropDownElem = dojo.query("td.filesDropDown", element)[0]; + + self.serverBox = new TextBox({ + name: "Server", + value: self.serverURL, + style: "width: 65%", + + onKeyUp: function(e) { + if (self.browseButton) { + if (this.get("value") !== self.serverURL) { + self.browseButton.setAttribute('label', 'Browse'); + } else { + self.browseButton.setAttribute('label', 'Refresh'); + } + } + }, + + onKeyDown: function(e) { + var code = e.keyCode || e.which; + if( code === 13 ) { + e.preventDefault(); + self.refreshServer(this.get("value")); + return false; + } + }, + }); + + self.browseButton = new Button({ + label: "Browse", + onClick: function(){ + self.refreshServer(self.serverBox.get("value")); + } + }); + + self.filesDropDownContent = domConst.toDom('<div />'); + self.filesDropDownContent.appendChild(self.serverBox.domNode); + self.filesDropDownContent.appendChild(self.browseButton.domNode); + self.filesDropDownContent.appendChild(self.fileTree.domNode); + + self.filesToolTip = new TooltipDialog({ content:self.filesDropDownContent, style:"max-height:320px"}); + self.filesDropDown = new DropDownButton({ label: "Files", dropDown: self.filesToolTip }); + self.filesDropDownElem.appendChild(self.filesDropDown.domNode); + + self.fileStandby = new Standby({target: self.filesDropDownContent }); + self.filesDropDownContent.appendChild(self.fileStandby.domNode); + } + } else { + array.forEach(dojo.query(".treeNavigation", element), function(entry, i) { + entry.style.display = "none"; + }); + } + } + activateTreeNavigation(self.treeNavigationStyle); + + if (self.serverURL) { + self.refreshServer(self.serverURL); + self.updateScene(); + } + /** + * === MOVIE DROPDOWN ==================== + */ + + if (self.enableMovies) { + self.movieDropDownElem = dojo.query("div.movieDropDown", element)[0]; + self.movieAddButtonElem = dojo.query("button.movieAddButton", element)[0]; + + self.movieDropDownContent = domConst.toDom( + '<div style="overflow: auto; max-height: 420px;"> \ + <table><tr class="movieFormatLengthRow" /></tr><tr class="movieWidthHeightLengthRow" /></table> \ + <div class=\"dndArea\" /> \ + </div>' + ); + + self.movieFormatLengthRowElem = dojo.query("tr.movieFormatLengthRow", self.movieDropDownContent)[0]; + self.movieWidthHeightLengthRowElem = dojo.query("tr.movieWidthHeightLengthRow", self.movieDropDownContent)[0]; + self.movieDnDArea = dojo.query("div.dndArea", self.movieDropDownContent)[0]; + + self.createMovieThumb = function(item, mode) { + if (mode == 'avatar') { + // when dragged + var avatar = dojo.create( 'div', { innerHTML: item.data }); + var avatarPose = dojo.clone(self.pose); + avatarPose.width = 60; + avatarPose.height = 60; + var avatarImgUrl = urlSuffixForPose(avatarPose); + avatar.innerHTML = '<img src=' + self.imagePath + avatarImgUrl + ' /> '; + item.srcEcc = "VRMLViewer"; + item.iconPoseUrl = self.imagePath + avatarImgUrl; + item.imagePath = self.imagePath; + item.serverURL = self.serverURL; + item.pose = avatarPose; + return {node: avatar, data: item, type: item.type}; + } else { + + // when added to list + var thumb = domConst.toDom("\ + <div>\ + <table><tr><td>\ + <img class=\"movieThumb\"/>\ + <img class=\"removeThumb\" style=\"vertical-align: top; margin: -3px 0px 0px -8px; width: 20px; height: 20px;\"/>\ + </td><td align=\"left\">\ + <table><tr>\ + <td>Frame:</td><td><div class=\"relFrameLength\"/></td>\ + <td><div class=\"fillInSeries\" \></td>\ + </tr><tr>\ + <td>Transition:</td><td><div class=\"relTransitionLength\"/></td>\ + </tr></table>\ + </td></tr></table>\ + </div>\ + "); + thumb = dojo.query("div", thumb)[0]; + + var thumbImgElem = dojo.query("img.movieThumb", thumb)[0]; + var removeImgElem = dojo.query("img.removeThumb", thumb)[0]; + var relFrameLengthElem = dojo.query("div.relFrameLength", thumb)[0]; + var relTransitionLengthElem = dojo.query("div.relTransitionLength", thumb)[0]; + var fillInSeriesElem = dojo.query("div.fillInSeries", thumb)[0]; + + item.getThisAndNeighborsFromDnD = function() { + var thisAndNeighbors = {}; + self.addToMovieHandler.forInItems(function(obj, key, ctx) { + if (obj.data === item) { + thisAndNeighbors.this = { key: key, obj: obj }; + } else { + thisAndNeighbors.before = { key: key, obj: obj }; + } + if (thisAndNeighbors.this) { + thisAndNeighbors.after = { key: key, obj: obj }; + return thisAndNeighbors; + } + }); + return thisAndNeighbors; + }; + + item.relFrameLengthSlider = new HorizontalSlider({ + value: 50, + title: "Relative Duration of Frame", + style: "width:150px;" + }, relFrameLengthElem); + + item.relTransitionLengthSlider = new HorizontalSlider({ + value: 100, + title: "Relative Duration of Transition", + style: "width:150px;" + }, relTransitionLengthElem); + + removeImgElem.onclick = function() { + var thisItem = item.getThisAndNeighborsFromDnD(); + if (thisItem.this) { + // haha - what a mess! + self.addToMovieHandler.selectNone(); + self.addToMovieHandler.selection[thisItem.this.key] = thisItem.this.obj; + self.addToMovieHandler.deleteSelectedNodes(); + } + // disable create button if this was the last one + if (!thisItem.after || !thisItem.before) { + self.movieCreateButton.setAttribute('disabled', true); + } + } + + item.fillInSeriesButton = new Button({ + label: "Insert Series", + style: "display: none;", + onClick: function(){ + alert("foo"); + } + }, fillInSeriesElem); + + removeImgElem.src = self.resRoot + "img/close.png"; + + var thumbPose = dojo.clone(self.pose); + thumbPose.width = self.pose.width / 10; + thumbPose.height = self.pose.height / 10; + var thumbImgUrl = urlSuffixForPose(thumbPose); + + thumbImgElem.src = self.imagePath + thumbImgUrl; + // removeImgElem.src = self.resRoot + 'img/close.png'; + + item.srcEcc = "VRMLViewer"; + item.iconPoseUrl = self.imagePath + thumbImgUrl; + item.imagePath = self.imagePath; + item.serverURL = self.serverURL; + item.pose = thumbPose; + + return {node: thumb, data: item, type: item.type}; + } + }; + + self.addToMovieHandler = new Source(self.movieDnDArea, {copyOnly: true, creator: self.createMovieThumb}); + + self.movieFormatSelection = new Selector({ + name: "movieFormat", + style: "width: 320px", + options: [] + }); + self.populateMovieCodecs("http://" + self.serverURL + '/movie/codecs', self.movieFormatSelection); + + self.movieFormatLengthRowElem.appendChild(dojo.create('td', { innerHTML: 'Format:'} )); + self.movieFormatLengthRowElem.appendChild(dojo.create('td', { colspan: "2"})); + self.movieFormatLengthRowElem.lastChild.appendChild(self.movieFormatSelection.domNode); + + self.movieHeightSpinner = new NumberSpinner({ + value: 400, + smallDelta: 1, + style: "width: 60px", + constraints: { min:40, places:0 }, + }); + + self.movieWidthSpinner = new NumberSpinner({ + value: 600, + smallDelta: 1, + style: "width: 60px", + constraints: { min:40, places:0 }, + }); + + self.movieCreateButton = new Button({ + label: "Create", + disabled: true, + onClick: function(){ + + var form = document.createElement("form"); + + form.setAttribute("method", "post"); + form.setAttribute("action", self.serverURL + "/movie"); + + var submitData = {}; + submitData.frames = []; + submitData.movieLength = self.movieDurationSpinner.value; + submitData.format = self.movieFormatSelection.value; + submitData.width = self.movieWidthSpinner.value; + submitData.height = self.movieHeightSpinner.value; + + self.addToMovieHandler.forInItems(function(obj, key, ctx) { + var jsonData = { + iconPoseUrl: obj.data.iconPoseUrl, + imagePath: obj.data.imagePath, + serverURL: obj.data.serverURL, + pose: obj.data.pose, + relFrameLength: obj.data.relFrameLengthSlider.value, + relTransitionLength: obj.data.relTransitionLengthSlider.value, + } + submitData.frames.push(jsonData); + }); + + var hiddenField = document.createElement("input"); + hiddenField.setAttribute("type", "hidden"); + hiddenField.setAttribute("name", "data"); + hiddenField.setAttribute("value", JSON.stringify(submitData)); + + form.appendChild(hiddenField); + + // this will not save the returned binary file + // self.xhr.post({ + // form: form, + // load: function(data){ + // alert("asd"); + // } + // }); + + document.body.appendChild(form); + form.submit(); + document.body.removeChild(form); + } + }); + + self.movieDurationSpinner = new NumberSpinner({ + value: 10, + smallDelta: 1, + style: "width: 40px", + constraints: { min:0, places:0 }, + }); + + // append format duration cell + self.movieWidthHeightLengthRowElem.appendChild(dojo.create('td', { innerHTML: 'Size:'} )); + var movieDimensionCell = dojo.create('td'); + movieDimensionCell.appendChild(self.movieWidthSpinner.domNode); + movieDimensionCell.appendChild(dojo.create('span', { innerHTML: "x"} )); + movieDimensionCell.appendChild(self.movieHeightSpinner.domNode); + movieDimensionCell.appendChild(self.movieDurationSpinner.domNode); + movieDimensionCell.appendChild(dojo.create('span', { innerHTML: "sec"} )); + self.movieWidthHeightLengthRowElem.appendChild(movieDimensionCell); + + self.movieWidthHeightLengthRowElem.appendChild(dojo.create('td', { align: "right"})); + self.movieWidthHeightLengthRowElem.lastChild.appendChild(self.movieCreateButton.domNode); + + + self.movieToolTip = new TooltipDialog({ content:self.movieDropDownContent }); + self.movieDropDown = new DropDownButton({ + label: "Movie", + style: "display: none;", + dropDown: self.movieToolTip }); + self.movieDropDownElem.appendChild(self.movieDropDown.domNode); + + self.movieAddButton = new Button({ + label: "+", + style: "margin-left: -10px; display: none;", + onClick: function(){ + if (self.movieFormatSelection.options.length == 0) { + self.populateMovieCodecs(self.serverURL + '/movie/codecs', self.movieFormatSelection); + } + // we could pass item.data here to creator + self.addToMovieHandler.insertNodes(false, [ { } ]); + self.movieCreateButton.setAttribute('disabled', false); + + } + }, self.movieAddButtonElem); + } else { + // remove movie controls + var movieControls = dojo.query("td.movieControls", element)[0]; + movieControls.parentNode.removeChild(movieControls); + } + + // do we have parameters for the initial pose? + if(self.params && self.params.pose) + self.setPose(self.params.imagePath, self.params.pose, self.params.serverURL); + + }); + }); + + +} diff --git a/apps/samples/vrml/viewer.html b/apps/samples/vrml/viewer.html index 9f42ba5..7357ee4 100644 --- a/apps/samples/vrml/viewer.html +++ b/apps/samples/vrml/viewer.html @@ -52,8 +52,9 @@ // } </script> + <script src="http://uscxml.tk.informatik.tu-darmstadt.de/scripts/osg.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script> - <script type="text/javascript" src="viewer.js"></script> + <script type="text/javascript" src="viewer-webgl.js"></script> <script type="text/javascript" src="annotations.js"></script> <script type="text/javascript"> @@ -74,11 +75,15 @@ }, enableMovies: false, enableDND: false, - modelNavigationStyle: "list", - listDirectory: "/10975/2", - poseNavigationStyle: "draggables", - imagePath: "/10975/2/latest.png", - serverURL: "http://85.22.93.138:8086/vrml", + enableWebGL: false, + enableSceneshots: true, + enableDraggables: true, + listNavigationStyle: true, + treeNavigationStyle: true, + listDirectory: "/hard_mp", + imagePath: "/hard_mp/HARD_MP_VAL_000", + imageFormat: "png", + serverURL: "http://localhost:8081/vrml", }); //var viewer2 = new VRMLViewer("scene2"); // var annotations = new Annotations("annotations1", { 'viewer': viewer }); diff --git a/apps/samples/vrml/vrml-server.scxml.old b/apps/samples/vrml/vrml-server.caching.scxml index 70a7c3a..70a7c3a 100644 --- a/apps/samples/vrml/vrml-server.scxml.old +++ b/apps/samples/vrml/vrml-server.caching.scxml diff --git a/apps/samples/vrml/vrml-server.pre-osgjs.scxml b/apps/samples/vrml/vrml-server.pre-osgjs.scxml new file mode 100644 index 0000000..e08afd4 --- /dev/null +++ b/apps/samples/vrml/vrml-server.pre-osgjs.scxml @@ -0,0 +1,333 @@ +<scxml datamodel="ecmascript" name="vrml"> + <script src="http://uscxml.tk.informatik.tu-darmstadt.de/scripts/dump.js" /> + <script src="http://uscxml.tk.informatik.tu-darmstadt.de/scripts/string.endsWith.js" /> + <script src="http://uscxml.tk.informatik.tu-darmstadt.de/scripts/array.last.js" /> + <script> + var wrls = {}; // information of the wrl, vrml files + var models = {}; // information of the osgb files + + var pathDelim = ':'; // we need to flatten directories - this will seperate them in filenames + + /** + * Transform a http request into a pose + */ + function reqToStruct(req) { + var struct = {}; + + var query = (('query' in req) ? req.query : {}); + + struct.pitch = (('pitch' in query && isNumber(query.pitch)) ? query.pitch : 0); + struct.roll = (('roll' in query && isNumber(query.roll)) ? query.roll : 0); + struct.yaw = (('yaw' in query && isNumber(query.yaw)) ? query.yaw : 0); + struct.zoom = (('zoom' in query && isNumber(query.zoom)) ? query.zoom : 1); + struct.x = (('x' in query && isNumber(query.x)) ? query.x : 0); + struct.y = (('y' in query && isNumber(query.y)) ? query.y : 0); + struct.z = (('z' in query && isNumber(query.z)) ? query.z : 0); + struct.width = (('width' in query && isNumber(query.width)) ? query.width : 640); + struct.height = (('height' in query && isNumber(query.height)) ? query.height : 480); + struct.autorotate = (('autorotate' in query && (query.autorotate === 'on' || query.autorotate === 'off')) ? query.autorotate : 'on'); + + var fileComp = req.pathComponent[req.pathComponent.length - 1]; + struct.file = fileComp.substr(0, fileComp.indexOf('.')); + struct.ext = fileComp.substr(fileComp.indexOf('.') + 1); + + struct.key = _event.data.pathComponent.slice(1, _event.data.pathComponent.length - 1).join(pathDelim); + if (struct.key.length > 0) + struct.key += pathDelim; + + // support for meta file "latest.ext" + if (struct.file === "latest") { + var latestStamp = 0; + for (var key in models) { + if (key.substring(0, struct.key.length) == struct.key) { + if (models[key].ctime > latestStamp) { + var name = models[key].strippedName; + struct.file = name.substring(name.lastIndexOf(pathDelim) + 1); + latestStamp = models[key].ctime; + } + } + } + } + + struct.key += struct.file; + + return struct; + } + + function keyForFile(file) { + var key = file.relDir.replace(/\//g, pathDelim).substr(1) + file.strippedName; + return key; + } + + function isSupportedFormat(extension) { + if (extension === "gif") + return true; + if (extension === "jpg") + return true; + if (extension === "jpeg") + return true; + if (extension === "png") + return true; + if (extension === "tif") + return true; + if (extension === "tiff") + return true; + if (extension === "bmp") + return true; + return false; + } + + // list all available models in a summary format for the topmost request + function overviewList() { + var struct = {}; + struct.models = {}; + for (key in models) { + var model = models[key]; + var group = models[key].group + var name = model.strippedName.split(pathDelim).last(); + var entry = assign(struct, ['models'].concat(group.substr(1).split('/')).concat(name), {}); + entry.url = + _ioprocessors['http'].location + model.relDir + model.strippedName.split(pathDelim).join('/') + '.png'; + entry.path = model.relDir + model.strippedName.split(pathDelim).join('/') + '.png'; + } + return struct; + } + + // check whether a given string represents a number + function isNumber(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + } + + // allow to set deep keys in an object + function assign(obj, path, value) { + if (typeof path === 'string') + path = path.split('.'); + if (!(path instanceof Array)) + return undefined; + + lastKeyIndex = path.length-1; + for (var i = 0; i < lastKeyIndex; ++ i) { + key = path[i]; + if (key.length == 0) + continue; + if (!(key in obj)) + obj[key] = {} + obj = obj[key]; + } + obj[path[lastKeyIndex]] = value; + return obj[path[lastKeyIndex]]; + } + </script> + <state id="main"> + <!-- Stop processing if no vrml-path was given on command line --> + <transition target="final" cond="_x['args']['vrml-path'] == undefined || _x['args']['vrml-path'].length == 0"> + <log expr="'No --vrml-path given'" /> + </transition> + + <!-- Stop processing if no tmp-path was given on command line --> + <transition target="final" cond="_x['args']['tmp-path'] == undefined || _x['args']['tmp-path'].length == 0"> + <log expr="'No --tmp-path given'" /> + </transition> + + <!-- Stop processing if any error occurs --> + <transition target="final" event="error"> + <log expr="'An error occured:'" /> + <script>dump(_event);</script> + </transition> + + <!-- Start the directory monitor for generated files --> + <invoke type="dirmon" id="dirmon.processed"> + <param name="dir" expr="_x['args']['tmp-path']" /> + <param name="recurse" expr="false" /> + <param name="reportExisting" expr="true" /> + <param name="suffix" expr="'osgb'" /> + <!-- Called for every file we found --> + <finalize> + <script> + var key = keyForFile(_event.data.file); + // this is a binary 3D file converted from the wrls + + if (_event.name === "file.deleted") { + delete models[key]; + print("Removed a vanished osgb file at " + key + "\n"); + } else { + models[key] = _event.data.file; + models[key].group = '/' + _event.data.file.name.split(pathDelim).slice(0,-1).join('/'); + print("Inserted a new osgb file at " + key + "\n"); + } + </script> + </finalize> + </invoke> + + <!-- Start the directory monitor for wrl files --> + <invoke type="dirmon" id="dirmon.vrml"> + <param name="dir" expr="_x['args']['vrml-path']" /> + <param name="recurse" expr="true" /> + <param name="suffix" expr="'vrml wrl'" /> + <finalize> + <script> + _event.key = keyForFile(_event.data.file); + if (_event.name === "file.existing" || _event.name === "file.added") { + wrls[_event.key] = _event.data.file; + var dirMonFile = _event.data.file.relDir.substr(1) + _event.data.file.strippedName + ".osgb" + // we already procressed this file + if (_invokers['dirmon.processed'].file[dirMonFile]) { + models[_event.key] = _event.data.file; + } + print("Inserting wrl " + _event.data.file.path + " from " + _event.data.file.relDir + " at " + _event.key + "\n"); + } + if (_event.name === "file.deleted") { + delete wrls[_event.key]; + delete models[_event.key]; + print("Deleting wrl " + _event.data.file.path + " from " + _event.data.file.relDir + " at " + _event.key + "\n"); + } + </script> + <if cond="models && _event.name !== 'file.deleted' && + (!(_event.key in models) || wrls[_event.key].mtime > models[_event.key].mtime)"> + <send target="#_osgvonvert.osgb"> + <param name="source" expr="_event.data.file.path" /> + <param name="dest" expr="_x['args']['tmp-path'] + '/' + _event.key + '.osgb'" /> + </send> + </if> + </finalize> + </invoke> + + <!-- Start the osgconvert invoker to transform 3D files --> + <invoke type="osgconvert" id="osgvonvert.osgb"> + <param name="threads" expr="4" /> + <finalize> + <script> + //dump(_event); + </script> + <if cond="'context' in _event.data"> + <!-- this was generated in reply to a request --> + <if cond="_event.name.endsWith('success')"> + <respond status="200" to="_event.data.context"> + <header name="Connection" value="close" /> + <header name="Content-Type" value="application/json" /> + <header name="Access-Control-Allow-Origin" value="*" /> + <header name="Content-Type" valueexpr="_event.data.content[_event.data.format].mimetype" /> + <content expr="_event.data.content[_event.data.format]" /> + </respond> + <else /> + <respond status="404" to="_event.data.context"> + <header name="Connection" value="close" /> + </respond> + </if> + </if> + </finalize> + </invoke> + + <!-- Start a nested SCXML interpreter to create movies from the images --> + <invoke type="scxml" id="scxml.ffmpeg" src="ffmpeg-server.invoked.scxml" autoforward="true"> + <param name="modelDir" expr="_x['args']['tmp-path']" /> + </invoke> + + <!-- Idle here --> + <state id="idle"> + <transition event="http.get" target="idle" cond=" + _event.data.pathComponent.length >= 2 && + _event.data.pathComponent[_event.data.pathComponent.length - 1].indexOf('.') !== -1"> + <!-- request for a specific format http://host/vrml/relative/path/format?query=string --> + <script> + //dump(_invokers['dirmon.vrml']); + _event.fileStruct = reqToStruct(_event.data); + </script> + <if cond="_event.fileStruct.key in models && isSupportedFormat(_event['fileStruct'].ext)"> + <!-- There is such a file available as osgb --> + <send target="#_osgvonvert.osgb"> + <param name="source" expr="models[_event['fileStruct'].key].path" /> + <param name="format" expr="_event['fileStruct'].ext" /> + <param name="pitch" expr="_event.fileStruct.pitch" /> + <param name="roll" expr="_event.fileStruct.roll" /> + <param name="yaw" expr="_event.fileStruct.yaw" /> + <param name="zoom" expr="_event.fileStruct.zoom" /> + <param name="x" expr="_event.fileStruct.x" /> + <param name="y" expr="_event.fileStruct.y" /> + <param name="z" expr="_event.fileStruct.z" /> + <param name="width" expr="_event.fileStruct.width" /> + <param name="height" expr="_event.fileStruct.height" /> + <param name="autorotate" expr="_event.fileStruct.autorotate" /> + <param name="context" expr="_event.origin" /> + </send> + <else /> + <!-- There is no such model --> + <respond status="404" to="_event.origin"> + <header name="Connection" value="close" /> + </respond> + </if> + </transition> + + <!-- + process request for JSON datastructures + --> + <transition event="http.get" target="idle" cond=" + _event.data.pathComponent.length == 2 && + _event.data.pathComponent[1] === 'models'"> + <script>//dump(_event)</script> + <respond status="200" to="_event.origin"> + <header name="Connection" value="close" /> + <header name="Content-Type" value="application/json" /> + <header name="Access-Control-Allow-Origin" value="*" /> + <content expr="models" /> + </respond> + </transition> + + <transition event="http.get" target="idle" cond=" + _event.data.pathComponent.length == 2 && + _event.data.pathComponent[1] === 'wrls'"> + <script>//dump(_event)</script> + <respond status="200" to="_event.origin"> + <header name="Connection" value="close" /> + <header name="Content-Type" value="application/json" /> + <header name="Access-Control-Allow-Origin" value="*" /> + <content expr="wrls" /> + </respond> + </transition> + + <!-- request for topmost list of all files --> + <transition event="http.get" target="idle" cond=" + _event.data.pathComponent.length == 1"> + <script>//dump(_event);</script> + <respond status="200" to="_event.origin"> + <header name="Connection" value="close" /> + <header name="Content-Type" value="application/json" /> + <header name="Access-Control-Allow-Origin" value="*" /> + <content expr="overviewList()" /> + </respond> + </transition> + + <!-- XHR CORS preflight response --> + <transition event="http.options" target="idle"> + <script>//dump(_event);</script> + <respond status="200" to="_event.origin"> + <header name="Access-Control-Allow-Origin" value="*" /> + <header name="Access-Control-Allow-Methods" value="GET, OPTIONS" /> + <header name="Access-Control-Allow-Headers" value="X-Requested-With" /> + </respond> + </transition> + + <transition event="render.done" target="idle"> + <script>//dump(_event);</script> + <respond status="200" to="_event.data.context"> + <header name="Connection" value="close" /> + <header name="Content-Type" valueexpr="_event.data.mimetype" /> + <header name="Content-Disposition" valueexpr="'attachment; filename=' + _event.data.filename" /> + <content expr="_event.data.movie" /> + </respond> + </transition> + + <transition event="send.codecs" target="idle"> + <script>//dump(_event);</script> + <respond status="200" to="_event.data.context"> + <header name="Connection" value="close" /> + <header name="Content-Type" valueexpr="_event.data.mimetype" /> + <header name="Content-Disposition" valueexpr="'attachment; filename=' + _event.data.filename" /> + <content expr="_event.data.codecs" /> + </respond> + </transition> + + </state> + </state> + <state id="final" final="true" /> +</scxml>
\ No newline at end of file diff --git a/apps/samples/vrml/vrml-server.scxml b/apps/samples/vrml/vrml-server.scxml index e08afd4..e35d221 100644 --- a/apps/samples/vrml/vrml-server.scxml +++ b/apps/samples/vrml/vrml-server.scxml @@ -4,7 +4,7 @@ <script src="http://uscxml.tk.informatik.tu-darmstadt.de/scripts/array.last.js" /> <script> var wrls = {}; // information of the wrl, vrml files - var models = {}; // information of the osgb files + var models = {}; // information of the osgb / osgjs files var pathDelim = ':'; // we need to flatten directories - this will seperate them in filenames @@ -50,7 +50,6 @@ } struct.key += struct.file; - return struct; } @@ -74,6 +73,8 @@ return true; if (extension === "bmp") return true; + if (extension === "osgjs") + return true; return false; } @@ -87,8 +88,8 @@ var name = model.strippedName.split(pathDelim).last(); var entry = assign(struct, ['models'].concat(group.substr(1).split('/')).concat(name), {}); entry.url = - _ioprocessors['http'].location + model.relDir + model.strippedName.split(pathDelim).join('/') + '.png'; - entry.path = model.relDir + model.strippedName.split(pathDelim).join('/') + '.png'; + _ioprocessors['http'].location + model.relDir + model.strippedName.split(pathDelim).join('/'); + entry.path = model.relDir + model.strippedName.split(pathDelim).join('/'); } return struct; } @@ -120,12 +121,12 @@ </script> <state id="main"> <!-- Stop processing if no vrml-path was given on command line --> - <transition target="final" cond="_x['args']['vrml-path'] == undefined || _x['args']['vrml-path'].length == 0"> + <transition target="final" cond="_x.args == undefined || _x.args['vrml-path'] == undefined || _x.args['vrml-path'].length == 0"> <log expr="'No --vrml-path given'" /> </transition> <!-- Stop processing if no tmp-path was given on command line --> - <transition target="final" cond="_x['args']['tmp-path'] == undefined || _x['args']['tmp-path'].length == 0"> + <transition target="final" cond="_x.args == undefined || _x.args['tmp-path'] == undefined || _x.args['tmp-path'].length == 0"> <log expr="'No --tmp-path given'" /> </transition> @@ -146,7 +147,6 @@ <script> var key = keyForFile(_event.data.file); // this is a binary 3D file converted from the wrls - if (_event.name === "file.deleted") { delete models[key]; print("Removed a vanished osgb file at " + key + "\n"); @@ -184,16 +184,21 @@ </script> <if cond="models && _event.name !== 'file.deleted' && (!(_event.key in models) || wrls[_event.key].mtime > models[_event.key].mtime)"> - <send target="#_osgvonvert.osgb"> + <send target="#_osgvonvert.toNative"> <param name="source" expr="_event.data.file.path" /> <param name="dest" expr="_x['args']['tmp-path'] + '/' + _event.key + '.osgb'" /> + <param name="optimizegeometry" expr="true" /> </send> </if> </finalize> </invoke> <!-- Start the osgconvert invoker to transform 3D files --> - <invoke type="osgconvert" id="osgvonvert.osgb"> + <invoke type="osgconvert" id="osgvonvert.toNative"> + <param name="threads" expr="4" /> + </invoke> + + <invoke type="osgconvert" id="osgvonvert.toClient"> <param name="threads" expr="4" /> <finalize> <script> @@ -204,9 +209,8 @@ <if cond="_event.name.endsWith('success')"> <respond status="200" to="_event.data.context"> <header name="Connection" value="close" /> - <header name="Content-Type" value="application/json" /> <header name="Access-Control-Allow-Origin" value="*" /> - <header name="Content-Type" valueexpr="_event.data.content[_event.data.format].mimetype" /> + <header name="Content-Type" valueexpr="_event.data.content[_event.data.format].mimeType" /> <content expr="_event.data.content[_event.data.format]" /> </respond> <else /> @@ -235,7 +239,7 @@ </script> <if cond="_event.fileStruct.key in models && isSupportedFormat(_event['fileStruct'].ext)"> <!-- There is such a file available as osgb --> - <send target="#_osgvonvert.osgb"> + <send target="#_osgvonvert.toClient"> <param name="source" expr="models[_event['fileStruct'].key].path" /> <param name="format" expr="_event['fileStruct'].ext" /> <param name="pitch" expr="_event.fileStruct.pitch" /> @@ -311,7 +315,7 @@ <script>//dump(_event);</script> <respond status="200" to="_event.data.context"> <header name="Connection" value="close" /> - <header name="Content-Type" valueexpr="_event.data.mimetype" /> + <header name="Content-Type" valueexpr="_event.data.movie.mimeType" /> <header name="Content-Disposition" valueexpr="'attachment; filename=' + _event.data.filename" /> <content expr="_event.data.movie" /> </respond> @@ -321,7 +325,7 @@ <script>//dump(_event);</script> <respond status="200" to="_event.data.context"> <header name="Connection" value="close" /> - <header name="Content-Type" valueexpr="_event.data.mimetype" /> + <header name="Content-Type" valueexpr="application/json" /> <header name="Content-Disposition" valueexpr="'attachment; filename=' + _event.data.filename" /> <content expr="_event.data.codecs" /> </respond> |