@@ -76,6 +77,7 @@
+
\ No newline at end of file
diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp
index 6a63168579..e7a9eef1ee 100644
--- a/domain-server/src/DomainServerSettingsManager.cpp
+++ b/domain-server/src/DomainServerSettingsManager.cpp
@@ -289,6 +289,9 @@ void DomainServerSettingsManager::updateSetting(const QString& key, const QJsonV
// we've cleared all of the settings below this value, so remove this one too
settingMap.remove(key);
}
+ } else if (newValue.isArray()) {
+ // we just assume array is replacement
+ settingMap[key] = newValue.toArray().toVariantList();
}
}
diff --git a/examples/leapHands.js b/examples/leapHands.js
index 222c0e4cf1..c9c3af0063 100644
--- a/examples/leapHands.js
+++ b/examples/leapHands.js
@@ -23,7 +23,7 @@ var leapHands = (function () {
fingers,
NUM_FINGERS = 5, // 0 = thumb; ...; 4 = pinky
THUMB = 0,
- NUM_FINGER_JOINTS = 3, // 0 = metacarpal(hand)-proximal(finger) joint; ...; 2 = intermediate-distal(tip) joint
+ NUM_FINGER_JOINTS = 3, // 0 = metacarpal(hand)-proximal(finger) joint; ...; 2 = intermediate-distal joint
MAX_HAND_INACTIVE_COUNT = 20,
calibrationStatus,
UNCALIBRATED = 0,
@@ -226,8 +226,6 @@ var leapHands = (function () {
function setUp() {
- // TODO: Leap Motion controller joint naming doesn't match up with skeleton joint naming; numbers are out by 1.
-
hands = [
{
jointName: "LeftHand",
@@ -246,6 +244,9 @@ var leapHands = (function () {
{ controller: Controller.createInputController("Spatial", "joint_R_wrist") }
];
+ // The Leap controller's first joint is the hand-metacarpal joint but this joint's data is not used because it's too
+ // dependent on the model skeleton exactly matching the Leap skeleton; using just the second and subsequent joints
+ // seems to work better over all.
fingers = [{}, {}];
fingers[0] = [
[
@@ -407,19 +408,26 @@ var leapHands = (function () {
MyAvatar.setJointModelPositionAndOrientation(hands[h].jointName, handOffset, handRotation, true);
// Finger joints ...
- // TODO: 2.0 * scale factors should not be necessary; Leap Motion controller code needs investigating.
for (i = 0; i < NUM_FINGERS; i += 1) {
for (j = 0; j < NUM_FINGER_JOINTS; j += 1) {
if (fingers[h][i][j].controller !== null) {
locRotation = fingers[h][i][j].controller.getLocRotation();
if (i === THUMB) {
- MyAvatar.setJointData(fingers[h][i][j].jointName,
- Quat.fromPitchYawRollRadians(2.0 * side * locRotation.y, 2.0 * -locRotation.z,
- 2.0 * side * -locRotation.x));
+ locRotation = {
+ x: side * locRotation.y,
+ y: side * -locRotation.z,
+ z: side * -locRotation.x,
+ w: locRotation.w
+ };
} else {
- MyAvatar.setJointData(fingers[h][i][j].jointName,
- Quat.fromPitchYawRollRadians(2.0 * -locRotation.x, 0.0, 2.0 * -locRotation.y));
+ locRotation = {
+ x: -locRotation.x,
+ y: -locRotation.z,
+ z: -locRotation.y,
+ w: locRotation.w
+ };
}
+ MyAvatar.setJointData(fingers[h][i][j].jointName, locRotation);
}
}
}
diff --git a/interface/resources/shaders/metavoxel_point.vert b/interface/resources/shaders/metavoxel_point.vert
index 1a4a4c56ce..02de2bfa01 100644
--- a/interface/resources/shaders/metavoxel_point.vert
+++ b/interface/resources/shaders/metavoxel_point.vert
@@ -13,16 +13,19 @@
uniform float pointScale;
-void main(void) {
+// the interpolated normal
+varying vec4 normal;
- // standard diffuse lighting
- gl_FrontColor = vec4(gl_Color.rgb * (gl_LightModel.ambient.rgb + gl_LightSource[0].ambient.rgb +
- gl_LightSource[0].diffuse.rgb * max(0.0, dot(gl_NormalMatrix * gl_Normal, gl_LightSource[0].position.xyz))),
- 0.0);
+void main(void) {
+ // transform and store the normal for interpolation
+ normal = vec4(normalize(gl_NormalMatrix * gl_Normal), 0.0);
// extract the first three components of the vertex for position
gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0);
// the final component is the size in world space
gl_PointSize = pointScale * gl_Vertex.w / gl_Position.w;
+
+ // copy the color for interpolation
+ gl_FrontColor = vec4(gl_Color.rgb, 0.0);
}
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index a31b148d1b..718360864a 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -153,7 +153,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_lastQueriedViewFrustum(),
_lastQueriedTime(usecTimestampNow()),
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
- _cameraPushback(0.0f),
_scaleMirror(1.0f),
_rotateMirror(0.0f),
_raiseMirror(0.0f),
@@ -605,37 +604,36 @@ void Application::paintGL() {
glEnable(GL_LINE_SMOOTH);
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
- _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
if (!OculusManager::isConnected()) {
- _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition());
- _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
+ _myCamera.setPosition(_myAvatar->getHead()->getEyePosition());
+ _myCamera.setRotation(_myAvatar->getHead()->getCameraOrientation());
}
// OculusManager::display() updates camera position and rotation a bit further on.
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
- //Note, the camera distance is set in Camera::setMode() so we dont have to do it here.
- _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing
- _myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition());
+ static const float THIRD_PERSON_CAMERA_DISTANCE = 1.5f;
+ _myCamera.setPosition(_myAvatar->getUprightHeadPosition() +
+ _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * THIRD_PERSON_CAMERA_DISTANCE * _myAvatar->getScale());
if (OculusManager::isConnected()) {
- _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation());
+ _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation());
} else {
- _myCamera.setTargetRotation(_myAvatar->getHead()->getOrientation());
+ _myCamera.setRotation(_myAvatar->getHead()->getOrientation());
}
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
- _myCamera.setTightness(0.0f);
//Only behave like a true mirror when in the OR
if (OculusManager::isConnected()) {
- _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
- _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
- _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0));
+ _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
+ _myCamera.setPosition(_myAvatar->getHead()->getEyePosition() +
+ glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) +
+ (_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
+ glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
} else {
- _myCamera.setTightness(0.0f);
- glm::vec3 eyePosition = _myAvatar->getHead()->getEyePosition();
- float headHeight = eyePosition.y - _myAvatar->getPosition().y;
- _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
- _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0));
- _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
+ _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
+ _myCamera.setPosition(_myAvatar->getHead()->getEyePosition() +
+ glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) +
+ (_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
+ glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
}
}
@@ -659,11 +657,13 @@ void Application::paintGL() {
ViewFrustumOffset viewFrustumOffset = Menu::getInstance()->getViewFrustumOffset();
// set the camera to third-person view but offset so we can see the frustum
- _viewFrustumOffsetCamera.setTargetPosition(_myCamera.getTargetPosition());
- _viewFrustumOffsetCamera.setTargetRotation(_myCamera.getTargetRotation() * glm::quat(glm::radians(glm::vec3(
- viewFrustumOffset.pitch, viewFrustumOffset.yaw, viewFrustumOffset.roll))));
- _viewFrustumOffsetCamera.setUpShift(viewFrustumOffset.up);
- _viewFrustumOffsetCamera.setDistance(viewFrustumOffset.distance);
+ glm::quat frustumRotation = glm::quat(glm::radians(glm::vec3(viewFrustumOffset.pitch, viewFrustumOffset.yaw, viewFrustumOffset.roll)));
+
+ _viewFrustumOffsetCamera.setPosition(_myCamera.getPosition() +
+ frustumRotation * glm::vec3(0.0f, viewFrustumOffset.up, -viewFrustumOffset.distance));
+
+ _viewFrustumOffsetCamera.setRotation(_myCamera.getRotation() * frustumRotation);
+
_viewFrustumOffsetCamera.initialize(); // force immediate snap to ideal position and orientation
_viewFrustumOffsetCamera.update(1.f/_fps);
whichCamera = &_viewFrustumOffsetCamera;
@@ -1779,10 +1779,8 @@ void Application::init() {
// TODO: move _myAvatar out of Application. Move relevant code to MyAvataar or AvatarManager
_avatarManager.init();
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
- _myCamera.setModeShiftPeriod(1.0f);
_mirrorCamera.setMode(CAMERA_MODE_MIRROR);
- _mirrorCamera.setModeShiftPeriod(0.0f);
OculusManager::connect();
if (OculusManager::isConnected()) {
@@ -2122,17 +2120,14 @@ void Application::cameraMenuChanged() {
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
_myCamera.setMode(CAMERA_MODE_MIRROR);
- _myCamera.setModeShiftPeriod(0.0f);
}
} else if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) {
if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) {
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
- _myCamera.setModeShiftPeriod(modeShiftPeriod);
}
} else {
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
- _myCamera.setModeShiftPeriod(modeShiftPeriod);
}
}
}
@@ -2962,7 +2957,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
}
}
- bool mirrorMode = (whichCamera.getInterpolatedMode() == CAMERA_MODE_MIRROR);
+ bool mirrorMode = (whichCamera.getMode() == CAMERA_MODE_MIRROR);
{
PerformanceTimer perfTimer("avatars");
_avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE,
@@ -3101,30 +3096,30 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
bool eyeRelativeCamera = false;
if (billboard) {
_mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees
- _mirrorCamera.setDistance(BILLBOARD_DISTANCE * _myAvatar->getScale());
- _mirrorCamera.setTargetPosition(_myAvatar->getPosition());
+ _mirrorCamera.setPosition(_myAvatar->getPosition() +
+ _myAvatar->getOrientation() * glm::vec3(0.f, 0.f, -1.0f) * BILLBOARD_DISTANCE * _myAvatar->getScale());
} else if (_rearMirrorTools->getZoomLevel() == BODY) {
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees
- _mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
- _mirrorCamera.setTargetPosition(_myAvatar->getChestPosition());
+ _mirrorCamera.setPosition(_myAvatar->getChestPosition() +
+ _myAvatar->getOrientation() * glm::vec3(0.f, 0.f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
} else { // HEAD zoom level
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees
- _mirrorCamera.setDistance(MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
if (_myAvatar->getSkeletonModel().isActive() && _myAvatar->getHead()->getFaceModel().isActive()) {
// as a hack until we have a better way of dealing with coordinate precision issues, reposition the
// face/body so that the average eye position lies at the origin
eyeRelativeCamera = true;
- _mirrorCamera.setTargetPosition(glm::vec3());
+ _mirrorCamera.setPosition(_myAvatar->getOrientation() * glm::vec3(0.f, 0.f, -1.0f) * MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
} else {
- _mirrorCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition());
+ _mirrorCamera.setPosition(_myAvatar->getHead()->getEyePosition() +
+ _myAvatar->getOrientation() * glm::vec3(0.f, 0.f, -1.0f) * MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
}
}
_mirrorCamera.setAspectRatio((float)region.width() / region.height());
- _mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f)));
+ _mirrorCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f)));
_mirrorCamera.update(1.0f/_fps);
// set the bounds of rear mirror view
diff --git a/interface/src/Application.h b/interface/src/Application.h
index ca26cffab8..248c4325bf 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -519,7 +519,6 @@ private:
QRect _mirrorViewRect;
RearMirrorTools* _rearMirrorTools;
- float _cameraPushback;
glm::mat4 _untranslatedViewMatrix;
glm::vec3 _viewMatrixTranslation;
glm::mat4 _projectionMatrix;
diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp
index 4a924b4ec3..79d66568bf 100644
--- a/interface/src/Camera.cpp
+++ b/interface/src/Camera.cpp
@@ -20,102 +20,21 @@
#include "Util.h"
#include "devices/OculusManager.h"
-const float CAMERA_FIRST_PERSON_MODE_UP_SHIFT = 0.0f;
-const float CAMERA_FIRST_PERSON_MODE_DISTANCE = 0.0f;
-const float CAMERA_FIRST_PERSON_MODE_TIGHTNESS = 100.0f;
-
-const float CAMERA_INDEPENDENT_MODE_UP_SHIFT = 0.0f;
-const float CAMERA_INDEPENDENT_MODE_DISTANCE = 0.0f;
-const float CAMERA_INDEPENDENT_MODE_TIGHTNESS = 100.0f;
-
-const float CAMERA_THIRD_PERSON_MODE_UP_SHIFT = -0.2f;
-const float CAMERA_THIRD_PERSON_MODE_DISTANCE = 1.5f;
-const float CAMERA_THIRD_PERSON_MODE_TIGHTNESS = 8.0f;
-
-const float CAMERA_MIRROR_MODE_UP_SHIFT = 0.0f;
-const float CAMERA_MIRROR_MODE_DISTANCE = 0.17f;
-const float CAMERA_MIRROR_MODE_TIGHTNESS = 100.0f;
-
Camera::Camera() :
_needsToInitialize(true),
_mode(CAMERA_MODE_THIRD_PERSON),
- _prevMode(CAMERA_MODE_THIRD_PERSON),
- _frustumNeedsReshape(true),
_position(0.0f, 0.0f, 0.0f),
- _idealPosition(0.0f, 0.0f, 0.0f),
- _targetPosition(0.0f, 0.0f, 0.0f),
_fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES),
_aspectRatio(16.0f/9.0f),
_nearClip(DEFAULT_NEAR_CLIP), // default
_farClip(DEFAULT_FAR_CLIP), // default
- _upShift(0.0f),
- _distance(0.0f),
- _tightness(10.0f), // default
- _previousUpShift(0.0f),
- _previousDistance(0.0f),
- _previousTightness(0.0f),
- _newUpShift(0.0f),
- _newDistance(0.0f),
- _newTightness(0.0f),
- _modeShift(1.0f),
- _linearModeShift(0.0f),
- _modeShiftPeriod(1.0f),
- _scale(1.0f),
- _lookingAt(0.0f, 0.0f, 0.0f),
- _isKeepLookingAt(false)
+ _scale(1.0f)
{
}
-void Camera::update(float deltaTime) {
-
- if (_mode != CAMERA_MODE_NULL) {
- // use iterative forces to push the camera towards the target position and angle
- updateFollowMode(deltaTime);
- }
-}
-
-// use iterative forces to keep the camera at the desired position and angle
-void Camera::updateFollowMode(float deltaTime) {
- if (_linearModeShift < 1.0f) {
- _linearModeShift += deltaTime / _modeShiftPeriod;
- if (_needsToInitialize || _linearModeShift > 1.0f) {
- _linearModeShift = 1.0f;
- _modeShift = 1.0f;
- _upShift = _newUpShift;
- _distance = _newDistance;
- _tightness = _newTightness;
- } else {
- _modeShift = ONE_HALF - ONE_HALF * cosf(_linearModeShift * PI );
- _upShift = _previousUpShift * (1.0f - _modeShift) + _newUpShift * _modeShift;
- _distance = _previousDistance * (1.0f - _modeShift) + _newDistance * _modeShift;
- _tightness = _previousTightness * (1.0f - _modeShift) + _newTightness * _modeShift;
- }
- }
-
- // derive t from tightness
- float t = _tightness * _modeShift * deltaTime;
- if (t > 1.0f) {
- t = 1.0f;
- }
-
- // handle keepLookingAt
- if (_isKeepLookingAt) {
- lookAt(_lookingAt);
- }
-
- // Update position and rotation, setting directly if tightness is 0.0
- if (_needsToInitialize || (_tightness == 0.0f)) {
- _rotation = _targetRotation;
- _idealPosition = _targetPosition + _scale * (_rotation * glm::vec3(0.0f, _upShift, _distance));
- _position = _idealPosition;
- _needsToInitialize = false;
- } else {
- // pull rotation towards ideal
- _rotation = safeMix(_rotation, _targetRotation, t);
- _idealPosition = _targetPosition + _scale * (_rotation * glm::vec3(0.0f, _upShift, _distance));
- _position += (_idealPosition - _position) * t;
- }
+void Camera::update(float deltaTime) {
+ return;
}
float Camera::getFarClip() const {
@@ -124,137 +43,46 @@ float Camera::getFarClip() const {
: std::numeric_limits
::max() - 1;
}
-void Camera::setModeShiftPeriod (float period) {
- const float MIN_PERIOD = 0.001f;
- const float MAX_PERIOD = 3.0f;
- _modeShiftPeriod = glm::clamp(period, MIN_PERIOD, MAX_PERIOD);
-
- // if a zero period was requested, we clearly want to snap immediately to the target
- if (period == 0.0f) {
- update(MAX_PERIOD);
- }
-}
-
-void Camera::setMode(CameraMode m) {
-
- _prevMode = _mode;
+void Camera::setMode(CameraMode m) {
_mode = m;
- _modeShift = 0.0;
- _linearModeShift = 0.0;
-
- _previousUpShift = _upShift;
- _previousDistance = _distance;
- _previousTightness = _tightness;
-
- if (_mode == CAMERA_MODE_THIRD_PERSON) {
- _newUpShift = CAMERA_THIRD_PERSON_MODE_UP_SHIFT;
- _newDistance = CAMERA_THIRD_PERSON_MODE_DISTANCE;
- _newTightness = CAMERA_THIRD_PERSON_MODE_TIGHTNESS;
- } else if (_mode == CAMERA_MODE_FIRST_PERSON) {
- _newUpShift = CAMERA_FIRST_PERSON_MODE_UP_SHIFT;
- _newDistance = CAMERA_FIRST_PERSON_MODE_DISTANCE;
- _newTightness = CAMERA_FIRST_PERSON_MODE_TIGHTNESS;
- } else if (_mode == CAMERA_MODE_MIRROR) {
- _newUpShift = CAMERA_MIRROR_MODE_UP_SHIFT;
- _newDistance = CAMERA_MIRROR_MODE_DISTANCE;
- _newTightness = CAMERA_MIRROR_MODE_TIGHTNESS;
- } else if (_mode == CAMERA_MODE_INDEPENDENT) {
- _newUpShift = CAMERA_INDEPENDENT_MODE_UP_SHIFT;
- _newDistance = CAMERA_INDEPENDENT_MODE_DISTANCE;
- _newTightness = CAMERA_INDEPENDENT_MODE_TIGHTNESS;
-
- }
}
-void Camera::setTargetPosition(const glm::vec3& t) {
- _targetPosition = t;
-
- // handle keepLookingAt
- if (_isKeepLookingAt) {
- lookAt(_lookingAt);
- }
-
-}
-
-void Camera::setTargetRotation( const glm::quat& targetRotation ) {
- _targetRotation = targetRotation;
-}
void Camera::setFieldOfView(float f) {
_fieldOfView = f;
- _frustumNeedsReshape = true;
}
void Camera::setAspectRatio(float a) {
- _aspectRatio = a;
- _frustumNeedsReshape = true;
+ _aspectRatio = a;
}
void Camera::setNearClip(float n) {
- _nearClip = n;
- _frustumNeedsReshape = true;
+ _nearClip = n;
}
void Camera::setFarClip(float f) {
- _farClip = f;
- _frustumNeedsReshape = true;
+ _farClip = f;
}
void Camera::setEyeOffsetPosition(const glm::vec3& p) {
_eyeOffsetPosition = p;
- _frustumNeedsReshape = true;
}
void Camera::setEyeOffsetOrientation(const glm::quat& o) {
_eyeOffsetOrientation = o;
- _frustumNeedsReshape = true;
+
}
void Camera::setScale(float s) {
_scale = s;
_needsToInitialize = true;
- _frustumNeedsReshape = true;
+
}
void Camera::initialize() {
_needsToInitialize = true;
- _modeShift = 0.0;
}
-// call to find out if the view frustum needs to be reshaped
-bool Camera::getFrustumNeedsReshape() const {
- return _frustumNeedsReshape;
-}
-
-// call this when deciding whether to render the head or not
-CameraMode Camera::getInterpolatedMode() const {
- const float SHIFT_THRESHOLD_INTO_FIRST_PERSON = 0.7f;
- const float SHIFT_THRESHOLD_OUT_OF_FIRST_PERSON = 0.6f;
- if ((_mode == CAMERA_MODE_FIRST_PERSON && _linearModeShift < SHIFT_THRESHOLD_INTO_FIRST_PERSON) ||
- (_prevMode == CAMERA_MODE_FIRST_PERSON && _linearModeShift < SHIFT_THRESHOLD_OUT_OF_FIRST_PERSON)) {
- return _prevMode;
- }
- return _mode;
-}
-
-// call this after reshaping the view frustum
-void Camera::setFrustumWasReshaped() {
- _frustumNeedsReshape = false;
-}
-
-void Camera::lookAt(const glm::vec3& lookAt) {
- glm::vec3 up = IDENTITY_UP;
- glm::mat4 lookAtMatrix = glm::lookAt(_targetPosition, lookAt, up);
- glm::quat rotation = glm::quat_cast(lookAtMatrix);
- rotation.w = -rotation.w; // Rosedale approved
- setTargetRotation(rotation);
-}
-
-void Camera::keepLookingAt(const glm::vec3& point) {
- lookAt(point);
- _isKeepLookingAt = true;
- _lookingAt = point;
-}
CameraScriptableObject::CameraScriptableObject(Camera* camera, ViewFrustum* viewFrustum) :
_camera(camera), _viewFrustum(viewFrustum)
diff --git a/interface/src/Camera.h b/interface/src/Camera.h
index 2bbbf0e751..ee4930272d 100644
--- a/interface/src/Camera.h
+++ b/interface/src/Camera.h
@@ -35,14 +35,9 @@ public:
void initialize(); // instantly put the camera at the ideal position and rotation.
void update( float deltaTime );
-
- void setUpShift(float u) { _upShift = u; }
- void setDistance(float d) { _distance = d; }
+
void setPosition(const glm::vec3& p) { _position = p; }
- void setTargetPosition(const glm::vec3& t);
- void setTightness(float t) { _tightness = t; }
- void setTargetRotation(const glm::quat& rotation);
- void setModeShiftPeriod(float r);
+ void setRotation(const glm::quat& rotation) { _rotation = rotation; };
void setMode(CameraMode m);
void setFieldOfView(float f);
void setAspectRatio(float a);
@@ -55,10 +50,6 @@ public:
const glm::vec3& getPosition() const { return _position; }
const glm::quat& getRotation() const { return _rotation; }
CameraMode getMode() const { return _mode; }
- float getModeShiftPeriod() const { return _modeShiftPeriod; }
- float getDistance() const { return _distance; }
- const glm::vec3& getTargetPosition() const { return _targetPosition; }
- const glm::quat& getTargetRotation() const { return _targetRotation; }
float getFieldOfView() const { return _fieldOfView; }
float getAspectRatio() const { return _aspectRatio; }
float getNearClip() const { return _scale * _nearClip; }
@@ -67,31 +58,11 @@ public:
const glm::quat& getEyeOffsetOrientation() const { return _eyeOffsetOrientation; }
float getScale() const { return _scale; }
- CameraMode getInterpolatedMode() const;
-
- bool getFrustumNeedsReshape() const; // call to find out if the view frustum needs to be reshaped
- void setFrustumWasReshaped(); // call this after reshaping the view frustum.
-
- // These only work on independent cameras
- /// one time change to what the camera is looking at
- void lookAt(const glm::vec3& value);
-
- /// fix what the camera is looking at, and keep the camera looking at this even if position changes
- void keepLookingAt(const glm::vec3& value);
-
- /// stops the keep looking at feature, doesn't change what's being looked at, but will stop camera from
- /// continuing to update it's orientation to keep looking at the item
- void stopLooking() { _isKeepLookingAt = false; }
-
private:
bool _needsToInitialize;
CameraMode _mode;
- CameraMode _prevMode;
- bool _frustumNeedsReshape;
glm::vec3 _position;
- glm::vec3 _idealPosition;
- glm::vec3 _targetPosition;
float _fieldOfView; // degrees
float _aspectRatio;
float _nearClip;
@@ -99,25 +70,8 @@ private:
glm::vec3 _eyeOffsetPosition;
glm::quat _eyeOffsetOrientation;
glm::quat _rotation;
- glm::quat _targetRotation;
- float _upShift;
- float _distance;
- float _tightness;
- float _previousUpShift;
- float _previousDistance;
- float _previousTightness;
- float _newUpShift;
- float _newDistance;
- float _newTightness;
- float _modeShift;
- float _linearModeShift;
- float _modeShiftPeriod;
- float _scale;
- glm::vec3 _lookingAt;
- bool _isKeepLookingAt;
-
- void updateFollowMode(float deltaTime);
+ float _scale;
};
@@ -129,25 +83,13 @@ public:
public slots:
QString getMode() const;
void setMode(const QString& mode);
- void setModeShiftPeriod(float r) {_camera->setModeShiftPeriod(r); }
- void setPosition(const glm::vec3& value) { _camera->setTargetPosition(value);}
+ void setPosition(const glm::vec3& value) { _camera->setPosition(value);}
glm::vec3 getPosition() const { return _camera->getPosition(); }
- void setOrientation(const glm::quat& value) { _camera->setTargetRotation(value); }
+ void setOrientation(const glm::quat& value) { _camera->setRotation(value); }
glm::quat getOrientation() const { return _camera->getRotation(); }
- // These only work on independent cameras
- /// one time change to what the camera is looking at
- void lookAt(const glm::vec3& value) { _camera->lookAt(value);}
-
- /// fix what the camera is looking at, and keep the camera looking at this even if position changes
- void keepLookingAt(const glm::vec3& value) { _camera->keepLookingAt(value);}
-
- /// stops the keep looking at feature, doesn't change what's being looked at, but will stop camera from
- /// continuing to update it's orientation to keep looking at the item
- void stopLooking() { _camera->stopLooking();}
-
PickRay computePickRay(float x, float y);
private:
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index d82fb85c8c..77009da18b 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -423,6 +423,10 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DisableAutoAdjustLOD);
+ QMenu* metavoxelOptionsMenu = developerMenu->addMenu("Metavoxels");
+ addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::DisplayHermiteData, 0, false,
+ Application::getInstance()->getMetavoxels(), SLOT(refreshVoxelData()));
+
QMenu* handOptionsMenu = developerMenu->addMenu("Hands");
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false);
diff --git a/interface/src/Menu.h b/interface/src/Menu.h
index f73f4b02a2..67a4163c67 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -374,6 +374,7 @@ namespace MenuOption {
const QString DisplayFrustum = "Display Frustum";
const QString DisplayHands = "Show Hand Info";
const QString DisplayHandTargets = "Show Hand Targets";
+ const QString DisplayHermiteData = "Display Hermite Data";
const QString DisplayModelBounds = "Display Model Bounds";
const QString DisplayModelElementChildProxies = "Display Model Element Children";
const QString DisplayModelElementProxy = "Display Model Element Bounds";
diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp
index 7faf1a5bf4..10a211f61b 100644
--- a/interface/src/MetavoxelSystem.cpp
+++ b/interface/src/MetavoxelSystem.cpp
@@ -137,6 +137,18 @@ void MetavoxelSystem::render() {
emit rendering();
}
+void MetavoxelSystem::refreshVoxelData() {
+ foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
+ if (node->getType() == NodeType::MetavoxelServer) {
+ QMutexLocker locker(&node->getMutex());
+ MetavoxelSystemClient* client = static_cast(node->getLinkedData());
+ if (client) {
+ QMetaObject::invokeMethod(client, "refreshVoxelData");
+ }
+ }
+ }
+}
+
class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor {
public:
@@ -577,6 +589,14 @@ void Augmenter::run() {
QMetaObject::invokeMethod(node->getLinkedData(), "setAugmentedData", Q_ARG(const MetavoxelData&, _data));
}
+void MetavoxelSystemClient::refreshVoxelData() {
+ // make it look as if all the colors have changed
+ MetavoxelData oldData = getAugmentedData();
+ oldData.touch(AttributeRegistry::getInstance()->getVoxelColorAttribute());
+
+ QThreadPool::globalInstance()->start(new Augmenter(_node, _data, oldData, _remoteDataLOD));
+}
+
void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) {
MetavoxelClient::dataChanged(oldData);
QThreadPool::globalInstance()->start(new Augmenter(_node, _data, getAugmentedData(), _remoteDataLOD));
@@ -970,12 +990,14 @@ void VoxelPoint::setNormal(const glm::vec3& normal) {
this->normal[2] = (char)(normal.z * 127.0f);
}
-VoxelBuffer::VoxelBuffer(const QVector& vertices, const QVector& indices,
+VoxelBuffer::VoxelBuffer(const QVector& vertices, const QVector& indices, const QVector& hermite,
const QVector& materials) :
_vertices(vertices),
_indices(indices),
+ _hermite(hermite),
_vertexCount(vertices.size()),
_indexCount(indices.size()),
+ _hermiteCount(hermite.size()),
_indexBuffer(QOpenGLBuffer::IndexBuffer),
_materials(materials) {
}
@@ -1095,6 +1117,39 @@ void VoxelBuffer::render(bool cursor) {
_vertexBuffer.release();
_indexBuffer.release();
+
+ if (_hermiteCount > 0 && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHermiteData)) {
+ if (!_hermiteBuffer.isCreated()) {
+ _hermiteBuffer.create();
+ _hermiteBuffer.bind();
+ _hermiteBuffer.allocate(_hermite.constData(), _hermite.size() * sizeof(glm::vec3));
+ _hermite.clear();
+
+ } else {
+ _hermiteBuffer.bind();
+ }
+
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+
+ glVertexPointer(3, GL_FLOAT, 0, 0);
+
+ Application::getInstance()->getDeferredLightingEffect()->getSimpleProgram().bind();
+
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glNormal3f(0.0f, 1.0f, 0.0f);
+
+ glLineWidth(1.0f);
+
+ glDrawArrays(GL_LINES, 0, _hermiteCount);
+
+ DefaultMetavoxelRendererImplementation::getBaseVoxelProgram().bind();
+
+ glEnableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+
+ _hermiteBuffer.release();
+ }
}
BufferDataAttribute::BufferDataAttribute(const QString& name) :
@@ -1117,7 +1172,10 @@ AttributeValue BufferDataAttribute::inherit(const AttributeValue& parentValue) c
void DefaultMetavoxelRendererImplementation::init() {
if (!_pointProgram.isLinked()) {
- _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert");
+ _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
+ "shaders/metavoxel_point.vert");
+ _pointProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
+ "shaders/metavoxel_voxel_base.frag");
_pointProgram.link();
_pointProgram.bind();
@@ -1560,18 +1618,19 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
if (!info.isLeaf) {
return DEFAULT_ORDER;
}
- VoxelBuffer* buffer = NULL;
+ BufferData* buffer = NULL;
VoxelColorDataPointer color = info.inputValues.at(0).getInlineValue();
VoxelMaterialDataPointer material = info.inputValues.at(1).getInlineValue();
VoxelHermiteDataPointer hermite = info.inputValues.at(2).getInlineValue();
- if (color && material && hermite) {
+
+ if (color && hermite) {
QVector vertices;
QVector indices;
+ QVector hermiteSegments;
// see http://www.frankpetterson.com/publications/dualcontour/dualcontour.pdf for a description of the
// dual contour algorithm for generating meshes from voxel data using Hermite-tagged edges
const QVector& colorContents = color->getContents();
- const QByteArray& materialContents = material->getContents();
const QVector& hermiteContents = hermite->getContents();
int size = color->getSize();
int area = size * size;
@@ -1589,7 +1648,7 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
int hermiteStride = hermite->getSize() * VoxelHermiteData::EDGE_COUNT;
int hermiteArea = hermiteStride * hermite->getSize();
- const char* materialData = materialContents.constData();
+ const char* materialData = material ? material->getContents().constData() : NULL;
// as we scan down the cube generating vertices between grid points, we remember the indices of the last
// (element, line, section--x, y, z) so that we can connect generated vertices as quads
@@ -1605,6 +1664,7 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
float highest = size - 1.0f;
float scale = info.size / highest;
const int ALPHA_OFFSET = 24;
+ bool displayHermite = Menu::getInstance()->isOptionChecked(MenuOption::DisplayHermiteData);
for (int z = 0; z < expanded; z++) {
const QRgb* colorY = colorZ;
for (int y = 0; y < expanded; y++) {
@@ -1667,7 +1727,8 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
int clampedX = qMax(x - 1, 0), clampedY = qMax(y - 1, 0), clampedZ = qMax(z - 1, 0);
const QRgb* hermiteBase = hermiteData + clampedZ * hermiteArea + clampedY * hermiteStride +
clampedX * VoxelHermiteData::EDGE_COUNT;
- const char* materialBase = materialData + clampedZ * area + clampedY * size + clampedX;
+ const char* materialBase = materialData ?
+ (materialData + clampedZ * area + clampedY * size + clampedX) : NULL;
int crossingCount = 0;
if (middleX) {
if (alpha0 != alpha1) {
@@ -1676,10 +1737,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha0 == 0) {
crossing.color = colorX[1];
- crossing.material = materialBase[1];
+ crossing.material = materialBase ? materialBase[1] : 0;
} else {
crossing.color = colorX[0];
- crossing.material = materialBase[0];
+ crossing.material = materialBase ? materialBase[0] : 0;
}
crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f, 0.0f);
crossing.axis = 0;
@@ -1691,10 +1752,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha1 == 0) {
crossing.color = colorX[offset3];
- crossing.material = materialBase[offset3];
+ crossing.material = materialBase ? materialBase[offset3] : 0;
} else {
crossing.color = colorX[1];
- crossing.material = materialBase[1];
+ crossing.material = materialBase ? materialBase[1] : 0;
}
crossing.point = glm::vec3(1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f);
crossing.axis = 1;
@@ -1705,10 +1766,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha2 == 0) {
crossing.color = colorX[offset3];
- crossing.material = materialBase[offset3];
+ crossing.material = materialBase ? materialBase[offset3] : 0;
} else {
crossing.color = colorX[size];
- crossing.material = materialBase[size];
+ crossing.material = materialBase ? materialBase[size] : 0;
}
crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f, 0.0f);
crossing.axis = 0;
@@ -1720,10 +1781,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha3 == 0) {
crossing.color = colorX[offset7];
- crossing.material = materialBase[offset7];
+ crossing.material = materialBase ? materialBase[offset7] : 0;
} else {
crossing.color = colorX[offset3];
- crossing.material = materialBase[offset3];
+ crossing.material = materialBase ? materialBase[offset3] : 0;
}
crossing.point = glm::vec3(1.0f, 1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL);
crossing.axis = 2;
@@ -1734,10 +1795,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha5 == 0) {
crossing.color = colorX[offset7];
- crossing.material = materialBase[offset7];
+ crossing.material = materialBase ? materialBase[offset7] : 0;
} else {
crossing.color = colorX[offset5];
- crossing.material = materialBase[offset5];
+ crossing.material = materialBase ? materialBase[offset5] : 0;
}
crossing.point = glm::vec3(1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f);
crossing.axis = 1;
@@ -1748,10 +1809,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha6 == 0) {
crossing.color = colorX[offset7];
- crossing.material = materialBase[offset7];
+ crossing.material = materialBase ? materialBase[offset7] : 0;
} else {
crossing.color = colorX[offset6];
- crossing.material = materialBase[offset6];
+ crossing.material = materialBase ? materialBase[offset6] : 0;
}
crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f, 1.0f);
crossing.axis = 0;
@@ -1765,10 +1826,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha1 == 0) {
crossing.color = colorX[offset5];
- crossing.material = materialBase[offset5];
+ crossing.material = materialBase ? materialBase[offset5] : 0;
} else {
crossing.color = colorX[1];
- crossing.material = materialBase[1];
+ crossing.material = materialBase ? materialBase[1] : 0;
}
crossing.point = glm::vec3(1.0f, 0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL);
crossing.axis = 2;
@@ -1779,10 +1840,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha4 == 0) {
crossing.color = colorX[offset5];
- crossing.material = materialBase[offset5];
+ crossing.material = materialBase ? materialBase[offset5] : 0;
} else {
crossing.color = colorX[area];
- crossing.material = materialBase[area];
+ crossing.material = materialBase ? materialBase[area] : 0;
}
crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f, 1.0f);
crossing.axis = 0;
@@ -1796,10 +1857,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha0 == 0) {
crossing.color = colorX[size];
- crossing.material = materialBase[size];
+ crossing.material = materialBase ? materialBase[size] : 0;
} else {
crossing.color = colorX[0];
- crossing.material = materialBase[0];
+ crossing.material = materialBase ? materialBase[0] : 0;
}
crossing.point = glm::vec3(0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f);
crossing.axis = 1;
@@ -1811,10 +1872,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha2 == 0) {
crossing.color = colorX[offset6];
- crossing.material = materialBase[offset6];
+ crossing.material = materialBase ? materialBase[offset6] : 0;
} else {
crossing.color = colorX[size];
- crossing.material = materialBase[size];
+ crossing.material = materialBase ? materialBase[size] : 0;
}
crossing.point = glm::vec3(0.0f, 1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL);
crossing.axis = 2;
@@ -1825,10 +1886,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha4 == 0) {
crossing.color = colorX[offset6];
- crossing.material = materialBase[offset6];
+ crossing.material = materialBase ? materialBase[offset6] : 0;
} else {
crossing.color = colorX[area];
- crossing.material = materialBase[area];
+ crossing.material = materialBase ? materialBase[area] : 0;
}
crossing.point = glm::vec3(0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f);
crossing.axis = 1;
@@ -1841,10 +1902,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
crossing.normal = unpackNormal(hermite);
if (alpha0 == 0) {
crossing.color = colorX[area];
- crossing.material = materialBase[area];
+ crossing.material = materialBase ? materialBase[area] : 0;
} else {
crossing.color = colorX[0];
- crossing.material = materialBase[0];
+ crossing.material = materialBase ? materialBase[0] : 0;
}
crossing.point = glm::vec3(0.0f, 0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL);
crossing.axis = 2;
@@ -1866,6 +1927,13 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
green += qGreen(crossing.color);
blue += qBlue(crossing.color);
+ if (displayHermite) {
+ glm::vec3 start = info.minimum + (glm::vec3(clampedX, clampedY, clampedZ) +
+ crossing.point) * scale;
+ hermiteSegments.append(start);
+ hermiteSegments.append(start + crossing.normal * scale);
+ }
+
// when assigning a material, search for its presence and, if not found,
// place it in the first empty slot
if (crossing.material != 0) {
@@ -2090,8 +2158,8 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
colorZ += area;
}
}
-
- buffer = new VoxelBuffer(vertices, indices, material->getMaterials());
+ buffer = new VoxelBuffer(vertices, indices, hermiteSegments,
+ material ? material->getMaterials() : QVector());
}
BufferDataPointer pointer(buffer);
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer));
diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h
index 10110a5c5c..52706aab56 100644
--- a/interface/src/MetavoxelSystem.h
+++ b/interface/src/MetavoxelSystem.h
@@ -56,6 +56,10 @@ signals:
void rendering();
+public slots:
+
+ void refreshVoxelData();
+
protected:
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
@@ -99,9 +103,11 @@ public:
MetavoxelData getAugmentedData();
void setRenderedAugmentedData(const MetavoxelData& data) { _renderedAugmentedData = data; }
-
+
virtual int parseData(const QByteArray& packet);
+ Q_INVOKABLE void refreshVoxelData();
+
protected:
virtual void dataChanged(const MetavoxelData& oldData);
@@ -234,7 +240,7 @@ public:
class VoxelBuffer : public BufferData {
public:
- VoxelBuffer(const QVector& vertices, const QVector& indices,
+ VoxelBuffer(const QVector& vertices, const QVector& indices, const QVector& hermite,
const QVector& materials = QVector());
virtual void render(bool cursor = false);
@@ -243,10 +249,13 @@ private:
QVector _vertices;
QVector _indices;
+ QVector _hermite;
int _vertexCount;
int _indexCount;
+ int _hermiteCount;
QOpenGLBuffer _vertexBuffer;
QOpenGLBuffer _indexBuffer;
+ QOpenGLBuffer _hermiteBuffer;
QVector _materials;
QVector _networkTextures;
};
@@ -272,6 +281,9 @@ public:
static void init();
+ static ProgramObject& getPointProgram() { return _pointProgram; }
+ static int getPointScaleLocation() { return _pointScaleLocation; }
+
static ProgramObject& getBaseHeightfieldProgram() { return _baseHeightfieldProgram; }
static int getBaseHeightScaleLocation() { return _baseHeightScaleLocation; }
static int getBaseColorScaleLocation() { return _baseColorScaleLocation; }
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 087d670760..c0ce474d16 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -1126,7 +1126,7 @@ void MyAvatar::renderBody(RenderMode renderMode, bool postLighting, float glowLe
// Render head so long as the camera isn't inside it
const Camera *camera = Application::getInstance()->getCamera();
- const glm::vec3 cameraPos = camera->getPosition() + (camera->getRotation() * glm::vec3(0.0f, 0.0f, 1.0f)) * camera->getDistance();
+ const glm::vec3 cameraPos = camera->getPosition();
if (shouldRenderHead(cameraPos, renderMode)) {
getHead()->render(1.0f, modelRenderMode, postLighting);
diff --git a/interface/src/devices/Joystick.cpp b/interface/src/devices/Joystick.cpp
index d220a827f1..fe67eaceaa 100644
--- a/interface/src/devices/Joystick.cpp
+++ b/interface/src/devices/Joystick.cpp
@@ -29,6 +29,10 @@ Joystick::Joystick(const QString& name, SDL_Joystick* sdlJoystick) :
#endif
Joystick::~Joystick() {
+ closeJoystick();
+}
+
+void Joystick::closeJoystick() {
#ifdef HAVE_SDL
SDL_JoystickClose(_sdlJoystick);
#endif
@@ -38,14 +42,12 @@ void Joystick::update() {
#ifdef HAVE_SDL
// update our current values, emit a signal when there is a change
for (int j = 0; j < getNumAxes(); j++) {
- float value = glm::round(SDL_JoystickGetAxis(_sdlJoystick, j) + 0.5f) / std::numeric_limits::max();
- const float DEAD_ZONE = 0.1f;
- float cleanValue = glm::abs(value) < DEAD_ZONE ? 0.0f : value;
-
- if (_axes[j] != cleanValue) {
+ float newValue = glm::round(SDL_JoystickGetAxis(_sdlJoystick, j) + 0.5f) / std::numeric_limits::max();
+
+ if (_axes[j] != newValue) {
float oldValue = _axes[j];
- _axes[j] = cleanValue;
- emit axisValueChanged(j, cleanValue, oldValue);
+ _axes[j] = newValue;
+ emit axisValueChanged(j, newValue, oldValue);
}
}
for (int j = 0; j < getNumButtons(); j++) {
diff --git a/interface/src/devices/Joystick.h b/interface/src/devices/Joystick.h
index 228e993204..8343c20a04 100644
--- a/interface/src/devices/Joystick.h
+++ b/interface/src/devices/Joystick.h
@@ -37,6 +37,12 @@ public:
void update();
+ void closeJoystick();
+
+#ifdef HAVE_SDL
+ void setSDLJoystick(SDL_Joystick* sdlJoystick) { _sdlJoystick = sdlJoystick; }
+#endif
+
const QString& getName() const { return _name; }
const QVector& getAxes() const { return _axes; }
diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp
index 65518b839c..eb48e3d463 100644
--- a/interface/src/devices/OculusManager.cpp
+++ b/interface/src/devices/OculusManager.cpp
@@ -311,10 +311,6 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
ovrPosef eyeRenderPose[ovrEye_Count];
- _camera->setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
- _camera->setDistance(0.0f);
- _camera->setUpShift(0.0f);
-
glMatrixMode(GL_PROJECTION);
glPushMatrix();
@@ -348,8 +344,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
orientation.z = eyeRenderPose[eye].Orientation.z;
orientation.w = eyeRenderPose[eye].Orientation.w;
- _camera->setTargetRotation(bodyOrientation * orientation);
- _camera->setTargetPosition(position + trackerPosition);
+ _camera->setRotation(bodyOrientation * orientation);
+ _camera->setPosition(position + trackerPosition);
// Store the latest left and right eye render locations for things that need to know
glm::vec3 thisEyePosition = position + trackerPosition +
@@ -413,8 +409,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
glBindTexture(GL_TEXTURE_2D, 0);
// Update camera for use by rest of Interface.
- whichCamera.setTargetPosition((_leftEyePosition + _rightEyePosition) / 2.f);
- whichCamera.setTargetRotation(_camera->getTargetRotation());
+ whichCamera.setPosition((_leftEyePosition + _rightEyePosition) / 2.f);
+ whichCamera.setRotation(_camera->getRotation());
#endif
}
diff --git a/interface/src/scripting/JoystickScriptingInterface.cpp b/interface/src/scripting/JoystickScriptingInterface.cpp
index 1e35c11f61..87f841c494 100644
--- a/interface/src/scripting/JoystickScriptingInterface.cpp
+++ b/interface/src/scripting/JoystickScriptingInterface.cpp
@@ -27,17 +27,10 @@ JoystickScriptingInterface& JoystickScriptingInterface::getInstance() {
JoystickScriptingInterface::JoystickScriptingInterface() :
_openJoysticks(),
- _availableDeviceNames()
+ _availableDeviceNames(),
+ _isInitialized(false)
{
-#ifdef HAVE_SDL
- SDL_Init(SDL_INIT_JOYSTICK);
-
- int joystickCount = SDL_NumJoysticks();
-
- for (int i = 0; i < joystickCount; i++) {
- _availableDeviceNames << SDL_JoystickName(i);
- }
-#endif
+ reset();
}
JoystickScriptingInterface::~JoystickScriptingInterface() {
@@ -45,18 +38,53 @@ JoystickScriptingInterface::~JoystickScriptingInterface() {
#ifdef HAVE_SDL
SDL_Quit();
+ _isInitialized = false;
+#endif
+}
+
+void JoystickScriptingInterface::reset() {
+#ifdef HAVE_SDL
+
+ if (_isInitialized) {
+ _isInitialized = false;
+
+ // close all the open joysticks before we quit
+ foreach(Joystick* openJoystick, _openJoysticks) {
+ openJoystick->closeJoystick();
+ }
+
+ SDL_Quit();
+ }
+
+ bool initSuccess = (SDL_Init(SDL_INIT_JOYSTICK) == 0);
+
+ if (initSuccess) {
+
+ int joystickCount = SDL_NumJoysticks();
+
+ for (int i = 0; i < joystickCount; i++) {
+ _availableDeviceNames << SDL_JoystickName(i);
+ }
+
+ foreach(const QString& joystickName, _openJoysticks.keys()) {
+ _openJoysticks[joystickName]->setSDLJoystick(openSDLJoystickWithName(joystickName));
+ }
+
+ _isInitialized = true;
+ }
#endif
}
void JoystickScriptingInterface::update() {
#ifdef HAVE_SDL
- PerformanceTimer perfTimer("JoystickScriptingInterface::update");
- SDL_JoystickUpdate();
-
- foreach(Joystick* joystick, _openJoysticks) {
- joystick->update();
+ if (_isInitialized) {
+ PerformanceTimer perfTimer("JoystickScriptingInterface::update");
+ SDL_JoystickUpdate();
+
+ foreach(Joystick* joystick, _openJoysticks) {
+ joystick->update();
+ }
}
-
#endif
}
@@ -64,17 +92,13 @@ Joystick* JoystickScriptingInterface::joystickWithName(const QString& name) {
Joystick* matchingJoystick = _openJoysticks.value(name);
#ifdef HAVE_SDL
if (!matchingJoystick) {
- // we haven't opened a joystick with this name yet - enumerate our SDL devices and see if it exists
- int joystickCount = SDL_NumJoysticks();
+ SDL_Joystick* openSDLJoystick = openSDLJoystickWithName(name);
- for (int i = 0; i < joystickCount; i++) {
- if (SDL_JoystickName(i) == name) {
- matchingJoystick = _openJoysticks.insert(name, new Joystick(name, SDL_JoystickOpen(i))).value();
- break;
- }
+ if (openSDLJoystick) {
+ matchingJoystick = _openJoysticks.insert(name, new Joystick(name, openSDLJoystick)).value();
+ } else {
+ qDebug() << "No matching joystick found with name" << name << "- returning NULL pointer.";
}
-
- qDebug() << "No matching joystick found with name" << name << "- returning NULL pointer.";
}
#endif
@@ -82,3 +106,20 @@ Joystick* JoystickScriptingInterface::joystickWithName(const QString& name) {
}
+#ifdef HAVE_SDL
+
+SDL_Joystick* JoystickScriptingInterface::openSDLJoystickWithName(const QString &name) {
+ // we haven't opened a joystick with this name yet - enumerate our SDL devices and see if it exists
+ int joystickCount = SDL_NumJoysticks();
+
+ for (int i = 0; i < joystickCount; i++) {
+ if (SDL_JoystickName(i) == name) {
+ return SDL_JoystickOpen(i);
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+#endif
diff --git a/interface/src/scripting/JoystickScriptingInterface.h b/interface/src/scripting/JoystickScriptingInterface.h
index 98e38f5698..02624c70d5 100644
--- a/interface/src/scripting/JoystickScriptingInterface.h
+++ b/interface/src/scripting/JoystickScriptingInterface.h
@@ -31,13 +31,19 @@ public:
public slots:
Joystick* joystickWithName(const QString& name);
+ void reset();
private:
+#ifdef HAVE_SDL
+ SDL_Joystick* openSDLJoystickWithName(const QString& name);
+#endif
+
JoystickScriptingInterface();
~JoystickScriptingInterface();
QMap _openJoysticks;
QStringList _availableDeviceNames;
+ bool _isInitialized;
};
#endif // hifi_JoystickScriptingInterface_h
diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui
index 4120515b3d..fa75ea9be8 100644
--- a/interface/ui/chatWindow.ui
+++ b/interface/ui/chatWindow.ui
@@ -225,14 +225,9 @@ border-color: palette(dark); border-style: solid; border-left-width: 1px; borde
60
-
-
- Helvetica,Arial,sans-serif
- 14
-
-
-
+ font-family: Arial;
+font-size: 14px;
QFrame::NoFrame
diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp
index 4ec9912b01..7f987db9ed 100644
--- a/libraries/entities/src/EntityCollisionSystem.cpp
+++ b/libraries/entities/src/EntityCollisionSystem.cpp
@@ -115,6 +115,11 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) {
return; // bail early if this entity is to be ignored...
}
+ // don't collide entities with unknown IDs,
+ if (!entityA->isKnownID()) {
+ return;
+ }
+
glm::vec3 penetration;
EntityItem* entityB = NULL;
@@ -133,6 +138,11 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) {
penetration = collision->_penetration;
entityB = static_cast(collision->_extraData);
+ // don't collide entities with unknown IDs,
+ if (!entityB->isKnownID()) {
+ continue; // skip this loop pass if the entity has an unknown ID
+ }
+
// NOTE: 'penetration' is the depth that 'entityA' overlaps 'entityB'. It points from A into B.
glm::vec3 penetrationInTreeUnits = penetration / (float)(TREE_SCALE);
@@ -267,6 +277,12 @@ void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) {
}
void EntityCollisionSystem::applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo) {
+
+ // don't collide entities with unknown IDs,
+ if (!entity->isKnownID()) {
+ return;
+ }
+
// HALTING_* params are determined using expected acceleration of gravity over some timescale.
// This is a HACK for entities that bounce in a 1.0 gravitational field and should eventually be made more universal.
const float HALTING_ENTITY_PERIOD = 0.0167f; // ~1/60th of a second
diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp
index aec9a069be..44c333a03f 100644
--- a/libraries/metavoxels/src/AttributeRegistry.cpp
+++ b/libraries/metavoxels/src/AttributeRegistry.cpp
@@ -1616,8 +1616,74 @@ bool VoxelColorAttribute::merge(void*& parent, void* children[], bool postRead)
maxSize = qMax(maxSize, pointer->getSize());
}
}
- *(VoxelColorDataPointer*)&parent = VoxelColorDataPointer();
- return maxSize == 0;
+ if (maxSize == 0) {
+ *(VoxelColorDataPointer*)&parent = VoxelColorDataPointer();
+ return true;
+ }
+ int size = maxSize;
+ int area = size * size;
+ QVector contents(area * size);
+ int halfSize = size / 2;
+ int halfSizeComplement = size - halfSize;
+ for (int i = 0; i < MERGE_COUNT; i++) {
+ VoxelColorDataPointer child = decodeInline(children[i]);
+ if (!child) {
+ continue;
+ }
+ const QVector& childContents = child->getContents();
+ int childSize = child->getSize();
+ int childArea = childSize * childSize;
+ const int INDEX_MASK = 1;
+ int xIndex = i & INDEX_MASK;
+ const int Y_SHIFT = 1;
+ int yIndex = (i >> Y_SHIFT) & INDEX_MASK;
+ int Z_SHIFT = 2;
+ int zIndex = (i >> Z_SHIFT) & INDEX_MASK;
+ QRgb* dest = contents.data() + (zIndex * halfSize * area) + (yIndex * halfSize * size) + (xIndex * halfSize);
+ const QRgb* src = childContents.data();
+
+ const int MAX_ALPHA = 255;
+ if (childSize == size) {
+ // simple case: one destination value for four child values
+ for (int z = 0; z < halfSizeComplement; z++) {
+ int offset4 = (z == halfSize) ? 0 : childArea;
+ for (int y = 0; y < halfSizeComplement; y++) {
+ int offset2 = (y == halfSize) ? 0 : childSize;
+ int offset6 = offset4 + offset2;
+ for (QRgb* end = dest + halfSizeComplement; dest != end; ) {
+ int offset1 = (dest == end - 1) ? 0 : 1;
+ QRgb v0 = src[0], v1 = src[offset1], v2 = src[offset2], v3 = src[offset2 + offset1], v4 = src[offset4],
+ v5 = src[offset4 + offset1], v6 = src[offset6], v7 = src[offset6 + offset1];
+ src += (1 + offset1);
+ int a0 = qAlpha(v0), a1 = qAlpha(v1), a2 = qAlpha(v2), a3 = qAlpha(v3),
+ a4 = qAlpha(v4), a5 = qAlpha(v5), a6 = qAlpha(v6), a7 = qAlpha(v7);
+ if (a0 == 0) {
+ *dest++ = qRgba(0, 0, 0, 0);
+ continue;
+ }
+ int alphaTotal = a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7;
+ *dest++ = qRgba(
+ (qRed(v0) * a0 + qRed(v1) * a1 + qRed(v2) * a2 + qRed(v3) * a3 +
+ qRed(v4) * a4 + qRed(v5) * a5 + qRed(v6) * a6 + qRed(v7) * a7) / alphaTotal,
+ (qGreen(v0) * a0 + qGreen(v1) * a1 + qGreen(v2) * a2 + qGreen(v3) * a3 +
+ qGreen(v4) * a4 + qGreen(v5) * a5 + qGreen(v6) * a6 + qGreen(v7) * a7) / alphaTotal,
+ (qBlue(v0) * a0 + qBlue(v1) * a1 + qBlue(v2) * a2 + qBlue(v3) * a3 +
+ qBlue(v4) * a4 + qBlue(v5) * a5 + qBlue(v6) * a6 + qBlue(v7) * a7) / alphaTotal,
+ MAX_ALPHA);
+ }
+ dest += halfSize;
+ src += offset2;
+ }
+ dest += halfSize * size;
+ src += offset4;
+ }
+ } else {
+ // more complex: N destination values for four child values
+ // ...
+ }
+ }
+ *(VoxelColorDataPointer*)&parent = VoxelColorDataPointer(new VoxelColorData(contents, size));
+ return false;
}
const int VOXEL_MATERIAL_HEADER_SIZE = sizeof(qint32) * 6;
@@ -2020,8 +2086,87 @@ bool VoxelHermiteAttribute::merge(void*& parent, void* children[], bool postRead
maxSize = qMax(maxSize, pointer->getSize());
}
}
- *(VoxelHermiteDataPointer*)&parent = VoxelHermiteDataPointer();
- return maxSize == 0;
+ if (maxSize == 0) {
+ *(VoxelHermiteDataPointer*)&parent = VoxelHermiteDataPointer();
+ return true;
+ }
+ int size = maxSize;
+ int area = size * size;
+ QVector contents(area * size * VoxelHermiteData::EDGE_COUNT);
+ int halfSize = size / 2;
+ int halfSizeComplement = size - halfSize;
+ for (int i = 0; i < MERGE_COUNT; i++) {
+ VoxelHermiteDataPointer child = decodeInline(children[i]);
+ if (!child) {
+ continue;
+ }
+ const QVector& childContents = child->getContents();
+ int childSize = child->getSize();
+ int childArea = childSize * childSize;
+ const int INDEX_MASK = 1;
+ int xIndex = i & INDEX_MASK;
+ const int Y_SHIFT = 1;
+ int yIndex = (i >> Y_SHIFT) & INDEX_MASK;
+ int Z_SHIFT = 2;
+ int zIndex = (i >> Z_SHIFT) & INDEX_MASK;
+ QRgb* dest = contents.data() + ((zIndex * halfSize * area) + (yIndex * halfSize * size) + (xIndex * halfSize)) *
+ VoxelHermiteData::EDGE_COUNT;
+ const QRgb* src = childContents.data();
+
+ if (childSize == size) {
+ // simple case: one destination value for four child values
+ for (int z = 0; z < halfSizeComplement; z++) {
+ int offset4 = (z == halfSize) ? 0 : (childArea * VoxelHermiteData::EDGE_COUNT);
+ for (int y = 0; y < halfSizeComplement; y++) {
+ int offset2 = (y == halfSize) ? 0 : (childSize * VoxelHermiteData::EDGE_COUNT);
+ int offset6 = offset4 + offset2;
+ for (QRgb* end = dest + halfSizeComplement * VoxelHermiteData::EDGE_COUNT; dest != end;
+ dest += VoxelHermiteData::EDGE_COUNT) {
+ int offset1 = (dest == end - VoxelHermiteData::EDGE_COUNT) ? 0 : VoxelHermiteData::EDGE_COUNT;
+ for (int i = 0; i < VoxelHermiteData::EDGE_COUNT; i++) {
+ QRgb v[] = { src[i], src[offset1 + i], src[offset2 + i], src[offset2 + offset1 + i],
+ src[offset4 + i], src[offset4 + offset1 + i], src[offset6 + i], src[offset6 + offset1 + i] };
+ glm::vec3 n[] = { unpackNormal(v[0]), unpackNormal(v[1]), unpackNormal(v[2]), unpackNormal(v[3]),
+ unpackNormal(v[4]), unpackNormal(v[5]), unpackNormal(v[6]), unpackNormal(v[7]) };
+ float l[] = { glm::length(n[0]), glm::length(n[1]), glm::length(n[2]), glm::length(n[3]),
+ glm::length(n[4]), glm::length(n[5]), glm::length(n[6]), glm::length(n[7]) };
+ float lengthTotal = l[0] + l[1] + l[2] + l[3] + l[4] + l[5] + l[6] + l[7];
+ if (lengthTotal == 0.0f) {
+ dest[i] = qRgba(0, 0, 0, 0);
+ continue;
+ }
+ glm::vec3 combinedNormal = n[0] * l[0] + n[1] * l[1] + n[2] * l[2] + n[3] * l[3] + n[4] * l[4] +
+ n[5] * l[5] + n[6] * l[6] + n[7] * l[7];
+ float combinedLength = glm::length(combinedNormal);
+ if (combinedLength > 0.0f) {
+ combinedNormal /= combinedLength;
+ }
+ float combinedOffset = 0.0f;
+ int mask = 1 << i;
+ for (int j = 0; j < MERGE_COUNT; j++) {
+ float offset = qAlpha(v[j]) * (0.5f / EIGHT_BIT_MAXIMUM);
+ if (j & mask) {
+ offset += 0.5f;
+ }
+ combinedOffset += offset * l[j];
+ }
+ dest[i] = packNormal(combinedNormal, EIGHT_BIT_MAXIMUM * combinedOffset / lengthTotal);
+ }
+ src += (VoxelHermiteData::EDGE_COUNT + offset1);
+ }
+ dest += (halfSize * VoxelHermiteData::EDGE_COUNT);
+ src += offset2;
+ }
+ dest += (halfSize * size * VoxelHermiteData::EDGE_COUNT);
+ src += offset4;
+ }
+ } else {
+ // more complex: N destination values for four child values
+ // ...
+ }
+ }
+ *(VoxelHermiteDataPointer*)&parent = VoxelHermiteDataPointer(new VoxelHermiteData(contents, size));
+ return false;
}
SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject,
diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp
index 07c55bd0ab..920482a016 100644
--- a/libraries/metavoxels/src/MetavoxelData.cpp
+++ b/libraries/metavoxels/src/MetavoxelData.cpp
@@ -374,6 +374,13 @@ void MetavoxelData::clear(const AttributePointer& attribute) {
}
}
+void MetavoxelData::touch(const AttributePointer& attribute) {
+ MetavoxelNode* root = _roots.value(attribute);
+ if (root) {
+ setRoot(attribute, root->touch(attribute));
+ }
+}
+
class FirstRaySpannerIntersectionVisitor : public RaySpannerIntersectionVisitor {
public:
@@ -1249,6 +1256,16 @@ void MetavoxelNode::countNodes(const AttributePointer& attribute, const glm::vec
}
}
+MetavoxelNode* MetavoxelNode::touch(const AttributePointer& attribute) const {
+ MetavoxelNode* node = new MetavoxelNode(getAttributeValue(attribute));
+ for (int i = 0; i < CHILD_COUNT; i++) {
+ if (_children[i]) {
+ node->setChild(i, _children[i]->touch(attribute));
+ }
+ }
+ return node;
+}
+
MetavoxelInfo::MetavoxelInfo(MetavoxelInfo* parentInfo, int inputValuesSize, int outputValuesSize) :
parentInfo(parentInfo),
inputValues(inputValuesSize),
diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h
index c693cf723c..db28ce056f 100644
--- a/libraries/metavoxels/src/MetavoxelData.h
+++ b/libraries/metavoxels/src/MetavoxelData.h
@@ -112,6 +112,9 @@ public:
/// Clears all data in the specified attribute layer.
void clear(const AttributePointer& attribute);
+ /// "Touches" all data in the specified attribute layer, making it look as if it has changed.
+ void touch(const AttributePointer& attribute);
+
/// Convenience function that finds the first spanner intersecting the provided ray.
SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction,
const AttributePointer& attribute, float& distance, const MetavoxelLOD& lod = MetavoxelLOD());
@@ -254,6 +257,8 @@ public:
void countNodes(const AttributePointer& attribute, const glm::vec3& minimum,
float size, const MetavoxelLOD& lod, int& internalNodes, int& leaves) const;
+ MetavoxelNode* touch(const AttributePointer& attribute) const;
+
private:
Q_DISABLE_COPY(MetavoxelNode)