//// automaticLookAt.js// This script controls the avatar's look-at-target for the head and eyes, according to other avatar's actions// It tries to simulate human interaction during group conversations//// Created by Luis Cuenca on 11/11/19// Copyright 2019 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// (function() { ////////////////////////////////////////////// // debugger.js /////// ////////////////////////////////////////////// var TEXT_BOX_WIDTH = 350; var TEXT_BOX_MIN_HEIGHT = 40; var TEXT_BOX_TOP_MARGIN = 100; var TEXT_CAPTION_HEIGHT = 30; var TEXT_CAPTION_COLOR = { red: 0, green: 0, blue: 0 }; var TEXT_CAPTION_SIZE = 18; var TEXT_CAPTION_MARGIN = 6; var CHECKBOX_MARK_MARGIN = 3; var DEGREE_TO_RADIAN = 0.0174533; var ENGAGED_AVATARS_DEBUG_COLOR = { red: 0, green: 255, blue: 255 }; var ENGAGED_AVATARS_DEBUG_ALPHA = 0.3; var FOCUS_AVATAR_DEBUG_COLOR = { red: 255, green: 0, blue: 0 }; var FOCUS_AVATAR_DEBUG_ALPHA = 1.0; var TALKER_AVATAR_DEBUG_COLOR = { red: 0, green: 0, blue: 0 }; var TALKER_AVATAR_DEBUG_ALPHA = 0.8; var DEFAULT_OUTLINE_COLOR = { red: 155, green: 155, blue: 255 }; var DEFAULT_OUTLINE_WIDTH = 2; var LookAtDebugger = function() { var self = this; var IMAGE_DIMENSIONS = {x: 0.2, y: 0.2, z:0.2}; var TARGET_ICON_PATH = Script.getExternalPath(Script.ExternalPaths.HF_Content, "/luis/test_scripts/LookAtApp/eyeFocus.png"); var INFINITY_ICON_PATH = Script.getExternalPath(Script.ExternalPaths.HF_Content, "/luis/test_scripts/LookAtApp/noFocus.png"); this.items = {}; this.active = false; // UI elements this.textBox; this.activeCheckBox; this.activeCheckBoxMark; this.activeCaption; this.textBoxHeight = 0.0; this.logs = []; this.getStyleProps = function(color, alpha) { return { fillUnoccludedColor: color, fillUnoccludedAlpha: alpha, fillOccludedColor: color, fillOccludedAlpha: alpha, outlineUnoccludedColor: DEFAULT_OUTLINE_COLOR, outlineUnoccludedAlpha: alpha, outlineOccludedColor: DEFAULT_OUTLINE_COLOR, outlineOccludedAlpha: alpha, outlineWidth: DEFAULT_OUTLINE_WIDTH, isOutlineSmooth: false } } this.Styles = { "engaged" : { "style": self.getStyleProps(ENGAGED_AVATARS_DEBUG_COLOR, ENGAGED_AVATARS_DEBUG_ALPHA), "name" : "engagedSel" }, "focus" : { "style": self.getStyleProps(FOCUS_AVATAR_DEBUG_COLOR, FOCUS_AVATAR_DEBUG_ALPHA), "name" : "focusSel" }, "talker" : { "style": self.getStyleProps(TALKER_AVATAR_DEBUG_COLOR, TALKER_AVATAR_DEBUG_ALPHA), "name" : "talkerSel" } }; this.eyeTarget; this.eyesTargetProps = { name: "Eyes-Target-Image", position: { x: 0.0, y: 0.0, z: 0.0 }, color: {red: 255, green: 0, blue: 255}, url: TARGET_ICON_PATH, dimensions: IMAGE_DIMENSIONS, alpha: 1.0, visible: false, emissive: true, ignoreRayIntersection: true, drawInFront: true, grabbable: false, isFacingAvatar: true }; this.headTarget; this.headTargetProps = { name: "Head-Target-Image", position: { x: 0.0, y: 0.0, z: 0.0 }, color: {red: 0, green: 255, blue: 255}, url: TARGET_ICON_PATH, dimensions: IMAGE_DIMENSIONS, alpha: 1.0, visible: false, emissive: true, ignoreRayIntersection: true, drawInFront: true, grabbable: false, isFacingAvatar: true }; this.textBoxProps = { x: Window.innerWidth - TEXT_BOX_WIDTH, y: TEXT_BOX_TOP_MARGIN, width: TEXT_BOX_WIDTH, height: TEXT_BOX_MIN_HEIGHT, alpha: 0.7, color: { red: 255, green: 255, blue: 255 } }; this.activeCheckBoxProps = { x: TEXT_CAPTION_MARGIN + self.textBoxProps.x, y: 2 * TEXT_CAPTION_MARGIN + self.textBoxProps.y, width: TEXT_CAPTION_SIZE, height: TEXT_CAPTION_SIZE, alpha: 0.0, borderWidth: 2, borderColor: TEXT_CAPTION_COLOR }; this.activeCheckBoxMarkProps = { x: self.activeCheckBoxProps.x + CHECKBOX_MARK_MARGIN, y: self.activeCheckBoxProps.y + CHECKBOX_MARK_MARGIN, width: TEXT_CAPTION_SIZE - 2.0 * CHECKBOX_MARK_MARGIN, height: TEXT_CAPTION_SIZE - 2.0 * CHECKBOX_MARK_MARGIN, visible: false, alpha: 1.0, color: TEXT_CAPTION_COLOR } this.captionProps = { x: 2 * TEXT_CAPTION_SIZE + self.textBoxProps.x, y: TEXT_CAPTION_MARGIN + self.textBoxProps.y, width: self.textBoxProps.width, height: 30, alpha: 1.0, backgroundAlpha: 0.0, visible: true, text: "Debug Auto Look At", font: { size: TEXT_CAPTION_SIZE }, color: TEXT_CAPTION_COLOR, topMargin: 0.5 * TEXT_CAPTION_MARGIN }; this.log = function(txt) { if (self.active) { self.logs.push(Overlays.addOverlay("text", self.captionProps)); var y = self.textBoxProps.y + self.captionProps.height * (self.logs.length); Overlays.editOverlay(self.logs[self.logs.length - 1], {y: y, text: txt}); var height = (TEXT_CAPTION_SIZE + 2.0 * TEXT_CAPTION_MARGIN) * (self.logs.length + 2); if (this.textBoxHeight !== height) { this.textBoxHeight = height Overlays.editOverlay(self.textBox, {height: height}); } } } this.clearLog = function() { for (var n = 0; n < self.logs.length; n++) { Overlays.deleteOverlay(self.logs[n]); } Overlays.editOverlay(self.textBox, self.textBoxProps); self.logs = []; self.log("____________________________"); } this.setActive = function(isActive) { self.active = isActive; if (!self.active) { self.turnOff(); } else { self.turnOn(); } }; this.onClick = function(event) { if (event.x > self.activeCheckBoxProps.x && event.x < (self.activeCheckBoxProps.x + self.activeCheckBoxProps.width) && event.y > self.activeCheckBoxProps.y && event.y < (self.activeCheckBoxProps.y + self.activeCheckBoxProps.height)) { self.setActive(!self.active); Overlays.editOverlay(self.activeCheckBoxMark, {visible: self.active}); } } this.turnOn = function() { for (var key in self.Styles) { var selStyle = self.Styles[key]; Selection.enableListHighlight(selStyle.name, selStyle.style); } if (!self.eyeTarget) { self.eyeTarget = Overlays.addOverlay("image3d", self.eyesTargetProps); } if (!self.headTarget) { self.headTarget = Overlays.addOverlay("image3d", self.headTargetProps); } } this.init = function() { if (!self.textBox) { self.textBox = Overlays.addOverlay("rectangle", self.textBoxProps); } if (!self.activeCheckBox) { self.activeCheckBox = Overlays.addOverlay("rectangle", self.activeCheckBoxProps); } if (!self.activeCheckBoxMark) { self.activeCheckBoxMark = Overlays.addOverlay("rectangle", self.activeCheckBoxMarkProps); } if (!self.activeCaption) { self.activeCaption = Overlays.addOverlay("text", self.captionProps); } }; this.highLightAvatars = function(engagedIDs, focusID, talkerID) { if (self.active) { self.clearSelection(); engagedIDs = !engagedIDs ? [] : engagedIDs; var focusIDs = !focusID ? [] : [focusID]; var talkerIDs = !talkerID ? [] : [talkerID]; self.highLightIDs(self.Styles.engaged.name, engagedIDs); self.highLightIDs(self.Styles.focus.name, focusIDs); self.highLightIDs(self.Styles.talker.name, talkerIDs); return true; } else { return false; } }; this.getTargetProps = function(target) { var distance = Vec3.length(Vec3.subtract(target, Camera.getPosition())); RETARGET_MAX_DISTANCE = 100.0; DIMENSION_SCALE = 0.05; var isInfinite = false; if (distance > RETARGET_MAX_DISTANCE) { isInfinite = true; var eyesToTarget = Vec3.multiply(RETARGET_MAX_DISTANCE, Vec3.normalize(Vec3.subtract(target, MyAvatar.getDefaultEyePosition()))); var newTarget = Vec3.sum(MyAvatar.getDefaultEyePosition(), eyesToTarget); var cameraToTarget = Vec3.normalize(Vec3.subtract(newTarget, Camera.getPosition())); target = Vec3.sum(Camera.getPosition(), cameraToTarget); distance = Vec3.length(cameraToTarget); } // Scale the target to appear always with the same size on screen var fov = DEGREE_TO_RADIAN * Camera.frustum.fieldOfView; var scale = (Camera.frustum.aspectRatio < 1.0 ? Camera.frustum.aspectRatio : 1.0) * DIMENSION_SCALE; var dimensionRatio = scale * (distance / (0.5 * Math.tan(0.5 * fov))); var dimensions = Vec3.multiply(dimensionRatio, IMAGE_DIMENSIONS); return {"dimensions": dimensions, "visible": true, "position": target, "url": isInfinite ? INFINITY_ICON_PATH : TARGET_ICON_PATH}; } this.showTarget = function(headTarget, eyeTarget) { if (!self.active) { return; } var targetProps = self.getTargetProps(eyeTarget); Overlays.editOverlay(self.eyeTarget, targetProps); var headTargetProps = self.getTargetProps(headTarget); Overlays.editOverlay(self.headTarget, headTargetProps); } this.hideEyeTarget = function() { Overlays.editOverlay(self.eyeTarget, {"visible": false}); } this.highLightIDs = function(selectionName, ids) { self.items[selectionName] = ids; for (var idx in ids) { Selection.addToSelectedItemsList(selectionName, "avatar", ids[idx]); } } this.clearSelection = function() { for (key in self.Styles) { var selStyle = self.Styles[key]; Selection.clearSelectedItemsList(selStyle.name); } } this.turnOff = function() { self.clearLog(); for (var key in self.Styles) { var selStyle = self.Styles[key]; Selection.disableListHighlight(selStyle.name); } Overlays.deleteOverlay(self.headTarget); self.headTarget = undefined; Overlays.deleteOverlay(self.eyeTarget); self.eyeTarget = undefined; } this.finish = function() { if (self.active) { self.setActive(false); } Overlays.deleteOverlay(self.textBox); self.textBox = undefined; Overlays.deleteOverlay(self.activeCheckBox); self.activeCheckBox = undefined; Overlays.deleteOverlay(self.activeCaption); self.activeCaption = undefined; Overlays.deleteOverlay(self.activeCheckBoxMark); self.activeCheckBoxMark = undefined; } this.init(); } ////////////////////////////////////////////// // randomHelper.js ////////// ////////////////////////////////////////////// var RandomHelper = function() { var self = this; this.createRandomIndexes = function(count) { var indexes = []; for (var n = 0; n < count; n++) { indexes.push(n); } var randomIndexes = []; for (var n = 0; n < count; n++) { var indexesCount = indexes.length; var randomIndex = 0; if (indexesCount > 1) { var randFactor = Math.random(); randomIndex = randFactor !== 1.0 ? Math.floor(randFactor * indexes.length) : indexes.length - 1; } randomIndexes.push(indexes[randomIndex]); indexes.splice(randomIndex, 1); } return randomIndexes; } this.getRandomKey = function(keypool) { // keypool can be an object. {key1: percentage1, key2: percentage2} or // keypool can be an array. [key1, key2] Equal percentage each component var equalChance = Array.isArray(keypool); var totalPercentage = 0.0; var percentages = {}; var normalizedPercentages = {}; var keys = equalChance ? keypool : Object.keys(keypool); for (var n = 0; n < keys.length; n++) { var key = keys[n]; percentages[key] = equalChance ? 1.0 / keys.length : keypool[key].chance; totalPercentage += equalChance ? percentages[key] : keypool[key].chance; } var accumulatedVal = 0.0; for (var n = 0; n < keys.length; n++) { var key = keys[n]; var val = accumulatedVal + (percentages[key] / totalPercentage); normalizedPercentages[key] = val; accumulatedVal = val; } var dice = Math.random(); var floor = 0.0; var hit = normalizedPercentages[keys[0]]; for (var n = 0; n < keys.length; n++) { var key = keys[n]; if (dice > floor && dice < normalizedPercentages[key]) { hit = key; break; } floor = normalizedPercentages[key]; } return { randomKey: hit, chance: percentages[hit]}; } } ////////////////////////////////////////////// // automaticMachine.js ////////// ////////////////////////////////////////////// var MIN_LOOKAT_HEAD_MIX_ALPHA = 0.04; var MAX_LOOKAT_HEAD_MIX_ALPHA = 0.08; var CAMERA_HEAD_MIX_ALPHA = 0.06; var TargetType = { "unknown" : 0, "avatar" : 1, "entity" : 2 } var TargetOffsetMode = { "noOffset" : 0, "onlyHead" : 1, "onlyEyes" : 2, "headAndEyes" : 3, "print" : function(sta) { return ("OffsetMode: " + (Object.keys(TargetOffsetMode))[sta]); } } var TargetMode = { "noTarget" : 0, "leftEye" : 1, "rightEye" : 2, "mouth" : 3, "leftHand" : 4, "rightHand" : 5, "random" : 6, "print" : function(sta) { return ("TargetMode: " + (Object.keys(TargetMode))[sta]); } } var ACTION_CONFIGURATION = { "TargetMode.mouth": { "joint": "Head", "stareTimeRange" : {"min": 0.2, "max": 2.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.7}, "TargetOffsetMode.onlyHead": {"chance": 0.3}, "TargetOffsetMode.onlyEyes": {"chance": 0.0}, "TargetOffsetMode.headAndEyes": {"chance": 0.0} }, "offsetAngleRange" : {"min": 1.0, "max": 5.0}, "chanceWhileListening" : 0.45, "chanceWhileTalking" : 0.25 }, "TargetMode.leftEye": { "joint": "LeftEye", "stareTimeRange" : {"min": 0.2, "max": 2.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.5}, "TargetOffsetMode.onlyHead": {"chance": 0.3}, "TargetOffsetMode.onlyEyes": {"chance": 0.1}, "TargetOffsetMode.headAndEyes": {"chance": 0.1} }, "offsetAngleRange" : {"min": 1.0, "max": 5.0}, "chanceWhileListening" : 0.20, "chanceWhileTalking" : 0.30 }, "TargetMode.rightEye": { "joint": "RightEye", "stareTimeRange" : {"min": 0.2, "max": 2.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.5}, "TargetOffsetMode.onlyHead": {"chance": 0.3}, "TargetOffsetMode.onlyEyes": {"chance": 0.1}, "TargetOffsetMode.headAndEyes": {"chance": 0.1} }, "offsetAngleRange" : {"min": 1.0, "max": 5.0}, "chanceWhileListening" : 0.20, "chanceWhileTalking" : 0.30 }, "TargetMode.leftHand": { "joint": "LeftHand", "stareTimeRange" : {"min": 0.2, "max": 2.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.9}, "TargetOffsetMode.onlyHead": {"chance": 0.1}, "TargetOffsetMode.onlyEyes": {"chance": 0.0}, "TargetOffsetMode.headAndEyes": {"chance": 0.0} }, "offsetAngleRange" : {"min": 1.0, "max": 10.0}, "chanceWhileListening" : 0.05, "chanceWhileTalking" : 0.05 }, "TargetMode.rightHand": { "joint": "RightHand", "stareTimeRange" : {"min": 0.2, "max": 2.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.9}, "TargetOffsetMode.onlyHead": {"chance": 0.1}, "TargetOffsetMode.onlyEyes": {"chance": 0.0}, "TargetOffsetMode.headAndEyes": {"chance": 0.0} }, "offsetAngleRange" : {"min": 1.0, "max": 10.0}, "chanceWhileListening" : 0.05, "chanceWhileTalking" : 0.05 }, "TargetMode.random": { "joint": "Head", "stareTimeRange" : {"min": 0.2, "max": 1.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.0}, "TargetOffsetMode.onlyHead": {"chance": 0.0}, "TargetOffsetMode.onlyEyes": {"chance": 0.4}, "TargetOffsetMode.headAndEyes": {"chance": 0.6} },Lines 1–500 of 1344. Load more
// // automaticLookAt.js // This script controls the avatar's look-at-target for the head and eyes, according to other avatar's actions // It tries to simulate human interaction during group conversations // // Created by Luis Cuenca on 11/11/19 // Copyright 2019 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 // (function() { ////////////////////////////////////////////// // debugger.js /////// ////////////////////////////////////////////// var TEXT_BOX_WIDTH = 350; var TEXT_BOX_MIN_HEIGHT = 40; var TEXT_BOX_TOP_MARGIN = 100; var TEXT_CAPTION_HEIGHT = 30; var TEXT_CAPTION_COLOR = { red: 0, green: 0, blue: 0 }; var TEXT_CAPTION_SIZE = 18; var TEXT_CAPTION_MARGIN = 6; var CHECKBOX_MARK_MARGIN = 3; var DEGREE_TO_RADIAN = 0.0174533; var ENGAGED_AVATARS_DEBUG_COLOR = { red: 0, green: 255, blue: 255 }; var ENGAGED_AVATARS_DEBUG_ALPHA = 0.3; var FOCUS_AVATAR_DEBUG_COLOR = { red: 255, green: 0, blue: 0 }; var FOCUS_AVATAR_DEBUG_ALPHA = 1.0; var TALKER_AVATAR_DEBUG_COLOR = { red: 0, green: 0, blue: 0 }; var TALKER_AVATAR_DEBUG_ALPHA = 0.8; var DEFAULT_OUTLINE_COLOR = { red: 155, green: 155, blue: 255 }; var DEFAULT_OUTLINE_WIDTH = 2; var LookAtDebugger = function() { var self = this; var IMAGE_DIMENSIONS = {x: 0.2, y: 0.2, z:0.2}; var TARGET_ICON_PATH = Script.getExternalPath(Script.ExternalPaths.HF_Content, "/luis/test_scripts/LookAtApp/eyeFocus.png"); var INFINITY_ICON_PATH = Script.getExternalPath(Script.ExternalPaths.HF_Content, "/luis/test_scripts/LookAtApp/noFocus.png"); this.items = {}; this.active = false; // UI elements this.textBox; this.activeCheckBox; this.activeCheckBoxMark; this.activeCaption; this.textBoxHeight = 0.0; this.logs = []; this.getStyleProps = function(color, alpha) { return { fillUnoccludedColor: color, fillUnoccludedAlpha: alpha, fillOccludedColor: color, fillOccludedAlpha: alpha, outlineUnoccludedColor: DEFAULT_OUTLINE_COLOR, outlineUnoccludedAlpha: alpha, outlineOccludedColor: DEFAULT_OUTLINE_COLOR, outlineOccludedAlpha: alpha, outlineWidth: DEFAULT_OUTLINE_WIDTH, isOutlineSmooth: false } } this.Styles = { "engaged" : { "style": self.getStyleProps(ENGAGED_AVATARS_DEBUG_COLOR, ENGAGED_AVATARS_DEBUG_ALPHA), "name" : "engagedSel" }, "focus" : { "style": self.getStyleProps(FOCUS_AVATAR_DEBUG_COLOR, FOCUS_AVATAR_DEBUG_ALPHA), "name" : "focusSel" }, "talker" : { "style": self.getStyleProps(TALKER_AVATAR_DEBUG_COLOR, TALKER_AVATAR_DEBUG_ALPHA), "name" : "talkerSel" } }; this.eyeTarget; this.eyesTargetProps = { name: "Eyes-Target-Image", position: { x: 0.0, y: 0.0, z: 0.0 }, color: {red: 255, green: 0, blue: 255}, url: TARGET_ICON_PATH, dimensions: IMAGE_DIMENSIONS, alpha: 1.0, visible: false, emissive: true, ignoreRayIntersection: true, drawInFront: true, grabbable: false, isFacingAvatar: true }; this.headTarget; this.headTargetProps = { name: "Head-Target-Image", position: { x: 0.0, y: 0.0, z: 0.0 }, color: {red: 0, green: 255, blue: 255}, url: TARGET_ICON_PATH, dimensions: IMAGE_DIMENSIONS, alpha: 1.0, visible: false, emissive: true, ignoreRayIntersection: true, drawInFront: true, grabbable: false, isFacingAvatar: true }; this.textBoxProps = { x: Window.innerWidth - TEXT_BOX_WIDTH, y: TEXT_BOX_TOP_MARGIN, width: TEXT_BOX_WIDTH, height: TEXT_BOX_MIN_HEIGHT, alpha: 0.7, color: { red: 255, green: 255, blue: 255 } }; this.activeCheckBoxProps = { x: TEXT_CAPTION_MARGIN + self.textBoxProps.x, y: 2 * TEXT_CAPTION_MARGIN + self.textBoxProps.y, width: TEXT_CAPTION_SIZE, height: TEXT_CAPTION_SIZE, alpha: 0.0, borderWidth: 2, borderColor: TEXT_CAPTION_COLOR }; this.activeCheckBoxMarkProps = { x: self.activeCheckBoxProps.x + CHECKBOX_MARK_MARGIN, y: self.activeCheckBoxProps.y + CHECKBOX_MARK_MARGIN, width: TEXT_CAPTION_SIZE - 2.0 * CHECKBOX_MARK_MARGIN, height: TEXT_CAPTION_SIZE - 2.0 * CHECKBOX_MARK_MARGIN, visible: false, alpha: 1.0, color: TEXT_CAPTION_COLOR } this.captionProps = { x: 2 * TEXT_CAPTION_SIZE + self.textBoxProps.x, y: TEXT_CAPTION_MARGIN + self.textBoxProps.y, width: self.textBoxProps.width, height: 30, alpha: 1.0, backgroundAlpha: 0.0, visible: true, text: "Debug Auto Look At", font: { size: TEXT_CAPTION_SIZE }, color: TEXT_CAPTION_COLOR, topMargin: 0.5 * TEXT_CAPTION_MARGIN }; this.log = function(txt) { if (self.active) { self.logs.push(Overlays.addOverlay("text", self.captionProps)); var y = self.textBoxProps.y + self.captionProps.height * (self.logs.length); Overlays.editOverlay(self.logs[self.logs.length - 1], {y: y, text: txt}); var height = (TEXT_CAPTION_SIZE + 2.0 * TEXT_CAPTION_MARGIN) * (self.logs.length + 2); if (this.textBoxHeight !== height) { this.textBoxHeight = height Overlays.editOverlay(self.textBox, {height: height}); } } } this.clearLog = function() { for (var n = 0; n < self.logs.length; n++) { Overlays.deleteOverlay(self.logs[n]); } Overlays.editOverlay(self.textBox, self.textBoxProps); self.logs = []; self.log("____________________________"); } this.setActive = function(isActive) { self.active = isActive; if (!self.active) { self.turnOff(); } else { self.turnOn(); } }; this.onClick = function(event) { if (event.x > self.activeCheckBoxProps.x && event.x < (self.activeCheckBoxProps.x + self.activeCheckBoxProps.width) && event.y > self.activeCheckBoxProps.y && event.y < (self.activeCheckBoxProps.y + self.activeCheckBoxProps.height)) { self.setActive(!self.active); Overlays.editOverlay(self.activeCheckBoxMark, {visible: self.active}); } } this.turnOn = function() { for (var key in self.Styles) { var selStyle = self.Styles[key]; Selection.enableListHighlight(selStyle.name, selStyle.style); } if (!self.eyeTarget) { self.eyeTarget = Overlays.addOverlay("image3d", self.eyesTargetProps); } if (!self.headTarget) { self.headTarget = Overlays.addOverlay("image3d", self.headTargetProps); } } this.init = function() { if (!self.textBox) { self.textBox = Overlays.addOverlay("rectangle", self.textBoxProps); } if (!self.activeCheckBox) { self.activeCheckBox = Overlays.addOverlay("rectangle", self.activeCheckBoxProps); } if (!self.activeCheckBoxMark) { self.activeCheckBoxMark = Overlays.addOverlay("rectangle", self.activeCheckBoxMarkProps); } if (!self.activeCaption) { self.activeCaption = Overlays.addOverlay("text", self.captionProps); } }; this.highLightAvatars = function(engagedIDs, focusID, talkerID) { if (self.active) { self.clearSelection(); engagedIDs = !engagedIDs ? [] : engagedIDs; var focusIDs = !focusID ? [] : [focusID]; var talkerIDs = !talkerID ? [] : [talkerID]; self.highLightIDs(self.Styles.engaged.name, engagedIDs); self.highLightIDs(self.Styles.focus.name, focusIDs); self.highLightIDs(self.Styles.talker.name, talkerIDs); return true; } else { return false; } }; this.getTargetProps = function(target) { var distance = Vec3.length(Vec3.subtract(target, Camera.getPosition())); RETARGET_MAX_DISTANCE = 100.0; DIMENSION_SCALE = 0.05; var isInfinite = false; if (distance > RETARGET_MAX_DISTANCE) { isInfinite = true; var eyesToTarget = Vec3.multiply(RETARGET_MAX_DISTANCE, Vec3.normalize(Vec3.subtract(target, MyAvatar.getDefaultEyePosition()))); var newTarget = Vec3.sum(MyAvatar.getDefaultEyePosition(), eyesToTarget); var cameraToTarget = Vec3.normalize(Vec3.subtract(newTarget, Camera.getPosition())); target = Vec3.sum(Camera.getPosition(), cameraToTarget); distance = Vec3.length(cameraToTarget); } // Scale the target to appear always with the same size on screen var fov = DEGREE_TO_RADIAN * Camera.frustum.fieldOfView; var scale = (Camera.frustum.aspectRatio < 1.0 ? Camera.frustum.aspectRatio : 1.0) * DIMENSION_SCALE; var dimensionRatio = scale * (distance / (0.5 * Math.tan(0.5 * fov))); var dimensions = Vec3.multiply(dimensionRatio, IMAGE_DIMENSIONS); return {"dimensions": dimensions, "visible": true, "position": target, "url": isInfinite ? INFINITY_ICON_PATH : TARGET_ICON_PATH}; } this.showTarget = function(headTarget, eyeTarget) { if (!self.active) { return; } var targetProps = self.getTargetProps(eyeTarget); Overlays.editOverlay(self.eyeTarget, targetProps); var headTargetProps = self.getTargetProps(headTarget); Overlays.editOverlay(self.headTarget, headTargetProps); } this.hideEyeTarget = function() { Overlays.editOverlay(self.eyeTarget, {"visible": false}); } this.highLightIDs = function(selectionName, ids) { self.items[selectionName] = ids; for (var idx in ids) { Selection.addToSelectedItemsList(selectionName, "avatar", ids[idx]); } } this.clearSelection = function() { for (key in self.Styles) { var selStyle = self.Styles[key]; Selection.clearSelectedItemsList(selStyle.name); } } this.turnOff = function() { self.clearLog(); for (var key in self.Styles) { var selStyle = self.Styles[key]; Selection.disableListHighlight(selStyle.name); } Overlays.deleteOverlay(self.headTarget); self.headTarget = undefined; Overlays.deleteOverlay(self.eyeTarget); self.eyeTarget = undefined; } this.finish = function() { if (self.active) { self.setActive(false); } Overlays.deleteOverlay(self.textBox); self.textBox = undefined; Overlays.deleteOverlay(self.activeCheckBox); self.activeCheckBox = undefined; Overlays.deleteOverlay(self.activeCaption); self.activeCaption = undefined; Overlays.deleteOverlay(self.activeCheckBoxMark); self.activeCheckBoxMark = undefined; } this.init(); } ////////////////////////////////////////////// // randomHelper.js ////////// ////////////////////////////////////////////// var RandomHelper = function() { var self = this; this.createRandomIndexes = function(count) { var indexes = []; for (var n = 0; n < count; n++) { indexes.push(n); } var randomIndexes = []; for (var n = 0; n < count; n++) { var indexesCount = indexes.length; var randomIndex = 0; if (indexesCount > 1) { var randFactor = Math.random(); randomIndex = randFactor !== 1.0 ? Math.floor(randFactor * indexes.length) : indexes.length - 1; } randomIndexes.push(indexes[randomIndex]); indexes.splice(randomIndex, 1); } return randomIndexes; } this.getRandomKey = function(keypool) { // keypool can be an object. {key1: percentage1, key2: percentage2} or // keypool can be an array. [key1, key2] Equal percentage each component var equalChance = Array.isArray(keypool); var totalPercentage = 0.0; var percentages = {}; var normalizedPercentages = {}; var keys = equalChance ? keypool : Object.keys(keypool); for (var n = 0; n < keys.length; n++) { var key = keys[n]; percentages[key] = equalChance ? 1.0 / keys.length : keypool[key].chance; totalPercentage += equalChance ? percentages[key] : keypool[key].chance; } var accumulatedVal = 0.0; for (var n = 0; n < keys.length; n++) { var key = keys[n]; var val = accumulatedVal + (percentages[key] / totalPercentage); normalizedPercentages[key] = val; accumulatedVal = val; } var dice = Math.random(); var floor = 0.0; var hit = normalizedPercentages[keys[0]]; for (var n = 0; n < keys.length; n++) { var key = keys[n]; if (dice > floor && dice < normalizedPercentages[key]) { hit = key; break; } floor = normalizedPercentages[key]; } return { randomKey: hit, chance: percentages[hit]}; } } ////////////////////////////////////////////// // automaticMachine.js ////////// ////////////////////////////////////////////// var MIN_LOOKAT_HEAD_MIX_ALPHA = 0.04; var MAX_LOOKAT_HEAD_MIX_ALPHA = 0.08; var CAMERA_HEAD_MIX_ALPHA = 0.06; var TargetType = { "unknown" : 0, "avatar" : 1, "entity" : 2 } var TargetOffsetMode = { "noOffset" : 0, "onlyHead" : 1, "onlyEyes" : 2, "headAndEyes" : 3, "print" : function(sta) { return ("OffsetMode: " + (Object.keys(TargetOffsetMode))[sta]); } } var TargetMode = { "noTarget" : 0, "leftEye" : 1, "rightEye" : 2, "mouth" : 3, "leftHand" : 4, "rightHand" : 5, "random" : 6, "print" : function(sta) { return ("TargetMode: " + (Object.keys(TargetMode))[sta]); } } var ACTION_CONFIGURATION = { "TargetMode.mouth": { "joint": "Head", "stareTimeRange" : {"min": 0.2, "max": 2.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.7}, "TargetOffsetMode.onlyHead": {"chance": 0.3}, "TargetOffsetMode.onlyEyes": {"chance": 0.0}, "TargetOffsetMode.headAndEyes": {"chance": 0.0} }, "offsetAngleRange" : {"min": 1.0, "max": 5.0}, "chanceWhileListening" : 0.45, "chanceWhileTalking" : 0.25 }, "TargetMode.leftEye": { "joint": "LeftEye", "stareTimeRange" : {"min": 0.2, "max": 2.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.5}, "TargetOffsetMode.onlyHead": {"chance": 0.3}, "TargetOffsetMode.onlyEyes": {"chance": 0.1}, "TargetOffsetMode.headAndEyes": {"chance": 0.1} }, "offsetAngleRange" : {"min": 1.0, "max": 5.0}, "chanceWhileListening" : 0.20, "chanceWhileTalking" : 0.30 }, "TargetMode.rightEye": { "joint": "RightEye", "stareTimeRange" : {"min": 0.2, "max": 2.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.5}, "TargetOffsetMode.onlyHead": {"chance": 0.3}, "TargetOffsetMode.onlyEyes": {"chance": 0.1}, "TargetOffsetMode.headAndEyes": {"chance": 0.1} }, "offsetAngleRange" : {"min": 1.0, "max": 5.0}, "chanceWhileListening" : 0.20, "chanceWhileTalking" : 0.30 }, "TargetMode.leftHand": { "joint": "LeftHand", "stareTimeRange" : {"min": 0.2, "max": 2.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.9}, "TargetOffsetMode.onlyHead": {"chance": 0.1}, "TargetOffsetMode.onlyEyes": {"chance": 0.0}, "TargetOffsetMode.headAndEyes": {"chance": 0.0} }, "offsetAngleRange" : {"min": 1.0, "max": 10.0}, "chanceWhileListening" : 0.05, "chanceWhileTalking" : 0.05 }, "TargetMode.rightHand": { "joint": "RightHand", "stareTimeRange" : {"min": 0.2, "max": 2.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.9}, "TargetOffsetMode.onlyHead": {"chance": 0.1}, "TargetOffsetMode.onlyEyes": {"chance": 0.0}, "TargetOffsetMode.headAndEyes": {"chance": 0.0} }, "offsetAngleRange" : {"min": 1.0, "max": 10.0}, "chanceWhileListening" : 0.05, "chanceWhileTalking" : 0.05 }, "TargetMode.random": { "joint": "Head", "stareTimeRange" : {"min": 0.2, "max": 1.0}, "headSpeedRange" : {"min": MAX_LOOKAT_HEAD_MIX_ALPHA, "max": MIN_LOOKAT_HEAD_MIX_ALPHA}, "offsetChances" : { "TargetOffsetMode.noOffset": {"chance": 0.0}, "TargetOffsetMode.onlyHead": {"chance": 0.0}, "TargetOffsetMode.onlyEyes": {"chance": 0.4}, "TargetOffsetMode.headAndEyes": {"chance": 0.6} },