fix merge conflicts

This commit is contained in:
Philip Rosedale 2015-12-30 00:42:14 -08:00
commit 118f919c8b
16 changed files with 3955 additions and 1029 deletions

View file

@ -286,7 +286,7 @@ function MyController(hand) {
//for visualizations
this.overlayLine = null;
this.particleBeam = null;
//for lights
this.spotlight = null;
this.pointlight = null;
@ -296,7 +296,7 @@ function MyController(hand) {
// how far from camera to search intersection?
this.intersectionDistance = 0.0;
this.searchSphereDistance = 0.0;
this.ignoreIK = false;
this.offsetPosition = Vec3.ZERO;
this.offsetRotation = Quat.IDENTITY;
@ -401,7 +401,7 @@ function MyController(hand) {
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}
})
});
} else {
@ -475,7 +475,7 @@ function MyController(hand) {
this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan);
} else {
this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan);
}
}
};
this.handleDistantParticleBeam = function(handPosition, objectPosition, color) {
@ -563,12 +563,12 @@ function MyController(hand) {
Entities.editEntity(this.particleBeam, {
rotation: orientation,
position: position,
visible: true,
color: color,
visible: true,
color: color,
emitSpeed: speed,
speedSpread: spread,
lifespan: lifespan
})
})
};
@ -584,7 +584,7 @@ function MyController(hand) {
x: 1,
y: 0,
z: 0
});
});
return {
p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)),
@ -818,19 +818,28 @@ function MyController(hand) {
})
}
Messages.sendMessage('Hifi-Light-Overlay-Ray-Check', JSON.stringify(pickRayBacked));
var intersection;
if (USE_BLACKLIST === true && blacklist.length !== 0) {
intersection = Entities.findRayIntersection(pickRay, true, [], blacklist);
intersection = Entities.findRayIntersection(pickRayBacked, true, [], blacklist);
} else {
intersection = Entities.findRayIntersection(pickRayBacked, true);
}
if (intersection.intersects) {
// the ray is intersecting something we can move.
this.intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection);
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA);
var defaultDisableNearGrabData = {
disableNearGrab: false
};
//sometimes we want things to stay right where they are when we let go.
var disableNearGrabData = getEntityCustomData('handControllerKey', intersection.entityID, defaultDisableNearGrabData);
if (intersection.properties.name == "Grab Debug Entity") {
continue;
@ -852,7 +861,11 @@ function MyController(hand) {
} else if (!intersection.properties.locked) {
this.grabbedEntity = intersection.entityID;
if (this.state == STATE_SEARCHING) {
this.setState(STATE_NEAR_GRABBING);
if (disableNearGrabData.disableNearGrab !== true) {
this.setState(STATE_NEAR_GRABBING);
} else {
//disable near grab on this thing
}
} else { // equipping
if (typeof grabbableData.spatialKey !== 'undefined') {
// TODO
@ -976,7 +989,18 @@ function MyController(hand) {
this.setState(STATE_NEAR_TRIGGER);
return;
} else if (!props.locked && props.collisionsWillMove) {
this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP)
var defaultDisableNearGrabData = {
disableNearGrab: false
};
//sometimes we want things to stay right where they are when we let go.
var disableNearGrabData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultDisableNearGrabData);
if (disableNearGrabData.disableNearGrab === true) {
//do nothing because near grab is disabled for this object
} else {
this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP)
}
return;
}
}
@ -1144,22 +1168,54 @@ function MyController(hand) {
this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab");
// mix in head motion
if (MOVE_WITH_HEAD) {
var objDistance = Vec3.length(objectToAvatar);
var before = Vec3.multiplyQbyV(this.currentCameraOrientation, {
x: 0.0,
y: 0.0,
z: objDistance
});
var after = Vec3.multiplyQbyV(Camera.orientation, {
x: 0.0,
y: 0.0,
z: objDistance
});
var change = Vec3.subtract(before, after);
this.currentCameraOrientation = Camera.orientation;
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change);
var defaultMoveWithHeadData = {
disableMoveWithHead: false
};
var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData);
if (handControllerData.disableMoveWithHead !== true) {
// mix in head motion
if (MOVE_WITH_HEAD) {
var objDistance = Vec3.length(objectToAvatar);
var before = Vec3.multiplyQbyV(this.currentCameraOrientation, {
x: 0.0,
y: 0.0,
z: objDistance
});
var after = Vec3.multiplyQbyV(Camera.orientation, {
x: 0.0,
y: 0.0,
z: objDistance
});
var change = Vec3.subtract(before, after);
this.currentCameraOrientation = Camera.orientation;
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change);
}
} else {
// print('should not head move!');
}
var defaultConstraintData = {
axisStart: false,
axisEnd: false,
}
var constraintData = getEntityCustomData('lightModifierKey', this.grabbedEntity, defaultConstraintData);
var clampedVector;
var targetPosition;
if (constraintData.axisStart !== false) {
clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisStart, constraintData.axisEnd);
targetPosition = clampedVector;
} else {
targetPosition = {
x: this.currentObjectPosition.x,
y: this.currentObjectPosition.y,
z: this.currentObjectPosition.z
}
}
@ -1182,7 +1238,7 @@ function MyController(hand) {
}
Entities.updateAction(this.grabbedEntity, this.actionID, {
targetPosition: this.currentObjectPosition,
targetPosition: targetPosition,
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
targetRotation: this.currentObjectRotation,
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
@ -1190,98 +1246,122 @@ function MyController(hand) {
});
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
};
this.nearGrabbing = function() {
var now = Date.now();
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
this.projectVectorAlongAxis = function(position, axisStart, axisEnd) {
if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) {
this.setState(STATE_RELEASE);
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
return;
}
var aPrime = Vec3.subtract(position, axisStart);
this.turnOffVisualizations();
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
this.activateEntity(this.grabbedEntity, grabbedProperties);
if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) {
Entities.editEntity(this.grabbedEntity, {
collisionsWillMove: false
});
}
var bPrime = Vec3.subtract(axisEnd, axisStart);
var handRotation = this.getHandRotation();
var handPosition = this.getHandPosition();
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
var objectRotation = grabbedProperties.rotation;
var currentObjectPosition = grabbedProperties.position;
var offset = Vec3.subtract(currentObjectPosition, handPosition);
if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) {
// if an object is "equipped" and has a spatialKey, use it.
this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false;
if (grabbableData.spatialKey.relativePosition || grabbableData.spatialKey.rightRelativePosition
|| grabbableData.spatialKey.leftRelativePosition) {
this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey);
} else {
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
var bPrimeMagnitude = Vec3.length(bPrime);
var dotProduct = Vec3.dot(aPrime, bPrime);
var scalar = dotProduct / bPrimeMagnitude;
if (scalar < 0) {
scalar = 0;
}
if (grabbableData.spatialKey.relativeRotation || grabbableData.spatialKey.rightRelativeRotation
|| grabbableData.spatialKey.leftRelativeRotation) {
if (scalar > 1) {
scalar = 1;
}
var projection = Vec3.sum(axisStart, Vec3.multiply(scalar, Vec3.normalize(bPrime)));
return projection
},
this.nearGrabbing = function() {
var now = Date.now();
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) {
this.setState(STATE_RELEASE);
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
return;
}
this.lineOff();
this.overlayLineOff();
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
this.activateEntity(this.grabbedEntity, grabbedProperties);
if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) {
Entities.editEntity(this.grabbedEntity, {
collisionsWillMove: false
});
}
var handRotation = this.getHandRotation();
var handPosition = this.getHandPosition();
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) {
// if an object is "equipped" and has a spatialKey, use it.
this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false;
this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey);
this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey);
} else {
this.ignoreIK = false;
var objectRotation = grabbedProperties.rotation;
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
}
} else {
this.ignoreIK = false;
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
}
this.actionID = NULL_ACTION_ID;
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
hand: this.hand === RIGHT_HAND ? "right" : "left",
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
relativePosition: this.offsetPosition,
relativeRotation: this.offsetRotation,
ttl: ACTION_TTL,
kinematic: NEAR_GRABBING_KINEMATIC,
kinematicSetVelocity: true,
ignoreIK: this.ignoreIK
});
if (this.actionID === NULL_ACTION_ID) {
this.actionID = null;
} else {
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
if (this.state == STATE_NEAR_GRABBING) {
this.setState(STATE_CONTINUE_NEAR_GRABBING);
var currentObjectPosition = grabbedProperties.position;
var offset = Vec3.subtract(currentObjectPosition, handPosition);
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
}
this.actionID = NULL_ACTION_ID;
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
hand: this.hand === RIGHT_HAND ? "right" : "left",
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
relativePosition: this.offsetPosition,
relativeRotation: this.offsetRotation,
ttl: ACTION_TTL,
kinematic: NEAR_GRABBING_KINEMATIC,
kinematicSetVelocity: true,
ignoreIK: this.ignoreIK
});
if (this.actionID === NULL_ACTION_ID) {
this.actionID = null;
} else {
// equipping
Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]);
this.startHandGrasp();
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
if (this.state == STATE_NEAR_GRABBING) {
this.setState(STATE_CONTINUE_NEAR_GRABBING);
} else {
// equipping
Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]);
this.startHandGrasp();
this.setState(STATE_CONTINUE_EQUIP_BD);
}
if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
} else {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]);
Entities.callEntityMethod(this.grabbedEntity, "startNearGrab");
this.setState(STATE_CONTINUE_EQUIP_BD);
}
if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
} else {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
this.currentHandControllerTipPosition =
(this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition;
Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]);
Entities.callEntityMethod(this.grabbedEntity, "startNearGrab");
}
this.currentHandControllerTipPosition =
(this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition;
this.currentObjectTime = Date.now();
};
this.currentObjectTime = Date.now();
};
this.continueNearGrabbing = function() {
if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) {
@ -1470,7 +1550,7 @@ function MyController(hand) {
}
if (USE_ENTITY_LINES_FOR_MOVING === true) {
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
}
Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger");
@ -1551,7 +1631,34 @@ function MyController(hand) {
if (this.grabbedEntity !== null) {
if (this.actionID !== null) {
Entities.deleteAction(this.grabbedEntity, this.actionID);
//add velocity whatnot
var defaultReleaseVelocityData = {
disableReleaseVelocity: false
};
//sometimes we want things to stay right where they are when we let go.
var releaseVelocityData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultReleaseVelocityData);
if (releaseVelocityData.disableReleaseVelocity === true) {
Entities.deleteAction(this.grabbedEntity, this.actionID);
Entities.editEntity(this.grabbedEntity, {
velocity: {
x: 0,
y: 0,
z: 0
},
angularVelocity: {
x: 0,
y: 0,
z: 0
}
})
Entities.deleteAction(this.grabbedEntity, this.actionID);
} else {
//don't make adjustments
Entities.deleteAction(this.grabbedEntity, this.actionID);
}
}
}
@ -1681,7 +1788,7 @@ Controller.enableMapping(MAPPING_NAME);
var handToDisable = 'none';
function update() {
if (handToDisable !== LEFT_HAND && handToDisable!=='both') {
if (handToDisable !== LEFT_HAND && handToDisable !== 'both') {
leftController.update();
}
if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') {
@ -1707,22 +1814,22 @@ handleHandMessages = function(channel, message, sender) {
}
} else if (channel === 'Hifi-Hand-Grab') {
try {
var data = JSON.parse(message);
var selectedController = (data.hand === 'left') ? leftController : rightController;
selectedController.release();
selectedController.setState(STATE_EQUIP);
selectedController.grabbedEntity = data.entityID;
} catch (e) { }
}
else if (channel === 'Hifi-Hand-RayPick-Blacklist' && sender === MyAvatar.sessionUUID) {
var data = JSON.parse(message);
var selectedController = (data.hand === 'left') ? leftController : rightController;
selectedController.release();
selectedController.setState(STATE_EQUIP);
selectedController.grabbedEntity = data.entityID;
} catch (e) {}
} else if (channel === 'Hifi-Hand-RayPick-Blacklist') {
try {
var data = JSON.parse(message);
var action = data.action;
var id = data.id;
var index = blacklist.indexOf(id);
if (action === 'add' && index ===-1) {
if (action === 'add' && index === -1) {
blacklist.push(id);
}
if (action === 'remove') {

File diff suppressed because it is too large Load diff

View file

@ -53,7 +53,9 @@ LightOverlayManager = function() {
if (visible != isVisible) {
visible = isVisible;
for (var id in entityOverlays) {
Overlays.editOverlay(entityOverlays[id], { visible: visible });
Overlays.editOverlay(entityOverlays[id], {
visible: visible
});
}
}
};
@ -61,8 +63,7 @@ LightOverlayManager = function() {
// Allocate or get an unused overlay
function getOverlay() {
if (unusedOverlays.length == 0) {
var overlay = Overlays.addOverlay("image3d", {
});
var overlay = Overlays.addOverlay("image3d", {});
allOverlays.push(overlay);
} else {
var overlay = unusedOverlays.pop();
@ -72,7 +73,9 @@ LightOverlayManager = function() {
function releaseOverlay(overlay) {
unusedOverlays.push(overlay);
Overlays.editOverlay(overlay, { visible: false });
Overlays.editOverlay(overlay, {
visible: false
});
}
function addEntity(entityID) {
@ -88,7 +91,11 @@ LightOverlayManager = function() {
visible: visible,
alpha: 0.9,
scale: 0.5,
color: { red: 255, green: 255, blue: 255 }
color: {
red: 255,
green: 255,
blue: 255
}
});
}
}
@ -123,4 +130,4 @@ LightOverlayManager = function() {
Overlays.deleteOverlay(allOverlays[i]);
}
});
};
};

View file

@ -0,0 +1,29 @@
This PR demonstrates one way in-world editing of objects might work.
Running this script will show light overlay icons in-world. Enter edit mode by running your distance beam through a light overlay. Exit using the red X.
When you distant grab the sliders, you can move them along their axis to change their values. You may also rotate / move the block to which the spotlight is attached.
To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js
To reset, I recommend stopping all scripts then re-loading lightLoader.js
When you run the lightLoader.js script, several scripts will be loaded:
- handControllerGrab.js (will not impart velocity when you move the parent or a slider, will not move sliders with head movement,will constrain movement for a slider to a given axis start and end, will support blacklisting of entities for raypicking during search for objects)
- lightModifier.js (listens for message to create sliders for a given light. will start with slider set to the light's initial properties)
- lightModifierTestScene.js (creates a light)
- slider.js (attached to each slider entity)
- lightParent.js (attached to a 3d model of a light, to which a light is parented, so you can move it around. or keep the current parent if a light already has a parent)
- visiblePanel.js (the transparent panel)
- closeButton.js (for closing the ui)
- ../libraries/lightOverlayManager.js (shows 2d overlays for lights in the world)
- ../libraries/entitySelectionTool.js (visualizes volume of the lights)
Current sliders are (top to bottom):
red
green
blue
intensity
cutoff
exponent
![capture](https://cloud.githubusercontent.com/assets/843228/11910139/afaaf1ae-a5a5-11e5-8b66-0eb3fc6976df.PNG)

View file

@ -0,0 +1,36 @@
//
// closeButton.js
//
// Created by James Pollack @imgntn on 12/15/2015
// Copyright 2015 High Fidelity, Inc.
//
// Entity script that closes sliders when interacted with.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
function CloseButton() {
return this;
}
CloseButton.prototype = {
preload: function(entityID) {
this.entityID = entityID;
var entityProperties = Entities.getEntityProperties(this.entityID, "userData");
this.initialProperties = entityProperties
this.userData = JSON.parse(entityProperties.userData);
},
startNearGrab: function() {
},
startFarTrigger: function() {
Messages.sendMessage('Hifi-Light-Modifier-Cleanup', 'callCleanup')
}
};
return new CloseButton();
});

View file

@ -0,0 +1,20 @@
//
// lightLoader.js
//
// Created by James Pollack @imgntn on 12/15/2015
// Copyright 2015 High Fidelity, Inc.
//
// Loads a test scene showing sliders that you can grab and move to change entity properties.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var grabScript = Script.resolvePath('../controllers/handControllerGrab.js?' + Math.random(0 - 100));
Script.load(grabScript);
var lightModifier = Script.resolvePath('lightModifier.js?' + Math.random(0 - 100));
Script.load(lightModifier);
Script.setTimeout(function() {
var lightModifierTestScene = Script.resolvePath('lightModifierTestScene.js?' + Math.random(0 - 100));
Script.load(lightModifierTestScene);
}, 750)

View file

@ -0,0 +1,876 @@
//
// lightModifier.js
//
// Created by James Pollack @imgntn on 12/15/2015
// Copyright 2015 High Fidelity, Inc.
//
// Given a selected light, instantiate some entities that represent various values you can dynamically adjust by grabbing and moving.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
//some experimental options
var ONLY_I_CAN_EDIT = false;
var SLIDERS_SHOULD_STAY_WITH_AVATAR = false;
var VERTICAL_SLIDERS = false;
var SHOW_OVERLAYS = true;
var SHOW_LIGHT_VOLUME = true;
var USE_PARENTED_PANEL = true;
var VISIBLE_PANEL = true;
var USE_LABELS = true;
var LEFT_LABELS = false;
var RIGHT_LABELS = true;
var ROTATE_CLOSE_BUTTON = false;
//variables for managing overlays
var selectionDisplay;
var selectionManager;
var lightOverlayManager;
//for when we make a 3d model of a light a parent for the light
var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?' + Math.random(0 - 100));
if (SHOW_OVERLAYS === true) {
Script.include('../libraries/gridTool.js');
Script.include('../libraries/entitySelectionTool.js?' + Math.random(0 - 100));
Script.include('../libraries/lightOverlayManager.js');
var grid = Grid();
gridTool = GridTool({
horizontalGrid: grid
});
gridTool.setVisible(false);
selectionDisplay = SelectionDisplay;
selectionManager = SelectionManager;
lightOverlayManager = new LightOverlayManager();
selectionManager.addEventListener(function() {
selectionDisplay.updateHandles();
lightOverlayManager.updatePositions();
});
lightOverlayManager.setVisible(true);
}
var DEFAULT_PARENT_ID = '{00000000-0000-0000-0000-000000000000}'
var AXIS_SCALE = 1;
var COLOR_MAX = 255;
var INTENSITY_MAX = 0.05;
var CUTOFF_MAX = 360;
var EXPONENT_MAX = 1;
var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100));
var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_very_good.fbx';
var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx';
var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100));
var TRANSPARENT_PANEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/transparent_box_alpha_15.fbx';
var VISIBLE_PANEL_SCRIPT_URL = Script.resolvePath('visiblePanel.js?' + Math.random(0, 100));
var RED = {
red: 255,
green: 0,
blue: 0
};
var GREEN = {
red: 0,
green: 255,
blue: 0
};
var BLUE = {
red: 0,
green: 0,
blue: 255
};
var PURPLE = {
red: 255,
green: 0,
blue: 255
};
var WHITE = {
red: 255,
green: 255,
blue: 255
};
var ORANGE = {
red: 255,
green: 165,
blue: 0
}
var SLIDER_DIMENSIONS = {
x: 0.075,
y: 0.075,
z: 0.075
};
var CLOSE_BUTTON_DIMENSIONS = {
x: 0.1,
y: 0.025,
z: 0.1
}
var LIGHT_MODEL_DIMENSIONS = {
x: 0.58,
y: 1.21,
z: 0.57
}
var PER_ROW_OFFSET = {
x: 0,
y: -0.2,
z: 0
};
var sliders = [];
var slidersRef = {
'color_red': null,
'color_green': null,
'color_blue': null,
intensity: null,
cutoff: null,
exponent: null
};
var light = null;
var basePosition;
var avatarRotation;
function entitySlider(light, color, sliderType, displayText, row) {
this.light = light;
this.lightID = light.id.replace(/[{}]/g, "");
this.initialProperties = light.initialProperties;
this.color = color;
this.sliderType = sliderType;
this.displayText = displayText;
this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET);
this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0);
this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot)));
this.basePosition.y += 1;
basePosition = this.basePosition;
avatarRot = this.avatarRot;
var message = {
lightID: this.lightID,
sliderType: this.sliderType,
sliderValue: null
};
if (this.sliderType === 'color_red') {
message.sliderValue = this.initialProperties.color.red
this.setValueFromMessage(message);
}
if (this.sliderType === 'color_green') {
message.sliderValue = this.initialProperties.color.green
this.setValueFromMessage(message);
}
if (this.sliderType === 'color_blue') {
message.sliderValue = this.initialProperties.color.blue
this.setValueFromMessage(message);
}
if (this.sliderType === 'intensity') {
message.sliderValue = this.initialProperties.intensity
this.setValueFromMessage(message);
}
if (this.sliderType === 'exponent') {
message.sliderValue = this.initialProperties.exponent
this.setValueFromMessage(message);
}
if (this.sliderType === 'cutoff') {
message.sliderValue = this.initialProperties.cutoff
this.setValueFromMessage(message);
}
this.setInitialSliderPositions();
this.createAxis();
this.createSliderIndicator();
if (USE_LABELS === true) {
this.createLabel()
}
return this;
}
//what's the ux for adjusting values? start with simple entities, try image overlays etc
entitySlider.prototype = {
createAxis: function() {
//start of line
var position;
var extension;
if (VERTICAL_SLIDERS == true) {
position = Vec3.sum(this.basePosition, Vec3.multiply(row, (Vec3.multiply(0.2, Quat.getRight(this.avatarRot)))));
//line starts on bottom and goes up
var upVector = Quat.getUp(this.avatarRot);
extension = Vec3.multiply(AXIS_SCALE, upVector);
} else {
position = Vec3.sum(this.basePosition, this.verticalOffset);
//line starts on left and goes to right
//set the end of the line to the right
var rightVector = Quat.getRight(this.avatarRot);
extension = Vec3.multiply(AXIS_SCALE, rightVector);
}
this.axisStart = position;
this.endOfAxis = Vec3.sum(position, extension);
this.createEndOfAxisEntity();
var properties = {
type: 'Line',
name: 'Hifi-Slider-Axis::' + this.sliderType,
color: this.color,
collisionsWillMove: false,
ignoreForCollisions: true,
dimensions: {
x: 3,
y: 3,
z: 3
},
position: position,
linePoints: [{
x: 0,
y: 0,
z: 0
}, extension],
lineWidth: 5,
};
this.axis = Entities.addEntity(properties);
},
createEndOfAxisEntity: function() {
//we use this to track the end of the axis while parented to a panel
var properties = {
name: 'Hifi-End-Of-Axis',
type: 'Box',
collisionsWillMove: false,
ignoreForCollisions: true,
dimensions: {
x: 0.01,
y: 0.01,
z: 0.01
},
color: {
red: 255,
green: 255,
blue: 255
},
position: this.endOfAxis,
parentID: this.axis,
visible: false
}
this.endOfAxisEntity = Entities.addEntity(this.endOfAxis);
},
createLabel: function() {
var LABEL_WIDTH = 0.25
var PER_LETTER_SPACING = 0.1;
var textWidth = this.displayText.length * PER_LETTER_SPACING;
var position;
if (LEFT_LABELS === true) {
var leftVector = Vec3.multiply(-1, Quat.getRight(this.avatarRot));
var extension = Vec3.multiply(textWidth, leftVector);
position = Vec3.sum(this.axisStart, extension);
}
if (RIGHT_LABELS === true) {
var rightVector = Quat.getRight(this.avatarRot);
var extension = Vec3.multiply(textWidth / 1.75, rightVector);
position = Vec3.sum(this.endOfAxis, extension);
}
var labelProperties = {
name: 'Hifi-Slider-Label-' + this.sliderType,
type: 'Text',
dimensions: {
x: textWidth,
y: 0.2,
z: 0.1
},
textColor: {
red: 255,
green: 255,
blue: 255
},
text: this.displayText,
lineHeight: 0.14,
backgroundColor: {
red: 0,
green: 0,
blue: 0
},
position: position,
rotation: this.avatarRot,
}
print('BEFORE CREATE LABEL' + JSON.stringify(labelProperties))
this.label = Entities.addEntity(labelProperties);
print('AFTER CREATE LABEL')
},
createSliderIndicator: function() {
var extensionVector;
var position;
if (VERTICAL_SLIDERS == true) {
position = Vec3.sum(this.basePosition, Vec3.multiply(row, (Vec3.multiply(0.2, Quat.getRight(this.avatarRot)))));
extensionVector = Quat.getUp(this.avatarRot);
} else {
position = Vec3.sum(this.basePosition, this.verticalOffset);
extensionVector = Quat.getRight(this.avatarRot);
}
var initialDistance;
if (this.sliderType === 'color_red') {
initialDistance = this.distanceRed;
}
if (this.sliderType === 'color_green') {
initialDistance = this.distanceGreen;
}
if (this.sliderType === 'color_blue') {
initialDistance = this.distanceBlue;
}
if (this.sliderType === 'intensity') {
initialDistance = this.distanceIntensity;
}
if (this.sliderType === 'cutoff') {
initialDistance = this.distanceCutoff;
}
if (this.sliderType === 'exponent') {
initialDistance = this.distanceExponent;
}
var extension = Vec3.multiply(initialDistance, extensionVector);
var sliderPosition = Vec3.sum(position, extension);
var properties = {
type: 'Sphere',
name: 'Hifi-Slider-' + this.sliderType,
dimensions: SLIDER_DIMENSIONS,
collisionsWillMove: true,
color: this.color,
position: sliderPosition,
script: SLIDER_SCRIPT_URL,
ignoreForCollisions: true,
userData: JSON.stringify({
lightModifierKey: {
lightID: this.lightID,
sliderType: this.sliderType,
axisStart: position,
axisEnd: this.endOfAxis,
},
handControllerKey: {
disableReleaseVelocity: true,
disableMoveWithHead: true,
disableNearGrab:true
}
}),
};
this.sliderIndicator = Entities.addEntity(properties);
},
setValueFromMessage: function(message) {
//message is not for our light
if (message.lightID !== this.lightID) {
// print('not our light')
return;
}
//message is not our type
if (message.sliderType !== this.sliderType) {
// print('not our slider type')
return
}
var lightProperties = Entities.getEntityProperties(this.lightID);
if (this.sliderType === 'color_red') {
Entities.editEntity(this.lightID, {
color: {
red: message.sliderValue,
green: lightProperties.color.green,
blue: lightProperties.color.blue
}
});
}
if (this.sliderType === 'color_green') {
Entities.editEntity(this.lightID, {
color: {
red: lightProperties.color.red,
green: message.sliderValue,
blue: lightProperties.color.blue
}
});
}
if (this.sliderType === 'color_blue') {
Entities.editEntity(this.lightID, {
color: {
red: lightProperties.color.red,
green: lightProperties.color.green,
blue: message.sliderValue,
}
});
}
if (this.sliderType === 'intensity') {
Entities.editEntity(this.lightID, {
intensity: message.sliderValue
});
}
if (this.sliderType === 'cutoff') {
Entities.editEntity(this.lightID, {
cutoff: message.sliderValue
});
}
if (this.sliderType === 'exponent') {
Entities.editEntity(this.lightID, {
exponent: message.sliderValue
});
}
},
setInitialSliderPositions: function() {
this.distanceRed = (this.initialProperties.color.red / COLOR_MAX) * AXIS_SCALE;
this.distanceGreen = (this.initialProperties.color.green / COLOR_MAX) * AXIS_SCALE;
this.distanceBlue = (this.initialProperties.color.blue / COLOR_MAX) * AXIS_SCALE;
this.distanceIntensity = (this.initialProperties.intensity / INTENSITY_MAX) * AXIS_SCALE;
this.distanceCutoff = (this.initialProperties.cutoff / CUTOFF_MAX) * AXIS_SCALE;
this.distanceExponent = (this.initialProperties.exponent / EXPONENT_MAX) * AXIS_SCALE;
}
};
var panel;
var visiblePanel;
function makeSliders(light) {
if (USE_PARENTED_PANEL === true) {
panel = createPanelEntity(MyAvatar.position);
}
if (light.type === 'spotlight') {
var USE_COLOR_SLIDER = true;
var USE_INTENSITY_SLIDER = true;
var USE_CUTOFF_SLIDER = true;
var USE_EXPONENT_SLIDER = true;
}
if (light.type === 'pointlight') {
var USE_COLOR_SLIDER = true;
var USE_INTENSITY_SLIDER = true;
var USE_CUTOFF_SLIDER = false;
var USE_EXPONENT_SLIDER = false;
}
if (USE_COLOR_SLIDER === true) {
slidersRef.color_red = new entitySlider(light, RED, 'color_red', 'Red', 1);
slidersRef.color_green = new entitySlider(light, GREEN, 'color_green', 'Green', 2);
slidersRef.color_blue = new entitySlider(light, BLUE, 'color_blue', 'Blue', 3);
sliders.push(slidersRef.color_red);
sliders.push(slidersRef.color_green);
sliders.push(slidersRef.color_blue);
}
if (USE_INTENSITY_SLIDER === true) {
slidersRef.intensity = new entitySlider(light, WHITE, 'intensity', 'Intensity', 4);
sliders.push(slidersRef.intensity);
}
if (USE_CUTOFF_SLIDER === true) {
slidersRef.cutoff = new entitySlider(light, PURPLE, 'cutoff', 'Cutoff', 5);
sliders.push(slidersRef.cutoff);
}
if (USE_EXPONENT_SLIDER === true) {
slidersRef.exponent = new entitySlider(light, ORANGE, 'exponent', 'Exponent', 6);
sliders.push(slidersRef.exponent);
}
createCloseButton(slidersRef.color_red.axisStart);
subscribeToSliderMessages();
if (USE_PARENTED_PANEL === true) {
parentEntitiesToPanel(panel);
}
if (SLIDERS_SHOULD_STAY_WITH_AVATAR === true) {
parentPanelToAvatar(panel);
}
if (VISIBLE_PANEL === true) {
visiblePanel = createVisiblePanel();
}
};
function parentPanelToAvatar(panel) {
//this is going to need some more work re: the sliders actually being grabbable. probably something to do with updating axis movement
Entities.editEntity(panel, {
parentID: MyAvatar.sessionUUID,
//actually figure out which one to parent it to -- probably a spine or something.
parentJointIndex: 1,
})
}
function parentEntitiesToPanel(panel) {
sliders.forEach(function(slider) {
Entities.editEntity(slider.axis, {
parentID: panel
})
Entities.editEntity(slider.sliderIndicator, {
parentID: panel
})
})
closeButtons.forEach(function(button) {
Entities.editEntity(button, {
parentID: panel
})
})
}
function createPanelEntity(position) {
print('CREATING PANEL at ' + JSON.stringify(position));
var panelProperties = {
name: 'Hifi-Slider-Panel',
type: 'Box',
dimensions: {
x: 0.1,
y: 0.1,
z: 0.1
},
visible: false,
collisionsWillMove: false,
ignoreForCollisions: true
}
var panel = Entities.addEntity(panelProperties);
return panel
}
function createVisiblePanel() {
var totalOffset = -PER_ROW_OFFSET.y * sliders.length;
var moveRight = Vec3.sum(basePosition, Vec3.multiply(AXIS_SCALE / 2, Quat.getRight(avatarRot)));
var moveDown = Vec3.sum(moveRight, Vec3.multiply((sliders.length + 1) / 2, PER_ROW_OFFSET))
var panelProperties = {
name: 'Hifi-Visible-Transparent-Panel',
type: 'Model',
modelURL: TRANSPARENT_PANEL_URL,
dimensions: {
x: AXIS_SCALE + 0.1,
y: totalOffset,
z: SLIDER_DIMENSIONS.z / 4
},
visible: true,
collisionsWillMove: false,
ignoreForCollisions: true,
position: moveDown,
rotation: avatarRot,
script: VISIBLE_PANEL_SCRIPT_URL
}
var panel = Entities.addEntity(panelProperties);
return panel
}
function createLightModel(position, rotation) {
var blockProperties = {
name: 'Hifi-Spotlight-Model',
type: 'Model',
shapeType: 'box',
modelURL: LIGHT_MODEL_URL,
dimensions: LIGHT_MODEL_DIMENSIONS,
collisionsWillMove: true,
position: position,
rotation: rotation,
script: PARENT_SCRIPT_URL,
userData: JSON.stringify({
handControllerKey: {
disableReleaseVelocity: true
}
})
};
var block = Entities.addEntity(blockProperties);
return block
}
var closeButtons = [];
function createCloseButton(axisStart) {
var MARGIN = 0.10;
var VERTICAL_OFFFSET = {
x: 0,
y: 0.15,
z: 0
};
var leftVector = Vec3.multiply(-1, Quat.getRight(avatarRot));
var extension = Vec3.multiply(MARGIN, leftVector);
var position = Vec3.sum(axisStart, extension);
var buttonProperties = {
name: 'Hifi-Close-Button',
type: 'Model',
modelURL: CLOSE_BUTTON_MODEL_URL,
dimensions: CLOSE_BUTTON_DIMENSIONS,
position: Vec3.sum(position, VERTICAL_OFFFSET),
rotation: Quat.multiply(avatarRot, Quat.fromPitchYawRollDegrees(90, 0, 45)),
//rotation: Quat.fromPitchYawRollDegrees(0, 0, 90),
collisionsWillMove: false,
ignoreForCollisions: true,
script: CLOSE_BUTTON_SCRIPT_URL,
userData: JSON.stringify({
grabbableKey: {
wantsTrigger: true
}
})
}
var button = Entities.addEntity(buttonProperties);
closeButtons.push(button);
if (ROTATE_CLOSE_BUTTON === true) {
Script.update.connect(rotateCloseButtons);
}
}
function rotateCloseButtons() {
closeButtons.forEach(function(button) {
Entities.editEntity(button, {
angularVelocity: {
x: 0,
y: 0.5,
z: 0
}
})
})
}
function subScribeToNewLights() {
Messages.subscribe('Hifi-Light-Mod-Receiver');
Messages.messageReceived.connect(handleLightModMessages);
}
function subscribeToSliderMessages() {
Messages.subscribe('Hifi-Slider-Value-Reciever');
Messages.messageReceived.connect(handleValueMessages);
}
function subscribeToLightOverlayRayCheckMessages() {
Messages.subscribe('Hifi-Light-Overlay-Ray-Check');
Messages.messageReceived.connect(handleLightOverlayRayCheckMessages);
}
function subscribeToCleanupMessages() {
Messages.subscribe('Hifi-Light-Modifier-Cleanup');
Messages.messageReceived.connect(handleCleanupMessages);
}
function handleLightModMessages(channel, message, sender) {
if (channel !== 'Hifi-Light-Mod-Receiver') {
return;
}
if (sender !== MyAvatar.sessionUUID) {
return;
}
var parsedMessage = JSON.parse(message);
makeSliders(parsedMessage.light);
light = parsedMessage.light.id
if (SHOW_LIGHT_VOLUME === true) {
selectionManager.setSelections([parsedMessage.light.id]);
}
}
function handleValueMessages(channel, message, sender) {
if (channel !== 'Hifi-Slider-Value-Reciever') {
return;
}
if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) {
return;
}
var parsedMessage = JSON.parse(message);
slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage);
}
var currentLight;
var block;
var oldParent = null;
var hasParent = false;
function handleLightOverlayRayCheckMessages(channel, message, sender) {
if (channel !== 'Hifi-Light-Overlay-Ray-Check') {
return;
}
if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) {
return;
}
var pickRay = JSON.parse(message);
var doesIntersect = lightOverlayManager.findRayIntersection(pickRay);
// print('DOES INTERSECT A LIGHT WE HAVE???' + doesIntersect.intersects);
if (doesIntersect.intersects === true) {
// print('FULL MESSAGE:::' + JSON.stringify(doesIntersect))
var lightID = doesIntersect.entityID;
if (currentLight === lightID) {
// print('ALREADY HAVE A BLOCK, EXIT')
return;
}
currentLight = lightID;
var lightProperties = Entities.getEntityProperties(lightID);
if (lightProperties.parentID !== DEFAULT_PARENT_ID) {
//this light has a parent already. so lets call our block the parent and then make sure not to delete it at the end;
oldParent = lightProperties.parentID;
hasParent = true;
block = lightProperties.parentID;
if (lightProperties.parentJointIndex !== -1) {
//should make sure to retain the parent too. but i don't actually know what the
}
} else {
block = createLightModel(lightProperties.position, lightProperties.rotation);
}
var light = {
id: lightID,
type: 'spotlight',
initialProperties: lightProperties
}
makeSliders(light);
if (SHOW_LIGHT_VOLUME === true) {
selectionManager.setSelections([lightID]);
}
Entities.editEntity(lightID, {
parentID: block,
parentJointIndex: -1
});
}
}
function handleCleanupMessages(channel, message, sender) {
if (channel !== 'Hifi-Light-Modifier-Cleanup') {
return;
}
if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) {
return;
}
if (message === 'callCleanup') {
cleanup(true);
}
}
function updateSliderAxis() {
sliders.forEach(function(slider) {
})
}
function cleanup(fromMessage) {
var i;
for (i = 0; i < sliders.length; i++) {
Entities.deleteEntity(sliders[i].axis);
Entities.deleteEntity(sliders[i].sliderIndicator);
Entities.deleteEntity(sliders[i].label);
}
while (closeButtons.length > 0) {
Entities.deleteEntity(closeButtons.pop());
}
//if the light was already parented to something we will want to restore that. or come up with groups or something clever.
if (oldParent !== null) {
Entities.editEntity(currentLight, {
parentID: oldParent,
});
} else {
Entities.editEntity(currentLight, {
parentID: null,
});
}
if (fromMessage !== true) {
Messages.messageReceived.disconnect(handleLightModMessages);
Messages.messageReceived.disconnect(handleValueMessages);
Messages.messageReceived.disconnect(handleLightOverlayRayCheckMessages);
lightOverlayManager.setVisible(false);
}
Entities.deleteEntity(panel);
Entities.deleteEntity(visiblePanel);
selectionManager.clearSelections();
if (ROTATE_CLOSE_BUTTON === true) {
Script.update.disconnect(rotateCloseButtons);
}
if (hasParent === false) {
Entities.deleteEntity(block);
}
oldParent = null;
hasParent = false;
currentLight = null;
sliders = [];
}
Script.scriptEnding.connect(cleanup);
Script.scriptEnding.connect(function() {
lightOverlayManager.setVisible(false);
})
subscribeToLightOverlayRayCheckMessages();
subScribeToNewLights();
subscribeToCleanupMessages();
//other light properties
// diffuseColor: { red: 255, green: 255, blue: 255 },
// ambientColor: { red: 255, green: 255, blue: 255 },
// specularColor: { red: 255, green: 255, blue: 255 },
// constantAttenuation: 1,
// linearAttenuation: 0,
// quadraticAttenuation: 0,
// exponent: 0,
// cutoff: 180, // in degrees

View file

@ -0,0 +1,73 @@
//
// lightModifierTestScene.js
//
// Created by James Pollack @imgntn on 12/15/2015
// Copyright 2015 High Fidelity, Inc.
//
// Given a selected light, instantiate some entities that represent various values you can dynamically adjust.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?' + Math.random(0 - 100));
var basePosition, avatarRot;
avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0);
basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(0, Quat.getUp(avatarRot)));
var light;
function createLight() {
var position = basePosition;
position.y += 2;
var lightTransform = evalLightWorldTransform(position, avatarRot);
var lightProperties = {
name: 'Hifi-Spotlight',
type: "Light",
isSpotlight: true,
dimensions: {
x: 2,
y: 2,
z: 8
},
color: {
red: 255,
green: 0,
blue: 255
},
intensity: 0.035,
exponent: 1,
cutoff: 30,
lifetime: -1,
position: lightTransform.p,
rotation: lightTransform.q
};
light = Entities.addEntity(lightProperties);
}
function evalLightWorldTransform(modelPos, modelRot) {
var MODEL_LIGHT_POSITION = {
x: 0,
y: -0.3,
z: 0
};
var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, {
x: 1,
y: 0,
z: 0
});
return {
p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)),
q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION)
};
}
function cleanup() {
Entities.deleteEntity(light);
}
Script.scriptEnding.connect(cleanup);
createLight();

View file

@ -0,0 +1,40 @@
//
// lightParent.js
//
// Created by James Pollack @imgntn on 12/15/2015
// Copyright 2015 High Fidelity, Inc.
//
// Entity script that tells the light parent to update the selection tool when we move it.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
function LightParent() {
return this;
}
LightParent.prototype = {
preload: function(entityID) {
this.entityID = entityID;
var entityProperties = Entities.getEntityProperties(this.entityID, "userData");
this.initialProperties = entityProperties
this.userData = JSON.parse(entityProperties.userData);
},
startNearGrab: function() {},
startDistantGrab: function() {
},
continueNearGrab: function() {
this.continueDistantGrab();
},
continueDistantGrab: function() {
Messages.sendMessage('entityToolUpdates', 'callUpdate');
},
};
return new LightParent();
});

View file

@ -0,0 +1,105 @@
//
// slider.js
//
// Created by James Pollack @imgntn on 12/15/2015
// Copyright 2015 High Fidelity, Inc.
//
// Entity script that sends a scaled value to a light based on its distance from the start of its constraint axis.
//
// 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 AXIS_SCALE = 1;
var COLOR_MAX = 255;
var INTENSITY_MAX = 0.05;
var CUTOFF_MAX = 360;
var EXPONENT_MAX = 1;
function Slider() {
return this;
}
Slider.prototype = {
preload: function(entityID) {
this.entityID = entityID;
var entityProperties = Entities.getEntityProperties(this.entityID, "userData");
var parsedUserData = JSON.parse(entityProperties.userData);
this.userData = parsedUserData.lightModifierKey;
},
startNearGrab: function() {
this.setInitialProperties();
},
startDistantGrab: function() {
this.setInitialProperties();
},
setInitialProperties: function() {
this.initialProperties = Entities.getEntityProperties(this.entityID);
},
continueNearGrab: function() {
// this.continueDistantGrab();
},
continueDistantGrab: function() {
this.setSliderValueBasedOnDistance();
},
setSliderValueBasedOnDistance: function() {
var currentPosition = Entities.getEntityProperties(this.entityID, "position").position;
var distance = Vec3.distance(this.userData.axisStart, currentPosition);
if (this.userData.sliderType === 'color_red' || this.userData.sliderType === 'color_green' || this.userData.sliderType === 'color_blue') {
this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, COLOR_MAX);
}
if (this.userData.sliderType === 'intensity') {
this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, INTENSITY_MAX);
}
if (this.userData.sliderType === 'cutoff') {
this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, CUTOFF_MAX);
}
if (this.userData.sliderType === 'exponent') {
this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, EXPONENT_MAX);
};
this.sendValueToSlider();
},
releaseGrab: function() {
Entities.editEntity(this.entityID, {
velocity: {
x: 0,
y: 0,
z: 0
},
angularVelocity: {
x: 0,
y: 0,
z: 0
}
})
this.sendValueToSlider();
},
scaleValueBasedOnDistanceFromStart: function(value, min2, max2) {
var min1 = 0;
var max1 = AXIS_SCALE;
var min2 = min2;
var max2 = max2;
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
},
sendValueToSlider: function() {
var _t = this;
var message = {
lightID: _t.userData.lightID,
sliderType: _t.userData.sliderType,
sliderValue: _t.sliderValue
}
Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message));
if (_t.userData.sliderType === 'cutoff') {
Messages.sendMessage('entityToolUpdates', 'callUpdate');
}
}
};
return new Slider();
});

View file

@ -0,0 +1,40 @@
//
// visiblePanel.js
//
// Created by James Pollack @imgntn on 12/15/2015
// Copyright 2015 High Fidelity, Inc.
//
// Entity script that disables picking on this panel.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
function VisiblePanel() {
return this;
}
VisiblePanel.prototype = {
preload: function(entityID) {
this.entityID = entityID;
var data = {
action: 'add',
id: this.entityID
};
Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data))
},
unload: function() {
var data = {
action: 'remove',
id: this.entityID
};
Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data))
}
};
return new VisiblePanel();
});

View file

@ -29,21 +29,14 @@
this.equipped = false;
this.forceMultiplier = 1;
this.laserLength = 100;
this.laserOffsets = {
y: .095
};
this.firingOffsets = {
z: 0.16
}
this.fireSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Guns/GUN-SHOT2.raw");
this.ricochetSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Guns/Ricochet.L.wav");
this.playRichochetSoundChance = 0.1;
this.fireVolume = 0.2;
this.bulletForce = 10;
this.showLaser = false;
};
Pistol.prototype = {
@ -58,20 +51,36 @@
if (!this.equipped) {
return;
}
this.toggleWithTriggerPressure();
this.updateProps();
if (this.showLaser) {
this.updateLaser();
}
this.toggleWithTriggerPressure();
},
updateProps: function() {
var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
this.position = gunProps.position;
this.rotation = gunProps.rotation;
this.firingDirection = Quat.getFront(this.rotation);
var upVec = Quat.getUp(this.rotation);
this.barrelPoint = Vec3.sum(this.position, Vec3.multiply(upVec, this.laserOffsets.y));
this.laserTip = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.laserLength));
this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z))
var pickRay = {
origin: this.barrelPoint,
direction: this.firingDirection
};
},
toggleWithTriggerPressure: function() {
this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.hand]);
if (this.triggerValue < RELOAD_THRESHOLD) {
// print('RELOAD');
this.canShoot = true;
}
if (this.canShoot === true && this.triggerValue === 1) {
// print('SHOOT');
this.fire();
this.canShoot = false;
}
@ -91,17 +100,10 @@
},
updateLaser: function() {
var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
var position = gunProps.position;
var rotation = gunProps.rotation;
this.firingDirection = Quat.getFront(rotation);
var upVec = Quat.getUp(rotation);
this.barrelPoint = Vec3.sum(position, Vec3.multiply(upVec, this.laserOffsets.y));
var laserTip = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.laserLength));
this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z))
Overlays.editOverlay(this.laser, {
start: this.barrelPoint,
end: laserTip,
end: this.laserTip,
alpha: 1
});
},
@ -114,19 +116,6 @@
});
},
preload: function(entityID) {
this.entityID = entityID;
// this.initControllerMapping();
this.laser = Overlays.addOverlay("line3d", {
start: ZERO_VECTOR,
end: ZERO_VECTOR,
color: COLORS.RED,
alpha: 1,
visible: true,
lineWidth: 2
});
},
triggerPress: function(hand, value) {
if (this.hand === hand && value === 1) {
//We are pulling trigger on the hand we have the gun in, so fire
@ -135,15 +124,16 @@
},
fire: function() {
var pickRay = {
origin: this.barrelPoint,
direction: this.firingDirection
};
Audio.playSound(this.fireSound, {
position: this.barrelPoint,
volume: this.fireVolume
});
var pickRay = {
origin: this.barrelPoint,
direction: this.firingDirection
};
this.createGunFireEffect(this.barrelPoint)
var intersection = Entities.findRayIntersectionBlocking(pickRay, true);
if (intersection.intersects) {
@ -170,11 +160,11 @@
},
createEntityHitEffect: function(position) {
var flash = Entities.addEntity({
var sparks = Entities.addEntity({
type: "ParticleEffect",
position: position,
lifetime: 4,
"name": "Flash Emitter",
"name": "Sparks Emitter",
"color": {
red: 228,
green: 128,
@ -228,7 +218,7 @@
});
Script.setTimeout(function() {
Entities.editEntity(flash, {
Entities.editEntity(sparks, {
isEmitting: false
});
}, 100);
@ -261,11 +251,11 @@
"z": 0
},
"accelerationSpread": {
"x": .2,
"x": 0.2,
"y": 0,
"z": .2
"z": 0.2
},
"radiusSpread": .04,
"radiusSpread": 0.04,
"particleRadius": 0.07,
"radiusStart": 0.07,
"radiusFinish": 0.07,
@ -282,11 +272,46 @@
});
}, 100);
var flash = Entities.addEntity({
Entities.editEntity(this.flash, {
isEmitting: true
});
Script.setTimeout(function() {
Entities.editEntity(_this.flash, {
isEmitting: false
});
}, 100)
},
preload: function(entityID) {
this.entityID = entityID;
this.laser = Overlays.addOverlay("line3d", {
start: ZERO_VECTOR,
end: ZERO_VECTOR,
color: COLORS.RED,
alpha: 1,
visible: true,
lineWidth: 2
});
this.laserOffsets = {
y: 0.095
};
this.firingOffsets = {
z: 0.16
}
var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
var position = gunProps.position;
var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
this.firingDirection = Quat.getFront(rotation);
var upVec = Quat.getUp(rotation);
this.barrelPoint = Vec3.sum(position, Vec3.multiply(upVec, this.laserOffsets.y));
this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z))
this.flash = Entities.addEntity({
type: "ParticleEffect",
position: position,
lifetime: 4,
position: this.barrelPoint,
"name": "Muzzle Flash",
isEmitting: false,
"color": {
red: 228,
green: 128,
@ -339,16 +364,13 @@
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
});
Script.setTimeout(function() {
Entities.editEntity(flash, {
isEmitting: false
});
}, 100)
}
Script.setTimeout(function() {
Entities.editEntity(_this.flash, {parentID: _this.entityID});
}, 500)
},
};
// entity scripts always need to return a newly constructed object of our type
return new Pistol();
});
});

View file

@ -3486,78 +3486,86 @@ namespace render {
// Background rendering decision
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
if (skyStage->getBackgroundMode() == model::SunSkyStage::NO_BACKGROUND) {
auto backgroundMode = skyStage->getBackgroundMode();
if (backgroundMode == model::SunSkyStage::NO_BACKGROUND) {
// this line intentionally left blank
} else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_DOME) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
PerformanceTimer perfTimer("stars");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::payloadRender<BackgroundRenderData>() ... stars...");
// should be the first rendering pass - w/o depth buffer / lighting
// compute starfield alpha based on distance from atmosphere
float alpha = 1.0f;
bool hasStars = true;
if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
// TODO: handle this correctly for zones
const EnvironmentData& closestData = background->_environment->getClosestData(args->_viewFrustum->getPosition()); // was theCamera instead of _viewFrustum
if (closestData.getHasStars()) {
const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f;
const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f;
glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation())
/ closestData.getAtmosphereOuterRadius();
float height = glm::distance(args->_viewFrustum->getPosition()/*theCamera.getPosition()*/, closestData.getAtmosphereCenter());
if (height < closestData.getAtmosphereInnerRadius()) {
// If we're inside the atmosphere, then determine if our keyLight is below the horizon
alpha = 0.0f;
if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
float directionY = glm::clamp(sunDirection.y,
-APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
+ APPROXIMATE_DISTANCE_FROM_HORIZON;
alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
}
} else if (height < closestData.getAtmosphereOuterRadius()) {
alpha = (height - closestData.getAtmosphereInnerRadius()) /
(closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius());
if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
float directionY = glm::clamp(sunDirection.y,
-APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
+ APPROXIMATE_DISTANCE_FROM_HORIZON;
alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
}
}
} else {
hasStars = false;
}
} else {
if (backgroundMode == model::SunSkyStage::SKY_BOX) {
auto skybox = skyStage->getSkybox();
if (skybox && skybox->getCubemap() && skybox->getCubemap()->isDefined()) {
PerformanceTimer perfTimer("skybox");
skybox->render(batch, *(args->_viewFrustum));
} else {
// If no skybox texture is available, render the SKY_DOME while it loads
backgroundMode = model::SunSkyStage::SKY_DOME;
}
// finally render the starfield
if (hasStars) {
background->_stars.render(args, alpha);
}
// draw the sky dome
if (/*!selfAvatarOnly &&*/ Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
PerformanceTimer perfTimer("atmosphere");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... atmosphere...");
background->_environment->renderAtmospheres(batch, *(args->_viewFrustum));
}
}
} else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_BOX) {
PerformanceTimer perfTimer("skybox");
auto skybox = skyStage->getSkybox();
if (skybox) {
skybox->render(batch, *(args->_viewFrustum));
if (backgroundMode == model::SunSkyStage::SKY_DOME) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
PerformanceTimer perfTimer("stars");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::payloadRender<BackgroundRenderData>() ... stars...");
// should be the first rendering pass - w/o depth buffer / lighting
// compute starfield alpha based on distance from atmosphere
float alpha = 1.0f;
bool hasStars = true;
if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
// TODO: handle this correctly for zones
const EnvironmentData& closestData = background->_environment->getClosestData(args->_viewFrustum->getPosition()); // was theCamera instead of _viewFrustum
if (closestData.getHasStars()) {
const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f;
const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f;
glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation())
/ closestData.getAtmosphereOuterRadius();
float height = glm::distance(args->_viewFrustum->getPosition()/*theCamera.getPosition()*/, closestData.getAtmosphereCenter());
if (height < closestData.getAtmosphereInnerRadius()) {
// If we're inside the atmosphere, then determine if our keyLight is below the horizon
alpha = 0.0f;
if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
float directionY = glm::clamp(sunDirection.y,
-APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
+ APPROXIMATE_DISTANCE_FROM_HORIZON;
alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
}
} else if (height < closestData.getAtmosphereOuterRadius()) {
alpha = (height - closestData.getAtmosphereInnerRadius()) /
(closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius());
if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
float directionY = glm::clamp(sunDirection.y,
-APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
+ APPROXIMATE_DISTANCE_FROM_HORIZON;
alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
}
}
} else {
hasStars = false;
}
}
// finally render the starfield
if (hasStars) {
background->_stars.render(args, alpha);
}
// draw the sky dome
if (/*!selfAvatarOnly &&*/ Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
PerformanceTimer perfTimer("atmosphere");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... atmosphere...");
background->_environment->renderAtmospheres(batch, *(args->_viewFrustum));
}
}
}
}
}

View file

@ -141,6 +141,11 @@ void RenderablePolyLineEntityItem::updateVertices() {
_vertices << v1 << v2;
}
// Guard against an empty polyline
if (finalIndex < 0) {
return;
}
// For last point we can assume binormals are the same since it represents the last two vertices of quad
point = _points.at(finalIndex);
v1 = point + binormal;

View file

@ -96,7 +96,12 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
}
});
// Render
gpu::TexturePointer skymap = skybox.getCubemap();
// FIXME: skymap->isDefined may not be threadsafe
assert(skymap && skymap->isDefined());
glm::mat4 projMat;
viewFrustum.evalProjectionMatrix(projMat);
@ -106,11 +111,6 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
batch.setViewTransform(viewTransform);
batch.setModelTransform(Transform()); // only for Mac
gpu::TexturePointer skymap;
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
skymap = skybox.getCubemap();
}
batch.setPipeline(thePipeline);
batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, skybox._dataBuffer);
batch.setResourceTexture(SKYBOX_SKYMAP_SLOT, skymap);
@ -118,6 +118,5 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
batch.draw(gpu::TRIANGLE_STRIP, 4);
batch.setResourceTexture(SKYBOX_SKYMAP_SLOT, nullptr);
}

View file

@ -48,6 +48,10 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum,
}
if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) {
gpu::TexturePointer skymap = skybox.getCubemap();
// FIXME: skymap->isDefined may not be threadsafe
assert(skymap && skymap->isDefined());
glm::mat4 projMat;
viewFrustum.evalProjectionMatrix(projMat);
@ -56,10 +60,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum,
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewTransform);
batch.setModelTransform(Transform()); // only for Mac
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
batch.setResourceTexture(0, skybox.getCubemap());
}
batch.setResourceTexture(0, skybox.getCubemap());
skybox._procedural->prepare(batch, glm::vec3(0), glm::vec3(1));
batch.draw(gpu::TRIANGLE_STRIP, 4);