summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/restart-on-term.sh9
-rw-r--r--apps/samples/vrml/ffmpeg-server.scxml245
-rw-r--r--apps/samples/vrml/img/close.pngbin0 -> 855 bytes
-rw-r--r--apps/samples/vrml/img/pitchRoll-handle.pngbin0 -> 6142 bytes
-rw-r--r--apps/samples/vrml/img/pitchRoll.pxmbin0 -> 29076 bytes
-rw-r--r--apps/samples/vrml/img/xy-handle.pngbin0 -> 4530 bytes
-rw-r--r--apps/samples/vrml/img/xy.pxmbin0 -> 29076 bytes
-rw-r--r--apps/samples/vrml/img/yawZoom-handle.pngbin0 -> 5603 bytes
-rw-r--r--apps/samples/vrml/img/yawZoom.pxmbin0 -> 29076 bytes
-rwxr-xr-xapps/samples/vrml/stress-vrml-server.pl35
-rw-r--r--apps/samples/vrml/viewer.html21
-rw-r--r--apps/samples/vrml/viewer.js320
-rw-r--r--apps/samples/vrml/vrml-server.scxml258
-rw-r--r--apps/samples/vrml/vrml-server.scxml.old416
-rw-r--r--apps/w3c-mmi/im/MMISessionManager.cpp3
15 files changed, 1102 insertions, 205 deletions
diff --git a/apps/restart-on-term.sh b/apps/restart-on-term.sh
new file mode 100644
index 0000000..37bb4fa
--- /dev/null
+++ b/apps/restart-on-term.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# see http://superuser.com/questions/223449/auto-restart-process-on-crash
+PROGRAM=$1
+
+RC=1
+while [ $RC -ne 0 ]; do
+ ./${PROGRAM}
+ RC=$?
+done
diff --git a/apps/samples/vrml/ffmpeg-server.scxml b/apps/samples/vrml/ffmpeg-server.scxml
new file mode 100644
index 0000000..1fd4038
--- /dev/null
+++ b/apps/samples/vrml/ffmpeg-server.scxml
@@ -0,0 +1,245 @@
+<scxml datamodel="ecmascript">
+ <script src="http://uscxml.tk.informatik.tu-darmstadt.de/scripts/dump.js" />
+
+ <script>
+//<![CDATA[
+ function clone(item) {
+ if (!item) { return item; } // null, undefined values check
+
+ var types = [ Number, String, Boolean ],
+ result;
+
+ // normalizing primitives if someone did new String('aaa'), or new Number('444');
+ types.forEach(function(type) {
+ if (item instanceof type) {
+ result = type( item );
+ }
+ });
+
+ if (typeof result == "undefined") {
+ if (Object.prototype.toString.call( item ) === "[object Array]") {
+ result = [];
+ item.forEach(function(child, index, array) {
+ result[index] = clone( child );
+ });
+ } else if (typeof item == "object") {
+ // testing that this is DOM
+ if (item.nodeType && typeof item.cloneNode == "function") {
+ var result = item.cloneNode( true );
+ } else if (!item.prototype) { // check that this is a literal
+ if (item instanceof Date) {
+ result = new Date(item);
+ } else {
+ // it is an object literal
+ result = {};
+ for (var i in item) {
+ result[i] = clone( item[i] );
+ }
+ }
+ } else {
+ // depending what you would like here,
+ // just keep the reference, or create new object
+ if (false && item.constructor) {
+ // would not advice to do that, reason? Read below
+ result = new item.constructor();
+ } else {
+ result = item;
+ }
+ }
+ } else {
+ result = item;
+ }
+ }
+
+ return result;
+ }
+//]]>
+ </script>
+
+ <datamodel>
+ <data id="modelDir" />
+ <data id="requests">{}</data>
+ </datamodel>
+
+ <state id="start">
+ <onentry>
+ <log expr="modelDir" />
+ </onentry>
+ <invoke type="osgconvert" id="osgvonvert.frame">
+ <param name="threads" expr="1" />
+ <finalize>
+ <script>
+ requests[_event.data.context].job.renderedFrames++;
+ </script>
+ <!-- osgconverter will copy its send request for the reply so these are still available -->
+ <send target="#_ffmpeg" event="render.frame">
+ <param name="frame" expr="_event.data.content.bmp" />
+ <param name="context" expr="_event.data.context" />
+ </send>
+ <if cond="requests[_event.data.context].job.renderedFrames &gt;= requests[_event.data.context].job.totalFrames">
+ <send target="#_ffmpeg" event="render.end">
+ <param name="context" expr="_event.data.context" />
+ </send>
+ </if>
+ </finalize>
+ </invoke>
+
+ <invoke type="ffmpeg" id="ffmpeg">
+ <finalize>
+ <script>
+// dump(_event);
+ </script>
+ <send target="#_parent" event="render.done">
+ <param name="context" expr="_event.data.context" />
+ <param name="movie" expr="_event.data.movie" />
+ <param name="mimetype" expr="_event.data.mimetype" />
+ <param name="filename" expr="_event.data.filename" />
+ </send>
+ <script>
+ // free up job in requests
+ requests[_event.data.context] = undefined;
+ </script>
+
+ </finalize>
+ </invoke>
+
+ <state id ="idle">
+ <!-- <onentry>
+ <script>
+ print("Invokers:");
+ dump(_invokers['ffmpeg']);
+ </script>
+ </onentry> -->
+ <transition event="http.post" target="idle" cond="
+ _event.data.pathComponent.length == 2 &amp;&amp;
+ _event.data.pathComponent[1] === 'movie'">
+ <!--
+ Something to encode just arrived.
+ Interpolate pose information and send each frame to the osg converter.
+ The finalize of the osgconverter will send the images to ffmpeg whose
+ finalize will trigger the response.
+ -->
+ <script>
+//<![CDATA[
+// dump(_event);
+ var pathDelim = ':'; // we need to flatten directories - this will seperate them in filenames
+
+ // store event
+ var job = {};
+ job.event = _event;
+ job.framesPerSec = 25;
+ job.lengthInSec = _event.data.content.data.movieLength;
+ job.format = _event.data.content.data.format;
+ job.height = _event.data.content.data.height;
+ job.width = _event.data.content.data.width;
+ job.keyFrames = _event.data.content.data.frames;
+ job.frames = [];
+ job.totalFrames = job.lengthInSec * job.framesPerSec
+ job.renderedFrames = 0;
+
+ // sanitize
+ if (job.height % 2)
+ job.height++;
+ if (job.width % 2)
+ job.width++;
+
+ // calculate overall relative length
+ var totalRelLength = 0;
+ for (var index in job.keyFrames) {
+ totalRelLength += job.keyFrames[index].relFrameLength;
+ }
+ var framesToRelLength = job.totalFrames / totalRelLength;
+
+ // create frames
+ for (var kfIndex = 0; job.keyFrames[kfIndex]; kfIndex++) {
+ var nextPose = false;
+ if (job.keyFrames[kfIndex + 1]) {
+ nextPose = job.keyFrames[kfIndex + 1].pose;
+ }
+ var keyFrame = job.keyFrames[kfIndex];
+
+ keyFrame.modelFile = keyFrame.imageURL.substr(keyFrame.serverURL.length + 1);
+ keyFrame.file = keyFrame.modelFile.substr(0, keyFrame.modelFile.indexOf('.'));
+ keyFrame.ext = keyFrame.modelFile.substr(keyFrame.modelFile.indexOf('.') + 1);
+
+ keyFrame.modelFile = keyFrame.file + ".osgb";
+ keyFrame.modelFile = keyFrame.modelFile.replace(/\//g, pathDelim);
+ keyFrame.modelFile = modelDir + '/' + keyFrame.modelFile;
+
+ var currentPose = keyFrame.pose;
+ var thisFrames = Math.round(keyFrame.relFrameLength * framesToRelLength);
+ var startTransitionAt = Math.round((100 - keyFrame.relTransitionLength) * 0.01 * thisFrames);
+ var transitionFrames = thisFrames - startTransitionAt;
+
+ //print("---------------------\n");
+ //print("lengthInSec: " + job.lengthInSec + "\n");
+ //print("totalFrames: " + job.totalFrames + "\n");
+ //print("thisFrames for " + kfIndex + ": " + thisFrames + "\n");
+ //print("startTransitionAt for " + kfIndex + ": " + startTransitionAt + "\n");
+ //print("transitionFrames for " + kfIndex + ": " + transitionFrames + "\n");
+
+ for (var frameIndex = 0; frameIndex < thisFrames && job.frames.length <= job.totalFrames; frameIndex++) {
+ var frame = clone(keyFrame);
+
+ if (frameIndex > startTransitionAt && nextPose) {
+
+ var transitionProgress = (frameIndex - startTransitionAt) / transitionFrames;
+ frame.pose.pitch += (nextPose.pitch - frame.pose.pitch) * transitionProgress;
+ frame.pose.roll += (nextPose.roll - frame.pose.roll) * transitionProgress;
+ frame.pose.yaw += (nextPose.yaw - frame.pose.yaw) * transitionProgress;
+ frame.pose.x += (nextPose.x - frame.pose.x) * transitionProgress;
+ frame.pose.y += (nextPose.y - frame.pose.y) * transitionProgress;
+ frame.pose.z += (nextPose.z - frame.pose.z) * transitionProgress;
+ frame.pose.zoom += (nextPose.zoom - frame.pose.zoom) * transitionProgress;
+
+ //print("#########################\n");
+ //print("Transition at: " + frameIndex + " \ Progress: " + transitionProgress + "\n");
+ //print("Interpolated pose:\n")
+ //dump(frame.pose);
+ }
+
+ job.frames.push(frame);
+ }
+ }
+ requests[_event.origin] = {};
+ requests[_event.origin].job = job;
+//]]>
+ </script>
+ <send target="#_ffmpeg" event="render.start" idlocation="requests[_event.origin].sendId">
+ <param name="context" expr="_event.origin" />
+ <param name="format" expr="requests[_event.origin].job.format" />
+ <param name="width" expr="requests[_event.origin].job.width" />
+ <param name="height" expr="requests[_event.origin].job.height" />
+ </send>
+ <foreach array="requests[_event.origin].job.frames" item="frame" index="index">
+ <send target="#_osgvonvert.frame">
+ <param name="format" expr="'bmp'" />
+ <!-- param name="dest" expr="'/Users/sradomski/Desktop/ctrl/' + index + '.bmp'" / -->
+ <param name="source" expr="frame.modelFile" />
+ <param name="pitch" expr="frame.pose.pitch" />
+ <param name="roll" expr="frame.pose.roll" />
+ <param name="yaw" expr="frame.pose.yaw" />
+ <param name="zoom" expr="frame.pose.zoom" />
+ <param name="x" expr="frame.pose.x" />
+ <param name="y" expr="frame.pose.y" />
+ <param name="z" expr="frame.pose.z" />
+ <param name="width" expr="requests[_event.origin].job.width" />
+ <param name="height" expr="requests[_event.origin].job.height" />
+ <param name="autorotate" expr="frame.pose.autorotate" />
+ <param name="context" expr="_event.origin" />
+ </send>
+ </foreach>
+ </transition>
+
+ <transition event="http.get" target="idle" cond="
+ _event.data.pathComponent.length == 3 &amp;&amp;
+ _event.data.pathComponent[1] === 'movie' &amp;&amp;
+ _event.data.pathComponent[2] === 'codecs'">
+ <send target="#_parent" event="send.codecs">
+ <param name="context" expr="_event.origin" />
+ <param name="codecs" expr="_invokers['ffmpeg']" />
+ </send>
+ </transition>
+ </state>
+ </state>
+</scxml> \ No newline at end of file
diff --git a/apps/samples/vrml/img/close.png b/apps/samples/vrml/img/close.png
new file mode 100644
index 0000000..7233cbe
--- /dev/null
+++ b/apps/samples/vrml/img/close.png
Binary files differ
diff --git a/apps/samples/vrml/img/pitchRoll-handle.png b/apps/samples/vrml/img/pitchRoll-handle.png
new file mode 100644
index 0000000..fcff0dd
--- /dev/null
+++ b/apps/samples/vrml/img/pitchRoll-handle.png
Binary files differ
diff --git a/apps/samples/vrml/img/pitchRoll.pxm b/apps/samples/vrml/img/pitchRoll.pxm
new file mode 100644
index 0000000..1dbc3e2
--- /dev/null
+++ b/apps/samples/vrml/img/pitchRoll.pxm
Binary files differ
diff --git a/apps/samples/vrml/img/xy-handle.png b/apps/samples/vrml/img/xy-handle.png
new file mode 100644
index 0000000..0edb8cc
--- /dev/null
+++ b/apps/samples/vrml/img/xy-handle.png
Binary files differ
diff --git a/apps/samples/vrml/img/xy.pxm b/apps/samples/vrml/img/xy.pxm
new file mode 100644
index 0000000..5e077ef
--- /dev/null
+++ b/apps/samples/vrml/img/xy.pxm
Binary files differ
diff --git a/apps/samples/vrml/img/yawZoom-handle.png b/apps/samples/vrml/img/yawZoom-handle.png
new file mode 100644
index 0000000..f6a54ee
--- /dev/null
+++ b/apps/samples/vrml/img/yawZoom-handle.png
Binary files differ
diff --git a/apps/samples/vrml/img/yawZoom.pxm b/apps/samples/vrml/img/yawZoom.pxm
new file mode 100644
index 0000000..ec00b18
--- /dev/null
+++ b/apps/samples/vrml/img/yawZoom.pxm
Binary files differ
diff --git a/apps/samples/vrml/stress-vrml-server.pl b/apps/samples/vrml/stress-vrml-server.pl
new file mode 100755
index 0000000..4145f29
--- /dev/null
+++ b/apps/samples/vrml/stress-vrml-server.pl
@@ -0,0 +1,35 @@
+#!/usr/bin/perl -w
+
+use Math::Round;
+
+my $pi = 3.14159;
+
+# make one thousand requests with random parameters
+for (my $i = 0; $i < 1000; $i++) {
+ my $pitch = rand(2*$pi);
+ my $roll = rand(2*$pi);
+ my $yaw = rand(2*$pi);
+ my $width = rand(400) + 200;
+ my $height = rand(400) + 200;
+ my $url = "http://epikur.local:8080/vrml/HARD_MP_VAL_002.png".
+ "?pitch=".sprintf("%.3f",$pitch).
+ "&roll=".sprintf("%.3f",$roll).
+ "&yaw=".sprintf("%.3f",$yaw).
+ "&width=".sprintf("%.0f",$width).
+ "&height=".sprintf("%.0f",$height);
+ print $url."\n";
+ `wget '$url'`;
+}
+
+# for (my $pitch = 0; $pitch < 2*$pi; $pitch += 0.01) {
+# for (my $roll = 0; $roll < 2*$pi; $roll += 0.01) {
+# for (my $yaw = 0; $yaw < 2*$pi; $yaw += 0.01) {
+# my $url = "http://epikur.local:8081/vrml/HARD_MP_VAL_002.png".
+# "?pitch=".sprintf("%.3f",$pitch).
+# "&roll=".sprintf("%.3f",$roll).
+# "&yaw=".sprintf("%.3f",$yaw);
+# print $url."\n";
+# `wget '$url'`;
+# }
+# }
+# } \ No newline at end of file
diff --git a/apps/samples/vrml/viewer.html b/apps/samples/vrml/viewer.html
index 9838c33..6e139e7 100644
--- a/apps/samples/vrml/viewer.html
+++ b/apps/samples/vrml/viewer.html
@@ -22,7 +22,22 @@
height:200px;
padding:7px;
}
- </style>
+ .tundra .dijitTooltipContainer {
+ background-color:rgba(200,200,200,0.5);
+ background:rgba(200,200,200,0.5);
+ }
+/* .removeThumb {
+ background-image: url(img/close.png);
+ background-repeat: no-repeat;
+ background-size: 100%;
+ text-align: center;
+ border: 0px;
+ width: 20px;
+ height: 20px;
+ vertical-align: top;
+ margin: -3px 0px 0px -8px;
+ }
+*/ </style>
<script type="text/javascript">
// dojoConfig = {
@@ -51,8 +66,8 @@
"height" : 400,
"autorotate" : false
},
- "serverURL": "http://smartvortex.tbm.tudelft.nl:8090/vrml",
- "imageURL": "http://smartvortex.tbm.tudelft.nl:8090/vrml/hook/HARD_MP_VAL_005.png"
+// "serverURL": "http://smartvortex.tbm.tudelft.nl:8090/vrml",
+// "imageURL": "http://smartvortex.tbm.tudelft.nl:8090/vrml/hook/HARD_MP_VAL_005.png"
});
var viewer2 = new VRMLViewer("scene2");
// var annotations = new Annotations("annotations1", { 'viewer': viewer });
diff --git a/apps/samples/vrml/viewer.js b/apps/samples/vrml/viewer.js
index 4cc167c..583f06f 100644
--- a/apps/samples/vrml/viewer.js
+++ b/apps/samples/vrml/viewer.js
@@ -35,6 +35,9 @@ function VRMLViewer(element, params) {
this.updateScene = function() {
if (self.imageURL && !self.batchChanges) {
self.imgElem.src = self.imageURL + urlSuffixForPose(self.pose);
+ // we are showing an image, activate additional controls
+ self.movieAddButton.domNode.style.display = "";
+ self.movieDropDown.domNode.style.display = "";
}
};
@@ -67,18 +70,52 @@ function VRMLViewer(element, params) {
return {x: lx,y: ly};
};
+ 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;
+ selectElem.options.push({ label: result.video[codec].longName, value: codec });
+ if (codec === "mpeg4")
+ selectElem[selectElem.options.length - 1].selected = true;
+ }
+ }
+ });
+ }
+
this.refreshServer = function(server) {
self.serverURL = server;
self.localStorage.put("vrmlServer", self.serverURL, null);
- self.progressElem.appendChild(self.progress.domNode);
- self.progress.start();
+// self.progressElem.appendChild(self.progress.domNode);
+// self.progress.start();
self.xhr.get({
// The URL to request
url: server,
handleAs:"json",
headers:{"X-Requested-With":null},
load: function(result) {
- self.progress.stop();
+// self.progress.stop();
for (id in self.fileStore.query) {
self.fileStore.remove(id);
}
@@ -140,7 +177,10 @@ function VRMLViewer(element, params) {
"dijit/TooltipDialog",
"dojo/dnd/Moveable",
"dojo/ready",
- "dojo/dnd/Source"],
+ "dojo/dnd/Source",
+ "dijit/form/HorizontalSlider",
+ "dijit/form/Select",
+ "dijit/form/NumberSpinner"],
function(domConst,
xhr,
dom,
@@ -157,7 +197,10 @@ function VRMLViewer(element, params) {
TooltipDialog,
Moveable,
ready,
- Source) {
+ Source,
+ HorizontalSlider,
+ Selector,
+ NumberSpinner) {
ready(function() {
@@ -185,7 +228,11 @@ function VRMLViewer(element, params) {
</div>\
<div style="position: absolute; left: 10px; top: 10px">\
<table></tr>\
- <td class="browseDropDown" style="vertical-align: middle"></td>\
+ <td class="filesDropDown" style="vertical-align: middle"></td>\
+ <td>\
+ <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="dragHandler" style="vertical-align: middle; padding-top: 4px;"></td>\
</tr></table>\
@@ -193,31 +240,33 @@ function VRMLViewer(element, params) {
<div style="position: absolute; right: 10px; top: 15%; height: 50%">\
<div class="zoomSlide"></div>\
</div>\
- <div style="position: absolute; right: 55%; top: 48%">\
+ <div 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.png" width="20px" style="padding: 2px 0px 0px 4px;" /></td>\
+ <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 style="position: absolute; right: 45%; top: 48%">\
- <div class="yawZoomHandler" 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="yawZoomHandlerImg" src="' + self.resRoot + 'img/yawZoom.png" width="20px" style="padding: 2px 0px 0px 4px;" /></td>\
- <td><div class="yawLabel"></div><div class="zoomLabel"></div></td>\
- </tr>\
- </table>\
+ <div 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 style="position: absolute; right: 50%; top: 58%">\
+ <div 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.png" width="20px" style="padding: 2px 0px 0px 4px;" /></td>\
+ <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>\
@@ -237,7 +286,9 @@ function VRMLViewer(element, params) {
// fetch special dom nodes for content
self.messageBox = dojo.query("div.messages", element)[0];
self.imgElem = dojo.query("img.model", element)[0];
- self.browseDropDownElem = dojo.query("td.browseDropDown", element)[0];
+ self.filesDropDownElem = dojo.query("td.filesDropDown", element)[0];
+ self.movieDropDownElem = dojo.query("div.movieDropDown", element)[0];
+ self.movieAddButtonElem = dojo.query("button.movieAddButton", element)[0];
self.resetButtonElem = dojo.query("button.resetButton", element)[0];
self.progressElem = dojo.query("div.progress", element)[0];
@@ -266,10 +317,18 @@ function VRMLViewer(element, params) {
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.pitch = self.pose.pitch % (2 * 3.14159);
// self.pose.roll = self.pose.roll % (2 * 3.14159);
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;
@@ -295,6 +354,13 @@ function VRMLViewer(element, params) {
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;
@@ -324,6 +390,13 @@ function VRMLViewer(element, params) {
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;
@@ -348,7 +421,7 @@ function VRMLViewer(element, params) {
item.imageURL = self.imageURL;
item.serverURL = self.serverURL;
item.pose = avatarPose;
- return {node: avatar, data: item, type: item.type};
+ 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};
@@ -375,7 +448,7 @@ function VRMLViewer(element, params) {
model: self.fileTreeModel,
persist: false,
showRoot: false,
- style: "height: 200px;",
+ style: "height: 300px;",
onClick: function(item){
if ('url' in item) {
self.imageURL = item.url;
@@ -405,7 +478,7 @@ function VRMLViewer(element, params) {
self.serverBox = new TextBox({
name: "Server",
value: self.serverURL,
- style: "width: 70%",
+ style: "width: 65%",
onKeyDown: function(e) {
var code = e.keyCode || e.which;
@@ -424,14 +497,203 @@ function VRMLViewer(element, params) {
}
});
- self.browseDropDownContent = domConst.toDom('<div />');
- self.browseDropDownContent.appendChild(self.serverBox.domNode);
- self.browseDropDownContent.appendChild(self.browseButton.domNode);
- self.browseDropDownContent.appendChild(self.fileList.domNode);
+ self.filesDropDownContent = domConst.toDom('<div />');
+ self.filesDropDownContent.appendChild(self.serverBox.domNode);
+ self.filesDropDownContent.appendChild(self.browseButton.domNode);
+ self.filesDropDownContent.appendChild(self.fileList.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.movieDropDownContent = domConst.toDom('<div style="overflow: auto; max-height: 420px;" />');
+
+ 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.imageURL + avatarImgUrl + ' /> ';
+ item.srcEcc = "VRMLViewer";
+ item.iconPoseUrl = self.imageURL + avatarImgUrl;
+ item.imageURL = self.imageURL;
+ item.serverURL = self.serverURL;
+ item.pose = avatarPose;
+ return {node: avatar, data: item, type: item.type};
+ } else {
+ // var thumb = dojo.create( 'div', { innerHTML: item.data });
+
+ // 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>\
+ </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];
+
+ item.relFrameLengthSlider = new HorizontalSlider({
+ value: 50,
+ title: "Relative Duration of Frame",
+ style: "width:150px;"
+ }, relFrameLengthElem);
+
+ item.relTransitionLengthSlider = new HorizontalSlider({
+ value: 80,
+ title: "Relative Duration of Transition",
+ style: "width:150px;"
+ }, relTransitionLengthElem);
+
+ removeImgElem.onclick = function() {
+ self.addToMovieHandler.forInItems(function(obj, key, ctx) {
+ if (obj.data === item) {
+ // haha - what a mess!
+ self.addToMovieHandler.selectNone();
+ self.addToMovieHandler.selection[key] = obj;
+ self.addToMovieHandler.deleteSelectedNodes();
+ }
+ });
+ }
+ 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.imageURL + thumbImgUrl;
+ // removeImgElem.src = self.resRoot + 'img/close.png';
+
+ item.srcEcc = "VRMLViewer";
+ item.iconPoseUrl = self.imageURL + thumbImgUrl;
+ item.imageURL = self.imageURL;
+ item.serverURL = self.serverURL;
+ item.pose = thumbPose;
+
+ return {node: thumb, data: item, type: item.type};
+ }
+ };
+
+ self.addToMovieHandler = new Source(self.movieDropDownContent, {copyOnly: true, creator: self.createMovieThumb});
+
+ self.movieFormatSelection = new Selector({
+ name: "movieFormat",
+ options: []
+ });
+ self.populateMovieCodecs(self.serverURL + '/movie/codecs', self.movieFormatSelection);
+
+ self.movieDropDownContent.appendChild(dojo.create( 'div', {
+ innerHTML: "Format: ",
+ style: "margin-right: 1em; margin-left: 0.2em; display:inline;"
+ }));
+ self.movieDropDownContent.appendChild(self.movieFormatSelection.domNode);
+
+ self.movieDurationSpinner = new NumberSpinner({
+ value: 10,
+ smallDelta: 1,
+ style: "width: 40px",
+ constraints: { min:0, places:0 },
+ });
+ self.movieDropDownContent.appendChild(self.movieDurationSpinner.domNode);
+ self.movieDropDownContent.appendChild(dojo.create( 'div', {
+ innerHTML: "sec ",
+ style: "margin-right: 1em; margin-left: 0.2em; display:inline;"
+ }));
+
+ self.movieHeightSpinner = new NumberSpinner({
+ value: 400,
+ smallDelta: 1,
+ style: "width: 60px",
+ constraints: { min:40, places:0 },
+ });
+ self.movieDropDownContent.appendChild(self.movieHeightSpinner.domNode);
+ self.movieDropDownContent.appendChild(dojo.create( 'div', {
+ innerHTML: "x",
+ style: "margin-right: 0.5em; margin-left: 0.5em; display:inline;"
+ }));
+
+ self.movieWidthSpinner = new NumberSpinner({
+ value: 600,
+ smallDelta: 1,
+ style: "width: 60px",
+ constraints: { min:40, places:0 },
+ });
+ self.movieDropDownContent.appendChild(self.movieWidthSpinner.domNode);
+
+ self.movieCreateButton = new Button({
+ label: "Create",
+ 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,
+ imageURL: obj.data.imageURL,
+ 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);
+
+ document.body.appendChild(form);
+ form.submit();
+ document.body.removeChild(form);
+ }
+ });
+ self.movieDropDownContent.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(){
+ // we could pass item.data here to creator
+ self.addToMovieHandler.insertNodes(false, [ { } ]);
+ }
+ }, self.movieAddButtonElem);
- self.browseToolTip = new TooltipDialog({ content:self.browseDropDownContent, style:"max-height:200px"});
- self.browseDropDown = new DropDownButton({ label: "Files", dropDown: self.browseToolTip });
- self.browseDropDownElem.appendChild(self.browseDropDown.domNode);
self.resetButton = new Button({
label: "Reset",
diff --git a/apps/samples/vrml/vrml-server.scxml b/apps/samples/vrml/vrml-server.scxml
index 8563cb9..20d63a6 100644
--- a/apps/samples/vrml/vrml-server.scxml
+++ b/apps/samples/vrml/vrml-server.scxml
@@ -5,55 +5,11 @@
<script>
var wrls = {}; // information of the wrl, vrml files
var models = {}; // information of the osgb files
- var processed = {}; // information about processed files
var pathDelim = ':'; // we need to flatten directories - this will seperate them in filenames
- /**
- * This pattern matches the query string we use as part of generated image filenames
- */
- var numPattern = '(-?[0-9]+\.?[0-9]*)';
- var formatPattern = new RegExp(
- '-(' + numPattern + // pitch
- '_' + numPattern + // roll
- '_' + numPattern + // yaw
- '_' + numPattern + // zoom
- '_' + numPattern + // x
- '_' + numPattern + // y
- '_' + numPattern + // z
- '_' + numPattern + // width
- '_' + numPattern + // height
- '_(off|on)' + // autorotate
- ')\\.\\w+$'); // end
-
- /**
- * Transform a file we found into a processed or model struct
- */
- function fileToStruct(file) {
- var struct = {};
- var formatMatch = formatPattern.exec(file.name);
- // is this a processed file?
- if (formatMatch &amp;&amp; formatMatch.length == 12) {
- struct.key = file.relDir.replace(/\//g, pathDelim).substr(1) + file.name.substr(0, file.name.length - formatMatch[0].length);
- struct.format = formatMatch[1] + '.' + file.extension;
- struct.pitch = parseFloat(formatMatch[2]);
- struct.roll = parseFloat(formatMatch[3]);
- struct.yaw = parseFloat(formatMatch[4]);
- struct.zoom = parseFloat(formatMatch[5]);
- struct.x = parseFloat(formatMatch[6]);
- struct.y = parseFloat(formatMatch[7]);
- struct.z = parseFloat(formatMatch[8]);
- struct.width = parseFloat(formatMatch[9]);
- struct.height = parseFloat(formatMatch[10]);
- struct.autorotate = parseFloat(formatMatch[11]);
- } else {
- struct.key = file.relDir.replace(/\//g, pathDelim).substr(1) + file.strippedName;
- }
- return struct;
- }
-
/**
- * Transform a http request into something to look up in the processed structure
+ * Transform a http request into a pose
*/
function reqToStruct(req) {
var struct = {};
@@ -80,21 +36,14 @@
struct.key += pathDelim;
struct.key += struct.file;
- struct.format =
- struct.pitch + '_' +
- struct.roll + '_' +
- struct.yaw + '_' +
- struct.zoom + '_' +
- struct.x + '_' +
- struct.y + '_' +
- struct.z + '_' +
- struct.width + '_' +
- struct.height + '_' +
- struct.autorotate + '.' +
- struct.ext;
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;
@@ -176,38 +125,21 @@
<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>
- _event.fileStruct = fileToStruct(_event.data.file);
- if (_event.data.file.extension === "osgb") {
- // this is a binary 3D file converted from the wrls
-
- if (_event.name === "file.deleted") {
- delete models[_event.fileStruct.key];
- print("Removed a vanished osgb file at " + _event.fileStruct.key + "\n");
- } else {
- models[_event.fileStruct.key] = _event.data.file;
- models[_event.fileStruct.key].group = '/' + _event.data.file.name.split(pathDelim).slice(0,-1).join('/');
- print("Inserted a new osgb file at " + _event.fileStruct.key + "\n");
- }
-
- } else if ('format' in _event.fileStruct) {
- // this is a processed file generated for some request
-
- if (_event.name === "file.deleted") {
- delete processed[_event.fileStruct.key][_event.fileStruct.format];
- print("Removed a vanished processed file at " + _event.fileStruct.key + "\n");
- } else {
- if (!(_event.fileStruct.key in processed)) {
- processed[_event.fileStruct.key] = {}
- }
- processed[_event.fileStruct.key][_event.fileStruct.format] = _event.data.file;
- print("Inserted a new processed file at " + _event.fileStruct.key + "\n");
- }
+ 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 " + _event.fileStruct.key + "\n");
} else {
- print("Ignoring " + _event.data.file.name + "\n");
+ 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>
@@ -220,23 +152,21 @@
<param name="suffix" expr="'vrml wrl'" />
<finalize>
<script>
- _event.fileStruct = fileToStruct(_event.data.file);
+ _event.key = keyForFile(_event.data.file);
if (_event.name === "file.existing" || _event.name === "file.added") {
- wrls[_event.fileStruct.key] = _event.data.file;
- print("Inserting wrl " + _event.data.file.path + " from " +_event.data.file.relDir + " at " + _event.fileStruct.key + "\n");
+ wrls[_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.fileStruct.key];
- print("Deleting wrl " + _event.data.file.path + " from " +_event.data.file.relDir + " at " + _event.fileStruct.key + "\n");
+ delete wrls[_event.key];
+ print("Deleting wrl " + _event.data.file.path + " from " +_event.data.file.relDir + " at " + _event.key + "\n");
}
</script>
<if cond="models &amp;&amp;
- (!(_event.fileStruct.key in models) ||
- wrls[_event.fileStruct.key].mtime > models[_event.fileStruct.key].mtime)
- ">
+ (!(_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.fileStruct.key + '.osgb'" />
+ <param name="dest" expr="_x['args']['tmp-path'] + '/' + _event.key + '.osgb'" />
</send>
</if>
</finalize>
@@ -244,83 +174,59 @@
<!-- Start the osgconvert invoker to transform 3D files -->
<invoke type="osgconvert" id="osgvonvert.osgb">
- <param name="threads" expr="4" />
- <!--finalize>
+ <param name="threads" expr="20" />
+ <finalize>
<script>
- // we could put the file into the osgbs or processed here, but we rely on the directory monitors for now
- print("Received " + _event.name + " regarding " + _event.data.dest + "\n");
+ //dump(_event);
</script>
- </finalize-->
+ <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="*" />
+ <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.scxml" autoforward="true">
+ <param name="modelDir" expr="_x['args']['tmp-path']" />
+ </invoke>
+
<!-- Idle here -->
<state id="idle">
- <!--onentry>
- <log expr="_event" />
- </onentry -->
<transition event="http.get" target="idle" cond="
_event.data.pathComponent.length >= 2 &amp;&amp;
_event.data.pathComponent[_event.data.pathComponent.length - 1].indexOf('.') !== -1">
- <!-- request for a specific format
- http://host/vrml/relative/path/format?query=string -->
+ <!-- request for a specific format http://host/vrml/relative/path/format?query=string -->
<script>
_event.fileStruct = reqToStruct(_event.data);
- _event.dest = _x['args']['tmp-path'] + '/' + _event['fileStruct'].key + '-' + _event['fileStruct'].format;
-
- print("Got a request for [" + _event['fileStruct'].key + '-' + _event['fileStruct'].format + "]\n");
-// dump(_event);
</script>
- <if cond="_event['fileStruct'].key in models &amp;&amp; isSupportedFormat(_event['fileStruct'].ext)">
+ <if cond="_event.fileStruct.key in models &amp;&amp; isSupportedFormat(_event['fileStruct'].ext)">
<!-- There is such a file available as osgb -->
- <if cond="
- _event['fileStruct'].key in processed &amp;&amp;
- _event['fileStruct'].format in processed[_event['fileStruct'].key]">
- <script>
- //print("Sending " + processed[_event['fileStruct'].key][_event['fileStruct'].format].path + "\n");
- </script>
- <respond status="200" to="_event.origin">
- <header name="Connection" value="close" />
- <header name="Access-Control-Allow-Origin" value="*" />
- <content fileexpr="processed[_event['fileStruct'].key][_event['fileStruct'].format].path" />
- </respond>
- <else />
- <if cond="_event.name.endsWith('postponed')">
- <!--
- A postponed event we couldn't answer
- -->
- <respond status="404" to="_event.origin">
- <header name="Connection" value="close" />
- </respond>
- <else />
- <script>
- print("Processing outfile " + _event['dest'] + " from model " + _event['file'] + "\n");
- </script>
- <send target="#_osgvonvert.osgb">
- <param name="source" expr="models[_event['fileStruct'].key].path" />
- <param name="dest" expr="_event['dest']" />
- <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" />
- </send>
- <!--
- Redeliver the event once the untilexpr is true. The untilexpr has to evaluate
- into another valid expression that we will check again on stable configurations.
- -->
- <postpone
- untilexpr="
- '\'' + _event['fileStruct'].key + '\' in processed &amp;&amp;
- \'' + _event['fileStruct'].format + '\'' + ' in processed[\'' + _event['fileStruct'].key + '\'] ||
- _event.name === \'convert.failure\' &amp;&amp; _event.data.dest === \'' + _event['dest'] + '\''
- "/>
- </if>
- </if>
+ <send target="#_osgvonvert.osgb">
+ <param name="source" expr="models[_event['fileStruct'].key].path" />
+ <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">
@@ -346,18 +252,6 @@
<transition event="http.get" target="idle" cond="
_event.data.pathComponent.length == 2 &amp;&amp;
- _event.data.pathComponent[1] === 'processed'">
- <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="processed" />
- </respond>
- </transition>
-
- <transition event="http.get" target="idle" cond="
- _event.data.pathComponent.length == 2 &amp;&amp;
_event.data.pathComponent[1] === 'wrls'">
<script>//dump(_event)</script>
<respond status="200" to="_event.origin">
@@ -367,7 +261,7 @@
<content expr="wrls" />
</respond>
</transition>
-
+
<!-- request for topmost list of all files -->
<transition event="http.get" target="idle" cond="
_event.data.pathComponent.length == 1">
@@ -382,14 +276,34 @@
<!-- XHR CORS preflight response -->
<transition event="http.options" target="idle">
- <script>dump(_event);</script>
+ <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" />
diff --git a/apps/samples/vrml/vrml-server.scxml.old b/apps/samples/vrml/vrml-server.scxml.old
new file mode 100644
index 0000000..70a7c3a
--- /dev/null
+++ b/apps/samples/vrml/vrml-server.scxml.old
@@ -0,0 +1,416 @@
+<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 processed = {}; // information about processed files
+
+ var pathDelim = ':'; // we need to flatten directories - this will seperate them in filenames
+
+ /**
+ * This pattern matches the query string we use as part of generated image filenames
+ */
+ var numPattern = '(-?[0-9]+\.?[0-9]*)';
+ var formatPattern = new RegExp(
+ '-(' + numPattern + // pitch
+ '_' + numPattern + // roll
+ '_' + numPattern + // yaw
+ '_' + numPattern + // zoom
+ '_' + numPattern + // x
+ '_' + numPattern + // y
+ '_' + numPattern + // z
+ '_' + numPattern + // width
+ '_' + numPattern + // height
+ '_(off|on)' + // autorotate
+ ')\\.\\w+$'); // end
+
+ /**
+ * Transform a file we found into a processed or model struct
+ */
+ function fileToStruct(file) {
+ var struct = {};
+ var formatMatch = formatPattern.exec(file.name);
+ // is this a processed file?
+ if (formatMatch &amp;&amp; formatMatch.length == 12) {
+ struct.key = file.relDir.replace(/\//g, pathDelim).substr(1) + file.name.substr(0, file.name.length - formatMatch[0].length);
+ struct.format = formatMatch[1] + '.' + file.extension;
+ struct.pitch = parseFloat(formatMatch[2]);
+ struct.roll = parseFloat(formatMatch[3]);
+ struct.yaw = parseFloat(formatMatch[4]);
+ struct.zoom = parseFloat(formatMatch[5]);
+ struct.x = parseFloat(formatMatch[6]);
+ struct.y = parseFloat(formatMatch[7]);
+ struct.z = parseFloat(formatMatch[8]);
+ struct.width = parseFloat(formatMatch[9]);
+ struct.height = parseFloat(formatMatch[10]);
+ struct.autorotate = parseFloat(formatMatch[11]);
+ } else {
+ struct.key = file.relDir.replace(/\//g, pathDelim).substr(1) + file.strippedName;
+ }
+ return struct;
+ }
+
+ /**
+ * Transform a http request into something to look up in the processed structure
+ */
+ function reqToStruct(req) {
+ var struct = {};
+
+ var query = (('query' in req) ? req.query : {});
+
+ struct.pitch = (('pitch' in query &amp;&amp; isNumber(query.pitch)) ? query.pitch : 0);
+ struct.roll = (('roll' in query &amp;&amp; isNumber(query.roll)) ? query.roll : 0);
+ struct.yaw = (('yaw' in query &amp;&amp; isNumber(query.yaw)) ? query.yaw : 0);
+ struct.zoom = (('zoom' in query &amp;&amp; isNumber(query.zoom)) ? query.zoom : 1);
+ struct.x = (('x' in query &amp;&amp; isNumber(query.x)) ? query.x : 0);
+ struct.y = (('y' in query &amp;&amp; isNumber(query.y)) ? query.y : 0);
+ struct.z = (('z' in query &amp;&amp; isNumber(query.z)) ? query.z : 0);
+ struct.width = (('width' in query &amp;&amp; isNumber(query.width)) ? query.width : 640);
+ struct.height = (('height' in query &amp;&amp; isNumber(query.height)) ? query.height : 480);
+ struct.autorotate = (('autorotate' in query &amp;&amp; (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;
+ struct.key += struct.file;
+
+ struct.format =
+ struct.pitch + '_' +
+ struct.roll + '_' +
+ struct.yaw + '_' +
+ struct.zoom + '_' +
+ struct.x + '_' +
+ struct.y + '_' +
+ struct.z + '_' +
+ struct.width + '_' +
+ struct.height + '_' +
+ struct.autorotate + '.' +
+ struct.ext;
+ return struct;
+ }
+
+ 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)) &amp;&amp; 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 &lt; 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" />
+ <!-- Called for every file we found -->
+ <finalize>
+ <script>
+ _event.fileStruct = fileToStruct(_event.data.file);
+
+ if (_event.data.file.extension === "osgb") {
+ // this is a binary 3D file converted from the wrls
+
+ if (_event.name === "file.deleted") {
+ delete models[_event.fileStruct.key];
+ print("Removed a vanished osgb file at " + _event.fileStruct.key + "\n");
+ } else {
+ models[_event.fileStruct.key] = _event.data.file;
+ models[_event.fileStruct.key].group = '/' + _event.data.file.name.split(pathDelim).slice(0,-1).join('/');
+ print("Inserted a new osgb file at " + _event.fileStruct.key + "\n");
+ }
+
+ } else if ('format' in _event.fileStruct) {
+ // this is a processed file generated for some request
+
+ if (_event.name === "file.deleted") {
+ delete processed[_event.fileStruct.key][_event.fileStruct.format];
+ print("Removed a vanished processed file at " + _event.fileStruct.key + "\n");
+ } else {
+ if (!(_event.fileStruct.key in processed)) {
+ processed[_event.fileStruct.key] = {}
+ }
+ processed[_event.fileStruct.key][_event.fileStruct.format] = _event.data.file;
+ print("Inserted a new processed file at " + _event.fileStruct.key + "\n");
+ }
+ } else {
+ print("Ignoring " + _event.data.file.name + "\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.fileStruct = fileToStruct(_event.data.file);
+ if (_event.name === "file.existing" || _event.name === "file.added") {
+ wrls[_event.fileStruct.key] = _event.data.file;
+ print("Inserting wrl " + _event.data.file.path + " from " +_event.data.file.relDir + " at " + _event.fileStruct.key + "\n");
+ }
+ if (_event.name === "file.deleted") {
+ delete wrls[_event.fileStruct.key];
+ print("Deleting wrl " + _event.data.file.path + " from " +_event.data.file.relDir + " at " + _event.fileStruct.key + "\n");
+ }
+ </script>
+ <if cond="models &amp;&amp;
+ (!(_event.fileStruct.key in models) ||
+ wrls[_event.fileStruct.key].mtime > models[_event.fileStruct.key].mtime)
+ ">
+ <send target="#_osgvonvert.osgb">
+ <param name="source" expr="_event.data.file.path" />
+ <param name="dest" expr="_x['args']['tmp-path'] + '/' + _event.fileStruct.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>
+ <!-- <file operation="write" contentexpr="_event.data.content" sandbox="off" urlexpr="_event.data.dest" /> -->
+ </finalize>
+ <!--finalize>
+ <script>
+ // we could put the file into the osgbs or processed here, but we rely on the directory monitors for now
+ print("Received " + _event.name + " regarding " + _event.data.dest + "\n");
+ </script>
+ </finalize-->
+ </invoke>
+
+ <!-- Start a nested SCXML interpreter to create movies from the images -->
+ <!-- <invoke type="scxml" id="scxml.ffmpeg" src="ffmpeg-server.scxml" autoforward="true">
+ <param name="modelDir" expr="_x['args']['tmp-path']" />
+ </invoke> -->
+
+ <!-- Idle here -->
+ <state id="idle">
+ <!--onentry>
+ <log expr="_event" />
+ </onentry -->
+ <transition event="http.get" target="idle" cond="
+ _event.data.pathComponent.length >= 2 &amp;&amp;
+ _event.data.pathComponent[_event.data.pathComponent.length - 1].indexOf('.') !== -1">
+ <!-- request for a specific format
+ http://host/vrml/relative/path/format?query=string -->
+ <script>
+ _event.fileStruct = reqToStruct(_event.data);
+ _event.dest = _x['args']['tmp-path'] + '/' + _event['fileStruct'].key + '-' + _event['fileStruct'].format;
+ print("Got a request for [" + _event['fileStruct'].key + '-' + _event['fileStruct'].format + "]\n");
+// dump(_event);
+ </script>
+ <if cond="_event['fileStruct'].key in models &amp;&amp; isSupportedFormat(_event['fileStruct'].ext)">
+ <!-- There is such a file available as osgb -->
+ <if cond="
+ _event['fileStruct'].key in processed &amp;&amp;
+ _event['fileStruct'].format in processed[_event['fileStruct'].key]">
+ <script>
+ //print("Sending " + processed[_event['fileStruct'].key][_event['fileStruct'].format].path + "\n");
+ </script>
+ <respond status="200" to="_event.origin">
+ <header name="Connection" value="close" />
+ <header name="Access-Control-Allow-Origin" value="*" />
+ <content fileexpr="processed[_event['fileStruct'].key][_event['fileStruct'].format].path" />
+ </respond>
+ <else />
+ <if cond="_event.name.endsWith('postponed')">
+ <!--
+ A postponed event we couldn't answer
+ -->
+ <respond status="404" to="_event.origin">
+ <header name="Connection" value="close" />
+ </respond>
+ <else />
+ <script>
+ print("Processing outfile " + _event['dest'] + " from model " + _event['file'] + "\n");
+ </script>
+ <send target="#_osgvonvert.osgb">
+ <param name="source" expr="models[_event['fileStruct'].key].path" />
+ <param name="dest" expr="_event['dest']" />
+ <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" />
+ </send>
+ <!--
+ Redeliver the event once the untilexpr is true. The untilexpr has to evaluate
+ into another valid expression that we will check again on stable configurations.
+ -->
+ <postpone
+ untilexpr="
+ '\'' + _event['fileStruct'].key + '\' in processed &amp;&amp;
+ \'' + _event['fileStruct'].format + '\'' + ' in processed[\'' + _event['fileStruct'].key + '\'] ||
+ _event.name === \'convert.failure\' &amp;&amp; _event.data.dest === \'' + _event['dest'] + '\''
+ "/>
+ </if>
+ </if>
+ <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 &amp;&amp;
+ _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 &amp;&amp;
+ _event.data.pathComponent[1] === 'processed'">
+ <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="processed" />
+ </respond>
+ </transition>
+
+ <transition event="http.get" target="idle" cond="
+ _event.data.pathComponent.length == 2 &amp;&amp;
+ _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>
+
+ </state>
+ </state>
+ <state id="final" final="true" />
+</scxml> \ No newline at end of file
diff --git a/apps/w3c-mmi/im/MMISessionManager.cpp b/apps/w3c-mmi/im/MMISessionManager.cpp
index 83d4dea..2e68ff4 100644
--- a/apps/w3c-mmi/im/MMISessionManager.cpp
+++ b/apps/w3c-mmi/im/MMISessionManager.cpp
@@ -1,6 +1,7 @@
#include "MMISessionManager.h"
#include <uscxml/NameSpacingParser.h>
#include <uscxml/concurrency/tinythread.h>
+#include <uscxml/UUID.h>
#include <io/uri.hpp>
#include <glog/logging.h>
@@ -135,7 +136,7 @@ void MMISessionManager::received(const NewContextRequest& mmiEvent, const std::s
newDOM.appendChild(newDOM.importNode(_protoInterpreter.getDocument().getDocumentElement(), true));
// instantiate new interpreter and name it after the context
- std::string contextId = Interpreter::getUUID();
+ std::string contextId = UUID::getUUID();
Interpreter interpreter = Interpreter::fromDOM(newDOM);
interpreter.setFactory(_factory);
interpreter.setName(contextId);