mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 14:03:55 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into hobbes
This commit is contained in:
commit
eacbcf2881
43 changed files with 3057 additions and 1430 deletions
|
@ -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);
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -249,6 +249,8 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
|
|||
|
||||
processedBytes += bytesRead;
|
||||
|
||||
Q_UNUSED(somethingChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,8 @@ bool AtmospherePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& property
|
|||
|
||||
processedBytes += bytesRead;
|
||||
|
||||
Q_UNUSED(somethingChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -66,6 +66,8 @@ bool SkyboxPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlag
|
|||
|
||||
processedBytes += bytesRead;
|
||||
|
||||
Q_UNUSED(somethingChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -121,6 +121,8 @@ bool StagePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags
|
|||
|
||||
processedBytes += bytesRead;
|
||||
|
||||
Q_UNUSED(somethingChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -37,3 +37,9 @@ InputPluginList getInputPlugins() {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void saveInputPluginSettings(const InputPluginList& plugins) {
|
||||
foreach (auto inputPlugin, plugins) {
|
||||
inputPlugin->saveSettings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ PacketQueue::PacketPointer PacketQueue::takePacket() {
|
|||
}
|
||||
|
||||
unsigned int PacketQueue::nextIndex() {
|
||||
_currentIndex = (++_currentIndex) % _channels.size();
|
||||
_currentIndex = (_currentIndex + 1) % _channels.size();
|
||||
return _currentIndex;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
PluginContainer* Plugin::CONTAINER{ nullptr };
|
||||
|
||||
QString Plugin::UNKNOWN_PLUGIN_ID("unknown");
|
||||
|
||||
void Plugin::setContainer(PluginContainer* container) {
|
||||
CONTAINER = container;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -15,4 +15,5 @@ public:
|
|||
|
||||
const DisplayPluginList& getDisplayPlugins();
|
||||
const InputPluginList& getInputPlugins();
|
||||
void saveSettings();
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
83
libraries/shared/src/SettingHandle.cpp
Normal file
83
libraries/shared/src/SettingHandle.cpp
Normal 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();
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
1172
unpublishedScripts/hiddenEntityReset.js
Normal file
1172
unpublishedScripts/hiddenEntityReset.js
Normal file
File diff suppressed because it is too large
Load diff
45
unpublishedScripts/immediateClientReset.js
Normal file
45
unpublishedScripts/immediateClientReset.js
Normal 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
Loading…
Reference in a new issue