// moodLight.js // // This script can be tested in Interface, but should ultimately run as an AC script. // Tweens serveral set moodlights. // // Created by Thijs Wenker on September 21, 2016. // Copyright 2016 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 // // Light schedules have the Cycle Percentage as key and the color as value var DEFAULT_LIGHT_SCHEDULE = { 0.0: {red: 247, green: 175, blue: 42}, 0.3334: {red: 250, green: 20, blue: 112}, 0.6667: {red: 0, green: 128, blue: 102}, }; var DEFAULT_LIGHT_SCHEDULE_2 = { 0.0: {red: 199, green: 43, blue: 0}, 0.3334: {red: 107, green: 3, blue: 148}, 0.6667: {red: 0, green: 13, blue: 150}, }; // Setup your mood-light below var moodLights = [ { properties: { name: 'color Debug', position: { x: -27.46241426467896, y: 8.558837890625, z: -32.07110595703125 }, type: 'Sphere' }, schedule: DEFAULT_LIGHT_SCHEDULE }, { properties: { cutoff: 90, dimensions: { x: 59.687240600585938, y: 59.687240600585938, z: 59.687240600585938 }, falloffRadius: 100, intensity: 2.2999999523162842, name: 'RotatingLight1', position: { x: -27.00, y: 8.6062, z: -32.2729 }, rotation: { w: 1, x: -1.52587890625e-05, y: -1.52587890625e-05, z: -1.52587890625e-05 }, type: 'Light' }, schedule: DEFAULT_LIGHT_SCHEDULE }, { properties: { cutoff: 90, dimensions: { x: 68.6043701171875, y: 68.6043701171875, z: 68.6043701171875 }, falloffRadius: 10, intensity: 15, name: 'RotatingLight2', position: { x: -27.00, y: 4.6453, z: -32.1627 }, rotation: { w: 1, x: -1.52587890625e-05, y: -1.52587890625e-05, z: -1.52587890625e-05 }, type: 'Light' }, schedule: DEFAULT_LIGHT_SCHEDULE_2 } ]; // The time it takes for a cycle to 100% complete (1.0) var CYCLE_SECONDS = 100; // 5 minutes // MAX_INACTIVE_SECONDS will contineous be added with the age to the lifetime, when the script is inactive the lights will disappear var MAX_INACTIVE_SECONDS = 10; // How frequently do we send out updates per second? : var UPDATE_FREQUENCY = 50; //Hz const MILLISECONDS_PER_SECOND = 1000; function getNearestArrayValues(array, goal, continuous) { var floorValue = null, ceilValue = null; array.forEach(function(entry) { if ((floorValue === null || entry > floorValue) && entry <= goal) { floorValue = entry; } if ((ceilValue === null || entry < ceilValue) && entry >= goal) { ceilValue = entry; } }); if (continuous && floorValue === null) { floorValue = Math.max.apply(Math, array); } if (continuous && ceilValue === null) { ceilValue = Math.min.apply(Math, array); } return { floor: floorValue, ceil: ceilValue }; } function tweeningPercentage(min, max, current) { var currentOffset = (current >= min ? (current - min) : (current + 1 - min)); var dividerOffset = max - min; if (min > max) { dividerOffset += 1; } return currentOffset / dividerOffset; } function mix(valueA, valueB, mixPercentage) { return valueA + mixPercentage * (valueB - valueA); } function MoodLight(properties, schedule) { this.properties = properties; this.schedule = schedule; this.properties['lifetime'] = MAX_INACTIVE_SECONDS; this.entityID = Entities.addEntity(this.properties); this.creationSeconds = Date.now() / MILLISECONDS_PER_SECOND; } MoodLight.prototype = { properties: null, schedule: null, entityID: null, creationSeconds: null, getCurrentColor: function() { var percentageOfCycle = ((Date.now() / MILLISECONDS_PER_SECOND) % CYCLE_SECONDS) / CYCLE_SECONDS; var minMaxKey = getNearestArrayValues(Object.keys(this.schedule), percentageOfCycle, true); var minColor = this.schedule[minMaxKey.floor]; var maxColor = this.schedule[minMaxKey.ceil]; var mixPercentage = tweeningPercentage(minMaxKey.floor, minMaxKey.ceil, percentageOfCycle); var mixedColor = { red: mix(minColor.red, maxColor.red, mixPercentage), green: mix(minColor.green, maxColor.green, mixPercentage), blue: mix(minColor.blue, maxColor.blue, mixPercentage), }; //print((percentageOfCycle * 100).toFixed(3) + '% ' + JSON.stringify(minColor) + ' mix ( ' + (mixPercentage * 100).toFixed(3) + '% ' + ' ) ' + JSON.stringify(maxColor) + ' = ' + JSON.stringify(mixedColor)); return mixedColor; }, getNewLifetime: function() { return ((Date.now() / MILLISECONDS_PER_SECOND) -this.creationSeconds) + MAX_INACTIVE_SECONDS; }, update: function() { var newProperties = {}; newProperties['lifetime'] = this.getNewLifetime(); newProperties['color'] = this.getCurrentColor(); Entities.editEntity(this.entityID, newProperties); } }; var moodLightInstances = []; var initialized = false; Script.setInterval(function() { if (!initialized) { if (Entities.serversExist() && Entities.canRez()) { Entities.setPacketsPerSecond(60000); moodLights.forEach(function(moodLight) { moodLightInstances.push(new MoodLight(moodLight.properties, moodLight.schedule)); }); initialized = true; } return; } moodLightInstances.forEach(function(moodLight) { moodLight.update(); }); }, MILLISECONDS_PER_SECOND / UPDATE_FREQUENCY);