Add the "Light Bulb Generator" app

This adds the "Light Bulb Generator" application:
To generate rapidly a visible glowing light source with its light beam.
This commit is contained in:
Alezia Kurdis 2022-07-13 22:24:54 -04:00 committed by GitHub
parent 897ca71ad5
commit 62b79e6fc8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 509 additions and 2 deletions

Binary file not shown.

View file

@ -0,0 +1,33 @@
{
"DataVersion": 0,
"Entities": [
{
"type": "Sphere",
"name": "LIGHT_BULB",
"locked": false,
"dimensions": {
"x": 0.06,
"y": 0.06,
"z": 0.06
},
"rotation": {
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"grab": {
"grabbable": false
},
"color": {
"red": 255,
"green": 255,
"blue": 255
},
"userData": "{\"lightIntensity\":5,\"lightSpotCutOff\": 30,\"lightRange\": 10}",
"script": "https://aleziakurdis.github.io/lightBulb/lightBulb.js"
}
],
"Id": "{5cbb14bf-ca6c-4aa9-bcfa-1a53c8438669}",
"Version": 133
}

View file

@ -0,0 +1,143 @@
"use strict";
//
// app-lightBulb.js
//
// Created by Alezia Kurdis, April 23rd 2022.
// Copyright 2022 Overte e.V.
//
// Application to generate light bulbs.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
var jsMainFileName = "app-lightBulb.js";
var ROOT = Script.resolvePath('').split(jsMainFileName)[0];
var intensity = 5;
var angle = 30;
var range = 10;
var wOrH = "white";
var hue = 30;
var APP_NAME = "BULB";
var APP_URL = ROOT + "lightBulb.html";
var APP_ICON_INACTIVE = ROOT + "icon_inactive.png";
var APP_ICON_ACTIVE = ROOT + "icon_active.png";
var LIGHT_BULB_SCRIPT = ROOT + "lightBulb.js";
var appStatus = false;
var channel = "com.overte.app.lightBulb";
var timestamp = 0;
var INTERCALL_DELAY = 200; //0.3 sec
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.screenChanged.connect(onScreenChanged);
var button = tablet.addButton({
text: APP_NAME,
icon: APP_ICON_INACTIVE,
activeIcon: APP_ICON_ACTIVE
});
function clicked(){
if (appStatus === true) {
tablet.webEventReceived.disconnect(onAppWebEventReceived);
tablet.gotoHomeScreen();
appStatus = false;
}else{
tablet.gotoWebScreen(APP_URL + "?woh=" + wOrH + "&hue=" + hue + "&int=" + intensity + "&ang=" + angle + "&ran=" + range);
tablet.webEventReceived.connect(onAppWebEventReceived);
appStatus = true;
}
button.editProperties({
isActive: appStatus
});
}
button.clicked.connect(clicked);
function onAppWebEventReceived(message) {
var d = new Date();
var n = d.getTime();
var messageObj = JSON.parse(message);
if (messageObj.channel === channel) {
if (messageObj.action === "GEN_LIGHT_BULB" && (n - timestamp) > INTERCALL_DELAY) {
d = new Date();
timestamp = d.getTime();
intensity = messageObj.lightIntensity;
angle = messageObj.lightSpotCutOff;
range = messageObj.lightRange;
wOrH = messageObj.colorMode;
hue = messageObj.hue;
generatelightBulb(messageObj);
}
}
}
function onScreenChanged(type, url) {
if (type == "Web" && url.indexOf(APP_URL) != -1) {
appStatus = true;
} else {
appStatus = false;
}
button.editProperties({
isActive: appStatus
});
}
function cleanup() {
if (appStatus) {
tablet.gotoHomeScreen();
tablet.webEventReceived.disconnect(onMoreAppWebEventReceived);
}
tablet.screenChanged.disconnect(onScreenChanged);
tablet.removeButton(button);
}
function generatelightBulb(data) {
var id = Entities.addEntity({
"type": "Sphere",
"name": "LIGHT_BULB",
"locked": false,
"dimensions": {
"x": 0.06,
"y": 0.06,
"z": 0.06
},
"rotation": {
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"position": Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -2 })),
"grab": {
"grabbable": false
},
"color": {
"red": data.color.red,
"green": data.color.green,
"blue": data.color.blue
},
"userData": "{\"lightIntensity\":" + data.lightIntensity + ",\"lightSpotCutOff\": " + data.lightSpotCutOff + ",\"lightRange\": " + data.lightRange + "}",
"script": LIGHT_BULB_SCRIPT
}, "domain");
}
Script.scriptEnding.connect(cleanup);
}());

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,211 @@
<!DOCTYPE html>
<!--
lightBulb.html
Created by Alezia Kurdis, April 23rd 2022.
Copyright 2022 Overte e.V.
HTML UI for an application to generate light bulbs.
Distributed under the Apache License, Version 2.0.
See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-->
<html>
<head>
<meta charset="UTF-8">
<script>
//Parameters
function findGetParameter(parameterName) {
var result = null,
tmp = [];
var items = location.search.substr(1).split("&");
for (var index = 0; index < items.length; index++) {
tmp = items[index].split("=");
if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
}
return result;
}
var channel = "com.overte.app.lightBulb";
//Paths
var thisPageName = "lightBulb.html";
var currentPath = window.location.protocol + "//" + window.location.host + window.location.pathname;
var ROOTPATH = currentPath.replace(thisPageName, "");
</script>
<style>
@font-face {
font-family: FiraSans-SemiBold;
src: url(FiraSans-SemiBold.ttf);
}
body {
background: #363842;
font-family: FiraSans-SemiBold;
font-size: 18px;
color: #FFFFFF;
text-decoration: none;
font-style: normal;
font-variant: normal;
text-transform: none;
}
#colorPreview {
background: #ffffff;
border: 1px solid #000000;
width: 100px;
height: 60px;
}
</style>
</head>
<body>
<h1>LIGHT BULB GENERATOR</h1><hr>
Color: <br>
<table><tr><td>
<div id = "colorPreview"></div>
</td><td>
<input type = "radio" id="colorWhite" name="colorType" onclick="setColor();" value = "white" checked>White<br>
<input type = "radio" id="colorHue" name="colorType" onclick="setColor();" value = "hue">Hue <input id="hue" type="number" size = "5" value="30" onchange='setColor();'>&deg;
</td></tr></table>
<br><br>
Intensity: <input id="intensity" type="number" size = "5" value="5" onchange='setColor();'><br><br>
Beam angle: <input id="beamAngle" type="number" size = "5" value="30" onchange='setColor();'>&deg;<br><br>
Range: <input id="range" type="number" size = "5" value="10" onchange='setColor();'>m<br><br><br>
<button onClick='genLightBulb();'>GENERATE A LIGHT BULB</button>
<script>
function setColor() {
var color;
var hue = parseInt(document.getElementById("hue").value, 10)/360;
if (document.getElementById("colorWhite").checked) {
color = hslToRgb(hue, 1, 1);
} else {
color = hslToRgb(hue, 1, 0.5);
}
var h = parseInt(document.getElementById("hue").value,10);
if (h >= 720 || h < -720) {
document.getElementById("hue").value = 0;
} else if (h < 0) {
document.getElementById("hue").value = h + 360;
} else if (h >= 360) {
document.getElementById("hue").value = h - 360;
}
document.getElementById("colorPreview").style.backgroundColor = "rgb(" + color[0] + ", " + color[1] + ", " + color[2] + ")";
var i = parseInt(document.getElementById("intensity").value,10);
if (i < 0) {
document.getElementById("intensity").value = 0;
}
var a = parseInt(document.getElementById("beamAngle").value,10);
if (a < 0) {
document.getElementById("beamAngle").value = 0;
}
if (a >= 180) {
document.getElementById("beamAngle").value = 180;
}
var r = parseInt(document.getElementById("range").value,10);
if (r < 0) {
document.getElementById("range").value = 0;
}
}
function genLightBulb(){
var hue = parseInt(document.getElementById("hue").value, 10)/360;
var colorMode = "white";
if (document.getElementById("colorWhite").checked) {
color = hslToRgb(hue, 1, 1);
} else {
color = hslToRgb(hue, 1, 0.6);
colorMode = "hue";
}
var lightColor = {"red": color[0], "green": color[1], "blue": color[2]};
var intensity = parseInt(document.getElementById("intensity").value,10);
var beamAngle = parseInt(document.getElementById("beamAngle").value,10);
var range = parseInt(document.getElementById("range").value,10);
var data = {
"action": "GEN_LIGHT_BULB",
"channel": channel,
"color": lightColor,
"lightIntensity": intensity,
"lightSpotCutOff": beamAngle,
"lightRange": range,
"colorMode": colorMode,
"hue": parseInt(document.getElementById("hue").value, 10)
};
EventBridge.emitWebEvent(JSON.stringify(data));
}
/*
* Converts an HSL color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param {number} h The hue
* @param {number} s The saturation
* @param {number} l The lightness
* @return {Array} The RGB representation
*/
function hslToRgb(h, s, l){
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
}else{
var hue2rgb = function hue2rgb(p, q, t){
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
//Reading paramaters and apply them
var parameter = findGetParameter("woh");
if(parameter === null){parameter = "white";}
if (parameter === "white") {
document.getElementById("colorWhite").checked = true;
document.getElementById("colorHue").checked = false;
} else {
document.getElementById("colorWhite").checked = false;
document.getElementById("colorHue").checked = true;
}
parameter = findGetParameter("hue");
document.getElementById("hue").value = parseInt(parameter, 10);
parameter = findGetParameter("int");
document.getElementById("intensity").value = parseInt(parameter, 10);
parameter = findGetParameter("ang");
document.getElementById("beamAngle").value = parseInt(parameter, 10);
parameter = findGetParameter("ran");
document.getElementById("range").value = parseInt(parameter, 10);
setColor();
</script>
</body>
</html>

View file

@ -0,0 +1,111 @@
"use strict";
//
// lightBulb.js
//
// Created by Alezia Kurdis, July 14th, 2021.
// Copyright 2022 Overte e.V.
//
// Turn a shape to a light bulb.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function(){
var ROOT = Script.resolvePath('').split("lightBulb.js")[0];
var DEG_TO_RAD = Math.PI/180;
var lightID = Uuid.NULL;
var materialID = Uuid.NULL;
this.preload = function(entityID) {
var properties = Entities.getEntityProperties(entityID, ["renderWithZones", "color", "userData"]);
var renderWithZones = properties.renderWithZones;
var color = properties.color;
var userData = JSON.parse(properties.userData);
var lightIntensity = userData.lightIntensity ? userData.lightIntensity : 5;
var lightSpotCutOff = userData.lightSpotCutOff ? userData.lightSpotCutOff : 30;
var lightRange = userData.lightRange ? userData.lightRange : 10;
lightID = Entities.addEntity({
"parentID": entityID,
"renderWithZones": renderWithZones,
"locked": false,
"localPosition": {"x": 0.0, "y": 0.0, "z": 0.0},
"localRotation": {
"x": -0.7071,
"y": 0.0,
"z": 0.0,
"w": 0.7071
},
"name": "bulb-light",
"grab": {
"grabbable": false
},
"type": "Light",
"dimensions": {
"x": lightRange * 2,
"y": lightRange * 2,
"z": lightRange * 2
},
"color": color,
"intensity": lightIntensity,
"falloffRadius": 1,
"isSpotlight": true,
"visible": true,
"exponent": 1,
"cutoff": lightSpotCutOff
},"local");
var sumColorCompnent = (color.red/255) +(color.green/255) +(color.blue/255);
if (sumColorCompnent === 0) {
sumColorCompnent = 0.001;
}
var bloomFactor = 9 / sumColorCompnent;
var materialContent = {
"materialVersion": 1,
"materials": [
{
"name": "bulb",
"albedo": [1, 1, 1],
"metallic": 1,
"roughness": 1,
"opacity": 1,
"emissive": [(color.red/255) * bloomFactor, (color.green/255) * bloomFactor, (color.blue/255) * bloomFactor],
"scattering": 0,
"unlit": false,
"cullFaceMode": "CULL_NONE",
"model": "hifi_pbr"
}
]
};
materialID = Entities.addEntity({
"type": "Material",
"parentID": entityID,
"renderWithZones": renderWithZones,
"locked": false,
"localPosition": {"x": 0.0, "y": 0.2, "z": 0.0},
"name": "bulb-material",
"materialURL": "materialData",
"priority": 1,
"materialData": JSON.stringify(materialContent)
},"local");
};
this.unload = function(entityID) {
//Termination proces
if (lightID !== Uuid.NULL) {
Entities.deleteEntity(lightID);
}
if (materialID !== Uuid.NULL) {
Entities.deleteEntity(materialID);
}
};
})

View file

@ -67,7 +67,7 @@ var metadata = { "applications":
"isActive": true,
"directory": "radar",
"name": "Radar",
"description": "Show where people are and teleport in the domain. <a href='http://ctrlaltstudio.com/vircadia/radar' target=`_blank`>More info...</a>",
"description": "Show where people are and teleport in the domain.",
"jsfile": "radar/radar.js",
"icon": "radar/assets/radar-i.svg",
"caption": "RADAR"
@ -85,7 +85,7 @@ var metadata = { "applications":
"isActive": true,
"directory": "nametags",
"name": "Nametags",
"description": "Display users' display names above their heads. <a href='http://ctrlaltstudio.com/vircadia/nametags' target=`_blank`>More info...</a>",
"description": "Display users' display names above their heads.",
"jsfile": "nametags/nametags.js",
"icon": "nametags/assets/nametags-i.svg",
"caption": "NAMETAGS"
@ -116,6 +116,15 @@ var metadata = { "applications":
"jsfile": "odometer/odometer.js",
"icon": "odometer/appicon_i.png",
"caption": "ODOMETER"
},
{
"isActive": true,
"directory": "lightBulb",
"name": "Light Bulb Generator",
"description": "Generate rapidly a visible glowing light source with its light beam.",
"jsfile": "lightBulb/app-lightBulb.js",
"icon": "lightBulb/icon_inactive.png",
"caption": "BULB"
}
]
};