mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
fix merge conflicts
This commit is contained in:
commit
118f919c8b
16 changed files with 3955 additions and 1029 deletions
|
@ -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
|
@ -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]);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
29
examples/light_modifier/README.md
Normal file
29
examples/light_modifier/README.md
Normal 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
|
||||
|
||||

|
36
examples/light_modifier/closeButton.js
Normal file
36
examples/light_modifier/closeButton.js
Normal 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();
|
||||
});
|
20
examples/light_modifier/lightLoader.js
Normal file
20
examples/light_modifier/lightLoader.js
Normal 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)
|
876
examples/light_modifier/lightModifier.js
Normal file
876
examples/light_modifier/lightModifier.js
Normal 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
|
73
examples/light_modifier/lightModifierTestScene.js
Normal file
73
examples/light_modifier/lightModifierTestScene.js
Normal 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();
|
40
examples/light_modifier/lightParent.js
Normal file
40
examples/light_modifier/lightParent.js
Normal 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();
|
||||
});
|
105
examples/light_modifier/slider.js
Normal file
105
examples/light_modifier/slider.js
Normal 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();
|
||||
});
|
40
examples/light_modifier/visiblePanel.js
Normal file
40
examples/light_modifier/visiblePanel.js
Normal 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();
|
||||
});
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue