// // playbackMaster.js // acScripts // // Created by Edgar Pironti on 11/17/15. // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // Script.include("./AgentPoolController.js"); HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var masterController = new MasterController(); var input_text = null; // Script. DO NOT MODIFY BEYOND THIS LINE. //Script.include("../libraries/toolBars.js"); Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); // We want small icons Tool.IMAGE_HEIGHT /= 2; Tool.IMAGE_WIDTH /= 2; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; var LOAD = 6; var windowDimensions = Controller.getViewportDimensions(); var TOOL_ICON_URL = HIFI_PUBLIC_BUCKET + "images/tools/"; var ALPHA_ON = 1.0; var ALPHA_OFF = 0.7; var COLOR_TOOL_BAR = { red: 0, green: 0, blue: 0 }; var COLOR_MASTER = { red: 0, green: 0, blue: 0 }; var TEXT_HEIGHT = 12; var TEXT_MARGIN = 3; // Add new features to Actor class: Actor.prototype.destroy = function() { print("Actor.prototype.destroy"); print("Need to fire myself" + this.agentID); masterController.fireAgent(this); } Actor.prototype.resetClip = function(clipURL, onLoadClip) { this.clipURL = clipURL; this.onLoadClip = onLoadClip; if (this.isConnected()) { this.onLoadClip(this); } } Actor.prototype.onMousePressEvent = function(clickedOverlay) { if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { masterController.sendCommand(this.agentID, PLAY); } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { masterController.sendCommand(this.agentID, PLAY_LOOP); } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { masterController.sendCommand(this.agentID, STOP); } else if (this.nameOverlay === clickedOverlay) { print("Actor: " + JSON.stringify(this)); } else { return false; } return true; } Actor.prototype._buildUI = function() { print("Actor.prototype._buildUI = " + JSON.stringify(this)); this.toolbar = new ToolBar(0, 0, ToolBar.HORIZONTAL); this.toolbar.setBack(COLOR_TOOL_BAR, ALPHA_OFF); this.playIcon = this.toolbar.addTool({ imageURL: TOOL_ICON_URL + "play.svg", subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT, alpha: ALPHA_OFF, visible: true }, false); var playLoopWidthFthis = 1.65; this.playLoopIcon = this.toolbar.addTool({ imageURL: TOOL_ICON_URL + "play-and-loop.svg", subImage: { x: 0, y: 0, width: playLoopWidthFthis * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, width: playLoopWidthFthis * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT, alpha: ALPHA_OFF, visible: true }, false); this.stopIcon = this.toolbar.addTool({ imageURL: TOOL_ICON_URL + "recording-stop.svg", width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT, alpha: ALPHA_OFF, visible: true }, false); this.nameOverlay = Overlays.addOverlay("text", { backgroundColor: { red: 0, green: 0, blue: 0 }, font: { size: TEXT_HEIGHT }, text: "AC offline", x: 0, y: 0, width: this.toolbar.width + ToolBar.SPACING, height: TEXT_HEIGHT + TEXT_MARGIN, leftMargin: TEXT_MARGIN, topMargin: TEXT_MARGIN, alpha: ALPHA_OFF, backgroundAlpha: ALPHA_OFF, visible: true }); } Actor.prototype._destroyUI = function() { this.toolbar.cleanup(); Overlays.deleteOverlay(this.nameOverlay); } Actor.prototype.moveUI = function(pos) { var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; this.toolbar.move(pos.x, pos.y); Overlays.editOverlay(this.nameOverlay, { x: this.toolbar.x - ToolBar.SPACING, y: this.toolbar.y - textSize }); } Director = function() { this.actors = new Array(); this.toolbar = null; this._buildUI(); this.requestPerformanceLoad = false; this.performanceURL = ""; }; Director.prototype.destroy = function () { print("Director.prototype.destroy") this.clearActors(); this.toolbar.cleanup(); Overlays.deleteOverlay(this.nameOverlay); } Director.prototype.clearActors = function () { print("Director.prototype.clearActors") while (this.actors.length > 0) { this.actors.pop().destroy(); } this.actors = new Array();// Brand new actors } Director.prototype._buildUI = function () { this.toolbar = new ToolBar(0, 0, ToolBar.HORIZONTAL); this.toolbar.setBack(COLOR_MASTER, ALPHA_OFF); this.onOffIcon = this.toolbar.addTool({ imageURL: TOOL_ICON_URL + "ac-on-off.svg", subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT, alpha: ALPHA_ON, visible: true }, true, true); this.playIcon = this.toolbar.addTool({ imageURL: TOOL_ICON_URL + "play.svg", subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT, alpha: ALPHA_OFF, visible: true }, false); var playLoopWidthFthis = 1.65; this.playLoopIcon = this.toolbar.addTool({ imageURL: TOOL_ICON_URL + "play-and-loop.svg", subImage: { x: 0, y: 0, width: playLoopWidthFthis * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, width: playLoopWidthFthis * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT, alpha: ALPHA_OFF, visible: true }, false); this.stopIcon = this.toolbar.addTool({ imageURL: TOOL_ICON_URL + "recording-stop.svg", width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT, alpha: ALPHA_OFF, visible: true }, false); this.loadIcon = this.toolbar.addTool({ imageURL: TOOL_ICON_URL + "recording-upload.svg", width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT, alpha: ALPHA_OFF, visible: true }, false); this.nameOverlay = Overlays.addOverlay("text", { backgroundColor: { red: 0, green: 0, blue: 0 }, font: { size: TEXT_HEIGHT }, text: "Master", x: 0, y: 0, width: this.toolbar.width + ToolBar.SPACING, height: TEXT_HEIGHT + TEXT_MARGIN, leftMargin: TEXT_MARGIN, topMargin: TEXT_MARGIN, alpha: ALPHA_OFF, backgroundAlpha: ALPHA_OFF, visible: true }); } Director.prototype.onMousePressEvent = function(clickedOverlay) { if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { print("master play"); masterController.sendCommand(BROADCAST_AGENTS, PLAY); } else if (this.onOffIcon === this.toolbar.clicked(clickedOverlay, false)) { this.clearActors(); return true; } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { masterController.sendCommand(BROADCAST_AGENTS, PLAY_LOOP); } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { masterController.sendCommand(BROADCAST_AGENTS, STOP); } else if (this.loadIcon === this.toolbar.clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { print("Performance file ready to be loaded url = " + input_text); this.requestPerformanceLoad = true; this.performanceURL = input_text; } } else if (this.nameOverlay === clickedOverlay) { print("Director: " + JSON.stringify(this)); } else { // Check individual controls for (var i = 0; i < this.actors.length; i++) { if (this.actors[i].onMousePressEvent(clickedOverlay)) { return true; } } return false; // nothing clicked from our known overlays } return true; } Director.prototype.moveUI = function(pos) { var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; var relative = { x: pos.x, y: pos.y + (this.actors.length + 1) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize) }; this.toolbar.move(relative.x, windowDimensions.y - relative.y); Overlays.editOverlay(this.nameOverlay, { x: this.toolbar.x - ToolBar.SPACING, y: this.toolbar.y - textSize }); for (var i = 0; i < this.actors.length; i++) { this.actors[i].moveUI({x: relative.x, y: windowDimensions.y - relative.y + (i + 1) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize)}); } } Director.prototype.reloadPerformance = function() { this.requestPerformanceLoad = false; if (this.performanceURL[0] == '{') { var jsonPerformance = JSON.parse(this.performanceURL); this.onPerformanceLoaded(jsonPerformance); } else { var urlpartition = this.performanceURL.split("."); print(urlpartition[0]); print(urlpartition[1]); if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { print("detected a unique clip url"); var oneClipPerformance = new Object(); oneClipPerformance.avatarClips = new Array(); oneClipPerformance.avatarClips[0] = input_text; print(JSON.stringify(oneClipPerformance)); // we make a local simple performance file with a single clip and pipe in directly this.onPerformanceLoaded(oneClipPerformance); return true; } else { // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? var localThis = this; Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); } } } Director.prototype.onPerformanceLoaded = function(performanceJSON) { // First fire all the current actors this.clearActors(); print("Director.prototype.onPerformanceLoaded = " + JSON.stringify(performanceJSON)); if (performanceJSON.avatarClips != null) { var numClips = performanceJSON.avatarClips.length; print("Found " + numClips + "in the performance file, and currently using " + this.actors.length + " actor(s)"); for (var i = 0; i < numClips; i++) { this.hireActor(performanceJSON.avatarClips[i]); } } } Director.prototype.hireActor = function(clipURL) { print("new actor = " + this.actors.length ); var newActor = new Actor(); newActor.clipURL = null; newActor.onLoadClip = function(clip) {}; var localThis = this; newActor.onHired = function(actor) { print("agent hired from Director! " + actor.agentID) Overlays.editOverlay(actor.nameOverlay, { text: "AC " + actor.agentID, backgroundColor: { red: 0, green: 255, blue: 0 } }); if (actor.clipURL != null) { print("agent hired, calling load clip for url " + actor.clipURL); actor.onLoadClip(actor); } }; newActor.onFired = function(actor) { print("agent fired from playbackMaster! " + actor.agentID); var index = localThis.actors.indexOf(actor); if (index >= 0) { localThis.actors.splice(index, 1); } actor._destroyUI(); actor.destroy(); moveUI(); } newActor.resetClip(clipURL, function(actor) { print("Load clip for agent" + actor.agentID + " calling load clip for url " + actor.clipURL); masterController.sendCommand(actor.agentID, LOAD, actor.clipURL); }); masterController.hireAgent(newActor); newActor._buildUI(); this.actors.push(newActor); moveUI(); } masterController.reset(); var director = new Director(); moveUI(); function mousePressEvent(event) { print("mousePressEvent"); clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); // Check director and actors director.onMousePressEvent(clickedOverlay); } function moveUI() { director.moveUI({ x: 70, y: 75}); } function update(deltaTime) { var newDimensions = Controller.getViewportDimensions(); if (windowDimensions.x != newDimensions.x || windowDimensions.y != newDimensions.y) { windowDimensions = newDimensions; moveUI(); } if (director.requestPerformanceLoad) { print("reloadPerformance " + director.performanceURL); director.reloadPerformance(); } masterController.update(deltaTime); } function scriptEnding() { print("cleanup") director.destroy(); masterController.destroy(); } Controller.mousePressEvent.connect(mousePressEvent); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding);