Merge branch 'master' of https://github.com/highfidelity/hifi into hobbes

This commit is contained in:
samcake 2015-10-08 12:06:34 -07:00
commit eacbcf2881
43 changed files with 3057 additions and 1430 deletions

View file

@ -32,7 +32,7 @@ var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to thei
var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did
var NO_INTERSECT_COLOR = { red: 10, green: 10, blue: 255}; // line color when pick misses
var INTERSECT_COLOR = { red: 250, green: 10, blue: 10}; // line color when pick hits
var LINE_ENTITY_DIMENSIONS = { x: 1000, y: 1000, z: 1000};
var LINE_ENTITY_DIMENSIONS = { x: 1000, y: 1000,z: 1000};
var LINE_LENGTH = 500;
@ -77,7 +77,9 @@ var STATE_NEAR_GRABBING = 4;
var STATE_CONTINUE_NEAR_GRABBING = 5;
var STATE_NEAR_GRABBING_NON_COLLIDING = 6;
var STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING = 7;
var STATE_RELEASE = 8;
var STATE_FAR_GRABBING_NON_COLLIDING = 8;
var STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING = 9;
var STATE_RELEASE = 10;
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js
@ -120,7 +122,7 @@ function MyController(hand, triggerAction) {
var TIP_CONTROLLER_OFFSET = 1;
this.triggerAction = triggerAction;
this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand;
this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET;
this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET;
this.actionID = null; // action this script created...
this.grabbedEntity = null; // on this entity.
@ -161,6 +163,12 @@ function MyController(hand, triggerAction) {
case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING:
this.continueNearGrabbingNonColliding();
break;
case STATE_FAR_GRABBING_NON_COLLIDING:
this.farGrabbingNonColliding();
break;
case STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING:
this.continueFarGrabbingNonColliding();
break;
case STATE_RELEASE:
this.release();
break;
@ -210,7 +218,7 @@ function MyController(hand, triggerAction) {
this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) +
(triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO));
}
this.triggerSmoothedSqueezed = function() {
return this.triggerValue > TRIGGER_ON_VALUE;
};
@ -251,9 +259,7 @@ function MyController(hand, triggerAction) {
};
var intersection = Entities.findRayIntersection(pickRay, true);
if (intersection.intersects &&
intersection.properties.collisionsWillMove === 1 &&
intersection.properties.locked === 0) {
if (intersection.intersects && intersection.properties.locked === 0) {
// the ray is intersecting something we can move.
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection);
@ -266,14 +272,22 @@ function MyController(hand, triggerAction) {
}
if (intersectionDistance < NEAR_PICK_MAX_DISTANCE) {
// the hand is very close to the intersected object. go into close-grabbing mode.
this.setState(STATE_NEAR_GRABBING);
if (intersection.properties.collisionsWillMove === 1) {
this.setState(STATE_NEAR_GRABBING);
} else {
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
}
} else {
// don't allow two people to distance grab the same object
if (entityIsGrabbedByOther(intersection.entityID)) {
this.grabbedEntity = null;
} else {
// the hand is far from the intersected object. go into distance-holding mode
this.setState(STATE_DISTANCE_HOLDING);
if (intersection.properties.collisionsWillMove === 1) {
this.setState(STATE_DISTANCE_HOLDING);
} else {
this.setState(STATE_FAR_GRABBING_NON_COLLIDING);
}
}
}
} else {
@ -369,19 +383,19 @@ function MyController(hand, triggerAction) {
// how far did avatar move this timestep?
var currentPosition = MyAvatar.position;
var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition);
var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition);
this.currentAvatarPosition = currentPosition;
// How far did the avatar turn this timestep?
// Note: The following code is too long because we need a Quat.quatBetween() function
// that returns the minimum quaternion between two quaternions.
var currentOrientation = MyAvatar.orientation;
if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) {
var negativeCurrentOrientation = {
x: -currentOrientation.x,
y: -currentOrientation.y,
z: -currentOrientation.z,
w: -currentOrientation.w
var negativeCurrentOrientation = {
x: -currentOrientation.x,
y: -currentOrientation.y,
z: -currentOrientation.z,
w: -currentOrientation.w
};
var avatarDeltaOrientation = Quat.multiply(negativeCurrentOrientation, Quat.inverse(this.currentAvatarOrientation));
} else {
@ -389,8 +403,8 @@ function MyController(hand, triggerAction) {
}
var handToAvatar = Vec3.subtract(handControllerPosition, this.currentAvatarPosition);
var objectToAvatar = Vec3.subtract(this.currentObjectPosition, this.currentAvatarPosition);
var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar);
var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar);
var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar);
var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar);
this.currentAvatarOrientation = currentOrientation;
// how far did hand move this timestep?
@ -411,7 +425,7 @@ function MyController(hand, triggerAction) {
var now = Date.now();
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
this.computeReleaseVelocity(deltaPosition, deltaTime, false);
this.currentObjectPosition = newObjectPosition;
this.currentObjectTime = now;
@ -440,7 +454,7 @@ function MyController(hand, triggerAction) {
this.lineOff();
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity,
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity,
["position", "rotation", "gravity", "ignoreForCollisions"]);
this.activateEntity(this.grabbedEntity, grabbedProperties);
@ -504,7 +518,9 @@ function MyController(hand, triggerAction) {
this.currentObjectTime = now;
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab");
Entities.updateAction(this.grabbedEntity, this.actionID, {lifetime: ACTION_LIFETIME});
Entities.updateAction(this.grabbedEntity, this.actionID, {
lifetime: ACTION_LIFETIME
});
};
this.nearGrabbingNonColliding = function() {
@ -521,14 +537,46 @@ function MyController(hand, triggerAction) {
this.setState(STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING);
};
this.farGrabbingNonColliding = function() {
if (this.triggerSmoothedReleased()) {
this.setState(STATE_RELEASE);
return;
}
if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
} else {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
Entities.callEntityMethod(this.grabbedEntity, "startFarGrabNonColliding");
this.setState(STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING);
};
this.continueNearGrabbingNonColliding = function() {
if (this.triggerSmoothedReleased()) {
this.setState(STATE_RELEASE);
return;
}
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabbingNonColliding");
};
this.continueFarGrabbingNonColliding = function() {
if (this.triggerSmoothedReleased()) {
this.setState(STATE_RELEASE);
return;
}
var handPosition = this.getHandPosition();
var pickRay = {
origin: handPosition,
direction: Quat.getUp(this.getHandRotation())
};
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
Entities.callEntityMethod(this.grabbedEntity, "continueFarGrabbingNonColliding");
};
_this.allTouchedIDs = {};
this.touchTest = function() {
var maxDistance = 0.05;
@ -618,8 +666,8 @@ function MyController(hand, triggerAction) {
this.lineOff();
if (this.grabbedEntity !== null) {
if(this.actionID !== null) {
Entities.deleteAction(this.grabbedEntity, this.actionID);
if (this.actionID !== null) {
Entities.deleteAction(this.grabbedEntity, this.actionID);
}
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
}
@ -650,7 +698,14 @@ function MyController(hand, triggerAction) {
if (data["refCount"] == 1) {
data["gravity"] = grabbedProperties.gravity;
data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
Entities.editEntity(entityID, {gravity: {x:0, y:0, z:0}, ignoreForCollisions: true});
Entities.editEntity(entityID, {
gravity: {
x: 0,
y: 0,
z: 0
},
ignoreForCollisions: true
});
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
@ -687,4 +742,4 @@ function cleanup() {
}
Script.scriptEnding.connect(cleanup);
Script.update.connect(update);
Script.update.connect(update);

View file

@ -28,7 +28,7 @@
FAST_EMIT_SPEED = 1.0,
GRAVITY_EMIT_ACCELERATON = { x: 0.0, y: -0.3, z: 0.0 },
ZERO_EMIT_ACCELERATON = { x: 0.0, y: 0.0, z: 0.0 },
PI = 3.141593,
PI = 3.141592,
DEG_TO_RAD = PI / 180.0,
NUM_PARTICLE_EXAMPLES = 18;

View file

@ -142,8 +142,15 @@ Item {
color: root.fontColor;
font.pixelSize: root.fontSize
visible: root.expanded;
text: "Avatar Mixer: " + root.avatarMixerKbps + " kbps, " +
root.avatarMixerPps + "pps";
text: "Avatar Mixer In: " + root.avatarMixerInKbps + " kbps, " +
root.avatarMixerInPps + "pps";
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
visible: root.expanded;
text: "Avatar Mixer Out: " + root.avatarMixerOutKbps + " kbps, " +
root.avatarMixerOutPps + "pps";
}
Text {
color: root.fontColor;

View file

@ -1825,17 +1825,16 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
}
#endif
auto offscreenUi = DependencyManager::get<OffscreenUi>();
QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget);
QMouseEvent mappedEvent(event->type(),
transformedPos,
event->screenPos(), event->button(),
event->buttons(), event->modifiers());
_entities.mouseMoveEvent(event, deviceID);
{
auto offscreenUi = DependencyManager::get<OffscreenUi>();
QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget);
QMouseEvent mappedEvent(event->type(),
transformedPos,
event->screenPos(), event->button(),
event->buttons(), event->modifiers());
_controllerScriptingInterface.emitMouseMoveEvent(&mappedEvent, deviceID); // send events to any registered scripts
}
_entities.mouseMoveEvent(&mappedEvent, deviceID);
_controllerScriptingInterface.emitMouseMoveEvent(&mappedEvent, deviceID); // send events to any registered scripts
// if one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface.isMouseCaptured()) {
@ -1851,19 +1850,19 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
// Inhibit the menu if the user is using alt-mouse dragging
_altPressed = false;
auto offscreenUi = DependencyManager::get<OffscreenUi>();
QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget);
QMouseEvent mappedEvent(event->type(),
transformedPos,
event->screenPos(), event->button(),
event->buttons(), event->modifiers());
if (!_aboutToQuit) {
_entities.mousePressEvent(event, deviceID);
_entities.mousePressEvent(&mappedEvent, deviceID);
}
{
auto offscreenUi = DependencyManager::get<OffscreenUi>();
QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget);
QMouseEvent mappedEvent(event->type(),
transformedPos,
event->screenPos(), event->button(),
event->buttons(), event->modifiers());
_controllerScriptingInterface.emitMousePressEvent(&mappedEvent); // send events to any registered scripts
}
_controllerScriptingInterface.emitMousePressEvent(&mappedEvent); // send events to any registered scripts
// if one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface.isMouseCaptured()) {
@ -1879,7 +1878,7 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
if (event->button() == Qt::LeftButton) {
// nobody handled this - make it an action event on the _window object
HFActionEvent actionEvent(HFActionEvent::startType(),
computePickRay(event->x(), event->y()));
computePickRay(mappedEvent.x(), mappedEvent.y()));
sendEvent(this, &actionEvent);
} else if (event->button() == Qt::RightButton) {
@ -1907,19 +1906,18 @@ void Application::mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceI
void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget);
QMouseEvent mappedEvent(event->type(),
transformedPos,
event->screenPos(), event->button(),
event->buttons(), event->modifiers());
if (!_aboutToQuit) {
_entities.mouseReleaseEvent(event, deviceID);
_entities.mouseReleaseEvent(&mappedEvent, deviceID);
}
{
auto offscreenUi = DependencyManager::get<OffscreenUi>();
QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget);
QMouseEvent mappedEvent(event->type(),
transformedPos,
event->screenPos(), event->button(),
event->buttons(), event->modifiers());
_controllerScriptingInterface.emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
}
_controllerScriptingInterface.emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
// if one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface.isMouseCaptured()) {
@ -1934,7 +1932,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
if (event->button() == Qt::LeftButton) {
// fire an action end event
HFActionEvent actionEvent(HFActionEvent::endType(),
computePickRay(event->x(), event->y()));
computePickRay(mappedEvent.x(), mappedEvent.y()));
sendEvent(this, &actionEvent);
}
}
@ -2351,6 +2349,7 @@ void Application::saveSettings() {
Menu::getInstance()->saveSettings();
getMyAvatar()->saveData();
PluginManager::getInstance()->saveSettings();
}
bool Application::importEntities(const QString& urlOrFilename) {
@ -4750,24 +4749,6 @@ mat4 Application::getEyeProjection(int eye) const {
return _viewFrustum.getProjection();
}
mat4 Application::getEyePose(int eye) const {
if (isHMDMode()) {
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
float IPDScale = hmdInterface->getIPDScale();
auto displayPlugin = getActiveDisplayPlugin();
mat4 headPose = displayPlugin->getHeadPose();
mat4 eyeToHead = displayPlugin->getEyeToHeadTransform((Eye)eye);
{
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
// Apply IPD scaling
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale);
eyeToHead[3] = vec4(eyeOffset, 1.0);
}
return eyeToHead * headPose;
}
return mat4();
}
mat4 Application::getEyeOffset(int eye) const {
// FIXME invert?
return getActiveDisplayPlugin()->getEyeToHeadTransform((Eye)eye);

View file

@ -198,7 +198,6 @@ public:
// TODO: carry that information on the Camera as a setting
bool isHMDMode() const;
glm::mat4 getHMDSensorPose() const;
glm::mat4 getEyePose(int eye) const;
glm::mat4 getEyeOffset(int eye) const;
glm::mat4 getEyeProjection(int eye) const;

View file

@ -549,7 +549,12 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
auto cameraMode = qApp->getCamera()->getMode();
if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) {
renderDisplayName(batch, *renderArgs->_viewFrustum, renderArgs->_viewport);
auto& frustum = *renderArgs->_viewFrustum;
auto textPosition = getDisplayNamePosition();
if (frustum.pointInFrustum(textPosition, true) == ViewFrustum::INSIDE) {
renderDisplayName(batch, frustum, textPosition);
}
}
endRender();
}
@ -685,120 +690,85 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) {
}
float Avatar::getBillboardSize() const {
return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));
return _scale * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));
}
#ifdef DEBUG
void debugValue(const QString& str, const glm::vec3& value) {
if (glm::any(glm::isnan(value)) || glm::any(glm::isinf(value))) {
qCWarning(interfaceapp) << "debugValue() " << str << value;
}
};
void debugValue(const QString& str, const float& value) {
if (glm::isnan(value) || glm::isinf(value)) {
qCWarning(interfaceapp) << "debugValue() " << str << value;
}
};
#define DEBUG_VALUE(str, value) debugValue(str, value)
#else
#define DEBUG_VALUE(str, value)
#endif
glm::vec3 Avatar::getDisplayNamePosition() const {
glm::vec3 namePosition(0.0f);
glm::vec3 bodyUpDirection = getBodyUpDirection();
DEBUG_VALUE("bodyUpDirection =", bodyUpDirection);
if (getSkeletonModel().getNeckPosition(namePosition)) {
namePosition += getBodyUpDirection() * getHeadHeight() * 1.1f;
float headHeight = getHeadHeight();
DEBUG_VALUE("namePosition =", namePosition);
DEBUG_VALUE("headHeight =", headHeight);
static const float SLIGHTLY_ABOVE = 1.1f;
namePosition += bodyUpDirection * headHeight * SLIGHTLY_ABOVE;
} else {
const float HEAD_PROPORTION = 0.75f;
namePosition = _position + getBodyUpDirection() * (getBillboardSize() * HEAD_PROPORTION);
float billboardSize = getBillboardSize();
DEBUG_VALUE("_position =", _position);
DEBUG_VALUE("billboardSize =", billboardSize);
namePosition = _position + bodyUpDirection * (billboardSize * HEAD_PROPORTION);
}
#ifdef DEBUG
// TODO: Temporary logging to track cause of invalid scale value; remove once cause has been fixed.
// See other TODO below.
if (glm::isnan(namePosition.x) || glm::isnan(namePosition.y) || glm::isnan(namePosition.z)
|| glm::isinf(namePosition.x) || glm::isinf(namePosition.y) || glm::isinf(namePosition.z)) {
qDebug() << "namePosition =" << namePosition;
glm::vec3 tempPosition(0.0f);
if (getSkeletonModel().getNeckPosition(tempPosition)) {
qDebug() << "getBodyUpDirection() =" << getBodyUpDirection();
qDebug() << "getHeadHeight() =" << getHeadHeight();
} else {
qDebug() << "_position =" << _position;
qDebug() << "getBodyUpDirection() =" << getBodyUpDirection();
qDebug() << "getBillboardSize() =" << getBillboardSize();
}
if (glm::any(glm::isnan(namePosition)) || glm::any(glm::isinf(namePosition))) {
qCWarning(interfaceapp) << "Invalid display name position" << namePosition
<< ", setting is to (0.0f, 0.5f, 0.0f)";
namePosition = glm::vec3(0.0f, 0.5f, 0.0f);
}
#endif
return namePosition;
}
Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize, const glm::ivec4& viewport) const {
Transform result;
// We assume textPosition is whithin the frustum
glm::vec3 textPosition = getDisplayNamePosition();
// Compute viewProjection matrix
glm::mat4 projMat, viewMat;
Transform view;
frustum.evalProjectionMatrix(projMat);
frustum.evalViewTransform(view);
glm::mat4 viewProj = projMat * view.getInverseMatrix(viewMat);
// Used to determine correct scale
glm::vec3 testPoint0 = textPosition;
glm::vec3 testPoint1 = testPoint0 + glm::normalize(frustum.getUp());
// testPoints projections
glm::vec4 p0 = viewProj * glm::vec4(testPoint0, 1.0);
glm::vec4 p1 = viewProj * glm::vec4(testPoint1, 1.0);
float windowSizeY = viewport.w;
const float DESIRED_HIGHT_ON_SCREEN = 20; // In pixels (this is double on retinas)
// Projected point are between -1.0f and 1.0f, hence 0.5f * windowSizeY
float pixelHeight = 0.5f * windowSizeY * glm::abs((p1.y / p1.w) - (p0.y / p0.w)); //
// Handles pixel density (especially for macs retina displays)
float devicePixelRatio = (float)qApp->getDevicePixelRatio() * qApp->getRenderResolutionScale(); // pixels / unit
// Compute correct scale to apply
float scale = DESIRED_HIGHT_ON_SCREEN / (fontSize * pixelHeight) * devicePixelRatio;
#ifdef DEBUG
// TODO: Temporary logging to track cause of invalid scale value; remove once cause has been fixed.
// Problem is probably due to an invalid getDisplayNamePosition(). See extra logging above.
if (scale == 0.0f || glm::isnan(scale) || glm::isinf(scale)) {
if (scale == 0.0f) {
qDebug() << "ASSERT because scale == 0.0f";
}
if (glm::isnan(scale)) {
qDebug() << "ASSERT because isnan(scale)";
}
if (glm::isinf(scale)) {
qDebug() << "ASSERT because isinf(scale)";
}
qDebug() << "textPosition =" << textPosition;
qDebug() << "projMat =" << projMat;
qDebug() << "viewMat =" << viewMat;
qDebug() << "viewProj =" << viewProj;
qDebug() << "windowSizeY =" << windowSizeY;
qDebug() << "p1 =" << p1;
qDebug() << "p0 =" << p0;
qDebug() << "qApp->getDevicePixelRatio() =" << qApp->getDevicePixelRatio();
qDebug() << "fontSize =" << fontSize;
qDebug() << "pixelHeight =" << pixelHeight;
qDebug() << "devicePixelRatio =" << devicePixelRatio;
}
#endif
// Compute pixel alignment offset
float clipToPix = 0.5f * windowSizeY / p1.w; // Got from clip to pixel coordinates
glm::vec4 screenPos = clipToPix * p1; // in pixels coords
glm::vec4 screenOffset = (glm::round(screenPos) - screenPos) / clipToPix; // in clip coords
glm::vec3 worldOffset = glm::vec3(screenOffset.x, screenOffset.y, 0.0f) / (float)pixelHeight;
Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, const glm::vec3& textPosition) const {
Q_ASSERT_X(frustum.pointInFrustum(textPosition, true) == ViewFrustum::INSIDE,
"Avatar::calculateDisplayNameTransform", "Text not in viewfrustum.");
glm::vec3 toFrustum = frustum.getPosition() - textPosition;
// Compute orientation
glm::vec3 dPosition = frustum.getPosition() - getPosition();
// If x and z are 0, atan(x, z) is undefined, so default to 0 degrees
float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z);
// If x and z are 0, atan(x, z) adais undefined, so default to 0 degrees
const float yawRotation = (toFrustum.x == 0.0f && toFrustum.z == 0.0f) ? 0.0f : glm::atan(toFrustum.x, toFrustum.z);
glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
// Set transform (The order IS important)
// Compute correct scale to apply
static const float DESIRED_HEIGHT_RAD = glm::radians(1.5f);
float scale = glm::length(toFrustum) * glm::tan(DESIRED_HEIGHT_RAD);
// Set transform
Transform result;
result.setTranslation(textPosition);
result.setRotation(orientation); // Always face the screen
result.postTranslate(worldOffset); // Pixel alignment
result.setScale(scale);
// raise by half the scale up so that textPosition be the bottom
result.postTranslate(Vectors::UP / 2.0f);
return result;
}
void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::ivec4& viewport) const {
void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::vec3& textPosition) const {
bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar();
// If we have nothing to draw, or it's totally transparent, or it's too close or behind the camera, return
const float CLIP_DISTANCE = 0.2f;
static const float CLIP_DISTANCE = 0.2f;
if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f
|| (glm::dot(frustum.getDirection(), getDisplayNamePosition() - frustum.getPosition()) <= CLIP_DISTANCE)) {
return;
@ -818,39 +788,45 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co
}
// Compute display name extent/position offset
glm::vec2 extent = renderer->computeExtent(renderedDisplayName);
QRect nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y);
const int text_x = -nameDynamicRect.width() / 2;
const int text_y = -nameDynamicRect.height() / 2;
// Compute background position/size
static const float SLIGHTLY_IN_FRONT = 0.1f;
const int border = 0.1f * nameDynamicRect.height();
const int left = text_x - border;
const int bottom = text_y - border;
const int width = nameDynamicRect.width() + 2.0f * border;
const int height = nameDynamicRect.height() + 2.0f * border;
const int bevelDistance = 0.1f * height;
// Display name and background colors
glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha);
glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f,
(_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA);
// Compute display name transform
auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize(), viewport);
batch.setModelTransform(textTransform);
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, true, true, true);
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
bevelDistance, backgroundColor);
// Render actual name
QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();
// Render text slightly in front to avoid z-fighting
textTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_IN_FRONT * renderer->getFontSize()));
batch.setModelTransform(textTransform);
renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor);
const glm::vec2 extent = renderer->computeExtent(renderedDisplayName);
if (!glm::any(glm::isCompNull(extent, EPSILON))) {
const QRect nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y);
const int text_x = -nameDynamicRect.width() / 2;
const int text_y = -nameDynamicRect.height() / 2;
// Compute background position/size
static const float SLIGHTLY_IN_FRONT = 0.1f;
static const float BORDER_RELATIVE_SIZE = 0.1f;
static const float BEVEL_FACTOR = 0.1f;
const int border = BORDER_RELATIVE_SIZE * nameDynamicRect.height();
const int left = text_x - border;
const int bottom = text_y - border;
const int width = nameDynamicRect.width() + 2.0f * border;
const int height = nameDynamicRect.height() + 2.0f * border;
const int bevelDistance = BEVEL_FACTOR * height;
// Display name and background colors
glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha);
glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f,
(_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA);
// Compute display name transform
auto textTransform = calculateDisplayNameTransform(frustum, textPosition);
// Test on extent above insures abs(height) > 0.0f
textTransform.postScale(1.0f / height);
batch.setModelTransform(textTransform);
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, true, true, true);
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
bevelDistance, backgroundColor);
// Render actual name
QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();
// Render text slightly in front to avoid z-fighting
textTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_IN_FRONT * renderer->getFontSize()));
batch.setModelTransform(textTransform);
renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor);
}
}
void Avatar::setSkeletonOffset(const glm::vec3& offset) {

View file

@ -217,8 +217,8 @@ protected:
float getPelvisFloatingHeight() const;
glm::vec3 getDisplayNamePosition() const;
Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize, const glm::ivec4& viewport) const;
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::ivec4& viewport) const;
Transform calculateDisplayNameTransform(const ViewFrustum& frustum, const glm::vec3& textPosition) const;
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::vec3& textPosition) const;
virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f);
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const;
virtual void fixupModelsInScene();

View file

@ -200,9 +200,6 @@ void PreferencesDialog::loadPreferences() {
ui.sixenseReticleMoveSpeedSpin->setValue(InputDevice::getReticleMoveSpeed());
SixenseManager& sixense = SixenseManager::getInstance();
ui.invertSixenseButtonsCheckBox->setChecked(sixense.getInvertButtons());
// LOD items
auto lodManager = DependencyManager::get<LODManager>();
ui.desktopMinimumFPSSpin->setValue(lodManager->getDesktopLODDecreaseFPS());
@ -276,9 +273,7 @@ void PreferencesDialog::savePreferences() {
qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
SixenseManager& sixense = SixenseManager::getInstance();
InputDevice::setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
sixense.setInvertButtons(ui.invertSixenseButtonsCheckBox->isChecked());
auto audio = DependencyManager::get<AudioClient>();
MixedProcessedAudioStream& stream = audio->getReceivedAudioStream();

View file

@ -167,15 +167,15 @@ void Stats::updateStats(bool force) {
if (_expanded || force) {
SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer);
if (avatarMixer) {
STAT_UPDATE(avatarMixerKbps, roundf(
bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AvatarMixer) +
bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer)));
STAT_UPDATE(avatarMixerPps, roundf(
bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer) +
bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer)));
STAT_UPDATE(avatarMixerInKbps, roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AvatarMixer)));
STAT_UPDATE(avatarMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer)));
STAT_UPDATE(avatarMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer)));
STAT_UPDATE(avatarMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer)));
} else {
STAT_UPDATE(avatarMixerKbps, -1);
STAT_UPDATE(avatarMixerPps, -1);
STAT_UPDATE(avatarMixerInKbps, -1);
STAT_UPDATE(avatarMixerInPps, -1);
STAT_UPDATE(avatarMixerOutKbps, -1);
STAT_UPDATE(avatarMixerOutPps, -1);
}
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
if (audioMixerNode || force) {

View file

@ -47,8 +47,10 @@ class Stats : public QQuickItem {
STATS_PROPERTY(QVector3D, position, QVector3D(0, 0, 0) )
STATS_PROPERTY(float, velocity, 0)
STATS_PROPERTY(float, yaw, 0)
STATS_PROPERTY(int, avatarMixerKbps, 0)
STATS_PROPERTY(int, avatarMixerPps, 0)
STATS_PROPERTY(int, avatarMixerInKbps, 0)
STATS_PROPERTY(int, avatarMixerInPps, 0)
STATS_PROPERTY(int, avatarMixerOutKbps, 0)
STATS_PROPERTY(int, avatarMixerOutPps, 0)
STATS_PROPERTY(int, audioMixerKbps, 0)
STATS_PROPERTY(int, audioMixerPps, 0)
STATS_PROPERTY(int, downloads, 0)
@ -122,8 +124,10 @@ signals:
void positionChanged();
void velocityChanged();
void yawChanged();
void avatarMixerKbpsChanged();
void avatarMixerPpsChanged();
void avatarMixerInKbpsChanged();
void avatarMixerInPpsChanged();
void avatarMixerOutKbpsChanged();
void avatarMixerOutPpsChanged();
void audioMixerKbpsChanged();
void audioMixerPpsChanged();
void downloadsChanged();

View file

@ -2768,40 +2768,6 @@
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_26">
<property name="topMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QCheckBox" name="invertSixenseButtonsCheckBox">
<property name="baseSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="text">
<string>Invert Mouse Buttons</string>
</property>
<property name="iconSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_16">
<property name="spacing">

View file

@ -132,7 +132,6 @@ public:
bool getJointStateTranslation(int index, glm::vec3& translation) const;
void applyJointRotationDelta(int jointIndex, const glm::quat& delta, float priority);
JointState getJointState(int jointIndex) const; // XXX
bool getVisibleJointState(int index, glm::quat& rotation) const;
void clearJointState(int index);
void clearJointStates();
void clearJointAnimationPriority(int index);
@ -154,9 +153,6 @@ public:
bool getJointRotation(int jointIndex, glm::quat& rotation) const;
bool getJointTranslation(int jointIndex, glm::vec3& translation) const;
bool getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const;
bool getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& position,
glm::vec3 translation, glm::quat rotation) const;
bool getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& result, glm::quat rotation) const;
glm::mat4 getJointTransform(int jointIndex) const;
glm::mat4 getJointVisibleTransform(int jointIndex) const;
void setJointVisibleTransform(int jointIndex, glm::mat4 newTransform);
@ -179,7 +175,6 @@ public:
float priority, float mix = 1.0f);
bool getJointRotationInConstrainedFrame(int jointIndex, glm::quat& rotOut) const;
glm::quat getJointDefaultRotationInParentFrame(int jointIndex);
void updateVisibleJointStates();
void clearJointStatePriorities();
virtual void updateJointState(int index, glm::mat4 rootTransform) = 0;

View file

@ -249,6 +249,8 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
processedBytes += bytesRead;
Q_UNUSED(somethingChanged);
return true;
}

View file

@ -108,6 +108,8 @@ bool AtmospherePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& property
processedBytes += bytesRead;
Q_UNUSED(somethingChanged);
return true;
}

View file

@ -620,7 +620,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(textColor, xColor, setTextColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundColor, xColor, setBackgroundColor);
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(shapeType, ShapeType);
COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, float, setMaxParticles);
COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, quint32, setMaxParticles);
COPY_PROPERTY_FROM_QSCRIPTVALUE(lifespan, float, setLifespan);
COPY_PROPERTY_FROM_QSCRIPTVALUE(isEmitting, bool, setIsEmitting);
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitRate, float, setEmitRate);
@ -1320,7 +1320,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
if (properties.getType() == EntityTypes::ParticleEffect) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAX_PARTICLES, float, setMaxParticles);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAX_PARTICLES, quint32, setMaxParticles);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFESPAN, float, setLifespan);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMITTING_PARTICLES, bool, setIsEmitting);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_RATE, float, setEmitRate);

View file

@ -173,6 +173,10 @@ typedef QVector<glm::vec3> qVectorVec3;
typedef QVector<float> qVectorFloat;
inline float float_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); }
inline quint64 quint64_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); }
inline quint32 quint32_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
// Use QString::toUInt() so that isValid is set to false if the number is outside the quint32 range.
return v.toString().toUInt(&isValid);
}
inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }

View file

@ -1,4 +1,3 @@
//
// ParticleEffectEntityItem.cpp
// libraries/entities/src
@ -31,8 +30,6 @@
#include <glm/gtx/transform.hpp>
#include <QtCore/QJsonDocument>
#include <QDebug>
#include <ByteCountCoding.h>
#include <GeometryUtil.h>
#include <Interpolate.h>
@ -46,27 +43,53 @@
const glm::vec3 X_AXIS = glm::vec3(1.0f, 0.0f, 0.0f);
const glm::vec3 Z_AXIS = glm::vec3(0.0f, 0.0f, 1.0f);
const float SCRIPT_MAXIMUM_PI = 3.1416f; // Round up so that reasonable property values work
const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 };
const xColor ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD = { 0, 0, 0 };
const float ParticleEffectEntityItem::DEFAULT_ALPHA = 1.0f;
const float ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD = 0.0f;
const float ParticleEffectEntityItem::DEFAULT_ALPHA_START = DEFAULT_ALPHA;
const float ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH = DEFAULT_ALPHA;
const float ParticleEffectEntityItem::MINIMUM_ALPHA = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_ALPHA = 1.0f;
const quint32 ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES = 1000;
const quint32 ParticleEffectEntityItem::MINIMUM_MAX_PARTICLES = 1;
const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 10000;
const float ParticleEffectEntityItem::DEFAULT_LIFESPAN = 3.0f;
const float ParticleEffectEntityItem::MINIMUM_LIFESPAN = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_LIFESPAN = 86400.0f; // 1 day
const float ParticleEffectEntityItem::DEFAULT_EMIT_RATE = 15.0f;
const float ParticleEffectEntityItem::MINIMUM_EMIT_RATE = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 1000.0f;
const float ParticleEffectEntityItem::DEFAULT_EMIT_SPEED = 5.0f;
const float ParticleEffectEntityItem::MINIMUM_EMIT_SPEED = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_EMIT_SPEED = 1000.0f; // Approx mach 3
const float ParticleEffectEntityItem::DEFAULT_SPEED_SPREAD = 1.0f;
const glm::quat ParticleEffectEntityItem::DEFAULT_EMIT_ORIENTATION = glm::angleAxis(-PI_OVER_TWO, X_AXIS); // Vertical
const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_DIMENSIONS = glm::vec3(0.0f, 0.0f, 0.0f); // Emit from point
const float ParticleEffectEntityItem::MINIMUM_EMIT_DIMENSION = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_EMIT_DIMENSION = (float)TREE_SCALE;
const float ParticleEffectEntityItem::DEFAULT_EMIT_RADIUS_START = 1.0f; // Emit from surface (when emitDimensions > 0)
const float ParticleEffectEntityItem::MINIMUM_EMIT_RADIUS_START = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_EMIT_RADIUS_START = 1.0f;
const float ParticleEffectEntityItem::MINIMUM_POLAR = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_POLAR = SCRIPT_MAXIMUM_PI;
const float ParticleEffectEntityItem::DEFAULT_POLAR_START = 0.0f; // Emit along z-axis
const float ParticleEffectEntityItem::DEFAULT_POLAR_FINISH = 0.0f; // ""
const float ParticleEffectEntityItem::MINIMUM_AZIMUTH = -SCRIPT_MAXIMUM_PI;
const float ParticleEffectEntityItem::MAXIMUM_AZIMUTH = SCRIPT_MAXIMUM_PI;
const float ParticleEffectEntityItem::DEFAULT_AZIMUTH_START = -PI; // Emit full circumference (when polarFinish > 0)
const float ParticleEffectEntityItem::DEFAULT_AZIMUTH_FINISH = PI; // ""
const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION(0.0f, -9.8f, 0.0f);
const float ParticleEffectEntityItem::MINIMUM_EMIT_ACCELERATION = -100.0f; // ~ 10g
const float ParticleEffectEntityItem::MAXIMUM_EMIT_ACCELERATION = 100.0f;
const glm::vec3 ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD(0.0f, 0.0f, 0.0f);
const float ParticleEffectEntityItem::MINIMUM_ACCELERATION_SPREAD = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_ACCELERATION_SPREAD = 100.0f;
const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f;
const float ParticleEffectEntityItem::MINIMUM_PARTICLE_RADIUS = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_PARTICLE_RADIUS = (float)TREE_SCALE;
const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f;
const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS;
const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS;
@ -111,37 +134,177 @@ ParticleEffectEntityItem::~ParticleEffectEntityItem() {
}
void ParticleEffectEntityItem::setAlpha(float alpha) {
if (MINIMUM_ALPHA <= alpha && alpha <= MAXIMUM_ALPHA) {
_alpha = alpha;
}
}
void ParticleEffectEntityItem::setAlphaStart(float alphaStart) {
if (MINIMUM_ALPHA <= alphaStart && alphaStart <= MAXIMUM_ALPHA) {
_alphaStart = alphaStart;
_isAlphaStartInitialized = true;
}
}
void ParticleEffectEntityItem::setAlphaFinish(float alphaFinish) {
if (MINIMUM_ALPHA <= alphaFinish && alphaFinish <= MAXIMUM_ALPHA) {
_alphaFinish = alphaFinish;
_isAlphaFinishInitialized = true;
}
}
void ParticleEffectEntityItem::setAlphaSpread(float alphaSpread) {
if (MINIMUM_ALPHA <= alphaSpread && alphaSpread <= MAXIMUM_ALPHA) {
_alphaSpread = alphaSpread;
}
}
void ParticleEffectEntityItem::setLifespan(float lifespan) {
if (MINIMUM_LIFESPAN <= lifespan && lifespan <= MAXIMUM_LIFESPAN) {
_lifespan = lifespan;
}
}
void ParticleEffectEntityItem::setEmitRate(float emitRate) {
if (MINIMUM_EMIT_RATE <= emitRate && emitRate <= MAXIMUM_EMIT_RATE) {
_emitRate = emitRate;
}
}
void ParticleEffectEntityItem::setEmitSpeed(float emitSpeed) {
_emitSpeed = emitSpeed;
computeAndUpdateDimensions();
if (MINIMUM_EMIT_SPEED <= emitSpeed && emitSpeed <= MAXIMUM_EMIT_SPEED) {
_emitSpeed = emitSpeed;
computeAndUpdateDimensions();
}
}
void ParticleEffectEntityItem::setSpeedSpread(float speedSpread) {
_speedSpread = speedSpread;
computeAndUpdateDimensions();
if (MINIMUM_EMIT_SPEED <= speedSpread && speedSpread <= MAXIMUM_EMIT_SPEED) {
_speedSpread = speedSpread;
computeAndUpdateDimensions();
}
}
void ParticleEffectEntityItem::setEmitOrientation(const glm::quat& emitOrientation) {
_emitOrientation = emitOrientation;
_emitOrientation = glm::normalize(emitOrientation);
computeAndUpdateDimensions();
}
void ParticleEffectEntityItem::setEmitDimensions(const glm::vec3& emitDimensions) {
_emitDimensions = emitDimensions;
computeAndUpdateDimensions();
bool updated = false;
if (MINIMUM_EMIT_DIMENSION <= emitDimensions.x && emitDimensions.x <= MAXIMUM_EMIT_DIMENSION) {
_emitDimensions.x = emitDimensions.x;
updated = true;
}
if (MINIMUM_EMIT_DIMENSION <= emitDimensions.y && emitDimensions.y <= MAXIMUM_EMIT_DIMENSION) {
_emitDimensions.y = emitDimensions.y;
updated = true;
}
if (MINIMUM_EMIT_DIMENSION <= emitDimensions.z && emitDimensions.z <= MAXIMUM_EMIT_DIMENSION) {
_emitDimensions.z = emitDimensions.z;
updated = true;
}
if (updated) {
computeAndUpdateDimensions();
}
}
void ParticleEffectEntityItem::setEmitRadiusStart(float emitRadiusStart) {
if (MINIMUM_EMIT_RADIUS_START <= emitRadiusStart && emitRadiusStart <= MAXIMUM_EMIT_RADIUS_START) {
_emitRadiusStart = emitRadiusStart;
}
}
void ParticleEffectEntityItem::setPolarStart(float polarStart) {
if (MINIMUM_POLAR <= polarStart && polarStart <= MAXIMUM_POLAR) {
_polarStart = polarStart;
}
}
void ParticleEffectEntityItem::setPolarFinish(float polarFinish) {
if (MINIMUM_POLAR <= polarFinish && polarFinish <= MAXIMUM_POLAR) {
_polarFinish = polarFinish;
}
}
void ParticleEffectEntityItem::setAzimuthStart(float azimuthStart) {
if (MINIMUM_AZIMUTH <= azimuthStart && azimuthStart <= MAXIMUM_AZIMUTH) {
_azimuthStart = azimuthStart;
}
}
void ParticleEffectEntityItem::setAzimuthFinish(float azimuthFinish) {
if (MINIMUM_AZIMUTH <= azimuthFinish && azimuthFinish <= MAXIMUM_AZIMUTH) {
_azimuthFinish = azimuthFinish;
}
}
void ParticleEffectEntityItem::setEmitAcceleration(const glm::vec3& emitAcceleration) {
_emitAcceleration = emitAcceleration;
computeAndUpdateDimensions();
bool updated = false;
if (MINIMUM_EMIT_ACCELERATION <= emitAcceleration.x && emitAcceleration.x <= MAXIMUM_EMIT_ACCELERATION) {
_emitAcceleration.x = emitAcceleration.x;
updated = true;
}
if (MINIMUM_EMIT_ACCELERATION <= emitAcceleration.y && emitAcceleration.y <= MAXIMUM_EMIT_ACCELERATION) {
_emitAcceleration.y = emitAcceleration.y;
updated = true;
}
if (MINIMUM_EMIT_ACCELERATION <= emitAcceleration.z && emitAcceleration.z <= MAXIMUM_EMIT_ACCELERATION) {
_emitAcceleration.z = emitAcceleration.z;
updated = true;
}
if (updated) {
computeAndUpdateDimensions();
}
}
void ParticleEffectEntityItem::setAccelerationSpread(const glm::vec3& accelerationSpread){
_accelerationSpread = accelerationSpread;
computeAndUpdateDimensions();
bool updated = false;
if (MINIMUM_ACCELERATION_SPREAD <= accelerationSpread.x && accelerationSpread.x <= MAXIMUM_ACCELERATION_SPREAD) {
_accelerationSpread.x = accelerationSpread.x;
updated = true;
}
if (MINIMUM_ACCELERATION_SPREAD <= accelerationSpread.y && accelerationSpread.y <= MAXIMUM_ACCELERATION_SPREAD) {
_accelerationSpread.y = accelerationSpread.y;
updated = true;
}
if (MINIMUM_ACCELERATION_SPREAD <= accelerationSpread.z && accelerationSpread.z <= MAXIMUM_ACCELERATION_SPREAD) {
_accelerationSpread.z = accelerationSpread.z;
updated = true;
}
if (updated) {
computeAndUpdateDimensions();
}
}
void ParticleEffectEntityItem::setParticleRadius(float particleRadius) {
if (MINIMUM_PARTICLE_RADIUS <= particleRadius && particleRadius <= MAXIMUM_PARTICLE_RADIUS) {
_particleRadius = particleRadius;
}
}
void ParticleEffectEntityItem::setRadiusStart(float radiusStart) {
if (MINIMUM_PARTICLE_RADIUS <= radiusStart && radiusStart <= MAXIMUM_PARTICLE_RADIUS) {
_radiusStart = radiusStart;
_isRadiusStartInitialized = true;
}
}
void ParticleEffectEntityItem::setRadiusFinish(float radiusFinish) {
if (MINIMUM_PARTICLE_RADIUS <= radiusFinish && radiusFinish <= MAXIMUM_PARTICLE_RADIUS) {
_radiusFinish = radiusFinish;
_isRadiusFinishInitialized = true;
}
}
void ParticleEffectEntityItem::setRadiusSpread(float radiusSpread) {
if (MINIMUM_PARTICLE_RADIUS <= radiusSpread && radiusSpread <= MAXIMUM_PARTICLE_RADIUS) {
_radiusSpread = radiusSpread;
}
}
void ParticleEffectEntityItem::computeAndUpdateDimensions() {
const float time = _lifespan * 1.1f; // add 10% extra time to account for incremental timer accumulation error
@ -485,12 +648,12 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
_particleLifetimes[i] -= deltaTime;
// if particle has died.
if (_particleLifetimes[i] <= 0.0f) {
if (_particleLifetimes[i] <= 0.0f || _lifespan == 0.0f) {
// move head forward
_particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles;
}
else {
float age = (1.0f - _particleLifetimes[i] / _lifespan); // 0.0 .. 1.0
float age = 1.0f - _particleLifetimes[i] / _lifespan; // 0.0 .. 1.0
updateRadius(i, age);
updateColor(i, age);
updateAlpha(i, age);
@ -500,7 +663,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
}
// emit new particles, but only if we are emmitting
if (isEmittingParticles()) {
if (isEmittingParticles() && _emitRate > 0.0f && _lifespan > 0.0f && _polarStart <= _polarFinish) {
float timeLeftInFrame = deltaTime;
while (_timeUntilNextEmit < timeLeftInFrame) {
@ -518,10 +681,18 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
_radiusMiddles[i] =_particleRadius;
_radiusFinishes[i] = getRadiusFinish();
} else {
float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1.0f) * _radiusSpread / _particleRadius;
_radiusStarts[i] = spreadMultiplier * getRadiusStart();
_radiusMiddles[i] = spreadMultiplier * _particleRadius;
_radiusFinishes[i] = spreadMultiplier * getRadiusFinish();
float spreadMultiplier;
if (_particleRadius > 0.0f) {
spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _radiusSpread / _particleRadius;
} else {
spreadMultiplier = 1.0f;
}
_radiusStarts[i] =
glm::clamp(spreadMultiplier * getRadiusStart(), MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
_radiusMiddles[i] =
glm::clamp(spreadMultiplier * _particleRadius, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
_radiusFinishes[i] =
glm::clamp(spreadMultiplier * getRadiusFinish(), MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
}
updateRadius(i, 0.0f);
@ -530,8 +701,8 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
// Emit along z-axis from position
_particlePositions[i] = getPosition();
_particleVelocities[i] =
(_emitSpeed + (2.0f * randFloat() - 1.0f) * _speedSpread) * (_emitOrientation * Z_AXIS);
_particleAccelerations[i] = _emitAcceleration + (2.0f * randFloat() - 1.0f) * _accelerationSpread;
(_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * Z_AXIS);
_particleAccelerations[i] = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread;
} else {
// Emit around point or from ellipsoid
@ -547,15 +718,14 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
if (_azimuthFinish >= _azimuthStart) {
azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat();
} else {
azimuth = _azimuthStart + (2.0f * PI + _azimuthFinish - _azimuthStart) * randFloat();
azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * randFloat();
}
glm::vec3 emitDirection;
if (_emitDimensions == glm::vec3()) {
// Point
emitDirection = glm::angleAxis(PI_OVER_TWO - elevation, X_AXIS) * Z_AXIS;
emitDirection = glm::angleAxis(azimuth, Z_AXIS) * emitDirection;
emitDirection = glm::quat(glm::vec3(PI_OVER_TWO - elevation, 0.0f, azimuth)) * Z_AXIS;
_particlePositions[i] = getPosition();
} else {
@ -563,7 +733,8 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
float radiusScale = 1.0f;
if (_emitRadiusStart < 1.0f) {
float emitRadiusStart = glm::max(_emitRadiusStart, EPSILON); // Avoid math complications at center
float randRadius = emitRadiusStart + (1.0f - emitRadiusStart) * randFloat();
float randRadius =
emitRadiusStart + randFloatInRange(0.0f, MAXIMUM_EMIT_RADIUS_START - emitRadiusStart);
radiusScale = 1.0f - std::pow(1.0f - randRadius, 3.0f);
}
@ -582,8 +753,8 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
}
_particleVelocities[i] =
(_emitSpeed + (2.0f * randFloat() - 1.0f) * _speedSpread) * (_emitOrientation * emitDirection);
_particleAccelerations[i] = _emitAcceleration + (2.0f * randFloat() - 1.0f) * _accelerationSpread;
(_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection);
_particleAccelerations[i] = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread;
}
integrateParticle(i, timeLeftInFrame);
extendBounds(_particlePositions[i]);
@ -598,10 +769,13 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
xColor middleColor = getXColor();
xColor finishColor = getColorFinish();
float spread = 2.0f * randFloat() - 1.0f;
float spreadMultiplierRed = 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red;
float spreadMultiplierGreen = 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green;
float spreadMultiplierBlue = 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue;
float spread = randFloatInRange(-1.0f, 1.0f);
float spreadMultiplierRed =
middleColor.red > 0 ? 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red : 1.0f;
float spreadMultiplierGreen =
middleColor.green > 0 ? 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green : 1.0f;
float spreadMultiplierBlue =
middleColor.blue > 0 ? 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue : 1.0f;
_colorStarts[i].red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f);
_colorStarts[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f);
@ -623,7 +797,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
_alphaMiddles[i] = _alpha;
_alphaFinishes[i] = getAlphaFinish();
} else {
float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1) * _alphaSpread / _alpha;
float spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _alphaSpread / _alpha;
_alphaStarts[i] = spreadMultiplier * getAlphaStart();
_alphaMiddles[i] = spreadMultiplier * _alpha;
_alphaFinishes[i] = spreadMultiplier * getAlphaFinish();
@ -645,7 +819,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
}
void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
if (_maxParticles != maxParticles) {
if (_maxParticles != maxParticles && MINIMUM_MAX_PARTICLES <= maxParticles && maxParticles <= MAXIMUM_MAX_PARTICLES) {
_maxParticles = maxParticles;
// TODO: try to do something smart here and preserve the state of existing particles.

View file

@ -12,6 +12,7 @@
#define hifi_ParticleEffectEntityItem_h
#include <AnimationLoop.h>
#include "EntityItem.h"
class ParticleEffectEntityItem : public EntityItem {
@ -69,22 +70,25 @@ public:
void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; }
xColor getColorSpread() const { return _colorSpread; }
static const float MAXIMUM_ALPHA;
static const float MINIMUM_ALPHA;
static const float DEFAULT_ALPHA;
void setAlpha(float alpha) { _alpha = alpha; }
void setAlpha(float alpha);
float getAlpha() const { return _alpha; }
static const float DEFAULT_ALPHA_START;
bool _isAlphaStartInitialized = false;
void setAlphaStart(float alphaStart) { _alphaStart = alphaStart; _isAlphaStartInitialized = true; }
void setAlphaStart(float alphaStart);
float getAlphaStart() const { return _isAlphaStartInitialized ? _alphaStart : _alpha; }
static const float DEFAULT_ALPHA_FINISH;
bool _isAlphaFinishInitialized = false;
void setAlphaFinish(float alphaFinish) { _alphaFinish = alphaFinish; _isAlphaFinishInitialized = true; }
void setAlphaFinish(float alphaFinish);
float getAlphaFinish() const { return _isAlphaFinishInitialized ? _alphaFinish : _alpha; }
static const float DEFAULT_ALPHA_SPREAD;
void setAlphaSpread(float alphaSpread) { _alphaSpread = alphaSpread; }
void setAlphaSpread(float alphaSpread);
float getAlphaSpread() const { return _alphaSpread; }
void updateShapeType(ShapeType type);
@ -97,18 +101,26 @@ public:
void setIsEmitting(bool isEmitting) { _isEmitting = isEmitting; }
static const quint32 DEFAULT_MAX_PARTICLES;
static const quint32 MINIMUM_MAX_PARTICLES;
static const quint32 MAXIMUM_MAX_PARTICLES;
void setMaxParticles(quint32 maxParticles);
quint32 getMaxParticles() const { return _maxParticles; }
static const float DEFAULT_LIFESPAN;
void setLifespan(float lifespan) { _lifespan = lifespan; }
static const float MINIMUM_LIFESPAN;
static const float MAXIMUM_LIFESPAN;
void setLifespan(float lifespan);
float getLifespan() const { return _lifespan; }
static const float DEFAULT_EMIT_RATE;
void setEmitRate(float emitRate) { _emitRate = emitRate; }
static const float MINIMUM_EMIT_RATE;
static const float MAXIMUM_EMIT_RATE;
void setEmitRate(float emitRate);
float getEmitRate() const { return _emitRate; }
static const float DEFAULT_EMIT_SPEED;
static const float MINIMUM_EMIT_SPEED;
static const float MAXIMUM_EMIT_SPEED;
void setEmitSpeed(float emitSpeed);
float getEmitSpeed() const { return _emitSpeed; }
@ -121,53 +133,69 @@ public:
const glm::quat& getEmitOrientation() const { return _emitOrientation; }
static const glm::vec3 DEFAULT_EMIT_DIMENSIONS;
static const float MINIMUM_EMIT_DIMENSION;
static const float MAXIMUM_EMIT_DIMENSION;
void setEmitDimensions(const glm::vec3& emitDimensions);
const glm::vec3& getEmitDimensions() const { return _emitDimensions; }
static const float DEFAULT_EMIT_RADIUS_START;
void setEmitRadiusStart(float emitRadiusStart) { _emitRadiusStart = emitRadiusStart; }
static const float MINIMUM_EMIT_RADIUS_START;
static const float MAXIMUM_EMIT_RADIUS_START;
void setEmitRadiusStart(float emitRadiusStart);
float getEmitRadiusStart() const { return _emitRadiusStart; }
static const float MINIMUM_POLAR;
static const float MAXIMUM_POLAR;
static const float DEFAULT_POLAR_START;
void setPolarStart(float polarStart) { _polarStart = polarStart; }
void setPolarStart(float polarStart);
float getPolarStart() const { return _polarStart; }
static const float DEFAULT_POLAR_FINISH;
void setPolarFinish(float polarFinish) { _polarFinish = polarFinish; }
void setPolarFinish(float polarFinish);
float getPolarFinish() const { return _polarFinish; }
static const float MINIMUM_AZIMUTH;
static const float MAXIMUM_AZIMUTH;
static const float DEFAULT_AZIMUTH_START;
void setAzimuthStart(float azimuthStart) { _azimuthStart = azimuthStart; }
void setAzimuthStart(float azimuthStart);
float getAzimuthStart() const { return _azimuthStart; }
static const float DEFAULT_AZIMUTH_FINISH;
void setAzimuthFinish(float azimuthFinish) { _azimuthFinish = azimuthFinish; }
void setAzimuthFinish(float azimuthFinish);
float getAzimuthFinish() const { return _azimuthFinish; }
static const glm::vec3 DEFAULT_EMIT_ACCELERATION;
static const float MINIMUM_EMIT_ACCELERATION;
static const float MAXIMUM_EMIT_ACCELERATION;
void setEmitAcceleration(const glm::vec3& emitAcceleration);
const glm::vec3& getEmitAcceleration() const { return _emitAcceleration; }
static const glm::vec3 DEFAULT_ACCELERATION_SPREAD;
static const float MINIMUM_ACCELERATION_SPREAD;
static const float MAXIMUM_ACCELERATION_SPREAD;
void setAccelerationSpread(const glm::vec3& accelerationSpread);
const glm::vec3& getAccelerationSpread() const { return _accelerationSpread; }
static const float DEFAULT_PARTICLE_RADIUS;
void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; }
static const float MINIMUM_PARTICLE_RADIUS;
static const float MAXIMUM_PARTICLE_RADIUS;
void setParticleRadius(float particleRadius);
float getParticleRadius() const { return _particleRadius; }
static const float DEFAULT_RADIUS_START;
bool _isRadiusStartInitialized = false;
void setRadiusStart(float radiusStart) { _radiusStart = radiusStart; _isRadiusStartInitialized = true; }
void setRadiusStart(float radiusStart);
float getRadiusStart() const { return _isRadiusStartInitialized ? _radiusStart : _particleRadius; }
static const float DEFAULT_RADIUS_FINISH;
bool _isRadiusFinishInitialized = false;
void setRadiusFinish(float radiusFinish) { _radiusFinish = radiusFinish; _isRadiusFinishInitialized = true; }
void setRadiusFinish(float radiusFinish);
float getRadiusFinish() const { return _isRadiusFinishInitialized ? _radiusFinish : _particleRadius; }
static const float DEFAULT_RADIUS_SPREAD;
void setRadiusSpread(float radiusSpread) { _radiusSpread = radiusSpread; }
void setRadiusSpread(float radiusSpread);
float getRadiusSpread() const { return _radiusSpread; }
void computeAndUpdateDimensions();

View file

@ -66,6 +66,8 @@ bool SkyboxPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlag
processedBytes += bytesRead;
Q_UNUSED(somethingChanged);
return true;
}

View file

@ -121,6 +121,8 @@ bool StagePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags
processedBytes += bytesRead;
Q_UNUSED(somethingChanged);
return true;
}

View file

@ -1512,7 +1512,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
}
extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex);
buildModelMesh(extracted, url);
buildModelMesh(extracted.mesh, url);
if (extracted.mesh.isEye) {
if (maxJointIndex == geometry.leftEyeJointIndex) {

View file

@ -388,7 +388,7 @@ public:
ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex);
QHash<QString, ExtractedMesh> meshes;
void buildModelMesh(ExtractedMesh& extracted, const QString& url);
static void buildModelMesh(FBXMesh& extractedMesh, const QString& url);
FBXTexture getTexture(const QString& textureID);

View file

@ -386,11 +386,11 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn
return data.extracted;
}
void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) {
void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("buildModelMesh failed -- .*");
unsigned int totalSourceIndices = 0;
foreach(const FBXMeshPart& part, extracted.mesh.parts) {
foreach(const FBXMeshPart& part, extractedMesh.parts) {
totalSourceIndices += (part.quadTrianglesIndices.size() + part.triangleIndices.size());
}
@ -399,18 +399,18 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) {
return;
}
if (extracted.mesh.vertices.size() == 0) {
if (extractedMesh.vertices.size() == 0) {
qCDebug(modelformat) << "buildModelMesh failed -- no vertices, url = " << url;
return;
}
FBXMesh& fbxMesh = extracted.mesh;
FBXMesh& fbxMesh = extractedMesh;
model::MeshPointer mesh(new model::Mesh());
// Grab the vertices in a buffer
auto vb = std::make_shared<gpu::Buffer>();
vb->setData(extracted.mesh.vertices.size() * sizeof(glm::vec3),
(const gpu::Byte*) extracted.mesh.vertices.data());
vb->setData(extractedMesh.vertices.size() * sizeof(glm::vec3),
(const gpu::Byte*) extractedMesh.vertices.data());
gpu::BufferView vbv(vb, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
mesh->setVertexBuffer(vbv);
@ -486,7 +486,7 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) {
unsigned int totalIndices = 0;
foreach(const FBXMeshPart& part, extracted.mesh.parts) {
foreach(const FBXMeshPart& part, extractedMesh.parts) {
totalIndices += (part.quadTrianglesIndices.size() + part.triangleIndices.size());
}
@ -502,10 +502,10 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) {
int offset = 0;
std::vector< model::Mesh::Part > parts;
if (extracted.mesh.parts.size() > 1) {
if (extractedMesh.parts.size() > 1) {
indexNum = 0;
}
foreach(const FBXMeshPart& part, extracted.mesh.parts) {
foreach(const FBXMeshPart& part, extractedMesh.parts) {
model::Mesh::Part modelPart(indexNum, 0, 0, model::Mesh::TRIANGLES);
if (part.quadTrianglesIndices.size()) {
@ -545,5 +545,5 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) {
// model::Box box =
mesh->evalPartBound(0);
extracted.mesh._mesh = mesh;
extractedMesh._mesh = mesh;
}

View file

@ -532,6 +532,8 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping,
mesh.meshExtents.addPoint(vertex);
geometry.meshExtents.addPoint(vertex);
}
FBXReader::buildModelMesh(mesh, url.toString());
// fbxDebugDump(geometry);
} catch(const std::exception& e) {
qCDebug(modelformat) << "OBJ reader fail: " << e.what();

View file

@ -37,3 +37,9 @@ InputPluginList getInputPlugins() {
}
return result;
}
void saveInputPluginSettings(const InputPluginList& plugins) {
foreach (auto inputPlugin, plugins) {
inputPlugin->saveSettings();
}
}

View file

@ -16,6 +16,7 @@
#include <GLMHelpers.h>
#include <NumericalConstants.h>
#include <PerfStat.h>
#include <SettingHandle.h>
#include <plugins/PluginContainer.h>
#include "NumericalConstants.h"
@ -38,7 +39,7 @@ const unsigned int RIGHT_MASK = 1U << 1;
#ifdef HAVE_SIXENSE
const int CALIBRATION_STATE_IDLE = 0;
const int CALIBRATION_STATE_X = 1;
const int CALIBRATION_STATE_IN_PROGRESS = 1;
const int CALIBRATION_STATE_COMPLETE = 2;
const glm::vec3 DEFAULT_AVATAR_POSITION(-0.25f, -0.35f, -0.3f); // in hydra frame
@ -56,25 +57,23 @@ typedef int (*SixenseTakeIntAndSixenseControllerData)(int, sixenseControllerData
#endif
const QString SixenseManager::NAME = "Sixense";
const QString SixenseManager::HYDRA_ID_STRING = "Razer Hydra";
const QString MENU_PARENT = "Avatar";
const QString MENU_NAME = "Sixense";
const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
const QString TOGGLE_SMOOTH = "Smooth Sixense Movement";
const float DEFAULT_REACH_LENGTH = 1.5f;
SixenseManager& SixenseManager::getInstance() {
static SixenseManager sharedInstance;
return sharedInstance;
}
SixenseManager::SixenseManager() :
InputDevice("Hydra"),
#ifdef __APPLE__
_sixenseLibrary(NULL),
#endif
_reachLength(DEFAULT_REACH_LENGTH),
_hydrasConnected(false)
{
}
bool SixenseManager::isSupported() const {
@ -92,7 +91,7 @@ void SixenseManager::activate() {
CONTAINER->addMenu(MENU_PATH);
CONTAINER->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
[this] (bool clicked) { this->setFilter(clicked); },
[this] (bool clicked) { this->setSixenseFilter(clicked); },
true, true);
#ifdef __APPLE__
@ -120,6 +119,7 @@ void SixenseManager::activate() {
SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit");
#endif
loadSettings();
sixenseInit();
#endif
}
@ -144,7 +144,7 @@ void SixenseManager::deactivate() {
#endif
}
void SixenseManager::setFilter(bool filter) {
void SixenseManager::setSixenseFilter(bool filter) {
#ifdef HAVE_SIXENSE
#ifdef __APPLE__
SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled");
@ -282,6 +282,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft);
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, Vectors::UNIT_Y));
xAxis = glm::normalize(glm::cross(Vectors::UNIT_Y, zAxis));
_reachLength = glm::dot(xAxis, _reachRight - _reachLeft);
_avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis)));
const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f;
_avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR;
@ -317,7 +318,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
_lastDistance = reach;
_lockExpiry = usecTimestampNow() + LOCK_DURATION;
// move to next state
_calibrationState = CALIBRATION_STATE_X;
_calibrationState = CALIBRATION_STATE_IN_PROGRESS;
}
return;
}
@ -327,7 +328,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
_averageLeft = 0.9f * _averageLeft + 0.1f * positionLeft;
_averageRight = 0.9f * _averageRight + 0.1f * positionRight;
if (_calibrationState == CALIBRATION_STATE_X) {
if (_calibrationState == CALIBRATION_STATE_IN_PROGRESS) {
// compute new sliding average
float distance = glm::distance(_averageLeft, _averageRight);
if (fabsf(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) {
@ -340,7 +341,6 @@ void SixenseManager::updateCalibration(void* controllersX) {
// lock has expired so clamp the data and move on
_lockExpiry = now + LOCK_DURATION;
_lastDistance = 0.0f;
_reachUp = 0.5f * (_reachLeft + _reachRight);
_calibrationState = CALIBRATION_STATE_COMPLETE;
qCDebug(inputplugins, "success: sixense calibration: left");
}
@ -543,6 +543,31 @@ void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
}
// virtual
void SixenseManager::saveSettings() const {
Settings settings;
QString idString = getID();
settings.beginGroup(idString);
{
settings.setVec3Value(QString("avatarPosition"), _avatarPosition);
settings.setQuatValue(QString("avatarRotation"), _avatarRotation);
settings.setValue(QString("reachLength"), QVariant(_reachLength));
}
settings.endGroup();
}
void SixenseManager::loadSettings() {
Settings settings;
QString idString = getID();
settings.beginGroup(idString);
{
settings.getVec3ValueIfValid(QString("avatarPosition"), _avatarPosition);
settings.getQuatValueIfValid(QString("avatarRotation"), _avatarRotation);
settings.getFloatValueIfValid(QString("reachLength"), _reachLength);
}
settings.endGroup();
}
UserInputMapper::Input SixenseManager::makeInput(unsigned int button, int index) {
return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON);
}

View file

@ -58,12 +58,11 @@ public:
SixenseManager();
static SixenseManager& getInstance();
// Plugin functions
virtual bool isSupported() const override;
virtual bool isJointController() const override { return true; }
const QString& getName() const override { return NAME; }
const QString& getID() const override { return HYDRA_ID_STRING; }
virtual void activate() override;
virtual void deactivate() override;
@ -77,15 +76,15 @@ public:
virtual void update(float deltaTime, bool jointsCaptured) override;
virtual void focusOutEvent() override;
bool getInvertButtons() const { return _invertButtons; }
void setInvertButtons(bool invertSixenseButtons) { _invertButtons = invertSixenseButtons; }
UserInputMapper::Input makeInput(unsigned int button, int index);
UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index);
UserInputMapper::Input makeInput(JointChannel joint);
virtual void saveSettings() const override;
virtual void loadSettings() override;
public slots:
void setFilter(bool filter);
void setSixenseFilter(bool filter);
private:
void handleButtonEvent(unsigned int buttons, int index);
@ -99,7 +98,7 @@ private:
// these are calibration results
glm::vec3 _avatarPosition; // in hydra-frame
glm::quat _avatarRotation; // in hydra-frame
float _armLength;
float _reachLength;
// these are measured values used to compute the calibration results
quint64 _lockExpiry;
@ -107,9 +106,8 @@ private:
glm::vec3 _averageRight;
glm::vec3 _reachLeft;
glm::vec3 _reachRight;
glm::vec3 _reachUp;
glm::vec3 _reachForward;
float _lastDistance;
bool _useSixenseFilter = true;
#ifdef __APPLE__
QLibrary* _sixenseLibrary;
@ -117,9 +115,8 @@ private:
bool _hydrasConnected;
bool _invertButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS;
static const QString NAME;
static const QString HYDRA_ID_STRING;
};
#endif // hifi_SixenseManager_h

View file

@ -19,17 +19,17 @@ BandwidthRecorder::Channel::Channel() {
}
float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() {
float delt = _input.getEventDeltaAverage();
if (delt > 0.0f) {
return (1.0f / delt);
float averageTimeBetweenPackets = _input.getEventDeltaAverage();
if (averageTimeBetweenPackets > 0.0f) {
return (1.0f / averageTimeBetweenPackets);
}
return 0.0f;
}
float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() {
float delt = _input.getEventDeltaAverage();
if (delt > 0.0f) {
return (1.0f / _output.getEventDeltaAverage());
float averageTimeBetweenPackets = _output.getEventDeltaAverage();
if (averageTimeBetweenPackets > 0.0f) {
return (1.0f / averageTimeBetweenPackets);
}
return 0.0f;
}

View file

@ -55,7 +55,7 @@ PacketQueue::PacketPointer PacketQueue::takePacket() {
}
unsigned int PacketQueue::nextIndex() {
_currentIndex = (++_currentIndex) % _channels.size();
_currentIndex = (_currentIndex + 1) % _channels.size();
return _currentIndex;
}

View file

@ -241,20 +241,21 @@ ViewFrustum::location ViewFrustum::boxInKeyhole(const AABox& box) const {
return result;
}
ViewFrustum::location ViewFrustum::pointInFrustum(const glm::vec3& point) const {
ViewFrustum::location ViewFrustum::pointInFrustum(const glm::vec3& point, bool ignoreKeyhole) const {
ViewFrustum::location regularResult = INSIDE;
ViewFrustum::location keyholeResult = OUTSIDE;
// If we have a keyholeRadius, check that first, since it's cheaper
if (_keyholeRadius >= 0.0f) {
if (!ignoreKeyhole && _keyholeRadius >= 0.0f) {
keyholeResult = pointInKeyhole(point);
}
if (keyholeResult == INSIDE) {
return keyholeResult;
if (keyholeResult == INSIDE) {
return keyholeResult;
}
}
// If we're not known to be INSIDE the keyhole, then check the regular frustum
for(int i=0; i < 6; i++) {
for(int i = 0; i < 6; ++i) {
float distance = _planes[i].distance(point);
if (distance < 0) {
return keyholeResult; // escape early will be the value from checking the keyhole

View file

@ -79,7 +79,7 @@ public:
typedef enum {OUTSIDE, INTERSECT, INSIDE} location;
ViewFrustum::location pointInFrustum(const glm::vec3& point) const;
ViewFrustum::location pointInFrustum(const glm::vec3& point, bool ignoreKeyhole = false) const;
ViewFrustum::location sphereInFrustum(const glm::vec3& center, float radius) const;
ViewFrustum::location cubeInFrustum(const AACube& cube) const;
ViewFrustum::location boxInFrustum(const AABox& box) const;

View file

@ -35,9 +35,8 @@ public:
if (rayResult.m_collisionObject == _me) {
return 1.0f;
}
return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace
);
}
return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
}
protected:
btRigidBody* _me;
};

View file

@ -9,6 +9,8 @@
PluginContainer* Plugin::CONTAINER{ nullptr };
QString Plugin::UNKNOWN_PLUGIN_ID("unknown");
void Plugin::setContainer(PluginContainer* container) {
CONTAINER = container;
}

View file

@ -7,6 +7,8 @@
//
#pragma once
#include <assert.h>
#include <QString>
#include <QObject>
@ -14,7 +16,12 @@
class Plugin : public QObject {
public:
/// \return human-readable name
virtual const QString& getName() const = 0;
/// \return string ID (not necessarily human-readable)
virtual const QString& getID() const { assert(false); return UNKNOWN_PLUGIN_ID; }
virtual bool isSupported() const;
static void setContainer(PluginContainer* container);
@ -37,6 +44,11 @@ public:
*/
virtual void idle();
virtual void saveSettings() const {}
virtual void loadSettings() {}
protected:
static PluginContainer* CONTAINER;
static QString UNKNOWN_PLUGIN_ID;
};

View file

@ -8,6 +8,8 @@
#include "PluginManager.h"
#include <mutex>
#include "Forward.h"
PluginManager* PluginManager::getInstance() {
static PluginManager _manager;
return &_manager;
@ -16,6 +18,7 @@ PluginManager* PluginManager::getInstance() {
// TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class
extern DisplayPluginList getDisplayPlugins();
extern InputPluginList getInputPlugins();
extern void saveInputPluginSettings(const InputPluginList& plugins);
const DisplayPluginList& PluginManager::getDisplayPlugins() {
static DisplayPluginList displayPlugins;
@ -35,3 +38,6 @@ const InputPluginList& PluginManager::getInputPlugins() {
return inputPlugins;
}
void PluginManager::saveSettings() {
saveInputPluginSettings(getInputPlugins());
}

View file

@ -15,4 +15,5 @@ public:
const DisplayPluginList& getDisplayPlugins();
const InputPluginList& getInputPlugins();
void saveSettings();
};

View file

@ -11,12 +11,13 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QEventLoop>
#include <QtCore/QFileInfo>
#include <QtCore/QTimer>
#include <QtCore/QThread>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QScriptEngine>
#include <QScriptValue>
#include <QtScript/QScriptEngine>
#include <QtScript/QScriptValue>
#include <AudioConstants.h>
#include <AudioEffectOptions.h>
@ -942,6 +943,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
#endif
auto scriptCache = DependencyManager::get<ScriptCache>();
bool isFileUrl = isURL && scriptOrURL.startsWith("file://");
// first check the syntax of the script contents
QScriptSyntaxCheckResult syntaxCheck = QScriptEngine::checkSyntax(contents);
@ -950,7 +952,9 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
qCDebug(scriptengine) << " " << syntaxCheck.errorMessage() << ":"
<< syntaxCheck.errorLineNumber() << syntaxCheck.errorColumnNumber();
qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL;
scriptCache->addScriptToBadScriptList(scriptOrURL);
if (!isFileUrl) {
scriptCache->addScriptToBadScriptList(scriptOrURL);
}
return; // done processing script
}
@ -965,14 +969,21 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID;
qCDebug(scriptengine) << " NOT CONSTRUCTOR";
qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL;
scriptCache->addScriptToBadScriptList(scriptOrURL);
if (!isFileUrl) {
scriptCache->addScriptToBadScriptList(scriptOrURL);
}
return; // done processing script
}
QScriptValue entityScriptConstructor = evaluate(contents);
int64_t lastModified = 0;
if (isFileUrl) {
QString file = QUrl(scriptOrURL).toLocalFile();
lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();
}
QScriptValue entityScriptConstructor = evaluate(contents);
QScriptValue entityScriptObject = entityScriptConstructor.construct();
EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject };
EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified };
_entityScripts[entityID] = newDetails;
if (isURL) {
setParentURL("");
@ -1022,6 +1033,41 @@ void ScriptEngine::unloadAllEntityScripts() {
_entityScripts.clear();
}
void ScriptEngine::refreshFileScript(const EntityItemID& entityID) {
if (!_entityScripts.contains(entityID)) {
return;
}
static bool recurseGuard = false;
if (recurseGuard) {
return;
}
recurseGuard = true;
EntityScriptDetails details = _entityScripts[entityID];
// Check to see if a file based script needs to be reloaded (easier debugging)
if (details.lastModified > 0) {
QString filePath = QUrl(details.scriptText).toLocalFile();
auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch();
if (lastModified > details.lastModified) {
qDebug() << "Reloading modified script " << details.scriptText;
QFile file(filePath);
file.open(QIODevice::ReadOnly);
QString scriptContents = QTextStream(&file).readAll();
this->unloadEntityScript(entityID);
this->entityScriptContentAvailable(entityID, details.scriptText, scriptContents, true, true);
if (!_entityScripts.contains(entityID)) {
qWarning() << "Reload script " << details.scriptText << " failed";
} else {
details = _entityScripts[entityID];
}
}
}
recurseGuard = false;
}
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
@ -1039,6 +1085,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
"entityID:" << entityID << "methodName:" << methodName;
#endif
refreshFileScript(entityID);
if (_entityScripts.contains(entityID)) {
EntityScriptDetails details = _entityScripts[entityID];
QScriptValue entityScript = details.scriptObject; // previously loaded
@ -1069,6 +1116,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
"entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
#endif
refreshFileScript(entityID);
if (_entityScripts.contains(entityID)) {
EntityScriptDetails details = _entityScripts[entityID];
QScriptValue entityScript = details.scriptObject; // previously loaded
@ -1101,6 +1149,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
"entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
#endif
refreshFileScript(entityID);
if (_entityScripts.contains(entityID)) {
EntityScriptDetails details = _entityScripts[entityID];
QScriptValue entityScript = details.scriptObject; // previously loaded

View file

@ -45,6 +45,7 @@ class EntityScriptDetails {
public:
QString scriptText;
QScriptValue scriptObject;
int64_t lastModified;
};
class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScriptEngineProvider {
@ -171,6 +172,7 @@ private:
bool evaluatePending() const { return _evaluatesPending > 0; }
void timerFired();
void stopAllTimers();
void refreshFileScript(const EntityItemID& entityID);
void setParentURL(const QString& parentURL) { _parentURL = parentURL; }

View file

@ -0,0 +1,83 @@
//
// SettingHandle.h
//
//
// Created by AndrewMeadows 2015.10.05
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "SettingHandle.h"
#include <math.h>
void Settings::getFloatValueIfValid(const QString& name, float& floatValue) {
const QVariant badDefaultValue = NAN;
bool ok = true;
float tempFloat = value(name, badDefaultValue).toFloat(&ok);
if (ok && !isnan(tempFloat)) {
floatValue = tempFloat;
}
}
void Settings::getBoolValue(const QString& name, bool& boolValue) {
const QVariant defaultValue = false;
boolValue = value(name, defaultValue).toBool();
}
void Settings::setVec3Value(const QString& name, const glm::vec3& vecValue) {
beginGroup(name);
{
setValue(QString("x"), vecValue.x);
setValue(QString("y"), vecValue.y);
setValue(QString("z"), vecValue.z);
}
endGroup();
}
void Settings::getVec3ValueIfValid(const QString& name, glm::vec3& vecValue) {
beginGroup(name);
{
bool ok = true;
const QVariant badDefaultValue = NAN;
float x = value(QString("x"), badDefaultValue).toFloat(&ok);
float y = value(QString("y"), badDefaultValue).toFloat(&ok);
float z = value(QString("z"), badDefaultValue).toFloat(&ok);
if (ok && (!isnan(x) && !isnan(y) && !isnan(z))) {
vecValue = glm::vec3(x, y, z);
}
}
endGroup();
}
void Settings::setQuatValue(const QString& name, const glm::quat& quatValue) {
beginGroup(name);
{
setValue(QString("x"), quatValue.x);
setValue(QString("y"), quatValue.y);
setValue(QString("z"), quatValue.z);
setValue(QString("w"), quatValue.w);
}
endGroup();
}
void Settings::getQuatValueIfValid(const QString& name, glm::quat& quatValue) {
beginGroup(name);
{
bool ok = true;
const QVariant badDefaultValue = NAN;
float x = value(QString("x"), badDefaultValue).toFloat(&ok);
float y = value(QString("y"), badDefaultValue).toFloat(&ok);
float z = value(QString("z"), badDefaultValue).toFloat(&ok);
float w = value(QString("w"), badDefaultValue).toFloat(&ok);
if (ok && (!isnan(x) && !isnan(y) && !isnan(z) && !isnan(w))) {
quatValue = glm::quat(w, x, y, z);
}
}
endGroup();
}

View file

@ -18,11 +18,22 @@
#include <QString>
#include <QVariant>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include "SettingInterface.h"
// TODO: remove
class Settings : public QSettings {
public:
void getFloatValueIfValid(const QString& name, float& floatValue);
void getBoolValue(const QString& name, bool& boolValue);
void setVec3Value(const QString& name, const glm::vec3& vecValue);
void getVec3ValueIfValid(const QString& name, glm::vec3& vecValue);
void setQuatValue(const QString& name, const glm::quat& quatValue);
void getQuatValueIfValid(const QString& name, glm::quat& quatValue);
};
namespace Setting {
@ -65,4 +76,4 @@ namespace Setting {
}
}
#endif // hifi_SettingHandle_h
#endif // hifi_SettingHandle_h

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,45 @@
// immediateClientReset.js
// Created by Eric Levin on 9/23/2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */
var masterResetScript = Script.resolvePath("masterReset.js");
var hiddenEntityScriptURL = Script.resolvePath("hiddenEntityReset.js");
Script.include(masterResetScript);
function createHiddenMasterSwitch() {
var resetKey = "resetMe";
var masterSwitch = Entities.addEntity({
type: "Box",
name: "Master Switch",
script: hiddenEntityScriptURL,
dimensions: {x: 0.7, y: 0.2, z: 0.1},
position: {x: 543.9, y: 496.05, z: 502.43},
rotation: Quat.fromPitchYawRollDegrees(0, 33, 0),
visible: false
});
}
var entities = Entities.findEntities(MyAvatar.position, 100);
entities.forEach(function(entity) {
//params: customKey, id, defaultValue
var name = Entities.getEntityProperties(entity, "name").name
if (name === "Master Switch") {
Entities.deleteEntity(entity);
}
});
createHiddenMasterSwitch();
MasterReset();

File diff suppressed because it is too large Load diff