Merge branch 'master' of github.com:highfidelity/hifi into near-grab-via-parenting

This commit is contained in:
Seth Alves 2015-12-10 13:39:46 -08:00
commit f394bbc495
68 changed files with 1079 additions and 890 deletions

View file

@ -15,17 +15,16 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
# 0.6 public # 0.6 public
# URL http://static.oculus.com/sdk-downloads/0.6.0.1/Public/1435190862/ovr_sdk_win_0.6.0.1.zip # URL http://static.oculus.com/sdk-downloads/0.6.0.1/Public/1435190862/ovr_sdk_win_0.6.0.1.zip
# URL_MD5 4b3ef825f9a1d6d3035c9f6820687da9 # URL_MD5 4b3ef825f9a1d6d3035c9f6820687da9
# 0.7 alpha # 0.8 public
# URL https://s3.amazonaws.com/static.oculus.com/sdk-downloads/0.7.0.0/Public/Alpha/ovr_sdk_win_0.7.0.0_RC1.zip # URL http://static.oculus.com/sdk-downloads/0.8.0.0/Public/1445451746/ovr_sdk_win_0.8.0.0.zip
# URL_MD5 a562bb9d117087b2cf9d86653ea70fd8 # URL_MD5 54944b03b95149d6010f84eb701b9647
if (WIN32) if (WIN32)
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${EXTERNAL_NAME}
URL http://static.oculus.com/sdk-downloads/0.6.0.1/Public/1435190862/ovr_sdk_win_0.6.0.1.zip URL http://static.oculus.com/sdk-downloads/0.8.0.0/Public/1445451746/ovr_sdk_win_0.8.0.0.zip
URL_MD5 4b3ef825f9a1d6d3035c9f6820687da9 URL_MD5 54944b03b95149d6010f84eb701b9647
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""
INSTALL_COMMAND "" INSTALL_COMMAND ""

View file

@ -7,9 +7,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${EXTERNAL_NAME}
#URL https://github.com/ValveSoftware/openvr/archive/0.9.1.zip URL https://github.com/ValveSoftware/openvr/archive/v0.9.12.zip
URL http://hifi-public.s3.amazonaws.com/dependencies/openvr-0.9.1.zip URL_MD5 c08dced68ce4e341e1467e6814ae419d
URL_MD5 f986f5a6815e9454c53c5bf58ce02fdc
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""
INSTALL_COMMAND "" INSTALL_COMMAND ""

View file

@ -202,31 +202,41 @@ function entityIsGrabbedByOther(entityID) {
} }
function getSpatialOffsetPosition(hand, spatialKey) { function getSpatialOffsetPosition(hand, spatialKey) {
var position = Vec3.ZERO;
if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) {
return spatialKey.leftRelativePosition; position = spatialKey.leftRelativePosition;
} }
if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) {
return spatialKey.rightRelativePosition; position = spatialKey.rightRelativePosition;
} }
if (spatialKey.relativePosition) { if (spatialKey.relativePosition) {
return spatialKey.relativePosition; position = spatialKey.relativePosition;
} }
return Vec3.ZERO; return position;
} }
var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y);
function getSpatialOffsetRotation(hand, spatialKey) { function getSpatialOffsetRotation(hand, spatialKey) {
var rotation = Quat.IDENTITY;
if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) {
return spatialKey.leftRelativeRotation; rotation = spatialKey.leftRelativeRotation;
} }
if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) {
return spatialKey.rightRelativeRotation; rotation = spatialKey.rightRelativeRotation;
} }
if (spatialKey.relativeRotation) { if (spatialKey.relativeRotation) {
return spatialKey.relativeRotation; rotation = spatialKey.relativeRotation;
} }
return Quat.IDENTITY; // Flip left hand
if (hand !== RIGHT_HAND) {
rotation = Quat.multiply(yFlip, rotation);
}
return rotation;
} }
function MyController(hand) { function MyController(hand) {
@ -254,6 +264,7 @@ function MyController(hand) {
this.overlayLine = null; this.overlayLine = null;
this.ignoreIK = false;
this.offsetPosition = Vec3.ZERO; this.offsetPosition = Vec3.ZERO;
this.offsetRotation = Quat.IDENTITY; this.offsetRotation = Quat.IDENTITY;
@ -853,9 +864,12 @@ function MyController(hand) {
if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) {
// if an object is "equipped" and has a spatialKey, use it. // if an object is "equipped" and has a spatialKey, use it.
this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false;
this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey);
this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey);
} else { } else {
this.ignoreIK = false;
var objectRotation = grabbedProperties.rotation; var objectRotation = grabbedProperties.rotation;
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
@ -872,7 +886,8 @@ function MyController(hand) {
relativeRotation: this.offsetRotation, relativeRotation: this.offsetRotation,
ttl: ACTION_TTL, ttl: ACTION_TTL,
kinematic: NEAR_GRABBING_KINEMATIC, kinematic: NEAR_GRABBING_KINEMATIC,
kinematicSetVelocity: true kinematicSetVelocity: true,
ignoreIK: this.ignoreIK
}); });
if (this.actionID === NULL_ACTION_ID) { if (this.actionID === NULL_ACTION_ID) {
this.actionID = null; this.actionID = null;
@ -956,7 +971,8 @@ function MyController(hand) {
relativeRotation: this.offsetRotation, relativeRotation: this.offsetRotation,
ttl: ACTION_TTL, ttl: ACTION_TTL,
kinematic: NEAR_GRABBING_KINEMATIC, kinematic: NEAR_GRABBING_KINEMATIC,
kinematicSetVelocity: true kinematicSetVelocity: true,
ignoreIK: this.ignoreIK
}); });
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
} }
@ -982,6 +998,7 @@ function MyController(hand) {
// use a spring to pull the object to where it will be when equipped // use a spring to pull the object to where it will be when equipped
var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey);
var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey);
var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false;
var handRotation = this.getHandRotation(); var handRotation = this.getHandRotation();
var handPosition = this.getHandPosition(); var handPosition = this.getHandPosition();
var targetRotation = Quat.multiply(handRotation, relativeRotation); var targetRotation = Quat.multiply(handRotation, relativeRotation);
@ -996,7 +1013,8 @@ function MyController(hand) {
linearTimeScale: EQUIP_SPRING_TIMEFRAME, linearTimeScale: EQUIP_SPRING_TIMEFRAME,
targetRotation: targetRotation, targetRotation: targetRotation,
angularTimeScale: EQUIP_SPRING_TIMEFRAME, angularTimeScale: EQUIP_SPRING_TIMEFRAME,
ttl: ACTION_TTL ttl: ACTION_TTL,
ignoreIK: ignoreIK
}); });
if (this.equipSpringID === NULL_ACTION_ID) { if (this.equipSpringID === NULL_ACTION_ID) {
this.equipSpringID = null; this.equipSpringID = null;
@ -1009,7 +1027,8 @@ function MyController(hand) {
linearTimeScale: EQUIP_SPRING_TIMEFRAME, linearTimeScale: EQUIP_SPRING_TIMEFRAME,
targetRotation: targetRotation, targetRotation: targetRotation,
angularTimeScale: EQUIP_SPRING_TIMEFRAME, angularTimeScale: EQUIP_SPRING_TIMEFRAME,
ttl: ACTION_TTL ttl: ACTION_TTL,
ignoreIK: ignoreIK
}); });
} }

View file

@ -298,7 +298,6 @@
var elModelAnimationLastFrame = document.getElementById("property-model-animation-last-frame"); var elModelAnimationLastFrame = document.getElementById("property-model-animation-last-frame");
var elModelAnimationLoop = document.getElementById("property-model-animation-loop"); var elModelAnimationLoop = document.getElementById("property-model-animation-loop");
var elModelAnimationHold = document.getElementById("property-model-animation-hold"); var elModelAnimationHold = document.getElementById("property-model-animation-hold");
var elModelAnimationStartAutomatically = document.getElementById("property-model-animation-start-automatically");
var elModelTextures = document.getElementById("property-model-textures"); var elModelTextures = document.getElementById("property-model-textures");
var elModelOriginalTextures = document.getElementById("property-model-original-textures"); var elModelOriginalTextures = document.getElementById("property-model-original-textures");
@ -532,7 +531,6 @@
elModelAnimationLastFrame.value = properties.animation.lastFrame; elModelAnimationLastFrame.value = properties.animation.lastFrame;
elModelAnimationLoop.checked = properties.animation.loop; elModelAnimationLoop.checked = properties.animation.loop;
elModelAnimationHold.checked = properties.animation.hold; elModelAnimationHold.checked = properties.animation.hold;
elModelAnimationStartAutomatically.checked = properties.animation.startAutomatically;
elModelTextures.value = properties.textures; elModelTextures.value = properties.textures;
elModelOriginalTextures.value = properties.originalTextures; elModelOriginalTextures.value = properties.originalTextures;
} else if (properties.type == "Web") { } else if (properties.type == "Web") {
@ -785,7 +783,6 @@
elModelAnimationLastFrame.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'lastFrame')); elModelAnimationLastFrame.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'lastFrame'));
elModelAnimationLoop.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'loop')); elModelAnimationLoop.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'loop'));
elModelAnimationHold.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'hold')); elModelAnimationHold.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'hold'));
elModelAnimationStartAutomatically.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'startAutomatically'));
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures')); elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
@ -1348,12 +1345,6 @@
<input type='checkbox' id="property-model-animation-hold"> <input type='checkbox' id="property-model-animation-hold">
</span> </span>
</div> </div>
<div class="model-section property">
<span class="label">Animation Start Automatically</span>
<span class="value">
<input type='checkbox' id="property-model-animation-start-automatically">
</span>
</div>
<div class="model-section property"> <div class="model-section property">
<div class="label">Textures</div> <div class="label">Textures</div>
<div class="value"> <div class="value">

View file

@ -74,7 +74,9 @@ var keysToIgnore = [
'shapeType', 'shapeType',
'isEmitting', 'isEmitting',
'sittingPoints', 'sittingPoints',
'originalTextures' 'originalTextures',
'parentJointIndex',
'parentID'
]; ];
var individualKeys = []; var individualKeys = [];

View file

@ -66,21 +66,6 @@
max2: 15 max2: 15
} }
var BOW_SPATIAL_KEY = {
leftRelativePosition: {
x: 0.05,
y: 0.06,
z: -0.05
},
rightRelativePosition: {
x: -0.05,
y: 0.06,
z: -0.05
},
relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90)
}
var USE_DEBOUNCE = false; var USE_DEBOUNCE = false;
var TRIGGER_CONTROLS = [ var TRIGGER_CONTROLS = [
@ -168,11 +153,9 @@
var handToDisable = this.initialHand === 'right' ? 'left' : 'right'; var handToDisable = this.initialHand === 'right' ? 'left' : 'right';
Messages.sendMessage('Hifi-Hand-Disabler', handToDisable); Messages.sendMessage('Hifi-Hand-Disabler', handToDisable);
setEntityCustomData('grabbableKey', this.entityID, { var data = getEntityCustomData('grabbableKey', this.entityID, {});
grabbable: false, data.grabbable = false;
invertSolidWhileHeld: true, setEntityCustomData('grabbableKey', this.entityID, data);
spatialKey: BOW_SPATIAL_KEY
});
}, },
continueNearGrab: function() { continueNearGrab: function() {
@ -226,11 +209,10 @@
this.isGrabbed = false; this.isGrabbed = false;
this.stringDrawn = false; this.stringDrawn = false;
this.deleteStrings(); this.deleteStrings();
setEntityCustomData('grabbableKey', this.entityID, {
grabbable: true, var data = getEntityCustomData('grabbableKey', this.entityID, {});
invertSolidWhileHeld: true, data.grabbable = true;
spatialKey: BOW_SPATIAL_KEY setEntityCustomData('grabbableKey', this.entityID, data);
});
Entities.deleteEntity(this.preNotchString); Entities.deleteEntity(this.preNotchString);
Entities.deleteEntity(this.arrow); Entities.deleteEntity(this.arrow);
this.aiming = false; this.aiming = false;

View file

@ -49,14 +49,14 @@ var bow = Entities.addEntity({
invertSolidWhileHeld: true, invertSolidWhileHeld: true,
spatialKey: { spatialKey: {
leftRelativePosition: { leftRelativePosition: {
x: 0.05, x: -0.02,
y: 0.06, y: 0.08,
z: -0.05 z: 0.09
}, },
rightRelativePosition: { relativePosition: {
x: -0.05, x: 0.02,
y: 0.06, y: 0.08,
z: -0.05 z: 0.09
}, },
relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90) relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90)
} }

View file

@ -53,8 +53,13 @@ var wand = Entities.addEntity({
y: 0.1, y: 0.1,
z: 0 z: 0
}, },
relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 90) relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, -90)
} }
} }
}) })
}); });
function scriptEnding() {
Entities.deleteEntity(wand);
}
Script.scriptEnding.connect(scriptEnding);

View file

@ -25,7 +25,7 @@
//we are creating lights that we don't want to get stranded so lets make sure that we can get rid of them //we are creating lights that we don't want to get stranded so lets make sure that we can get rid of them
var startTime = Date.now(); var startTime = Date.now();
//if you're going to be using this in a dungeon or something and holding it for a long time, increase this lifetime value. //if you're going to be using this in a dungeon or something and holding it for a long time, increase this lifetime value.
var LIFETIME = 25; var LIFETIME = 100;
var MSEC_PER_SEC = 1000.0; var MSEC_PER_SEC = 1000.0;
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
@ -85,9 +85,14 @@
this.hand = 'LEFT'; this.hand = 'LEFT';
}, },
startNearGrab: function() { startNearGrab: function(entityID) {
if (!this.hasSpotlight) { if (!this.hasSpotlight) {
var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation);
var glowLightTransform = glowLightWorldTransform(modelProperties.position, modelProperties.rotation);
//this light casts the beam //this light casts the beam
this.spotlight = Entities.addEntity({ this.spotlight = Entities.addEntity({
type: "Light", type: "Light",
@ -97,6 +102,7 @@
y: 2, y: 2,
z: 20 z: 20
}, },
parentID: this.entityID,
color: { color: {
red: 255, red: 255,
green: 255, green: 255,
@ -105,7 +111,9 @@
intensity: 2, intensity: 2,
exponent: 0.3, exponent: 0.3,
cutoff: 20, cutoff: 20,
lifetime: LIFETIME lifetime: LIFETIME,
position: lightTransform.p,
rotation: lightTransform.q,
}); });
//this light creates the effect of a bulb at the end of the flashlight //this light creates the effect of a bulb at the end of the flashlight
@ -116,6 +124,7 @@
y: 0.25, y: 0.25,
z: 0.25 z: 0.25
}, },
parentID: this.entityID,
isSpotlight: false, isSpotlight: false,
color: { color: {
red: 255, red: 255,
@ -123,8 +132,11 @@
blue: 255 blue: 255
}, },
exponent: 0, exponent: 0,
lifetime: LIFETIME,
cutoff: 90, // in degrees cutoff: 90, // in degrees
lifetime: LIFETIME position: glowLightTransform.p,
rotation: glowLightTransform.q,
}); });
this.hasSpotlight = true; this.hasSpotlight = true;
@ -142,7 +154,6 @@
//only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten //only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten
this.setWhichHand(); this.setWhichHand();
} else { } else {
this.updateLightPositions();
this.changeLightWithTriggerPressure(this.whichHand); this.changeLightWithTriggerPressure(this.whichHand);
} }
}, },
@ -159,29 +170,7 @@
this.lightOn = false; this.lightOn = false;
} }
}, },
updateLightPositions: function() {
var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
//move the two lights along the vectors we set above
var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation);
var glowLightTransform = glowLightWorldTransform(modelProperties.position, modelProperties.rotation);
//move them with the entity model
Entities.editEntity(this.spotlight, {
position: lightTransform.p,
rotation: lightTransform.q,
lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME
});
Entities.editEntity(this.glowLight, {
position: glowLightTransform.p,
rotation: glowLightTransform.q,
lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME
});
},
changeLightWithTriggerPressure: function(flashLightHand) { changeLightWithTriggerPressure: function(flashLightHand) {
if (flashLightHand === 'LEFT') { if (flashLightHand === 'LEFT') {

View file

@ -28,10 +28,10 @@ var pistol = Entities.addEntity({
spatialKey: { spatialKey: {
relativePosition: { relativePosition: {
x: 0, x: 0,
y: 0, y: 0.05,
z: 0 z: -0.08
}, },
relativeRotation: Quat.fromPitchYawRollDegrees(45, 90, 0) relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0)
}, },
invertSolidWhileHeld: true invertSolidWhileHeld: true
} }

View file

@ -100,6 +100,15 @@ else()
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM}) add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
endif() endif()
# These are external plugins, but we need to do the 'add dependency' here so that their
# binary directories get added to the fixup path
add_dependency_external_projects(sixense)
add_dependency_external_projects(sdl2)
if (WIN32)
add_dependency_external_projects(OpenVR)
endif()
# disable /OPT:REF and /OPT:ICF for the Debug builds # disable /OPT:REF and /OPT:ICF for the Debug builds
# This will prevent the following linker warnings # This will prevent the following linker warnings
# LINK : warning LNK4075: ignoring '/INCREMENTAL' due to '/OPT:ICF' specification # LINK : warning LNK4075: ignoring '/INCREMENTAL' due to '/OPT:ICF' specification

View file

@ -195,6 +195,8 @@ static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
static const unsigned int THROTTLED_SIM_FRAMERATE = 15; static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE; static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation
#ifndef __APPLE__ #ifndef __APPLE__
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
#else #else
@ -1122,29 +1124,6 @@ void Application::paintGL() {
_inPaint = true; _inPaint = true;
Finally clearFlagLambda([this] { _inPaint = false; }); Finally clearFlagLambda([this] { _inPaint = false; });
// Some LOD-like controls need to know a smoothly varying "potential" frame rate that doesn't
// include time waiting for vsync, and which can report a number above target if we've got the headroom.
// For example, if we're shooting for 75fps and paintWait is 3.3333ms (= 75% * 13.33ms), our deducedNonVSyncFps
// would be 100fps. In principle, a paintWait of zero would have deducedNonVSyncFps=75.
// Here we make a guess for deducedNonVSyncFps = 1 / deducedNonVSyncPeriod.
//
// Time between previous paintGL call and this one, which can vary not only with vSync misses, but also with QT timing.
// We're using this as a proxy for the time between vsync and displayEnd, below. (Not exact, but tends to be the same over time.)
// This is not the same as update(deltaTime), because the latter attempts to throttle to 60hz and also clamps to 1/4 second.
const float actualPeriod = diff / (float)USECS_PER_SECOND; // same as 1/instantaneousFps but easier for compiler to optimize
// Note that _lastPaintWait (stored at end of last call) is for the same paint cycle.
float deducedNonVSyncPeriod = actualPeriod - _lastPaintWait + _marginForDeducedFramePeriod; // plus a some non-zero time for machinery we can't measure
// We don't know how much time to allow for that, but if we went over the target period, we know it's at least the portion
// of paintWait up to the next vSync. This gives us enough of a penalty so that when actualPeriod crosses two cycles,
// the key part (and not an exagerated part) of _lastPaintWait is accounted for.
const float targetPeriod = getTargetFramePeriod();
if (_lastPaintWait > EPSILON && actualPeriod > targetPeriod) {
// Don't use C++ remainder(). It's authors are mathematically insane.
deducedNonVSyncPeriod += fmod(actualPeriod, _lastPaintWait);
}
_lastDeducedNonVSyncFps = 1.0f / deducedNonVSyncPeriod;
_lastInstantaneousFps = instantaneousFps;
auto displayPlugin = getActiveDisplayPlugin(); auto displayPlugin = getActiveDisplayPlugin();
// FIXME not needed anymore? // FIXME not needed anymore?
_offscreenContext->makeCurrent(); _offscreenContext->makeCurrent();
@ -1401,7 +1380,6 @@ void Application::paintGL() {
Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture)); Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture));
_lockedFramebufferMap[finalTexture] = scratchFramebuffer; _lockedFramebufferMap[finalTexture] = scratchFramebuffer;
uint64_t displayStart = usecTimestampNow();
Q_ASSERT(isCurrentContext(_offscreenContext->getContext())); Q_ASSERT(isCurrentContext(_offscreenContext->getContext()));
{ {
PROFILE_RANGE(__FUNCTION__ "/pluginSubmitScene"); PROFILE_RANGE(__FUNCTION__ "/pluginSubmitScene");
@ -1410,9 +1388,6 @@ void Application::paintGL() {
} }
Q_ASSERT(isCurrentContext(_offscreenContext->getContext())); Q_ASSERT(isCurrentContext(_offscreenContext->getContext()));
uint64_t displayEnd = usecTimestampNow();
const float displayPeriodUsec = (float)(displayEnd - displayStart); // usecs
_lastPaintWait = displayPeriodUsec / (float)USECS_PER_SECOND;
} }
{ {
@ -1423,6 +1398,14 @@ void Application::paintGL() {
batch.resetStages(); batch.resetStages();
}); });
} }
// Some LOD-like controls need to know a smoothly varying "potential" frame rate that doesn't
// include time waiting for sync, and which can report a number above target if we've got the headroom.
// In my tests, the following is mostly less than 0.5ms, and never more than 3ms. I don't think its worth measuring during runtime.
const float paintWaitAndQTTimerAllowance = 0.001f; // seconds
// Store both values now for use by next cycle.
_lastInstantaneousFps = instantaneousFps;
_lastUnsynchronizedFps = 1.0f / (((usecTimestampNow() - now) / (float)USECS_PER_SECOND) + paintWaitAndQTTimerAllowance);
} }
void Application::runTests() { void Application::runTests() {
@ -2905,7 +2888,7 @@ void Application::update(float deltaTime) {
_avatarUpdate->synchronousProcess(); _avatarUpdate->synchronousProcess();
{ if (true || _physicsEnabled) {
PerformanceTimer perfTimer("physics"); PerformanceTimer perfTimer("physics");
static VectorOfMotionStates motionStates; static VectorOfMotionStates motionStates;
@ -2961,6 +2944,7 @@ void Application::update(float deltaTime) {
} }
myAvatar->harvestResultsFromPhysicsSimulation(); myAvatar->harvestResultsFromPhysicsSimulation();
myAvatar->simulateAttachments(deltaTime);
} }
} }
@ -3253,6 +3237,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
bool Application::isHMDMode() const { bool Application::isHMDMode() const {
return getActiveDisplayPlugin()->isHmd(); return getActiveDisplayPlugin()->isHmd();
} }
float Application::getTargetFrameRate() { return getActiveDisplayPlugin()->getTargetFrameRate(); }
QRect Application::getDesirableApplicationGeometry() { QRect Application::getDesirableApplicationGeometry() {
QRect applicationGeometry = getWindow()->geometry(); QRect applicationGeometry = getWindow()->geometry();
@ -3786,6 +3771,8 @@ void Application::domainChanged(const QString& domainHostname) {
updateWindowTitle(); updateWindowTitle();
clearDomainOctreeDetails(); clearDomainOctreeDetails();
_domainConnectionRefusals.clear(); _domainConnectionRefusals.clear();
// disable physics until we have enough information about our new location to not cause craziness.
_physicsEnabled = false;
} }
void Application::handleDomainConnectionDeniedPacket(QSharedPointer<ReceivedMessage> message) { void Application::handleDomainConnectionDeniedPacket(QSharedPointer<ReceivedMessage> message) {
@ -3893,6 +3880,31 @@ void Application::trackIncomingOctreePacket(ReceivedMessage& message, SharedNode
} }
} }
bool Application::nearbyEntitiesAreReadyForPhysics() {
// this is used to avoid the following scenario:
// A table has some items sitting on top of it. The items are at rest, meaning they aren't active in bullet.
// Someone logs in close to the table. They receive information about the items on the table before they
// receive information about the table. The items are very close to the avatar's capsule, so they become
// activated in bullet. This causes them to fall to the floor, because the table's shape isn't yet in bullet.
EntityTreePointer entityTree = _entities.getTree();
if (!entityTree) {
return false;
}
QVector<EntityItemPointer> entities;
entityTree->withReadLock([&] {
AABox box(getMyAvatar()->getPosition() - glm::vec3(PHYSICS_READY_RANGE), glm::vec3(2 * PHYSICS_READY_RANGE));
entityTree->findEntities(box, entities);
});
foreach (EntityItemPointer entity, entities) {
if (!entity->isReadyToComputeShape()) {
return false;
}
}
return true;
}
int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) { int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) {
// But, also identify the sender, and keep track of the contained jurisdiction root for this server // But, also identify the sender, and keep track of the contained jurisdiction root for this server
@ -3938,7 +3950,12 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer
}); });
}); });
if (!_physicsEnabled && nearbyEntitiesAreReadyForPhysics()) {
// These stats packets are sent in between full sends of a scene.
// We keep physics disabled until we've recieved a full scene and everything near the avatar in that
// scene is ready to compute its collision shape.
_physicsEnabled = true;
}
return statsMessageLength; return statsMessageLength;
} }
@ -4021,7 +4038,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable); scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable);
connect(scriptEngine, SIGNAL(finished(const QString&)), clipboardScriptable, SLOT(deleteLater())); connect(scriptEngine, SIGNAL(finished(const QString&)), clipboardScriptable, SLOT(deleteLater()));
connect(scriptEngine, SIGNAL(finished(const QString&)), this, SLOT(scriptFinished(const QString&))); connect(scriptEngine, &ScriptEngine::finished, this, &Application::scriptFinished, Qt::DirectConnection);
connect(scriptEngine, SIGNAL(loadScript(const QString&, bool)), this, SLOT(loadScript(const QString&, bool))); connect(scriptEngine, SIGNAL(loadScript(const QString&, bool)), this, SLOT(loadScript(const QString&, bool)));
connect(scriptEngine, SIGNAL(reloadScript(const QString&, bool)), this, SLOT(reloadScript(const QString&, bool))); connect(scriptEngine, SIGNAL(reloadScript(const QString&, bool)), this, SLOT(reloadScript(const QString&, bool)));
@ -4267,10 +4284,13 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
QUrl scriptUrl(scriptFilename); QUrl scriptUrl(scriptFilename);
const QString& scriptURLString = scriptUrl.toString(); const QString& scriptURLString = scriptUrl.toString();
if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor {
&& !_scriptEnginesHash[scriptURLString]->isFinished()) { QReadLocker lock(&_scriptEnginesHashLock);
if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor
&& !_scriptEnginesHash[scriptURLString]->isFinished()) {
return _scriptEnginesHash[scriptURLString]; return _scriptEnginesHash[scriptURLString];
}
} }
ScriptEngine* scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface); ScriptEngine* scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface);
@ -4310,7 +4330,11 @@ void Application::reloadScript(const QString& scriptName, bool isUserLoaded) {
void Application::handleScriptEngineLoaded(const QString& scriptFilename) { void Application::handleScriptEngineLoaded(const QString& scriptFilename) {
ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(sender()); ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(sender());
_scriptEnginesHash.insertMulti(scriptFilename, scriptEngine); {
QWriteLocker lock(&_scriptEnginesHashLock);
_scriptEnginesHash.insertMulti(scriptFilename, scriptEngine);
}
_runningScriptsWidget->setRunningScripts(getRunningScripts()); _runningScriptsWidget->setRunningScripts(getRunningScripts());
UserActivityLogger::getInstance().loadedScript(scriptFilename); UserActivityLogger::getInstance().loadedScript(scriptFilename);
@ -4325,55 +4349,88 @@ void Application::handleScriptLoadError(const QString& scriptFilename) {
QMessageBox::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load."); QMessageBox::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load.");
} }
void Application::scriptFinished(const QString& scriptName) { QStringList Application::getRunningScripts() {
const QString& scriptURLString = QUrl(scriptName).toString(); QReadLocker lock(&_scriptEnginesHashLock);
QHash<QString, ScriptEngine*>::iterator it = _scriptEnginesHash.find(scriptURLString); return _scriptEnginesHash.keys();
if (it != _scriptEnginesHash.end()) { }
_scriptEnginesHash.erase(it);
_runningScriptsWidget->scriptStopped(scriptName); ScriptEngine* Application::getScriptEngine(const QString& scriptHash) {
_runningScriptsWidget->setRunningScripts(getRunningScripts()); QReadLocker lock(&_scriptEnginesHashLock);
return _scriptEnginesHash.value(scriptHash, nullptr);
}
void Application::scriptFinished(const QString& scriptName, ScriptEngine* engine) {
bool removed = false;
{
QWriteLocker lock(&_scriptEnginesHashLock);
const QString& scriptURLString = QUrl(scriptName).toString();
for (auto it = _scriptEnginesHash.find(scriptURLString); it != _scriptEnginesHash.end(); ++it) {
if (it.value() == engine) {
_scriptEnginesHash.erase(it);
removed = true;
break;
}
}
}
if (removed) {
postLambdaEvent([this, scriptName]() {
_runningScriptsWidget->scriptStopped(scriptName);
_runningScriptsWidget->setRunningScripts(getRunningScripts());
});
} }
} }
void Application::stopAllScripts(bool restart) { void Application::stopAllScripts(bool restart) {
if (restart) { {
// Delete all running scripts from cache so that they are re-downloaded when they are restarted QReadLocker lock(&_scriptEnginesHashLock);
auto scriptCache = DependencyManager::get<ScriptCache>();
for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin(); if (restart) {
// Delete all running scripts from cache so that they are re-downloaded when they are restarted
auto scriptCache = DependencyManager::get<ScriptCache>();
for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
it != _scriptEnginesHash.constEnd(); it++) { it != _scriptEnginesHash.constEnd(); it++) {
if (!it.value()->isFinished()) { if (!it.value()->isFinished()) {
scriptCache->deleteScript(it.key()); scriptCache->deleteScript(it.key());
}
} }
} }
}
// Stop and possibly restart all currently running scripts // Stop and possibly restart all currently running scripts
for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin(); for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
it != _scriptEnginesHash.constEnd(); it++) { it != _scriptEnginesHash.constEnd(); it++) {
if (it.value()->isFinished()) { if (it.value()->isFinished()) {
continue; continue;
}
if (restart && it.value()->isUserLoaded()) {
connect(it.value(), &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) {
reloadScript(scriptName);
});
}
QMetaObject::invokeMethod(it.value(), "stop");
//it.value()->stop();
qCDebug(interfaceapp) << "stopping script..." << it.key();
} }
if (restart && it.value()->isUserLoaded()) {
connect(it.value(), SIGNAL(finished(const QString&)), SLOT(reloadScript(const QString&)));
}
it.value()->stop();
qCDebug(interfaceapp) << "stopping script..." << it.key();
} }
getMyAvatar()->clearScriptableSettings(); getMyAvatar()->clearScriptableSettings();
} }
bool Application::stopScript(const QString& scriptHash, bool restart) { bool Application::stopScript(const QString& scriptHash, bool restart) {
bool stoppedScript = false; bool stoppedScript = false;
if (_scriptEnginesHash.contains(scriptHash)) { {
ScriptEngine* scriptEngine = _scriptEnginesHash[scriptHash]; QReadLocker lock(&_scriptEnginesHashLock);
if (restart) { if (_scriptEnginesHash.contains(scriptHash)) {
auto scriptCache = DependencyManager::get<ScriptCache>(); ScriptEngine* scriptEngine = _scriptEnginesHash[scriptHash];
scriptCache->deleteScript(QUrl(scriptHash)); if (restart) {
connect(scriptEngine, SIGNAL(finished(const QString&)), SLOT(reloadScript(const QString&))); auto scriptCache = DependencyManager::get<ScriptCache>();
scriptCache->deleteScript(QUrl(scriptHash));
connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) {
reloadScript(scriptName);
});
}
scriptEngine->stop();
stoppedScript = true;
qCDebug(interfaceapp) << "stopping script..." << scriptHash;
} }
scriptEngine->stop();
stoppedScript = true;
qCDebug(interfaceapp) << "stopping script..." << scriptHash;
} }
if (_scriptEnginesHash.empty()) { if (_scriptEnginesHash.empty()) {
getMyAvatar()->clearScriptableSettings(); getMyAvatar()->clearScriptableSettings();
@ -4392,6 +4449,7 @@ void Application::reloadOneScript(const QString& scriptName) {
} }
void Application::loadDefaultScripts() { void Application::loadDefaultScripts() {
QReadLocker lock(&_scriptEnginesHashLock);
if (!_scriptEnginesHash.contains(DEFAULT_SCRIPTS_JS_URL)) { if (!_scriptEnginesHash.contains(DEFAULT_SCRIPTS_JS_URL)) {
loadScript(DEFAULT_SCRIPTS_JS_URL); loadScript(DEFAULT_SCRIPTS_JS_URL);
} }

View file

@ -160,14 +160,9 @@ public:
uint32_t getFrameCount() { return _frameCount; } uint32_t getFrameCount() { return _frameCount; }
float getFps() const { return _fps; } float getFps() const { return _fps; }
float const HMD_TARGET_FRAME_RATE = 75.0f; float getTargetFrameRate(); // frames/second
float const DESKTOP_TARGET_FRAME_RATE = 60.0f;
float getTargetFrameRate() { return isHMDMode() ? HMD_TARGET_FRAME_RATE : DESKTOP_TARGET_FRAME_RATE; }
float getTargetFramePeriod() { return isHMDMode() ? 1.0f / HMD_TARGET_FRAME_RATE : 1.0f / DESKTOP_TARGET_FRAME_RATE; } // same as 1/getTargetFrameRate, but w/compile-time division
float getLastInstanteousFps() const { return _lastInstantaneousFps; } float getLastInstanteousFps() const { return _lastInstantaneousFps; }
float getLastPaintWait() const { return _lastPaintWait; }; float getLastUnsynchronizedFps() const { return _lastUnsynchronizedFps; }
float getLastDeducedNonVSyncFps() const { return _lastDeducedNonVSyncFps; }
void setMarginForDeducedFramePeriod(float newValue) { _marginForDeducedFramePeriod = newValue; }
float getFieldOfView() { return _fieldOfView.get(); } float getFieldOfView() { return _fieldOfView.get(); }
void setFieldOfView(float fov); void setFieldOfView(float fov);
@ -202,8 +197,8 @@ public:
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; } NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
QStringList getRunningScripts() { return _scriptEnginesHash.keys(); } QStringList getRunningScripts();
ScriptEngine* getScriptEngine(const QString& scriptHash) { return _scriptEnginesHash.value(scriptHash, NULL); } ScriptEngine* getScriptEngine(const QString& scriptHash);
float getRenderResolutionScale() const; float getRenderResolutionScale() const;
@ -336,7 +331,7 @@ private slots:
void loadSettings(); void loadSettings();
void saveSettings(); void saveSettings();
void scriptFinished(const QString& scriptName); void scriptFinished(const QString& scriptName, ScriptEngine* engine);
void saveScripts(); void saveScripts();
void reloadScript(const QString& scriptName, bool isUserLoaded = true); void reloadScript(const QString& scriptName, bool isUserLoaded = true);
@ -395,6 +390,7 @@ private:
bool importSVOFromURL(const QString& urlString); bool importSVOFromURL(const QString& urlString);
bool nearbyEntitiesAreReadyForPhysics();
int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode); int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode);
void trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket); void trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket);
@ -442,9 +438,7 @@ private:
QElapsedTimer _timerStart; QElapsedTimer _timerStart;
QElapsedTimer _lastTimeUpdated; QElapsedTimer _lastTimeUpdated;
float _lastInstantaneousFps { 0.0f }; float _lastInstantaneousFps { 0.0f };
float _lastPaintWait { 0.0f }; float _lastUnsynchronizedFps { 0.0f };
float _lastDeducedNonVSyncFps { 0.0f };
float _marginForDeducedFramePeriod{ 0.002f }; // 2ms, adjustable
ShapeManager _shapeManager; ShapeManager _shapeManager;
PhysicalEntitySimulation _entitySimulation; PhysicalEntitySimulation _entitySimulation;
@ -505,6 +499,7 @@ private:
TouchEvent _lastTouchEvent; TouchEvent _lastTouchEvent;
QReadWriteLock _scriptEnginesHashLock;
RunningScriptsWidget* _runningScriptsWidget; RunningScriptsWidget* _runningScriptsWidget;
QHash<QString, ScriptEngine*> _scriptEnginesHash; QHash<QString, ScriptEngine*> _scriptEnginesHash;
bool _runningScriptsWidgetWasVisible; bool _runningScriptsWidgetWasVisible;
@ -564,6 +559,7 @@ private:
bool _isForeground = true; // starts out assumed to be in foreground bool _isForeground = true; // starts out assumed to be in foreground
bool _inPaint = false; bool _inPaint = false;
bool _isGLInitialized { false }; bool _isGLInitialized { false };
bool _physicsEnabled { false };
}; };
#endif // hifi_Application_h #endif // hifi_Application_h

View file

@ -200,7 +200,6 @@ void Avatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("skeleton"); PerformanceTimer perfTimer("skeleton");
_skeletonModel.getRig()->copyJointsFromJointData(_jointData); _skeletonModel.getRig()->copyJointsFromJointData(_jointData);
_skeletonModel.simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations); _skeletonModel.simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations);
simulateAttachments(deltaTime);
locationChanged(); // joints changed, so if there are any children, update them. locationChanged(); // joints changed, so if there are any children, update them.
_hasNewJointRotations = false; _hasNewJointRotations = false;
_hasNewJointTranslations = false; _hasNewJointTranslations = false;

View file

@ -69,6 +69,7 @@ public:
void init(); void init();
void simulate(float deltaTime); void simulate(float deltaTime);
void simulateAttachments(float deltaTime);
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition); virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition);
@ -87,7 +88,6 @@ public:
bool isInitialized() const { return _initialized; } bool isInitialized() const { return _initialized; }
SkeletonModel& getSkeletonModel() { return _skeletonModel; } SkeletonModel& getSkeletonModel() { return _skeletonModel; }
const SkeletonModel& getSkeletonModel() const { return _skeletonModel; } const SkeletonModel& getSkeletonModel() const { return _skeletonModel; }
const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; }
glm::vec3 getChestPosition() const; glm::vec3 getChestPosition() const;
float getAvatarScale() const { return getScale().y; } float getAvatarScale() const { return getScale().y; }
const Head* getHead() const { return static_cast<const Head*>(_headData); } const Head* getHead() const { return static_cast<const Head*>(_headData); }
@ -217,8 +217,6 @@ protected:
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const; virtual bool shouldRenderHead(const RenderArgs* renderArgs) const;
virtual void fixupModelsInScene(); virtual void fixupModelsInScene();
void simulateAttachments(float deltaTime);
virtual void updateJointMappings(); virtual void updateJointMappings();
render::ItemID _renderItemID; render::ItemID _renderItemID;

View file

@ -111,7 +111,6 @@ void AvatarManager::init() {
_renderDistanceController.setKP(0.0008f); // Usually about 0.6 of largest that doesn't oscillate when other parameters 0. _renderDistanceController.setKP(0.0008f); // Usually about 0.6 of largest that doesn't oscillate when other parameters 0.
_renderDistanceController.setKI(0.0006f); // Big enough to bring us to target with the above KP. _renderDistanceController.setKI(0.0006f); // Big enough to bring us to target with the above KP.
_renderDistanceController.setKD(0.000001f); // A touch of kd increases the speed by which we get there. _renderDistanceController.setKD(0.000001f); // A touch of kd increases the speed by which we get there.
} }
void AvatarManager::updateMyAvatar(float deltaTime) { void AvatarManager::updateMyAvatar(float deltaTime) {
@ -146,13 +145,19 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
PerformanceTimer perfTimer("otherAvatars"); PerformanceTimer perfTimer("otherAvatars");
_renderDistanceController.setMeasuredValueSetpoint(qApp->getTargetFrameRate()); // No problem updating in flight. float distance;
// The PID controller raises the controlled value when the measured value goes up. if (!qApp->isThrottleRendering()) {
// The measured value is frame rate. When the controlled value (1 / render cutoff distance) _renderDistanceController.setMeasuredValueSetpoint(qApp->getTargetFrameRate()); // No problem updating in flight.
// goes up, the render cutoff distance gets closer, the number of rendered avatars is less, and frame rate // The PID controller raises the controlled value when the measured value goes up.
// goes up. // The measured value is frame rate. When the controlled value (1 / render cutoff distance)
const float deduced = qApp->getLastDeducedNonVSyncFps(); // goes up, the render cutoff distance gets closer, the number of rendered avatars is less, and frame rate
const float distance = 1.0f / _renderDistanceController.update(deduced, deltaTime); // goes up.
const float deduced = qApp->getLastUnsynchronizedFps();
distance = 1.0f / _renderDistanceController.update(deduced, deltaTime);
} else {
// Here we choose to just use the maximum render cutoff distance if throttled.
distance = 1.0f / _renderDistanceController.getControlledValueLowLimit();
}
_renderDistanceAverage.updateAverage(distance); _renderDistanceAverage.updateAverage(distance);
_renderDistance = _renderDistanceAverage.getAverage(); _renderDistance = _renderDistanceAverage.getAverage();
int renderableCount = 0; int renderableCount = 0;

View file

@ -323,11 +323,6 @@ void MyAvatar::simulate(float deltaTime) {
return; return;
} }
{
PerformanceTimer perfTimer("attachments");
simulateAttachments(deltaTime);
}
{ {
PerformanceTimer perfTimer("joints"); PerformanceTimer perfTimer("joints");
// copy out the skeleton joints from the model // copy out the skeleton joints from the model
@ -1058,7 +1053,7 @@ void MyAvatar::rebuildSkeletonBody() {
void MyAvatar::prepareForPhysicsSimulation() { void MyAvatar::prepareForPhysicsSimulation() {
relayDriveKeysToCharacterController(); relayDriveKeysToCharacterController();
_characterController.setTargetVelocity(getTargetVelocity()); _characterController.setTargetVelocity(getTargetVelocity());
_characterController.setAvatarPositionAndOrientation(getPosition(), getOrientation()); _characterController.setPositionAndOrientation(getPosition(), getOrientation());
if (qApp->isHMDMode()) { if (qApp->isHMDMode()) {
updateHMDFollowVelocity(); updateHMDFollowVelocity();
} else if (_followSpeed > 0.0f) { } else if (_followSpeed > 0.0f) {
@ -1071,7 +1066,7 @@ void MyAvatar::prepareForPhysicsSimulation() {
void MyAvatar::harvestResultsFromPhysicsSimulation() { void MyAvatar::harvestResultsFromPhysicsSimulation() {
glm::vec3 position = getPosition(); glm::vec3 position = getPosition();
glm::quat orientation = getOrientation(); glm::quat orientation = getOrientation();
_characterController.getAvatarPositionAndOrientation(position, orientation); _characterController.getPositionAndOrientation(position, orientation);
nextAttitude(position, orientation); nextAttitude(position, orientation);
if (_followSpeed > 0.0f) { if (_followSpeed > 0.0f) {
adjustSensorTransform(); adjustSensorTransform();

View file

@ -11,255 +11,25 @@
#include "MyCharacterController.h" #include "MyCharacterController.h"
#include <BulletCollision/CollisionShapes/btMultiSphereShape.h> #include <BulletUtil.h>
#include <BulletDynamics/Dynamics/btRigidBody.h>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <LinearMath/btDefaultMotionState.h>
#include <GLMHelpers.h>
#include <PhysicsLogging.h>
#include <PhysicsCollisionGroups.h>
#include "MyAvatar.h" #include "MyAvatar.h"
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
const float DEFAULT_GRAVITY = -5.0f;
const float JUMP_SPEED = 3.5f;
const float MAX_FALL_HEIGHT = 20.0f;
// TODO: improve walking up steps // TODO: improve walking up steps
// TODO: make avatars able to walk up and down steps/slopes // TODO: make avatars able to walk up and down steps/slopes
// TODO: make avatars stand on steep slope // TODO: make avatars stand on steep slope
// TODO: make avatars not snag on low ceilings // TODO: make avatars not snag on low ceilings
// helper class for simple ray-traces from character
class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback {
public:
ClosestNotMe(btRigidBody* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0f, 0.0f, 0.0f), btVector3(0.0f, 0.0f, 0.0f)) {
_me = me;
}
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) {
if (rayResult.m_collisionObject == _me) {
return 1.0f;
}
return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
}
protected:
btRigidBody* _me;
};
MyCharacterController::MyCharacterController(MyAvatar* avatar) { MyCharacterController::MyCharacterController(MyAvatar* avatar) {
_halfHeight = 1.0f;
assert(avatar); assert(avatar);
_avatar = avatar; _avatar = avatar;
_enabled = false;
_floorDistance = MAX_FALL_HEIGHT;
_walkVelocity.setValue(0.0f, 0.0f, 0.0f);
_followVelocity.setValue(0.0f, 0.0f, 0.0f);
_jumpSpeed = JUMP_SPEED;
_isOnGround = false;
_isJumping = false;
_isFalling = false;
_isHovering = true;
_isPushingUp = false;
_jumpToHoverStart = 0;
_followTime = 0.0f;
_pendingFlags = PENDING_FLAG_UPDATE_SHAPE;
updateShapeIfNecessary(); updateShapeIfNecessary();
} }
MyCharacterController::~MyCharacterController() { MyCharacterController::~MyCharacterController() {
} }
void MyCharacterController::preStep(btCollisionWorld* collisionWorld) {
// trace a ray straight down to see if we're standing on the ground
const btTransform& xform = _rigidBody->getWorldTransform();
// rayStart is at center of bottom sphere
btVector3 rayStart = xform.getOrigin() - _halfHeight * _currentUp;
// rayEnd is some short distance outside bottom sphere
const btScalar FLOOR_PROXIMITY_THRESHOLD = 0.3f * _radius;
btScalar rayLength = _radius + FLOOR_PROXIMITY_THRESHOLD;
btVector3 rayEnd = rayStart - rayLength * _currentUp;
// scan down for nearby floor
ClosestNotMe rayCallback(_rigidBody);
rayCallback.m_closestHitFraction = 1.0f;
collisionWorld->rayTest(rayStart, rayEnd, rayCallback);
if (rayCallback.hasHit()) {
_floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius;
}
}
void MyCharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
btScalar actualSpeed = actualVelocity.length();
btVector3 desiredVelocity = _walkVelocity;
btScalar desiredSpeed = desiredVelocity.length();
const btScalar MIN_UP_PUSH = 0.1f;
if (desiredVelocity.dot(_currentUp) < MIN_UP_PUSH) {
_isPushingUp = false;
}
const btScalar MIN_SPEED = 0.001f;
if (_isHovering) {
if (desiredSpeed < MIN_SPEED) {
if (actualSpeed < MIN_SPEED) {
_rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
} else {
const btScalar HOVER_BRAKING_TIMESCALE = 0.1f;
btScalar tau = glm::max(dt / HOVER_BRAKING_TIMESCALE, 1.0f);
_rigidBody->setLinearVelocity((1.0f - tau) * actualVelocity);
}
} else {
const btScalar HOVER_ACCELERATION_TIMESCALE = 0.1f;
btScalar tau = dt / HOVER_ACCELERATION_TIMESCALE;
_rigidBody->setLinearVelocity(actualVelocity - tau * (actualVelocity - desiredVelocity));
}
} else {
if (onGround()) {
// walking on ground
if (desiredSpeed < MIN_SPEED) {
if (actualSpeed < MIN_SPEED) {
_rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
} else {
const btScalar HOVER_BRAKING_TIMESCALE = 0.1f;
btScalar tau = dt / HOVER_BRAKING_TIMESCALE;
_rigidBody->setLinearVelocity((1.0f - tau) * actualVelocity);
}
} else {
// TODO: modify desiredVelocity using floor normal
const btScalar WALK_ACCELERATION_TIMESCALE = 0.1f;
btScalar tau = dt / WALK_ACCELERATION_TIMESCALE;
btVector3 velocityCorrection = tau * (desiredVelocity - actualVelocity);
// subtract vertical component
velocityCorrection -= velocityCorrection.dot(_currentUp) * _currentUp;
_rigidBody->setLinearVelocity(actualVelocity + velocityCorrection);
}
} else {
// transitioning to flying
btVector3 velocityCorrection = desiredVelocity - actualVelocity;
const btScalar FLY_ACCELERATION_TIMESCALE = 0.2f;
btScalar tau = dt / FLY_ACCELERATION_TIMESCALE;
if (!_isPushingUp) {
// actually falling --> compute a different velocity attenuation factor
const btScalar FALL_ACCELERATION_TIMESCALE = 2.0f;
tau = dt / FALL_ACCELERATION_TIMESCALE;
// zero vertical component
velocityCorrection -= velocityCorrection.dot(_currentUp) * _currentUp;
}
_rigidBody->setLinearVelocity(actualVelocity + tau * velocityCorrection);
}
}
// Rather than add _followVelocity to the velocity of the RigidBody, we explicitly teleport
// the RigidBody forward according to the formula: distance = rate * time
if (_followVelocity.length2() > 0.0f) {
btTransform bodyTransform = _rigidBody->getWorldTransform();
bodyTransform.setOrigin(bodyTransform.getOrigin() + dt * _followVelocity);
_rigidBody->setWorldTransform(bodyTransform);
}
_followTime += dt;
}
void MyCharacterController::jump() {
// check for case where user is holding down "jump" key...
// we'll eventually tansition to "hover"
if (!_isJumping) {
if (!_isHovering) {
_jumpToHoverStart = usecTimestampNow();
_pendingFlags |= PENDING_FLAG_JUMP;
}
} else {
quint64 now = usecTimestampNow();
const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100);
if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) {
_isPushingUp = true;
setHovering(true);
}
}
}
bool MyCharacterController::onGround() const {
const btScalar FLOOR_PROXIMITY_THRESHOLD = 0.3f * _radius;
return _floorDistance < FLOOR_PROXIMITY_THRESHOLD;
}
void MyCharacterController::setHovering(bool hover) {
if (hover != _isHovering) {
_isHovering = hover;
_isJumping = false;
if (_rigidBody) {
if (hover) {
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
} else {
_rigidBody->setGravity(DEFAULT_GRAVITY * _currentUp);
}
}
}
}
void MyCharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) {
_boxScale = scale;
float x = _boxScale.x;
float z = _boxScale.z;
float radius = 0.5f * sqrtf(0.5f * (x * x + z * z));
float halfHeight = 0.5f * _boxScale.y - radius;
float MIN_HALF_HEIGHT = 0.1f;
if (halfHeight < MIN_HALF_HEIGHT) {
halfHeight = MIN_HALF_HEIGHT;
}
// compare dimensions
float radiusDelta = glm::abs(radius - _radius);
float heightDelta = glm::abs(halfHeight - _halfHeight);
if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) {
// shape hasn't changed --> nothing to do
} else {
if (_dynamicsWorld) {
// must REMOVE from world prior to shape update
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
}
_pendingFlags |= PENDING_FLAG_UPDATE_SHAPE;
// only need to ADD back when we happen to be enabled
if (_enabled) {
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
}
}
// it's ok to change offset immediately -- there are no thread safety issues here
_shapeLocalOffset = corner + 0.5f * _boxScale;
}
void MyCharacterController::setEnabled(bool enabled) {
if (enabled != _enabled) {
if (enabled) {
// Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit.
// Setting the ADD bit here works for all cases so we don't even bother checking other bits.
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
} else {
if (_dynamicsWorld) {
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
}
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
_isOnGround = false;
}
setHovering(true);
_enabled = enabled;
}
}
void MyCharacterController::updateShapeIfNecessary() { void MyCharacterController::updateShapeIfNecessary() {
if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
_pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE;
@ -300,7 +70,7 @@ void MyCharacterController::updateShapeIfNecessary() {
if (_isHovering) { if (_isHovering) {
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
} else { } else {
_rigidBody->setGravity(DEFAULT_GRAVITY * _currentUp); _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
} }
//_rigidBody->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); //_rigidBody->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);
} else { } else {
@ -309,98 +79,3 @@ void MyCharacterController::updateShapeIfNecessary() {
} }
} }
void MyCharacterController::updateUpAxis(const glm::quat& rotation) {
btVector3 oldUp = _currentUp;
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
if (!_isHovering) {
const btScalar MIN_UP_ERROR = 0.01f;
if (oldUp.distance(_currentUp) > MIN_UP_ERROR) {
_rigidBody->setGravity(DEFAULT_GRAVITY * _currentUp);
}
}
}
void MyCharacterController::setAvatarPositionAndOrientation(
const glm::vec3& position,
const glm::quat& orientation) {
// TODO: update gravity if up has changed
updateUpAxis(orientation);
btQuaternion bodyOrientation = glmToBullet(orientation);
btVector3 bodyPosition = glmToBullet(position + orientation * _shapeLocalOffset);
_avatarBodyTransform = btTransform(bodyOrientation, bodyPosition);
}
void MyCharacterController::getAvatarPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const {
if (_enabled && _rigidBody) {
const btTransform& avatarTransform = _rigidBody->getWorldTransform();
rotation = bulletToGLM(avatarTransform.getRotation());
position = bulletToGLM(avatarTransform.getOrigin()) - rotation * _shapeLocalOffset;
}
}
void MyCharacterController::setTargetVelocity(const glm::vec3& velocity) {
//_walkVelocity = glmToBullet(_avatarData->getTargetVelocity());
_walkVelocity = glmToBullet(velocity);
}
void MyCharacterController::setFollowVelocity(const glm::vec3& velocity) {
_followVelocity = glmToBullet(velocity);
}
glm::vec3 MyCharacterController::getLinearVelocity() const {
glm::vec3 velocity(0.0f);
if (_rigidBody) {
velocity = bulletToGLM(_rigidBody->getLinearVelocity());
}
return velocity;
}
void MyCharacterController::preSimulation() {
if (_enabled && _dynamicsWorld) {
// slam body to where it is supposed to be
_rigidBody->setWorldTransform(_avatarBodyTransform);
// scan for distant floor
// rayStart is at center of bottom sphere
btVector3 rayStart = _avatarBodyTransform.getOrigin() - _halfHeight * _currentUp;
// rayEnd is straight down MAX_FALL_HEIGHT
btScalar rayLength = _radius + MAX_FALL_HEIGHT;
btVector3 rayEnd = rayStart - rayLength * _currentUp;
ClosestNotMe rayCallback(_rigidBody);
rayCallback.m_closestHitFraction = 1.0f;
_dynamicsWorld->rayTest(rayStart, rayEnd, rayCallback);
if (rayCallback.hasHit()) {
_floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius;
const btScalar MIN_HOVER_HEIGHT = 3.0f;
if (_isHovering && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) {
setHovering(false);
}
// TODO: use collision events rather than ray-trace test to disable jumping
const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius;
if (_floorDistance < JUMP_PROXIMITY_THRESHOLD) {
_isJumping = false;
}
} else {
_floorDistance = FLT_MAX;
setHovering(true);
}
if (_pendingFlags & PENDING_FLAG_JUMP) {
_pendingFlags &= ~ PENDING_FLAG_JUMP;
if (onGround()) {
_isJumping = true;
btVector3 velocity = _rigidBody->getLinearVelocity();
velocity += _jumpSpeed * _currentUp;
_rigidBody->setLinearVelocity(velocity);
}
}
}
_followTime = 0.0f;
}
void MyCharacterController::postSimulation() {
// postSimulation() exists for symmetry and just in case we need to do something here later
}

View file

@ -13,12 +13,8 @@
#ifndef hifi_MyCharacterController_h #ifndef hifi_MyCharacterController_h
#define hifi_MyCharacterController_h #define hifi_MyCharacterController_h
#include <btBulletDynamicsCommon.h>
#include <glm/glm.hpp>
#include <BulletUtil.h>
#include <CharacterController.h> #include <CharacterController.h>
#include <SharedUtil.h> //#include <SharedUtil.h>
class btCollisionShape; class btCollisionShape;
class MyAvatar; class MyAvatar;
@ -28,79 +24,10 @@ public:
MyCharacterController(MyAvatar* avatar); MyCharacterController(MyAvatar* avatar);
~MyCharacterController (); ~MyCharacterController ();
// TODO: implement these when needed
virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) override { assert(false); }
virtual void reset(btCollisionWorld* collisionWorld) override { }
virtual void warp(const btVector3& origin) override { }
virtual void debugDraw(btIDebugDraw* debugDrawer) override { }
virtual void setUpInterpolate(bool value) override { }
// overrides from btCharacterControllerInterface
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTime) override {
preStep(collisionWorld);
playerStep(collisionWorld, deltaTime);
}
virtual void preStep(btCollisionWorld* collisionWorld) override;
virtual void playerStep(btCollisionWorld* collisionWorld, btScalar dt) override;
virtual bool canJump() const override { assert(false); return false; } // never call this
virtual void jump() override; // call this every frame the jump button is pressed
virtual bool onGround() const override;
// overrides from CharacterController
virtual void preSimulation() override;
virtual void postSimulation() override;
bool isHovering() const { return _isHovering; }
void setHovering(bool enabled);
void setEnabled(bool enabled);
bool isEnabled() const { return _enabled && _dynamicsWorld; }
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
virtual void updateShapeIfNecessary() override; virtual void updateShapeIfNecessary() override;
void setAvatarPositionAndOrientation( const glm::vec3& position, const glm::quat& orientation);
void getAvatarPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const;
void setTargetVelocity(const glm::vec3& velocity);
void setFollowVelocity(const glm::vec3& velocity);
float getFollowTime() const { return _followTime; }
glm::vec3 getLinearVelocity() const;
protected: protected:
void updateUpAxis(const glm::quat& rotation);
protected:
btVector3 _currentUp;
btVector3 _walkVelocity;
btVector3 _followVelocity;
btTransform _avatarBodyTransform;
glm::vec3 _shapeLocalOffset;
glm::vec3 _boxScale; // used to compute capsule shape
quint64 _jumpToHoverStart;
MyAvatar* _avatar { nullptr }; MyAvatar* _avatar { nullptr };
btScalar _halfHeight;
btScalar _radius;
btScalar _floorDistance;
btScalar _gravity;
btScalar _jumpSpeed;
btScalar _followTime;
bool _enabled;
bool _isOnGround;
bool _isJumping;
bool _isFalling;
bool _isHovering;
bool _isPushingUp;
}; };
#endif // hifi_MyCharacterController_h #endif // hifi_MyCharacterController_h

View file

@ -20,9 +20,6 @@
#include "Application.h" #include "Application.h"
#include "devices/MotionTracker.h" #include "devices/MotionTracker.h"
// TODO: this needs to be removed, as well as any related controller-specific information
#include <input-plugins/SixenseManager.h>
void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) { void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
if (event->type() == HFActionEvent::startType()) { if (event->type() == HFActionEvent::startType()) {
emit actionStartEvent(static_cast<HFActionEvent&>(*event)); emit actionStartEvent(static_cast<HFActionEvent&>(*event));

View file

@ -26,7 +26,6 @@
#include "Tooltip.h" #include "Tooltip.h"
#include "Application.h" #include "Application.h"
#include <input-plugins/SixenseManager.h> // TODO: any references to sixense should be removed here
#include <controllers/InputDevice.h> #include <controllers/InputDevice.h>

View file

@ -16,7 +16,6 @@
#include <avatar/AvatarManager.h> #include <avatar/AvatarManager.h>
#include <devices/DdeFaceTracker.h> #include <devices/DdeFaceTracker.h>
#include <devices/Faceshift.h> #include <devices/Faceshift.h>
#include <input-plugins/SixenseManager.h> // TODO: This should be replaced with InputDevice/InputPlugin, or something similar
#include <NetworkingConstants.h> #include <NetworkingConstants.h>
#include "Application.h" #include "Application.h"

View file

@ -47,7 +47,7 @@ const QString AvatarData::FRAME_NAME = "com.highfidelity.recording.AvatarData";
static std::once_flag frameTypeRegistration; static std::once_flag frameTypeRegistration;
AvatarData::AvatarData() : AvatarData::AvatarData() :
SpatiallyNestable(NestableTypes::Avatar, QUuid()), SpatiallyNestable(NestableType::Avatar, QUuid()),
_handPosition(0.0f), _handPosition(0.0f),
_targetScale(1.0f), _targetScale(1.0f),
_handState(0), _handState(0),

View file

@ -83,16 +83,16 @@ void Basic2DWindowOpenGLDisplayPlugin::internalPresent() {
} }
WindowOpenGLDisplayPlugin::internalPresent(); WindowOpenGLDisplayPlugin::internalPresent();
} }
const uint32_t THROTTLED_FRAMERATE = 15;
int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const { int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const {
static const int THROTTLED_PAINT_TIMER_DELAY_MS = MSECS_PER_SECOND / 15;
static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1; static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1;
int result = ULIMIITED_PAINT_TIMER_DELAY_MS; int result = ULIMIITED_PAINT_TIMER_DELAY_MS;
if (_isThrottled) {
result = THROTTLED_PAINT_TIMER_DELAY_MS;
}
if (0 != _framerateTarget) { if (0 != _framerateTarget) {
result = MSECS_PER_SECOND / _framerateTarget; result = MSECS_PER_SECOND / _framerateTarget;
} else if (_isThrottled) {
// This test wouldn't be necessary if we could depend on updateFramerate setting _framerateTarget.
// Alas, that gets complicated: isThrottled() is const and other stuff depends on it.
result = MSECS_PER_SECOND / THROTTLED_FRAMERATE;
} }
qDebug() << "New interval " << result; qDebug() << "New interval " << result;
@ -112,7 +112,6 @@ bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const {
return shouldThrottle; return shouldThrottle;
} }
void Basic2DWindowOpenGLDisplayPlugin::updateFramerate() { void Basic2DWindowOpenGLDisplayPlugin::updateFramerate() {
QAction* checkedFramerate{ nullptr }; QAction* checkedFramerate{ nullptr };
foreach(auto action, _framerateActions) { foreach(auto action, _framerateActions) {
@ -134,11 +133,13 @@ void Basic2DWindowOpenGLDisplayPlugin::updateFramerate() {
} else if (FRAMERATE_30 == actionText) { } else if (FRAMERATE_30 == actionText) {
_framerateTarget = 30; _framerateTarget = 30;
} }
} } else if (_isThrottled) {
_framerateTarget = THROTTLED_FRAMERATE;
}
int newInterval = getDesiredInterval(); int newInterval = getDesiredInterval();
qDebug() << newInterval; qDebug() << newInterval;
_timer.start(getDesiredInterval()); _timer.start(newInterval);
} }
// FIXME target the screen the window is currently on // FIXME target the screen the window is currently on

View file

@ -9,6 +9,8 @@
#include "WindowOpenGLDisplayPlugin.h" #include "WindowOpenGLDisplayPlugin.h"
const float TARGET_FRAMERATE_Basic2DWindowOpenGL = 60.0f;
class QScreen; class QScreen;
class QAction; class QAction;
@ -18,6 +20,8 @@ class Basic2DWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin {
public: public:
virtual const QString & getName() const override; virtual const QString & getName() const override;
virtual float getTargetFrameRate() override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; }
virtual void activate() override; virtual void activate() override;
virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override;

View file

@ -14,8 +14,6 @@
#include "stereo/InterleavedStereoDisplayPlugin.h" #include "stereo/InterleavedStereoDisplayPlugin.h"
#include "Basic2DWindowOpenGLDisplayPlugin.h" #include "Basic2DWindowOpenGLDisplayPlugin.h"
#include "openvr/OpenVrDisplayPlugin.h"
const QString& DisplayPlugin::MENU_PATH() { const QString& DisplayPlugin::MENU_PATH() {
static const QString value = "Display"; static const QString value = "Display";
return value; return value;
@ -25,22 +23,14 @@ const QString& DisplayPlugin::MENU_PATH() {
DisplayPluginList getDisplayPlugins() { DisplayPluginList getDisplayPlugins() {
DisplayPlugin* PLUGIN_POOL[] = { DisplayPlugin* PLUGIN_POOL[] = {
new Basic2DWindowOpenGLDisplayPlugin(), new Basic2DWindowOpenGLDisplayPlugin(),
new NullDisplayPlugin(),
#ifdef DEBUG #ifdef DEBUG
new NullDisplayPlugin(),
#endif #endif
// Stereo modes // Stereo modes
// SBS left/right // SBS left/right
new SideBySideStereoDisplayPlugin(), new SideBySideStereoDisplayPlugin(),
// Interleaved left/right // Interleaved left/right
new InterleavedStereoDisplayPlugin(), new InterleavedStereoDisplayPlugin(),
// HMDs
//#ifdef Q_OS_WIN
// // SteamVR SDK
// new OpenVrDisplayPlugin(),
//#endif
nullptr nullptr
}; };

View file

@ -15,6 +15,7 @@
#include <QtOpenGL/QGLWidget> #include <QtOpenGL/QGLWidget>
#include <QtGui/QImage> #include <QtGui/QImage>
#include <QtGui/QOpenGLContext>
#include <gl/GLWidget.h> #include <gl/GLWidget.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
@ -103,8 +104,12 @@ public:
// take the latest texture and present it // take the latest texture and present it
_context->makeCurrent(); _context->makeCurrent();
currentPlugin->present(); if (QOpenGLContext::currentContext() == _context->contextHandle()) {
_context->doneCurrent(); currentPlugin->present();
_context->doneCurrent();
} else {
qWarning() << "Makecurrent failed";
}
} }
_context->makeCurrent(); _context->makeCurrent();

View file

@ -74,7 +74,7 @@ protected:
ProgramPtr _program; ProgramPtr _program;
ShapeWrapperPtr _plane; ShapeWrapperPtr _plane;
Mutex _mutex; mutable Mutex _mutex;
SimpleMovingAverage _usecsPerFrame { 10 }; SimpleMovingAverage _usecsPerFrame { 10 };
QMap<uint32_t, uint32_t> _sceneTextureToFrameIndexMap; QMap<uint32_t, uint32_t> _sceneTextureToFrameIndexMap;

View file

@ -60,9 +60,6 @@ public:
void setTexture(gpu::TexturePointer texture) { _texture = texture; } void setTexture(gpu::TexturePointer texture) { _texture = texture; }
const gpu::TexturePointer& getTexture() const { return _texture; } const gpu::TexturePointer& getTexture() const { return _texture; }
bool getVisibleFlag() const { return _visibleFlag; }
void setVisibleFlag(bool visibleFlag) { _visibleFlag = visibleFlag; }
void render(RenderArgs* args) const { void render(RenderArgs* args) const {
assert(_pipeline); assert(_pipeline);
@ -81,23 +78,23 @@ public:
auto numIndices = _indexBuffer->getSize() / sizeof(uint16_t); auto numIndices = _indexBuffer->getSize() / sizeof(uint16_t);
batch.drawIndexed(gpu::TRIANGLES, numIndices); batch.drawIndexed(gpu::TRIANGLES, numIndices);
} }
EntityItemPointer _entity;
protected: protected:
EntityItemPointer _entity;
Transform _modelTransform; Transform _modelTransform;
AABox _bound; AABox _bound;
gpu::PipelinePointer _pipeline; gpu::PipelinePointer _pipeline;
gpu::Stream::FormatPointer _vertexFormat; gpu::Stream::FormatPointer _vertexFormat;
gpu::BufferPointer _vertexBuffer; gpu::BufferPointer _vertexBuffer;
gpu::BufferPointer _indexBuffer; gpu::BufferPointer _indexBuffer;
gpu::TexturePointer _texture; gpu::TexturePointer _texture;
bool _visibleFlag = true;
}; };
namespace render { namespace render {
template <> template <>
const ItemKey payloadGetKey(const ParticlePayload::Pointer& payload) { const ItemKey payloadGetKey(const ParticlePayload::Pointer& payload) {
if (payload->getVisibleFlag()) { if (payload->_entity->getVisible()) {
return ItemKey::Builder::transparentShape(); return ItemKey::Builder::transparentShape();
} else { } else {
return ItemKey::Builder().withInvisible().build(); return ItemKey::Builder().withInvisible().build();
@ -111,7 +108,10 @@ namespace render {
template <> template <>
void payloadRender(const ParticlePayload::Pointer& payload, RenderArgs* args) { void payloadRender(const ParticlePayload::Pointer& payload, RenderArgs* args) {
payload->render(args); if (payload->_entity->getVisible()) {
payload->render(args);
}
} }
} }

View file

@ -29,7 +29,6 @@ void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desire
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame, _animationLoop->getFirstFrame); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame, _animationLoop->getFirstFrame);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame, _animationLoop->getLastFrame); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame, _animationLoop->getLastFrame);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold, _animationLoop->getHold); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold, _animationLoop->getHold);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ANIMATION_START_AUTOMATICALLY, Animation, animation, StartAutomatically, startAutomatically, _animationLoop->getStartAutomatically);
} else { } else {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, Animation, animation, FPS, fps); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, Animation, animation, FPS, fps);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, Animation, animation, CurrentFrame, currentFrame); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, Animation, animation, CurrentFrame, currentFrame);
@ -38,7 +37,6 @@ void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desire
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_START_AUTOMATICALLY, Animation, animation, StartAutomatically, startAutomatically);
} }
} }
@ -58,7 +56,6 @@ void AnimationPropertyGroup::copyFromScriptValue(const QScriptValue& object, boo
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, firstFrame, float, _animationLoop->setFirstFrame); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, firstFrame, float, _animationLoop->setFirstFrame);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, lastFrame, float, _animationLoop->setLastFrame); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, lastFrame, float, _animationLoop->setLastFrame);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, hold, bool, _animationLoop->setHold); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, hold, bool, _animationLoop->setHold);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, startAutomatically, bool, _animationLoop->setStartAutomatically);
// legacy property support // legacy property support
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationFPS, float, _animationLoop->setFPS, _animationLoop->getFPS); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationFPS, float, _animationLoop->setFPS, _animationLoop->getFPS);
@ -73,7 +70,6 @@ void AnimationPropertyGroup::copyFromScriptValue(const QScriptValue& object, boo
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, firstFrame, float, setFirstFrame); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, firstFrame, float, setFirstFrame);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, lastFrame, float, setLastFrame); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, lastFrame, float, setLastFrame);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, hold, bool, setHold); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, hold, bool, setHold);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, startAutomatically, bool, setStartAutomatically);
// legacy property support // legacy property support
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationFPS, float, setFPS, getFPS); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationFPS, float, setFPS, getFPS);
@ -95,7 +91,6 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
float lastFrame = _animationLoop ? _animationLoop->getLastFrame() : getLastFrame(); float lastFrame = _animationLoop ? _animationLoop->getLastFrame() : getLastFrame();
bool loop = _animationLoop ? _animationLoop->getLoop() : getLoop(); bool loop = _animationLoop ? _animationLoop->getLoop() : getLoop();
bool hold = _animationLoop ? _animationLoop->getHold() : getHold(); bool hold = _animationLoop ? _animationLoop->getHold() : getHold();
bool startAutomatically = _animationLoop ? _animationLoop->getStartAutomatically() : getStartAutomatically();
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
QJsonObject settingsAsJsonObject = settingsAsJson.object(); QJsonObject settingsAsJsonObject = settingsAsJson.object();
@ -130,10 +125,6 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
running = settingsMap["hold"].toBool(); running = settingsMap["hold"].toBool();
} }
if (settingsMap.contains("startAutomatically")) {
running = settingsMap["startAutomatically"].toBool();
}
if (_animationLoop) { if (_animationLoop) {
_animationLoop->setFPS(fps); _animationLoop->setFPS(fps);
_animationLoop->setCurrentFrame(currentFrame); _animationLoop->setCurrentFrame(currentFrame);
@ -142,7 +133,6 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
_animationLoop->setLastFrame(lastFrame); _animationLoop->setLastFrame(lastFrame);
_animationLoop->setLoop(loop); _animationLoop->setLoop(loop);
_animationLoop->setHold(hold); _animationLoop->setHold(hold);
_animationLoop->setStartAutomatically(startAutomatically);
} else { } else {
setFPS(fps); setFPS(fps);
setCurrentFrame(currentFrame); setCurrentFrame(currentFrame);
@ -151,7 +141,6 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
setLastFrame(lastFrame); setLastFrame(lastFrame);
setLoop(loop); setLoop(loop);
setHold(hold); setHold(hold);
setStartAutomatically(startAutomatically);
} }
} }
@ -194,7 +183,6 @@ bool AnimationPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, _animationLoop->getFirstFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, _animationLoop->getFirstFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, _animationLoop->getLastFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, _animationLoop->getLastFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, _animationLoop->getHold()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, _animationLoop->getHold());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_START_AUTOMATICALLY, _animationLoop->getStartAutomatically());
} else { } else {
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame());
@ -203,7 +191,6 @@ bool AnimationPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, getFirstFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, getFirstFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, getLastFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, getLastFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, getHold()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, getHold());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_START_AUTOMATICALLY, getStartAutomatically());
} }
return true; return true;
@ -226,7 +213,6 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, _animationLoop->setFirstFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, _animationLoop->setFirstFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, _animationLoop->setLastFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, _animationLoop->setLastFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, _animationLoop->setHold); READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, _animationLoop->setHold);
READ_ENTITY_PROPERTY(PROP_ANIMATION_START_AUTOMATICALLY, bool, _animationLoop->setStartAutomatically);
} else { } else {
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS); READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame);
@ -235,7 +221,6 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, setFirstFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, setFirstFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, setLastFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, setLastFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold); READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold);
READ_ENTITY_PROPERTY(PROP_ANIMATION_START_AUTOMATICALLY, bool, setStartAutomatically);
} }
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_URL, URL); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_URL, URL);
@ -246,7 +231,6 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FIRST_FRAME, FirstFrame); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FIRST_FRAME, FirstFrame);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_LAST_FRAME, LastFrame); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_LAST_FRAME, LastFrame);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_HOLD, Hold); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_HOLD, Hold);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_START_AUTOMATICALLY, StartAutomatically);
processedBytes += bytesRead; processedBytes += bytesRead;
@ -273,7 +257,6 @@ EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FIRST_FRAME, firstFrame); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FIRST_FRAME, firstFrame);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_LAST_FRAME, lastFrame); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_LAST_FRAME, lastFrame);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_HOLD, hold); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_HOLD, hold);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_START_AUTOMATICALLY, startAutomatically);
return changedProperties; return changedProperties;
} }
@ -288,7 +271,6 @@ void AnimationPropertyGroup::getProperties(EntityItemProperties& properties) con
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FirstFrame, _animationLoop->getFirstFrame); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FirstFrame, _animationLoop->getFirstFrame);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, LastFrame, _animationLoop->getLastFrame); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, LastFrame, _animationLoop->getLastFrame);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Hold, _animationLoop->getHold); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Hold, _animationLoop->getHold);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, StartAutomatically, _animationLoop->getStartAutomatically);
} else { } else {
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FPS, getFPS); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FPS, getFPS);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, CurrentFrame, getCurrentFrame); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, CurrentFrame, getCurrentFrame);
@ -297,7 +279,6 @@ void AnimationPropertyGroup::getProperties(EntityItemProperties& properties) con
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FirstFrame, getFirstFrame); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FirstFrame, getFirstFrame);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, LastFrame, getLastFrame); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, LastFrame, getLastFrame);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Hold, getHold); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Hold, getHold);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, StartAutomatically, getStartAutomatically);
} }
} }
@ -313,7 +294,6 @@ bool AnimationPropertyGroup::setProperties(const EntityItemProperties& propertie
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FirstFrame, firstFrame, _animationLoop->setFirstFrame); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FirstFrame, firstFrame, _animationLoop->setFirstFrame);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, LastFrame, lastFrame, _animationLoop->setLastFrame); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, LastFrame, lastFrame, _animationLoop->setLastFrame);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Hold, hold, _animationLoop->setHold); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Hold, hold, _animationLoop->setHold);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, StartAutomatically, startAutomatically, _animationLoop->setStartAutomatically);
} else { } else {
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FPS, fps, setFPS); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FPS, fps, setFPS);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, CurrentFrame, currentFrame, setCurrentFrame); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, CurrentFrame, currentFrame, setCurrentFrame);
@ -322,7 +302,6 @@ bool AnimationPropertyGroup::setProperties(const EntityItemProperties& propertie
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FirstFrame, firstFrame, setFirstFrame); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FirstFrame, firstFrame, setFirstFrame);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, LastFrame, lastFrame, setLastFrame); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, LastFrame, lastFrame, setLastFrame);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Hold, hold, setHold); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Hold, hold, setHold);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, StartAutomatically, startAutomatically, setStartAutomatically);
} }
return somethingChanged; return somethingChanged;
@ -339,7 +318,6 @@ EntityPropertyFlags AnimationPropertyGroup::getEntityProperties(EncodeBitstreamP
requestedProperties += PROP_ANIMATION_FIRST_FRAME; requestedProperties += PROP_ANIMATION_FIRST_FRAME;
requestedProperties += PROP_ANIMATION_LAST_FRAME; requestedProperties += PROP_ANIMATION_LAST_FRAME;
requestedProperties += PROP_ANIMATION_HOLD; requestedProperties += PROP_ANIMATION_HOLD;
requestedProperties += PROP_ANIMATION_START_AUTOMATICALLY;
return requestedProperties; return requestedProperties;
} }
@ -363,7 +341,6 @@ void AnimationPropertyGroup::appendSubclassData(OctreePacketData* packetData, En
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, _animationLoop->getFirstFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, _animationLoop->getFirstFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, _animationLoop->getLastFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, _animationLoop->getLastFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, _animationLoop->getHold()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, _animationLoop->getHold());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_START_AUTOMATICALLY, _animationLoop->getStartAutomatically());
} else { } else {
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame());
@ -372,7 +349,6 @@ void AnimationPropertyGroup::appendSubclassData(OctreePacketData* packetData, En
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, getFirstFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, getFirstFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, getLastFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, getLastFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, getHold()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, getHold());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_START_AUTOMATICALLY, getStartAutomatically());
} }
} }
@ -395,7 +371,6 @@ int AnimationPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char
READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, _animationLoop->setFirstFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, _animationLoop->setFirstFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, _animationLoop->setLastFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, _animationLoop->setLastFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, _animationLoop->setHold); READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, _animationLoop->setHold);
READ_ENTITY_PROPERTY(PROP_ANIMATION_START_AUTOMATICALLY, bool, _animationLoop->setStartAutomatically);
} else { } else {
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS); READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame);
@ -404,7 +379,6 @@ int AnimationPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char
READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, setFirstFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, setFirstFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, setLastFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, setLastFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold); READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold);
READ_ENTITY_PROPERTY(PROP_ANIMATION_START_AUTOMATICALLY, bool, setStartAutomatically);
} }
return bytesRead; return bytesRead;

View file

@ -80,7 +80,6 @@ public:
DEFINE_PROPERTY(PROP_ANIMATION_FIRST_FRAME, FirstFrame, firstFrame, float, 0.0f); // was animationSettings.firstFrame DEFINE_PROPERTY(PROP_ANIMATION_FIRST_FRAME, FirstFrame, firstFrame, float, 0.0f); // was animationSettings.firstFrame
DEFINE_PROPERTY(PROP_ANIMATION_LAST_FRAME, LastFrame, lastFrame, float, AnimationLoop::MAXIMUM_POSSIBLE_FRAME); // was animationSettings.lastFrame DEFINE_PROPERTY(PROP_ANIMATION_LAST_FRAME, LastFrame, lastFrame, float, AnimationLoop::MAXIMUM_POSSIBLE_FRAME); // was animationSettings.lastFrame
DEFINE_PROPERTY(PROP_ANIMATION_HOLD, Hold, hold, bool, false); // was animationSettings.hold DEFINE_PROPERTY(PROP_ANIMATION_HOLD, Hold, hold, bool, false); // was animationSettings.hold
DEFINE_PROPERTY(PROP_ANIMATION_START_AUTOMATICALLY, StartAutomatically, startAutomatically, bool, false); // was animationSettings.startAutomatically
protected: protected:
void setFromOldAnimationSettings(const QString& value); void setFromOldAnimationSettings(const QString& value);

View file

@ -36,7 +36,7 @@ int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
EntityItem::EntityItem(const EntityItemID& entityItemID) : EntityItem::EntityItem(const EntityItemID& entityItemID) :
SpatiallyNestable(NestableTypes::Entity, entityItemID), SpatiallyNestable(NestableType::Entity, entityItemID),
_type(EntityTypes::Unknown), _type(EntityTypes::Unknown),
_lastSimulated(0), _lastSimulated(0),
_lastUpdated(0), _lastUpdated(0),
@ -1294,7 +1294,7 @@ void EntityItem::updatePosition(const glm::vec3& value) {
setLocalPosition(value); setLocalPosition(value);
_dirtyFlags |= Simulation::DIRTY_POSITION; _dirtyFlags |= Simulation::DIRTY_POSITION;
forEachDescendant([&](SpatiallyNestablePointer object) { forEachDescendant([&](SpatiallyNestablePointer object) {
if (object->getNestableType() == NestableTypes::Entity) { if (object->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object); EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
entity->_dirtyFlags |= Simulation::DIRTY_POSITION; entity->_dirtyFlags |= Simulation::DIRTY_POSITION;
} }
@ -1317,7 +1317,7 @@ void EntityItem::updateRotation(const glm::quat& rotation) {
setLocalOrientation(rotation); setLocalOrientation(rotation);
_dirtyFlags |= Simulation::DIRTY_ROTATION; _dirtyFlags |= Simulation::DIRTY_ROTATION;
forEachDescendant([&](SpatiallyNestablePointer object) { forEachDescendant([&](SpatiallyNestablePointer object) {
if (object->getNestableType() == NestableTypes::Entity) { if (object->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object); EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; entity->_dirtyFlags |= Simulation::DIRTY_ROTATION;
entity->_dirtyFlags |= Simulation::DIRTY_POSITION; entity->_dirtyFlags |= Simulation::DIRTY_POSITION;

View file

@ -747,7 +747,6 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_START_AUTOMATICALLY, Animation, animation, StartAutomatically, startAutomatically);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_CENTER, Atmosphere, atmosphere, Center, center); ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_CENTER, Atmosphere, atmosphere, Center, center);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_INNER_RADIUS, Atmosphere, atmosphere, InnerRadius, innerRadius); ADD_GROUP_PROPERTY_TO_MAP(PROP_ATMOSPHERE_INNER_RADIUS, Atmosphere, atmosphere, InnerRadius, innerRadius);

View file

@ -219,7 +219,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
// if the entity has children, run UpdateEntityOperator on them. If the children have children, recurse // if the entity has children, run UpdateEntityOperator on them. If the children have children, recurse
QQueue<SpatiallyNestablePointer> toProcess; QQueue<SpatiallyNestablePointer> toProcess;
foreach (SpatiallyNestablePointer child, entity->getChildren()) { foreach (SpatiallyNestablePointer child, entity->getChildren()) {
if (child && child->getNestableType() == NestableTypes::Entity) { if (child && child->getNestableType() == NestableType::Entity) {
toProcess.enqueue(child); toProcess.enqueue(child);
} }
} }
@ -232,7 +232,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
childEntity, newChildBBRelProperties); childEntity, newChildBBRelProperties);
recurseTreeWithOperator(&theChildOperator); recurseTreeWithOperator(&theChildOperator);
foreach (SpatiallyNestablePointer childChild, childEntity->getChildren()) { foreach (SpatiallyNestablePointer childChild, childEntity->getChildren()) {
if (childChild && childChild->getNestableType() == NestableTypes::Entity) { if (childChild && childChild->getNestableType() == NestableType::Entity) {
toProcess.enqueue(childChild); toProcess.enqueue(childChild);
} }
} }

View file

@ -384,11 +384,6 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
setAnimationHold(hold); setAnimationHold(hold);
} }
if (settingsMap.contains("startAutomatically")) {
bool startAutomatically = settingsMap["startAutomatically"].toBool();
setAnimationStartAutomatically(startAutomatically);
}
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE; _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
} }

View file

@ -97,9 +97,6 @@ public:
void setAnimationHold(bool hold) { _animationLoop.setHold(hold); } void setAnimationHold(bool hold) { _animationLoop.setHold(hold); }
bool getAnimationHold() const { return _animationLoop.getHold(); } bool getAnimationHold() const { return _animationLoop.getHold(); }
void setAnimationStartAutomatically(bool startAutomatically) { _animationLoop.setStartAutomatically(startAutomatically); }
bool getAnimationStartAutomatically() const { return _animationLoop.getStartAutomatically(); }
void setAnimationFirstFrame(float firstFrame) { _animationLoop.setFirstFrame(firstFrame); } void setAnimationFirstFrame(float firstFrame) { _animationLoop.setFirstFrame(firstFrame); }
float getAnimationFirstFrame() const { return _animationLoop.getFirstFrame(); } float getAnimationFirstFrame() const { return _animationLoop.getFirstFrame(); }

View file

@ -1,15 +1,7 @@
set(TARGET_NAME input-plugins) set(TARGET_NAME input-plugins)
setup_hifi_library() setup_hifi_library()
link_hifi_libraries(shared plugins controllers script-engine render-utils) link_hifi_libraries(shared plugins controllers script-engine)
GroupSources("src/input-plugins") GroupSources("src/input-plugins")
if (WIN32)
add_dependency_external_projects(OpenVR)
find_package(OpenVR REQUIRED)
target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
endif()
target_sdl2() target_sdl2()
target_sixense()

View file

@ -14,16 +14,12 @@
#include "KeyboardMouseDevice.h" #include "KeyboardMouseDevice.h"
#include "SDL2Manager.h" #include "SDL2Manager.h"
#include "SixenseManager.h"
#include "ViveControllerManager.h"
// TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class // TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class
InputPluginList getInputPlugins() { InputPluginList getInputPlugins() {
InputPlugin* PLUGIN_POOL[] = { InputPlugin* PLUGIN_POOL[] = {
new KeyboardMouseDevice(), new KeyboardMouseDevice(),
new SDL2Manager(), new SDL2Manager(),
new SixenseManager(),
new ViveControllerManager(),
nullptr nullptr
}; };

View file

@ -41,7 +41,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityAdd: case PacketType::EntityAdd:
case PacketType::EntityEdit: case PacketType::EntityEdit:
case PacketType::EntityData: case PacketType::EntityData:
return VERSION_ENTITIES_HAVE_PARENTS; return VERSION_ENTITITES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP;
case PacketType::AvatarData: case PacketType::AvatarData:
case PacketType::BulkAvatarData: case PacketType::BulkAvatarData:
return 17; return 17;

View file

@ -161,5 +161,6 @@ const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48;
const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49;
const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50; const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50;
const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51; const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51;
const PacketVersion VERSION_ENTITITES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP = 52;
#endif // hifi_PacketHeaders_h #endif // hifi_PacketHeaders_h

View file

@ -11,8 +11,55 @@
#include "CharacterController.h" #include "CharacterController.h"
#include <NumericalConstants.h>
#include "BulletUtil.h"
#include "PhysicsCollisionGroups.h" #include "PhysicsCollisionGroups.h"
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
const float JUMP_SPEED = 3.5f;
const float MAX_FALL_HEIGHT = 20.0f;
// helper class for simple ray-traces from character
class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback {
public:
ClosestNotMe(btRigidBody* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0f, 0.0f, 0.0f), btVector3(0.0f, 0.0f, 0.0f)) {
_me = me;
}
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) {
if (rayResult.m_collisionObject == _me) {
return 1.0f;
}
return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
}
protected:
btRigidBody* _me;
};
CharacterController::CharacterController() {
_halfHeight = 1.0f;
_enabled = false;
_floorDistance = MAX_FALL_HEIGHT;
_walkVelocity.setValue(0.0f, 0.0f, 0.0f);
_followVelocity.setValue(0.0f, 0.0f, 0.0f);
_jumpSpeed = JUMP_SPEED;
_isOnGround = false;
_isJumping = false;
_isFalling = false;
_isHovering = true;
_isPushingUp = false;
_jumpToHoverStart = 0;
_followTime = 0.0f;
_pendingFlags = PENDING_FLAG_UPDATE_SHAPE;
}
bool CharacterController::needsRemoval() const { bool CharacterController::needsRemoval() const {
return ((_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION) == PENDING_FLAG_REMOVE_FROM_SIMULATION); return ((_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION) == PENDING_FLAG_REMOVE_FROM_SIMULATION);
} }
@ -23,7 +70,7 @@ bool CharacterController::needsAddition() const {
void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
if (_dynamicsWorld != world) { if (_dynamicsWorld != world) {
if (_dynamicsWorld) { if (_dynamicsWorld) {
if (_rigidBody) { if (_rigidBody) {
_dynamicsWorld->removeRigidBody(_rigidBody); _dynamicsWorld->removeRigidBody(_rigidBody);
_dynamicsWorld->removeAction(this); _dynamicsWorld->removeAction(this);
@ -33,9 +80,13 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
if (world && _rigidBody) { if (world && _rigidBody) {
_dynamicsWorld = world; _dynamicsWorld = world;
_pendingFlags &= ~PENDING_FLAG_JUMP; _pendingFlags &= ~PENDING_FLAG_JUMP;
// Before adding the RigidBody to the world we must save its oldGravity to the side
// because adding an object to the world will overwrite it with the default gravity.
btVector3 oldGravity = _rigidBody->getGravity();
_dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR); _dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR);
_dynamicsWorld->addAction(this); _dynamicsWorld->addAction(this);
//reset(_dynamicsWorld); // restore gravity settings
_rigidBody->setGravity(oldGravity);
} }
} }
if (_dynamicsWorld) { if (_dynamicsWorld) {
@ -48,5 +99,283 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
} else { } else {
_pendingFlags &= ~PENDING_FLAG_REMOVE_FROM_SIMULATION; _pendingFlags &= ~PENDING_FLAG_REMOVE_FROM_SIMULATION;
} }
} }
void CharacterController::preStep(btCollisionWorld* collisionWorld) {
// trace a ray straight down to see if we're standing on the ground
const btTransform& xform = _rigidBody->getWorldTransform();
// rayStart is at center of bottom sphere
btVector3 rayStart = xform.getOrigin() - _halfHeight * _currentUp;
// rayEnd is some short distance outside bottom sphere
const btScalar FLOOR_PROXIMITY_THRESHOLD = 0.3f * _radius;
btScalar rayLength = _radius + FLOOR_PROXIMITY_THRESHOLD;
btVector3 rayEnd = rayStart - rayLength * _currentUp;
// scan down for nearby floor
ClosestNotMe rayCallback(_rigidBody);
rayCallback.m_closestHitFraction = 1.0f;
collisionWorld->rayTest(rayStart, rayEnd, rayCallback);
if (rayCallback.hasHit()) {
_floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius;
}
}
void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
btScalar actualSpeed = actualVelocity.length();
btVector3 desiredVelocity = _walkVelocity;
btScalar desiredSpeed = desiredVelocity.length();
const btScalar MIN_UP_PUSH = 0.1f;
if (desiredVelocity.dot(_currentUp) < MIN_UP_PUSH) {
_isPushingUp = false;
}
const btScalar MIN_SPEED = 0.001f;
if (_isHovering) {
if (desiredSpeed < MIN_SPEED) {
if (actualSpeed < MIN_SPEED) {
_rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
} else {
const btScalar HOVER_BRAKING_TIMESCALE = 0.1f;
btScalar tau = glm::max(dt / HOVER_BRAKING_TIMESCALE, 1.0f);
_rigidBody->setLinearVelocity((1.0f - tau) * actualVelocity);
}
} else {
const btScalar HOVER_ACCELERATION_TIMESCALE = 0.1f;
btScalar tau = dt / HOVER_ACCELERATION_TIMESCALE;
_rigidBody->setLinearVelocity(actualVelocity - tau * (actualVelocity - desiredVelocity));
}
} else {
if (onGround()) {
// walking on ground
if (desiredSpeed < MIN_SPEED) {
if (actualSpeed < MIN_SPEED) {
_rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
} else {
const btScalar HOVER_BRAKING_TIMESCALE = 0.1f;
btScalar tau = dt / HOVER_BRAKING_TIMESCALE;
_rigidBody->setLinearVelocity((1.0f - tau) * actualVelocity);
}
} else {
// TODO: modify desiredVelocity using floor normal
const btScalar WALK_ACCELERATION_TIMESCALE = 0.1f;
btScalar tau = dt / WALK_ACCELERATION_TIMESCALE;
btVector3 velocityCorrection = tau * (desiredVelocity - actualVelocity);
// subtract vertical component
velocityCorrection -= velocityCorrection.dot(_currentUp) * _currentUp;
_rigidBody->setLinearVelocity(actualVelocity + velocityCorrection);
}
} else {
// transitioning to flying
btVector3 velocityCorrection = desiredVelocity - actualVelocity;
const btScalar FLY_ACCELERATION_TIMESCALE = 0.2f;
btScalar tau = dt / FLY_ACCELERATION_TIMESCALE;
if (!_isPushingUp) {
// actually falling --> compute a different velocity attenuation factor
const btScalar FALL_ACCELERATION_TIMESCALE = 2.0f;
tau = dt / FALL_ACCELERATION_TIMESCALE;
// zero vertical component
velocityCorrection -= velocityCorrection.dot(_currentUp) * _currentUp;
}
_rigidBody->setLinearVelocity(actualVelocity + tau * velocityCorrection);
}
}
// Rather than add _followVelocity to the velocity of the RigidBody, we explicitly teleport
// the RigidBody forward according to the formula: distance = rate * time
if (_followVelocity.length2() > 0.0f) {
btTransform bodyTransform = _rigidBody->getWorldTransform();
bodyTransform.setOrigin(bodyTransform.getOrigin() + dt * _followVelocity);
_rigidBody->setWorldTransform(bodyTransform);
}
_followTime += dt;
}
void CharacterController::jump() {
// check for case where user is holding down "jump" key...
// we'll eventually tansition to "hover"
if (!_isJumping) {
if (!_isHovering) {
_jumpToHoverStart = usecTimestampNow();
_pendingFlags |= PENDING_FLAG_JUMP;
}
} else {
quint64 now = usecTimestampNow();
const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100);
if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) {
_isPushingUp = true;
setHovering(true);
}
}
}
bool CharacterController::onGround() const {
const btScalar FLOOR_PROXIMITY_THRESHOLD = 0.3f * _radius;
return _floorDistance < FLOOR_PROXIMITY_THRESHOLD;
}
void CharacterController::setHovering(bool hover) {
if (hover != _isHovering) {
_isHovering = hover;
_isJumping = false;
if (_rigidBody) {
if (hover) {
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
} else {
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
}
}
}
}
void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) {
_boxScale = scale;
float x = _boxScale.x;
float z = _boxScale.z;
float radius = 0.5f * sqrtf(0.5f * (x * x + z * z));
float halfHeight = 0.5f * _boxScale.y - radius;
float MIN_HALF_HEIGHT = 0.1f;
if (halfHeight < MIN_HALF_HEIGHT) {
halfHeight = MIN_HALF_HEIGHT;
}
// compare dimensions
float radiusDelta = glm::abs(radius - _radius);
float heightDelta = glm::abs(halfHeight - _halfHeight);
if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) {
// shape hasn't changed --> nothing to do
} else {
if (_dynamicsWorld) {
// must REMOVE from world prior to shape update
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
}
_pendingFlags |= PENDING_FLAG_UPDATE_SHAPE;
// only need to ADD back when we happen to be enabled
if (_enabled) {
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
}
}
// it's ok to change offset immediately -- there are no thread safety issues here
_shapeLocalOffset = corner + 0.5f * _boxScale;
}
void CharacterController::setEnabled(bool enabled) {
if (enabled != _enabled) {
if (enabled) {
// Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit.
// Setting the ADD bit here works for all cases so we don't even bother checking other bits.
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
} else {
if (_dynamicsWorld) {
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
}
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
_isOnGround = false;
}
setHovering(true);
_enabled = enabled;
}
}
void CharacterController::updateUpAxis(const glm::quat& rotation) {
btVector3 oldUp = _currentUp;
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
if (!_isHovering) {
const btScalar MIN_UP_ERROR = 0.01f;
if (oldUp.distance(_currentUp) > MIN_UP_ERROR) {
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
}
}
}
void CharacterController::setPositionAndOrientation(
const glm::vec3& position,
const glm::quat& orientation) {
// TODO: update gravity if up has changed
updateUpAxis(orientation);
btQuaternion bodyOrientation = glmToBullet(orientation);
btVector3 bodyPosition = glmToBullet(position + orientation * _shapeLocalOffset);
_characterBodyTransform = btTransform(bodyOrientation, bodyPosition);
}
void CharacterController::getPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const {
if (_enabled && _rigidBody) {
const btTransform& avatarTransform = _rigidBody->getWorldTransform();
rotation = bulletToGLM(avatarTransform.getRotation());
position = bulletToGLM(avatarTransform.getOrigin()) - rotation * _shapeLocalOffset;
}
}
void CharacterController::setTargetVelocity(const glm::vec3& velocity) {
//_walkVelocity = glmToBullet(_avatarData->getTargetVelocity());
_walkVelocity = glmToBullet(velocity);
}
void CharacterController::setFollowVelocity(const glm::vec3& velocity) {
_followVelocity = glmToBullet(velocity);
}
glm::vec3 CharacterController::getLinearVelocity() const {
glm::vec3 velocity(0.0f);
if (_rigidBody) {
velocity = bulletToGLM(_rigidBody->getLinearVelocity());
}
return velocity;
}
void CharacterController::preSimulation() {
if (_enabled && _dynamicsWorld) {
// slam body to where it is supposed to be
_rigidBody->setWorldTransform(_characterBodyTransform);
// scan for distant floor
// rayStart is at center of bottom sphere
btVector3 rayStart = _characterBodyTransform.getOrigin() - _halfHeight * _currentUp;
// rayEnd is straight down MAX_FALL_HEIGHT
btScalar rayLength = _radius + MAX_FALL_HEIGHT;
btVector3 rayEnd = rayStart - rayLength * _currentUp;
ClosestNotMe rayCallback(_rigidBody);
rayCallback.m_closestHitFraction = 1.0f;
_dynamicsWorld->rayTest(rayStart, rayEnd, rayCallback);
if (rayCallback.hasHit()) {
_floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius;
const btScalar MIN_HOVER_HEIGHT = 3.0f;
if (_isHovering && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) {
setHovering(false);
}
// TODO: use collision events rather than ray-trace test to disable jumping
const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius;
if (_floorDistance < JUMP_PROXIMITY_THRESHOLD) {
_isJumping = false;
}
} else {
_floorDistance = FLT_MAX;
setHovering(true);
}
if (_pendingFlags & PENDING_FLAG_JUMP) {
_pendingFlags &= ~ PENDING_FLAG_JUMP;
if (onGround()) {
_isJumping = true;
btVector3 velocity = _rigidBody->getLinearVelocity();
velocity += _jumpSpeed * _currentUp;
_rigidBody->setLinearVelocity(velocity);
}
}
}
_followTime = 0.0f;
}
void CharacterController::postSimulation() {
// postSimulation() exists for symmetry and just in case we need to do something here later
}

View file

@ -17,11 +17,14 @@
#include <btBulletDynamicsCommon.h> #include <btBulletDynamicsCommon.h>
#include <BulletDynamics/Character/btCharacterControllerInterface.h> #include <BulletDynamics/Character/btCharacterControllerInterface.h>
#include <GLMHelpers.h>
const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0; const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0;
const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1; const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1;
const uint32_t PENDING_FLAG_UPDATE_SHAPE = 1U << 2; const uint32_t PENDING_FLAG_UPDATE_SHAPE = 1U << 2;
const uint32_t PENDING_FLAG_JUMP = 1U << 3; const uint32_t PENDING_FLAG_JUMP = 1U << 3;
const float DEFAULT_CHARACTER_GRAVITY = -5.0f;
class btRigidBody; class btRigidBody;
class btCollisionWorld; class btCollisionWorld;
@ -29,31 +32,89 @@ class btDynamicsWorld;
class CharacterController : public btCharacterControllerInterface { class CharacterController : public btCharacterControllerInterface {
public: public:
CharacterController();
virtual ~CharacterController() {}
bool needsRemoval() const; bool needsRemoval() const;
bool needsAddition() const; bool needsAddition() const;
void setDynamicsWorld(btDynamicsWorld* world); void setDynamicsWorld(btDynamicsWorld* world);
btCollisionObject* getCollisionObject() { return _rigidBody; } btCollisionObject* getCollisionObject() { return _rigidBody; }
virtual void updateShapeIfNecessary() = 0; virtual void updateShapeIfNecessary() = 0;
virtual void preSimulation() = 0;
virtual void postSimulation() = 0;
// overrides from btCharacterControllerInterface
virtual void setWalkDirection(const btVector3 &walkDirection) { assert(false); } virtual void setWalkDirection(const btVector3 &walkDirection) { assert(false); }
virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) override { assert(false); }
virtual void reset(btCollisionWorld* collisionWorld) override { }
virtual void warp(const btVector3& origin) override { }
virtual void debugDraw(btIDebugDraw* debugDrawer) override { }
virtual void setUpInterpolate(bool value) override { }
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTime) override {
preStep(collisionWorld);
playerStep(collisionWorld, deltaTime);
}
virtual void preStep(btCollisionWorld *collisionWorld) override;
virtual void playerStep(btCollisionWorld *collisionWorld, btScalar dt) override;
virtual bool canJump() const override { assert(false); return false; } // never call this
virtual void jump() override;
virtual bool onGround() const;
void preSimulation();
void postSimulation();
void setPositionAndOrientation( const glm::vec3& position, const glm::quat& orientation);
void getPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const;
void setTargetVelocity(const glm::vec3& velocity);
void setFollowVelocity(const glm::vec3& velocity);
float getFollowTime() const { return _followTime; }
glm::vec3 getLinearVelocity() const;
bool isHovering() const { return _isHovering; }
void setHovering(bool enabled);
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
void setEnabled(bool enabled);
bool isEnabled() const { return _enabled && _dynamicsWorld; }
/* these from btCharacterControllerInterface remain to be overridden
virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) = 0;
virtual void reset() = 0;
virtual void warp(const btVector3 &origin) = 0;
virtual void preStep(btCollisionWorld *collisionWorld) = 0;
virtual void playerStep(btCollisionWorld *collisionWorld, btScalar dt) = 0;
virtual bool canJump() const = 0;
virtual void jump() = 0;
virtual bool onGround() const = 0;
*/
protected: protected:
void updateUpAxis(const glm::quat& rotation);
protected:
btVector3 _currentUp;
btVector3 _walkVelocity;
btVector3 _followVelocity;
btTransform _characterBodyTransform;
glm::vec3 _shapeLocalOffset;
glm::vec3 _boxScale; // used to compute capsule shape
quint64 _jumpToHoverStart;
btScalar _halfHeight;
btScalar _radius;
btScalar _floorDistance;
btScalar _gravity;
btScalar _jumpSpeed;
btScalar _followTime;
bool _enabled;
bool _isOnGround;
bool _isJumping;
bool _isFalling;
bool _isHovering;
bool _isPushingUp;
btDynamicsWorld* _dynamicsWorld { nullptr }; btDynamicsWorld* _dynamicsWorld { nullptr };
btRigidBody* _rigidBody { nullptr }; btRigidBody* _rigidBody { nullptr };
uint32_t _pendingFlags { 0 }; uint32_t _pendingFlags { 0 };
}; };
#endif // hifi_CharacterControllerInterface_h #endif // hifi_CharacterControllerInterface_h

View file

@ -58,6 +58,7 @@ public:
/// By default, all HMDs are stereo /// By default, all HMDs are stereo
virtual bool isStereo() const { return isHmd(); } virtual bool isStereo() const { return isHmd(); }
virtual bool isThrottled() const { return false; } virtual bool isThrottled() const { return false; }
virtual float getTargetFrameRate() { return 0.0f; }
// Rendering support // Rendering support

View file

@ -82,7 +82,7 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) {
} }
Q_DECLARE_METATYPE(controller::InputController*) Q_DECLARE_METATYPE(controller::InputController*)
static int inputControllerPointerId = qRegisterMetaType<controller::InputController*>(); //static int inputControllerPointerId = qRegisterMetaType<controller::InputController*>();
QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) { QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) {
return engine->newQObject(in); return engine->newQObject(in);
@ -183,7 +183,7 @@ void ScriptEngine::runInThread() {
QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines; QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines;
QMutex ScriptEngine::_allScriptsMutex; QMutex ScriptEngine::_allScriptsMutex;
bool ScriptEngine::_stoppingAllScripts = false; std::atomic<bool> ScriptEngine::_stoppingAllScripts { false };
void ScriptEngine::stopAllScripts(QObject* application) { void ScriptEngine::stopAllScripts(QObject* application) {
_allScriptsMutex.lock(); _allScriptsMutex.lock();
@ -752,7 +752,7 @@ void ScriptEngine::run() {
} }
if (_wantSignals) { if (_wantSignals) {
emit finished(_fileNameString); emit finished(_fileNameString, this);
} }
_isRunning = false; _isRunning = false;
@ -775,6 +775,10 @@ void ScriptEngine::stopAllTimers() {
void ScriptEngine::stop() { void ScriptEngine::stop() {
if (!_isFinished) { if (!_isFinished) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "stop");
return;
}
_isFinished = true; _isFinished = true;
if (_wantSignals) { if (_wantSignals) {
emit runningStateChanged(); emit runningStateChanged();

View file

@ -153,7 +153,7 @@ signals:
void errorLoadingScript(const QString& scriptFilename); void errorLoadingScript(const QString& scriptFilename);
void update(float deltaTime); void update(float deltaTime);
void scriptEnding(); void scriptEnding();
void finished(const QString& fileNameString); void finished(const QString& fileNameString, ScriptEngine* engine);
void cleanupMenuItem(const QString& menuItemString); void cleanupMenuItem(const QString& menuItemString);
void printedMessage(const QString& message); void printedMessage(const QString& message);
void errorMessage(const QString& message); void errorMessage(const QString& message);
@ -166,8 +166,8 @@ signals:
protected: protected:
QString _scriptContents; QString _scriptContents;
QString _parentURL; QString _parentURL;
bool _isFinished { false }; std::atomic<bool> _isFinished { false };
bool _isRunning { false }; std::atomic<bool> _isRunning { false };
int _evaluatesPending { 0 }; int _evaluatesPending { 0 };
bool _isInitialized { false }; bool _isInitialized { false };
QHash<QTimer*, QScriptValue> _timerFunctionMap; QHash<QTimer*, QScriptValue> _timerFunctionMap;
@ -193,7 +193,7 @@ protected:
Quat _quatLibrary; Quat _quatLibrary;
Vec3 _vec3Library; Vec3 _vec3Library;
ScriptUUID _uuidLibrary; ScriptUUID _uuidLibrary;
bool _isUserLoaded { false }; std::atomic<bool> _isUserLoaded { false };
bool _isReloading { false }; bool _isReloading { false };
ArrayBufferClass* _arrayBufferClass; ArrayBufferClass* _arrayBufferClass;
@ -206,7 +206,7 @@ protected:
static QSet<ScriptEngine*> _allKnownScriptEngines; static QSet<ScriptEngine*> _allKnownScriptEngines;
static QMutex _allScriptsMutex; static QMutex _allScriptsMutex;
static bool _stoppingAllScripts; static std::atomic<bool> _stoppingAllScripts;
}; };
#endif // hifi_ScriptEngine_h #endif // hifi_ScriptEngine_h

View file

@ -65,7 +65,7 @@ void PIDController::updateHistory(float measuredValue, float dt, float error, fl
} }
} }
void PIDController::reportHistory() { void PIDController::reportHistory() {
qCDebug(shared) << _label << "measured dt FIXME || error accumulated changed || p i d controlled"; qCDebug(shared) << _label << "measured dt || error accumulated changed || p i d controlled";
for (int i = 0; i < _history.size(); i++) { for (int i = 0; i < _history.size(); i++) {
Row& row = _history[i]; Row& row = _history[i];
qCDebug(shared) << row.measured << row.dt << qCDebug(shared) << row.measured << row.dt <<

View file

@ -15,7 +15,7 @@
#include "SpatiallyNestable.h" #include "SpatiallyNestable.h"
SpatiallyNestable::SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id) : SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) :
_nestableType(nestableType), _nestableType(nestableType),
_id(id), _id(id),
_transform() { _transform() {

View file

@ -25,17 +25,14 @@ using SpatiallyNestableWeakConstPointer = std::weak_ptr<const SpatiallyNestable>
using SpatiallyNestablePointer = std::shared_ptr<SpatiallyNestable>; using SpatiallyNestablePointer = std::shared_ptr<SpatiallyNestable>;
using SpatiallyNestableConstPointer = std::shared_ptr<const SpatiallyNestable>; using SpatiallyNestableConstPointer = std::shared_ptr<const SpatiallyNestable>;
class NestableTypes { enum class NestableType {
public: Entity,
using NestableType = enum NestableType_t { Avatar
Entity,
Avatar
};
}; };
class SpatiallyNestable : public std::enable_shared_from_this<SpatiallyNestable> { class SpatiallyNestable : public std::enable_shared_from_this<SpatiallyNestable> {
public: public:
SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id); SpatiallyNestable(NestableType nestableType, QUuid id);
virtual ~SpatiallyNestable() { } virtual ~SpatiallyNestable() { }
virtual const QUuid& getID() const { return _id; } virtual const QUuid& getID() const { return _id; }
@ -88,17 +85,17 @@ public:
virtual void setLocalScale(const glm::vec3& scale); virtual void setLocalScale(const glm::vec3& scale);
QList<SpatiallyNestablePointer> getChildren() const; QList<SpatiallyNestablePointer> getChildren() const;
NestableTypes::NestableType getNestableType() const { return _nestableType; } NestableType getNestableType() const { return _nestableType; }
// this object's frame // this object's frame
virtual const Transform getAbsoluteJointTransformInObjectFrame(int jointIndex) const; virtual const Transform getAbsoluteJointTransformInObjectFrame(int jointIndex) const;
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const { assert(false); return glm::quat(); } virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const { assert(false); return glm::quat(); }
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const { assert(false); return glm::vec3(); } virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const { assert(false); return glm::vec3(); }
SpatiallyNestablePointer getThisPointer() const; SpatiallyNestablePointer getThisPointer() const;
protected: protected:
NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData const NestableType _nestableType; // EntityItem or an AvatarData
QUuid _id; QUuid _id;
QUuid _parentID; // what is this thing's transform relative to? QUuid _parentID; // what is this thing's transform relative to?
quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to?

View file

@ -0,0 +1,12 @@
#
# Created by Bradley Austin Davis on 2015/11/18
# 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
#
set(TARGET_NAME hifiSixense)
setup_hifi_plugin(Script Qml Widgets)
link_hifi_libraries(shared controllers plugins input-plugins)
target_sixense()

View file

@ -21,14 +21,17 @@
#include <controllers/UserInputMapper.h> #include <controllers/UserInputMapper.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <DebugDraw.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <PathUtils.h> #include <PathUtils.h>
#include <PerfStat.h> #include <PerfStat.h>
#include <plugins/PluginContainer.h> #include <plugins/PluginContainer.h>
#include <SettingHandle.h> #include <SettingHandle.h>
#include <UserActivityLogger.h>
#include "InputPluginsLogging.h" #include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(inputplugins)
Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins")
static const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2 static const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2
static const unsigned int BUTTON_1 = 1U << 5; static const unsigned int BUTTON_1 = 1U << 5;
@ -48,6 +51,8 @@ const QString MENU_PARENT = "Avatar";
const QString MENU_NAME = "Sixense"; const QString MENU_NAME = "Sixense";
const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME; const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
const QString TOGGLE_SMOOTH = "Smooth Sixense Movement"; const QString TOGGLE_SMOOTH = "Smooth Sixense Movement";
const QString SHOW_DEBUG_RAW = "Debug Draw Raw Data";
const QString SHOW_DEBUG_CALIBRATED = "Debug Draw Calibrated Data";
bool SixenseManager::isSupported() const { bool SixenseManager::isSupported() const {
#ifdef HAVE_SIXENSE #ifdef HAVE_SIXENSE
@ -72,6 +77,14 @@ void SixenseManager::activate() {
[this] (bool clicked) { setSixenseFilter(clicked); }, [this] (bool clicked) { setSixenseFilter(clicked); },
true, true); true, true);
_container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, SHOW_DEBUG_RAW,
[this] (bool clicked) { _inputDevice->setDebugDrawRaw(clicked); },
true, false);
_container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, SHOW_DEBUG_CALIBRATED,
[this] (bool clicked) { _inputDevice->setDebugDrawCalibrated(clicked); },
true, false);
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>(); auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
userInputMapper->registerDevice(_inputDevice); userInputMapper->registerDevice(_inputDevice);
@ -149,6 +162,9 @@ void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) {
// we only support two controllers // we only support two controllers
SixenseControllerData controllers[2]; SixenseControllerData controllers[2];
// store the raw controller data for debug rendering
controller::Pose rawPoses[2];
int numActiveControllers = 0; int numActiveControllers = 0;
for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) { for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) {
if (!sixenseIsControllerEnabled(i)) { if (!sixenseIsControllerEnabled(i)) {
@ -175,7 +191,7 @@ void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) {
// Rotation of Palm // Rotation of Palm
glm::quat rotation(data->rot_quat[3], data->rot_quat[0], data->rot_quat[1], data->rot_quat[2]); glm::quat rotation(data->rot_quat[3], data->rot_quat[0], data->rot_quat[1], data->rot_quat[2]);
handlePoseEvent(deltaTime, position, rotation, left); handlePoseEvent(deltaTime, position, rotation, left);
rawPoses[i] = controller::Pose(position, rotation, glm::vec3(0), glm::quat());
} else { } else {
_poseStateMap.clear(); _poseStateMap.clear();
_collectedSamples.clear(); _collectedSamples.clear();
@ -197,9 +213,54 @@ void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) {
_axisStateMap[axisState.first] = 0.0f; _axisStateMap[axisState.first] = 0.0f;
} }
} }
if (_debugDrawCalibrated) {
auto poseIter = _poseStateMap.find(controller::StandardPoseChannel::LEFT_HAND);
if (poseIter != _poseStateMap.end() && poseIter->second.isValid()) {
DebugDraw::getInstance().addMyAvatarMarker("SIXENSE_CALIBRATED_LEFT", poseIter->second.rotation, poseIter->second.translation, glm::vec4(1));
} else {
DebugDraw::getInstance().removeMyAvatarMarker("SIXENSE_CALIBRATED_LEFT");
}
poseIter = _poseStateMap.find(controller::StandardPoseChannel::RIGHT_HAND);
if (poseIter != _poseStateMap.end() && poseIter->second.isValid()) {
DebugDraw::getInstance().addMyAvatarMarker("SIXENSE_CALIBRATED_RIGHT", poseIter->second.rotation, poseIter->second.translation, glm::vec4(1));
} else {
DebugDraw::getInstance().removeMyAvatarMarker("SIXENSE_CALIBRATED_RIGHT");
}
}
if (_debugDrawRaw) {
if (rawPoses[0].isValid()) {
DebugDraw::getInstance().addMyAvatarMarker("SIXENSE_RAW_LEFT", rawPoses[0].rotation, rawPoses[0].translation, glm::vec4(1));
} else {
DebugDraw::getInstance().removeMyAvatarMarker("SIXENSE_RAW_LEFT");
}
if (rawPoses[1].isValid()) {
DebugDraw::getInstance().addMyAvatarMarker("SIXENSE_RAW_RIGHT", rawPoses[1].rotation, rawPoses[1].translation, glm::vec4(1));
} else {
DebugDraw::getInstance().removeMyAvatarMarker("SIXENSE_RAW_RIGHT");
}
}
#endif // HAVE_SIXENSE #endif // HAVE_SIXENSE
} }
void SixenseManager::InputDevice::setDebugDrawRaw(bool flag) {
_debugDrawRaw = flag;
if (!flag) {
DebugDraw::getInstance().removeMyAvatarMarker("SIXENSE_RAW_LEFT");
DebugDraw::getInstance().removeMyAvatarMarker("SIXENSE_RAW_RIGHT");
}
}
void SixenseManager::InputDevice::setDebugDrawCalibrated(bool flag) {
_debugDrawCalibrated = flag;
if (!flag) {
DebugDraw::getInstance().removeMyAvatarMarker("SIXENSE_CALIBRATED_LEFT");
DebugDraw::getInstance().removeMyAvatarMarker("SIXENSE_CALIBRATED_RIGHT");
}
}
#ifdef HAVE_SIXENSE #ifdef HAVE_SIXENSE
// the calibration sequence is: // the calibration sequence is:

View file

@ -17,7 +17,7 @@
#include <controllers/InputDevice.h> #include <controllers/InputDevice.h>
#include <controllers/StandardControls.h> #include <controllers/StandardControls.h>
#include "InputPlugin.h" #include <plugins/InputPlugin.h>
struct _sixenseControllerData; struct _sixenseControllerData;
using SixenseControllerData = _sixenseControllerData; using SixenseControllerData = _sixenseControllerData;
@ -60,6 +60,8 @@ private:
class InputDevice : public controller::InputDevice { class InputDevice : public controller::InputDevice {
public: public:
InputDevice() : controller::InputDevice("Hydra") {} InputDevice() : controller::InputDevice("Hydra") {}
void setDebugDrawRaw(bool flag);
void setDebugDrawCalibrated(bool flag);
private: private:
// Device functions // Device functions
virtual controller::Input::NamedVector getAvailableInputs() const override; virtual controller::Input::NamedVector getAvailableInputs() const override;
@ -82,6 +84,8 @@ private:
float _lastDistance; float _lastDistance;
bool _requestReset { false }; bool _requestReset { false };
bool _debugDrawRaw { false };
bool _debugDrawCalibrated { false };
// these are measured values used to compute the calibration results // these are measured values used to compute the calibration results
quint64 _lockExpiry; quint64 _lockExpiry;
glm::vec3 _averageLeft; glm::vec3 _averageLeft;

View file

@ -0,0 +1,45 @@
//
// Created by Bradley Austin Davis on 2015/10/25
// 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 <mutex>
#include <QtCore/QObject>
#include <QtCore/QtPlugin>
#include <QtCore/QStringList>
#include <plugins/RuntimePlugin.h>
#include <plugins/InputPlugin.h>
#include "SixenseManager.h"
class SixenseProvider : public QObject, public InputProvider
{
Q_OBJECT
Q_PLUGIN_METADATA(IID InputProvider_iid FILE "plugin.json")
Q_INTERFACES(InputProvider)
public:
SixenseProvider(QObject* parent = nullptr) : QObject(parent) {}
virtual ~SixenseProvider() {}
virtual InputPluginList getInputPlugins() override {
static std::once_flag once;
std::call_once(once, [&] {
InputPluginPointer plugin(new SixenseManager());
if (plugin->isSupported()) {
_inputPlugins.push_back(plugin);
}
});
return _inputPlugins;
}
private:
InputPluginList _inputPlugins;
};
#include "SixenseProvider.moc"

View file

@ -17,8 +17,7 @@
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QLibrary> #include <QtCore/QLibrary>
#include <QtCore/QDebug>
#include "InputPluginsLogging.h"
#ifndef SIXENSE_LIB_FILENAME #ifndef SIXENSE_LIB_FILENAME
#define SIXENSE_LIB_FILENAME QCoreApplication::applicationDirPath() + "/../Frameworks/libsixense_x64" #define SIXENSE_LIB_FILENAME QCoreApplication::applicationDirPath() + "/../Frameworks/libsixense_x64"

View file

@ -0,0 +1 @@
{}

View file

@ -20,9 +20,7 @@ glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseP
} }
void OculusBaseDisplayPlugin::resetSensors() { void OculusBaseDisplayPlugin::resetSensors() {
#if (OVR_MAJOR_VERSION >= 6) ovr_RecenterPose(_session);
ovr_RecenterPose(_hmd);
#endif
} }
glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const { glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
@ -30,27 +28,39 @@ glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
} }
glm::mat4 OculusBaseDisplayPlugin::getHeadPose(uint32_t frameIndex) const { glm::mat4 OculusBaseDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
#if (OVR_MAJOR_VERSION >= 6) static uint32_t lastFrameSeen = 0;
auto frameTiming = ovr_GetFrameTiming(_hmd, frameIndex); auto displayTime = ovr_GetPredictedDisplayTime(_session, frameIndex);
auto trackingState = ovr_GetTrackingState(_hmd, frameTiming.DisplayMidpointSeconds); auto trackingState = ovr_GetTrackingState(_session, displayTime, frameIndex > lastFrameSeen);
if (frameIndex > lastFrameSeen) {
lastFrameSeen = frameIndex;
}
return toGlm(trackingState.HeadPose.ThePose); return toGlm(trackingState.HeadPose.ThePose);
#endif
} }
bool OculusBaseDisplayPlugin::isSupported() const { bool OculusBaseDisplayPlugin::isSupported() const {
#if (OVR_MAJOR_VERSION >= 6)
if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
return false; return false;
} }
bool result = false;
if (ovrHmd_Detect() > 0) { ovrSession session { nullptr };
result = true; ovrGraphicsLuid luid;
auto result = ovr_Create(&session, &luid);
if (!OVR_SUCCESS(result)) {
ovrErrorInfo error;
ovr_GetLastErrorInfo(&error);
ovr_Shutdown();
return false;
} }
auto hmdDesc = ovr_GetHmdDesc(session);
if (hmdDesc.Type == ovrHmd_None) {
ovr_Destroy(session);
ovr_Shutdown();
return false;
}
ovr_Shutdown(); ovr_Shutdown();
return result; return true;
#else
return false;
#endif
} }
// DLL based display plugins MUST initialize GLEW inside the DLL code. // DLL based display plugins MUST initialize GLEW inside the DLL code.
@ -69,28 +79,22 @@ void OculusBaseDisplayPlugin::deinit() {
void OculusBaseDisplayPlugin::activate() { void OculusBaseDisplayPlugin::activate() {
WindowOpenGLDisplayPlugin::activate(); WindowOpenGLDisplayPlugin::activate();
#if (OVR_MAJOR_VERSION >= 6)
if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
qFatal("Could not init OVR"); qFatal("Could not init OVR");
} }
#if (OVR_MAJOR_VERSION == 6) if (!OVR_SUCCESS(ovr_Create(&_session, &_luid))) {
if (!OVR_SUCCESS(ovr_Create(0, &_hmd))) {
#elif (OVR_MAJOR_VERSION == 7)
if (!OVR_SUCCESS(ovr_Create(&_hmd, &_luid))) {
#endif
Q_ASSERT(false);
qFatal("Failed to acquire HMD"); qFatal("Failed to acquire HMD");
} }
_hmdDesc = ovr_GetHmdDesc(_hmd); _hmdDesc = ovr_GetHmdDesc(_session);
_ipd = ovr_GetFloat(_hmd, OVR_KEY_IPD, _ipd); _ipd = ovr_GetFloat(_session, OVR_KEY_IPD, _ipd);
glm::uvec2 eyeSizes[2]; glm::uvec2 eyeSizes[2];
ovr_for_each_eye([&](ovrEyeType eye) { ovr_for_each_eye([&](ovrEyeType eye) {
_eyeFovs[eye] = _hmdDesc.DefaultEyeFov[eye]; _eyeFovs[eye] = _hmdDesc.DefaultEyeFov[eye];
ovrEyeRenderDesc& erd = _eyeRenderDescs[eye] = ovr_GetRenderDesc(_hmd, eye, _eyeFovs[eye]); ovrEyeRenderDesc& erd = _eyeRenderDescs[eye] = ovr_GetRenderDesc(_session, eye, _eyeFovs[eye]);
ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f ovrPerspectiveProjection =
ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded); ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
_eyeProjections[eye] = toGlm(ovrPerspectiveProjection); _eyeProjections[eye] = toGlm(ovrPerspectiveProjection);
@ -100,7 +104,7 @@ void OculusBaseDisplayPlugin::activate() {
_compositeEyeProjections[eye] = toGlm(ovrPerspectiveProjection); _compositeEyeProjections[eye] = toGlm(ovrPerspectiveProjection);
_eyeOffsets[eye] = erd.HmdToEyeViewOffset; _eyeOffsets[eye] = erd.HmdToEyeViewOffset;
eyeSizes[eye] = toGlm(ovr_GetFovTextureSize(_hmd, eye, erd.Fov, 1.0f)); eyeSizes[eye] = toGlm(ovr_GetFovTextureSize(_session, eye, erd.Fov, 1.0f));
}); });
ovrFovPort combined = _eyeFovs[Left]; ovrFovPort combined = _eyeFovs[Left];
combined.LeftTan = std::max(_eyeFovs[Left].LeftTan, _eyeFovs[Right].LeftTan); combined.LeftTan = std::max(_eyeFovs[Left].LeftTan, _eyeFovs[Right].LeftTan);
@ -115,34 +119,33 @@ void OculusBaseDisplayPlugin::activate() {
eyeSizes[0].x + eyeSizes[1].x, eyeSizes[0].x + eyeSizes[1].x,
std::max(eyeSizes[0].y, eyeSizes[1].y)); std::max(eyeSizes[0].y, eyeSizes[1].y));
if (!OVR_SUCCESS(ovr_ConfigureTracking(_hmd, if (!OVR_SUCCESS(ovr_ConfigureTracking(_session,
ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) { ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) {
qFatal("Could not attach to sensor device"); qFatal("Could not attach to sensor device");
} }
// Parent class relies on our _hmd intialization, so it must come after that. // Parent class relies on our _session intialization, so it must come after that.
memset(&_sceneLayer, 0, sizeof(ovrLayerEyeFov)); memset(&_sceneLayer, 0, sizeof(ovrLayerEyeFov));
_sceneLayer.Header.Type = ovrLayerType_EyeFov; _sceneLayer.Header.Type = ovrLayerType_EyeFov;
_sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; _sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
ovr_for_each_eye([&](ovrEyeType eye) { ovr_for_each_eye([&](ovrEyeType eye) {
ovrFovPort & fov = _sceneLayer.Fov[eye] = _eyeRenderDescs[eye].Fov; ovrFovPort & fov = _sceneLayer.Fov[eye] = _eyeRenderDescs[eye].Fov;
ovrSizei & size = _sceneLayer.Viewport[eye].Size = ovr_GetFovTextureSize(_hmd, eye, fov, 1.0f); ovrSizei & size = _sceneLayer.Viewport[eye].Size = ovr_GetFovTextureSize(_session, eye, fov, 1.0f);
_sceneLayer.Viewport[eye].Pos = { eye == ovrEye_Left ? 0 : size.w, 0 }; _sceneLayer.Viewport[eye].Pos = { eye == ovrEye_Left ? 0 : size.w, 0 };
}); });
if (!OVR_SUCCESS(ovr_ConfigureTracking(_hmd, if (!OVR_SUCCESS(ovr_ConfigureTracking(_session,
ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) { ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) {
qFatal("Could not attach to sensor device"); qFatal("Could not attach to sensor device");
} }
#endif
} }
void OculusBaseDisplayPlugin::deactivate() { void OculusBaseDisplayPlugin::deactivate() {
WindowOpenGLDisplayPlugin::deactivate(); WindowOpenGLDisplayPlugin::deactivate();
#if (OVR_MAJOR_VERSION >= 6) #if (OVR_MAJOR_VERSION >= 6)
ovr_Destroy(_hmd); ovr_Destroy(_session);
_hmd = nullptr; _session = nullptr;
ovr_Shutdown(); ovr_Shutdown();
#endif #endif
} }
@ -151,7 +154,7 @@ void OculusBaseDisplayPlugin::deactivate() {
float OculusBaseDisplayPlugin::getIPD() const { float OculusBaseDisplayPlugin::getIPD() const {
float result = OVR_DEFAULT_IPD; float result = OVR_DEFAULT_IPD;
#if (OVR_MAJOR_VERSION >= 6) #if (OVR_MAJOR_VERSION >= 6)
result = ovr_GetFloat(_hmd, OVR_KEY_IPD, result); result = ovr_GetFloat(_session, OVR_KEY_IPD, result);
#endif #endif
return result; return result;
} }

View file

@ -43,17 +43,13 @@ protected:
mat4 _compositeEyeProjections[2]; mat4 _compositeEyeProjections[2];
uvec2 _desiredFramebufferSize; uvec2 _desiredFramebufferSize;
#if (OVR_MAJOR_VERSION >= 6) ovrSession _session;
ovrHmd _hmd; ovrGraphicsLuid _luid;
float _ipd{ OVR_DEFAULT_IPD }; float _ipd{ OVR_DEFAULT_IPD };
ovrEyeRenderDesc _eyeRenderDescs[2]; ovrEyeRenderDesc _eyeRenderDescs[2];
ovrFovPort _eyeFovs[2]; ovrFovPort _eyeFovs[2];
ovrHmdDesc _hmdDesc; ovrHmdDesc _hmdDesc;
ovrLayerEyeFov _sceneLayer; ovrLayerEyeFov _sceneLayer;
#endif
#if (OVR_MAJOR_VERSION == 7)
ovrGraphicsLuid _luid;
#endif
}; };
#if (OVR_MAJOR_VERSION == 6) #if (OVR_MAJOR_VERSION == 6)

View file

@ -23,12 +23,16 @@
// ovr_CreateMirrorTextureGL, etc // ovr_CreateMirrorTextureGL, etc
template <typename C> template <typename C>
struct RiftFramebufferWrapper : public FramebufferWrapper<C, char> { struct RiftFramebufferWrapper : public FramebufferWrapper<C, char> {
ovrHmd hmd; ovrSession session;
RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) { RiftFramebufferWrapper(const ovrSession& session) : session(session) {
color = 0; color = 0;
depth = 0; depth = 0;
}; };
~RiftFramebufferWrapper() {
destroyColor();
}
void Resize(const uvec2 & size) { void Resize(const uvec2 & size) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo)); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo));
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
@ -39,6 +43,9 @@ struct RiftFramebufferWrapper : public FramebufferWrapper<C, char> {
} }
protected: protected:
virtual void destroyColor() {
}
virtual void initDepth() override final { virtual void initDepth() override final {
} }
}; };
@ -53,12 +60,6 @@ struct SwapFramebufferWrapper : public RiftFramebufferWrapper<ovrSwapTextureSet*
: RiftFramebufferWrapper(hmd) { : RiftFramebufferWrapper(hmd) {
} }
~SwapFramebufferWrapper() {
if (color) {
ovr_DestroySwapTextureSet(hmd, color);
color = nullptr;
}
}
void Increment() { void Increment() {
++color->CurrentIndex; ++color->CurrentIndex;
@ -66,13 +67,17 @@ struct SwapFramebufferWrapper : public RiftFramebufferWrapper<ovrSwapTextureSet*
} }
protected: protected:
virtual void initColor() override { virtual void destroyColor() override {
if (color) { if (color) {
ovr_DestroySwapTextureSet(hmd, color); ovr_DestroySwapTextureSet(session, color);
color = nullptr; color = nullptr;
} }
}
if (!OVR_SUCCESS(ovr_CreateSwapTextureSetGL(hmd, GL_RGBA, size.x, size.y, &color))) { virtual void initColor() override {
destroyColor();
if (!OVR_SUCCESS(ovr_CreateSwapTextureSetGL(session, GL_SRGB8_ALPHA8, size.x, size.y, &color))) {
qFatal("Unable to create swap textures"); qFatal("Unable to create swap textures");
} }
@ -107,20 +112,17 @@ struct MirrorFramebufferWrapper : public RiftFramebufferWrapper<ovrGLTexture*> {
MirrorFramebufferWrapper(const ovrHmd & hmd) MirrorFramebufferWrapper(const ovrHmd & hmd)
: RiftFramebufferWrapper(hmd) { } : RiftFramebufferWrapper(hmd) { }
virtual ~MirrorFramebufferWrapper() { private:
virtual void destroyColor() override {
if (color) { if (color) {
ovr_DestroyMirrorTexture(hmd, (ovrTexture*)color); ovr_DestroyMirrorTexture(session, (ovrTexture*)color);
color = nullptr; color = nullptr;
} }
} }
private:
void initColor() override { void initColor() override {
if (color) { destroyColor();
ovr_DestroyMirrorTexture(hmd, (ovrTexture*)color); ovrResult result = ovr_CreateMirrorTextureGL(session, GL_SRGB8_ALPHA8, size.x, size.y, (ovrTexture**)&color);
color = nullptr;
}
ovrResult result = ovr_CreateMirrorTextureGL(hmd, GL_RGBA, size.x, size.y, (ovrTexture**)&color);
Q_ASSERT(OVR_SUCCESS(result)); Q_ASSERT(OVR_SUCCESS(result));
} }
@ -154,8 +156,7 @@ void OculusDisplayPlugin::activate() {
void OculusDisplayPlugin::customizeContext() { void OculusDisplayPlugin::customizeContext() {
OculusBaseDisplayPlugin::customizeContext(); OculusBaseDisplayPlugin::customizeContext();
#if (OVR_MAJOR_VERSION >= 6) _sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_session));
_sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_hmd));
_sceneFbo->Init(getRecommendedRenderSize()); _sceneFbo->Init(getRecommendedRenderSize());
// We're rendering both eyes to the same texture, so only one of the // We're rendering both eyes to the same texture, so only one of the
@ -163,7 +164,7 @@ void OculusDisplayPlugin::customizeContext() {
_sceneLayer.ColorTexture[0] = _sceneFbo->color; _sceneLayer.ColorTexture[0] = _sceneFbo->color;
// not needed since the structure was zeroed on init, but explicit // not needed since the structure was zeroed on init, but explicit
_sceneLayer.ColorTexture[1] = nullptr; _sceneLayer.ColorTexture[1] = nullptr;
#endif
enableVsync(false); enableVsync(false);
// Only enable mirroring if we know vsync is disabled // Only enable mirroring if we know vsync is disabled
_enablePreview = !isVsyncEnabled(); _enablePreview = !isVsyncEnabled();
@ -177,7 +178,6 @@ void OculusDisplayPlugin::uncustomizeContext() {
} }
void OculusDisplayPlugin::internalPresent() { void OculusDisplayPlugin::internalPresent() {
#if (OVR_MAJOR_VERSION >= 6)
if (!_currentSceneTexture) { if (!_currentSceneTexture) {
return; return;
} }
@ -206,8 +206,10 @@ void OculusDisplayPlugin::internalPresent() {
auto size = _sceneFbo->size; auto size = _sceneFbo->size;
Context::Viewport(size.x, size.y); Context::Viewport(size.x, size.y);
glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); glBindTexture(GL_TEXTURE_2D, _currentSceneTexture);
//glEnable(GL_FRAMEBUFFER_SRGB);
GLenum err = glGetError(); GLenum err = glGetError();
drawUnitQuad(); drawUnitQuad();
//glDisable(GL_FRAMEBUFFER_SRGB);
}); });
uint32_t frameIndex { 0 }; uint32_t frameIndex { 0 };
@ -230,13 +232,12 @@ void OculusDisplayPlugin::internalPresent() {
viewScaleDesc.HmdToEyeViewOffset[1] = _eyeOffsets[1]; viewScaleDesc.HmdToEyeViewOffset[1] = _eyeOffsets[1];
ovrLayerHeader* layers = &_sceneLayer.Header; ovrLayerHeader* layers = &_sceneLayer.Header;
ovrResult result = ovr_SubmitFrame(_hmd, frameIndex, &viewScaleDesc, &layers, 1); ovrResult result = ovr_SubmitFrame(_session, frameIndex, &viewScaleDesc, &layers, 1);
if (!OVR_SUCCESS(result)) { if (!OVR_SUCCESS(result)) {
qDebug() << result; qDebug() << result;
} }
} }
_sceneFbo->Increment(); _sceneFbo->Increment();
#endif
/* /*
The swapbuffer call here is only required if we want to mirror the content to the screen. The swapbuffer call here is only required if we want to mirror the content to the screen.

View file

@ -12,12 +12,16 @@
struct SwapFramebufferWrapper; struct SwapFramebufferWrapper;
using SwapFboPtr = QSharedPointer<SwapFramebufferWrapper>; using SwapFboPtr = QSharedPointer<SwapFramebufferWrapper>;
const float TARGET_RATE_Oculus = 75.0f;
class OculusDisplayPlugin : public OculusBaseDisplayPlugin { class OculusDisplayPlugin : public OculusBaseDisplayPlugin {
public: public:
virtual void activate() override; virtual void activate() override;
virtual const QString & getName() const override; virtual const QString & getName() const override;
virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final; virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final;
virtual float getTargetFrameRate() override { return TARGET_RATE_Oculus; }
protected: protected:
virtual void internalPresent() override; virtual void internalPresent() override;
virtual void customizeContext() override; virtual void customizeContext() override;

View file

@ -13,6 +13,8 @@
#include <OVR_CAPI.h> #include <OVR_CAPI.h>
const float TARGET_RATE_OculusLegacy = 75.0f;
class OculusLegacyDisplayPlugin : public WindowOpenGLDisplayPlugin { class OculusLegacyDisplayPlugin : public WindowOpenGLDisplayPlugin {
public: public:
OculusLegacyDisplayPlugin(); OculusLegacyDisplayPlugin();
@ -25,6 +27,8 @@ public:
virtual bool eventFilter(QObject* receiver, QEvent* event) override; virtual bool eventFilter(QObject* receiver, QEvent* event) override;
virtual int getHmdScreen() const override; virtual int getHmdScreen() const override;
virtual float getTargetFrameRate() override { return TARGET_RATE_OculusLegacy; }
// Stereo specific methods // Stereo specific methods
virtual bool isHmd() const override { return true; } virtual bool isHmd() const override { return true; }
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override; virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override;

View file

@ -0,0 +1,27 @@
#
# Created by Bradley Austin Davis on 2015/11/18
# 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
#
# OpenVR is disabled until a) it works with threaded present and
# b) it doesn't interfere with Oculus SDK 0.8
if (FALSE)
#if (WIN32)
# we're using static GLEW, so define GLEW_STATIC
add_definitions(-DGLEW_STATIC)
set(TARGET_NAME openvr)
setup_hifi_plugin(OpenGL Script Qml Widgets)
link_hifi_libraries(shared gl networking controllers
plugins display-plugins input-plugins script-engine
render-utils model gpu render model-networking fbx)
include_hifi_library_headers(octree)
add_dependency_external_projects(OpenVR)
find_package(OpenVR REQUIRED)
target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
endif()

View file

@ -7,24 +7,23 @@
// //
#include "OpenVrDisplayPlugin.h" #include "OpenVrDisplayPlugin.h"
#if defined(Q_OS_WIN)
#include <memory> #include <memory>
#include <QMainWindow> #include <QMainWindow>
#include <QLoggingCategory>
#include <QGLWidget> #include <QGLWidget>
#include <GLMHelpers.h>
#include <QEvent> #include <QEvent>
#include <QResizeEvent> #include <QResizeEvent>
#include <GLMHelpers.h>
#include <gl/GlWindow.h>
#include <PerfStat.h> #include <PerfStat.h>
#include <plugins/PluginContainer.h> #include <plugins/PluginContainer.h>
#include <ViewFrustum.h> #include <ViewFrustum.h>
#include "OpenVrHelpers.h" #include "OpenVrHelpers.h"
#include "GLMHelpers.h"
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(displayplugins) Q_DECLARE_LOGGING_CATEGORY(displayplugins)
Q_LOGGING_CATEGORY(displayplugins, "hifi.displayplugins") Q_LOGGING_CATEGORY(displayplugins, "hifi.displayplugins")
@ -41,12 +40,11 @@ vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount]; mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
static mat4 _sensorResetMat; static mat4 _sensorResetMat;
static uvec2 _windowSize; static uvec2 _windowSize;
static ivec2 _windowPosition;
static uvec2 _renderTargetSize; static uvec2 _renderTargetSize;
struct PerEyeData { struct PerEyeData {
uvec2 _viewportOrigin; //uvec2 _viewportOrigin;
uvec2 _viewportSize; //uvec2 _viewportSize;
mat4 _projectionMatrix; mat4 _projectionMatrix;
mat4 _eyeOffset; mat4 _eyeOffset;
mat4 _pose; mat4 _pose;
@ -89,36 +87,17 @@ void OpenVrDisplayPlugin::activate() {
} }
Q_ASSERT(_hmd); Q_ASSERT(_hmd);
_hmd->GetWindowBounds(&_windowPosition.x, &_windowPosition.y, &_windowSize.x, &_windowSize.y);
_hmd->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y); _hmd->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y);
// Recommended render target size is per-eye, so double the X size for // Recommended render target size is per-eye, so double the X size for
// left + right eyes // left + right eyes
_renderTargetSize.x *= 2; _renderTargetSize.x *= 2;
openvr_for_each_eye([&](vr::Hmd_Eye eye) { openvr_for_each_eye([&](vr::Hmd_Eye eye) {
PerEyeData& eyeData = _eyesData[eye]; PerEyeData& eyeData = _eyesData[eye];
_hmd->GetEyeOutputViewport(eye,
&eyeData._viewportOrigin.x, &eyeData._viewportOrigin.y,
&eyeData._viewportSize.x, &eyeData._viewportSize.y);
eyeData._projectionMatrix = toGlm(_hmd->GetProjectionMatrix(eye, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, vr::API_OpenGL)); eyeData._projectionMatrix = toGlm(_hmd->GetProjectionMatrix(eye, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, vr::API_OpenGL));
eyeData._eyeOffset = toGlm(_hmd->GetEyeToHeadTransform(eye)); eyeData._eyeOffset = toGlm(_hmd->GetEyeToHeadTransform(eye));
}); });
_compositor = vr::VRCompositor();
vr::HmdError eError = vr::HmdError_None;
_compositor = (vr::IVRCompositor*)vr::VR_GetGenericInterface(vr::IVRCompositor_Version, &eError);
Q_ASSERT(eError == vr::HmdError_None);
Q_ASSERT(_compositor); Q_ASSERT(_compositor);
_compositor->SetGraphicsDevice(vr::Compositor_DeviceType_OpenGL, NULL);
uint32_t unSize = _compositor->GetLastError(NULL, 0);
if (unSize > 1) {
char* buffer = new char[unSize];
_compositor->GetLastError(buffer, unSize);
printf("Compositor - %s\n", buffer);
delete[] buffer;
}
Q_ASSERT(unSize <= 1);
WindowOpenGLDisplayPlugin::activate(); WindowOpenGLDisplayPlugin::activate();
} }
@ -132,6 +111,16 @@ void OpenVrDisplayPlugin::deactivate() {
WindowOpenGLDisplayPlugin::deactivate(); WindowOpenGLDisplayPlugin::deactivate();
} }
void OpenVrDisplayPlugin::customizeContext() {
static std::once_flag once;
std::call_once(once, []{
glewExperimental = true;
GLenum err = glewInit();
glGetError();
});
WindowOpenGLDisplayPlugin::customizeContext();
}
uvec2 OpenVrDisplayPlugin::getRecommendedRenderSize() const { uvec2 OpenVrDisplayPlugin::getRecommendedRenderSize() const {
return _renderTargetSize; return _renderTargetSize;
} }
@ -153,33 +142,41 @@ glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
} }
glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const { glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
return _trackedDevicePoseMat4[0]; glm::mat4 result;
{
Lock lock(_mutex);
result = _trackedDevicePoseMat4[0];
}
return result;
} }
void OpenVrDisplayPlugin::customizeContext() {
WindowOpenGLDisplayPlugin::customizeContext(); void OpenVrDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) {
WindowOpenGLDisplayPlugin::submitSceneTexture(frameIndex, sceneTexture, sceneSize);
} }
//void OpenVrDisplayPlugin::display(uint32_t frameIndex, uint32_t finalTexture, const glm::uvec2& sceneSize) { void OpenVrDisplayPlugin::internalPresent() {
// // Flip y-axis since GL UV coords are backwards. // Flip y-axis since GL UV coords are backwards.
// static vr::Compositor_TextureBounds leftBounds{ 0, 1, 0.5f, 0 }; static vr::VRTextureBounds_t leftBounds{ 0, 0, 0.5f, 1 };
// static vr::Compositor_TextureBounds rightBounds{ 0.5f, 1, 1, 0 }; static vr::VRTextureBounds_t rightBounds{ 0.5f, 0, 1, 1 };
// _compositor->Submit(vr::Eye_Left, (void*)finalTexture, &leftBounds); vr::Texture_t texture{ (void*)_currentSceneTexture, vr::API_OpenGL, vr::ColorSpace_Auto };
// _compositor->Submit(vr::Eye_Right, (void*)finalTexture, &rightBounds); {
// glFinish(); Lock lock(_mutex);
//} _compositor->Submit(vr::Eye_Left, &texture, &leftBounds);
_compositor->Submit(vr::Eye_Right, &texture, &rightBounds);
//void OpenVrDisplayPlugin::finishFrame() { }
//// swapBuffers(); glFinish();
// doneCurrent(); {
// _compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount); Lock lock(_mutex);
// for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { _compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0);
// _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking); for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
// } _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking);
// openvr_for_each_eye([&](vr::Hmd_Eye eye) { }
// _eyesData[eye]._pose = _trackedDevicePoseMat4[0]; openvr_for_each_eye([&](vr::Hmd_Eye eye) {
// }); _eyesData[eye]._pose = _trackedDevicePoseMat4[0];
//}; });
}
#endif
//WindowOpenGLDisplayPlugin::internalPresent();
}

View file

@ -9,10 +9,11 @@
#include <QtGlobal> #include <QtGlobal>
#if defined(Q_OS_WIN)
#include <openvr.h> #include <openvr.h>
#include "../WindowOpenGLDisplayPlugin.h" #include <display-plugins/WindowOpenGLDisplayPlugin.h>
const float TARGET_RATE_OpenVr = 90.0f; // FIXME: get from sdk tracked device property? This number is vive-only.
class OpenVrDisplayPlugin : public WindowOpenGLDisplayPlugin { class OpenVrDisplayPlugin : public WindowOpenGLDisplayPlugin {
public: public:
@ -20,9 +21,13 @@ public:
virtual const QString & getName() const override; virtual const QString & getName() const override;
virtual bool isHmd() const override { return true; } virtual bool isHmd() const override { return true; }
virtual float getTargetFrameRate() override { return TARGET_RATE_OpenVr; }
virtual void activate() override; virtual void activate() override;
virtual void deactivate() override; virtual void deactivate() override;
virtual void customizeContext() override;
virtual glm::uvec2 getRecommendedRenderSize() const override; virtual glm::uvec2 getRecommendedRenderSize() const override;
virtual glm::uvec2 getRecommendedUiSize() const override { return uvec2(1920, 1080); } virtual glm::uvec2 getRecommendedUiSize() const override { return uvec2(1920, 1080); }
@ -32,15 +37,13 @@ public:
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override; virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override;
virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override;
protected: protected:
// virtual void display(uint32_t frameIndex, uint32_t finalTexture, const glm::uvec2& sceneSize) override; virtual void internalPresent() override;
virtual void customizeContext() override;
private: private:
vr::IVRSystem* _hmd { nullptr }; vr::IVRSystem* _hmd { nullptr };
static const QString NAME; static const QString NAME;
}; };
#endif

View file

@ -7,14 +7,15 @@
// //
#include "OpenVrHelpers.h" #include "OpenVrHelpers.h"
#if defined(Q_OS_WIN)
#include <QtCore/QTimer>
#include <atomic> #include <atomic>
#include <mutex> #include <mutex>
#include "../Logging.h" #include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <QtCore/QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(displayplugins)
using Mutex = std::mutex; using Mutex = std::mutex;
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
@ -30,13 +31,13 @@ vr::IVRSystem* acquireOpenVrSystem() {
if (hmdPresent) { if (hmdPresent) {
Lock lock(mutex); Lock lock(mutex);
if (!activeHmd) { if (!activeHmd) {
qCDebug(displayPlugins) << "openvr: No vr::IVRSystem instance active, building"; qCDebug(displayplugins) << "openvr: No vr::IVRSystem instance active, building";
vr::HmdError eError = vr::HmdError_None; vr::EVRInitError eError = vr::VRInitError_None;
activeHmd = vr::VR_Init(&eError); activeHmd = vr::VR_Init(&eError);
qCDebug(displayPlugins) << "openvr display: HMD is " << activeHmd << " error is " << eError; qCDebug(displayplugins) << "openvr display: HMD is " << activeHmd << " error is " << eError;
} }
if (activeHmd) { if (activeHmd) {
qCDebug(displayPlugins) << "openvr: incrementing refcount"; qCDebug(displayplugins) << "openvr: incrementing refcount";
++refCount; ++refCount;
} }
} }
@ -46,10 +47,10 @@ vr::IVRSystem* acquireOpenVrSystem() {
void releaseOpenVrSystem() { void releaseOpenVrSystem() {
if (activeHmd) { if (activeHmd) {
Lock lock(mutex); Lock lock(mutex);
qDebug() << "openvr: decrementing refcount"; qCDebug(displayplugins) << "openvr: decrementing refcount";
--refCount; --refCount;
if (0 == refCount) { if (0 == refCount) {
qDebug() << "openvr: zero refcount, deallocate VR system"; qCDebug(displayplugins) << "openvr: zero refcount, deallocate VR system";
// Avoid spamming the VR system with activate/deactivate calls at system startup by // Avoid spamming the VR system with activate/deactivate calls at system startup by
// putting in a delay before we destory the shutdown the VR subsystem // putting in a delay before we destory the shutdown the VR subsystem
@ -71,5 +72,3 @@ void releaseOpenVrSystem() {
} }
} }
} }
#endif

View file

@ -7,9 +7,6 @@
// //
#pragma once #pragma once
#include <QtGlobal>
#if defined(Q_OS_WIN)
#include <openvr.h> #include <openvr.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
@ -18,5 +15,3 @@
vr::IVRSystem* acquireOpenVrSystem(); vr::IVRSystem* acquireOpenVrSystem();
void releaseOpenVrSystem(); void releaseOpenVrSystem();
#endif

View file

@ -0,0 +1,60 @@
//
// Created by Bradley Austin Davis on 2015/10/25
// 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 <mutex>
#include <QtCore/QObject>
#include <QtCore/QtPlugin>
#include <QtCore/QStringList>
#include <plugins/RuntimePlugin.h>
#include "OpenVrDisplayPlugin.h"
#include "ViveControllerManager.h"
class OpenVrProvider : public QObject, public DisplayProvider, InputProvider
{
Q_OBJECT
Q_PLUGIN_METADATA(IID DisplayProvider_iid FILE "plugin.json")
Q_INTERFACES(DisplayProvider)
Q_PLUGIN_METADATA(IID InputProvider_iid FILE "plugin.json")
Q_INTERFACES(InputProvider)
public:
OpenVrProvider(QObject* parent = nullptr) : QObject(parent) {}
virtual ~OpenVrProvider() {}
virtual DisplayPluginList getDisplayPlugins() override {
static std::once_flag once;
std::call_once(once, [&] {
DisplayPluginPointer plugin(new OpenVrDisplayPlugin());
if (plugin->isSupported()) {
_displayPlugins.push_back(plugin);
}
});
return _displayPlugins;
}
virtual InputPluginList getInputPlugins() override {
static std::once_flag once;
std::call_once(once, [&] {
InputPluginPointer plugin(new ViveControllerManager());
if (plugin->isSupported()) {
_inputPlugins.push_back(plugin);
}
});
return _inputPlugins;
}
private:
DisplayPluginList _displayPlugins;
InputPluginList _inputPlugins;
};
#include "OpenVrProvider.moc"

View file

@ -17,7 +17,6 @@
#include <gpu/Batch.h> #include <gpu/Batch.h>
#include <gpu/Context.h> #include <gpu/Context.h>
#include <DeferredLightingEffect.h> #include <DeferredLightingEffect.h>
#include <display-plugins/openvr/OpenVrHelpers.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <plugins/PluginContainer.h> #include <plugins/PluginContainer.h>
#include <UserActivityLogger.h> #include <UserActivityLogger.h>
@ -26,10 +25,10 @@
#include <controllers/StandardControls.h> #include <controllers/StandardControls.h>
#ifdef Q_OS_WIN #include "OpenVrHelpers.h"
extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]; extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount]; extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
#endif
vr::IVRSystem* acquireOpenVrSystem(); vr::IVRSystem* acquireOpenVrSystem();
void releaseOpenVrSystem(); void releaseOpenVrSystem();
@ -39,7 +38,7 @@ static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f,
CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET / 2.0f,
CONTROLLER_LENGTH_OFFSET * 2.0f); CONTROLLER_LENGTH_OFFSET * 2.0f);
static const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; static const char* CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
static const QString MENU_PARENT = "Avatar"; static const QString MENU_PARENT = "Avatar";
static const QString MENU_NAME = "Vive Controllers"; static const QString MENU_NAME = "Vive Controllers";
@ -49,19 +48,14 @@ static const QString RENDER_CONTROLLERS = "Render Hand Controllers";
const QString ViveControllerManager::NAME = "OpenVR"; const QString ViveControllerManager::NAME = "OpenVR";
bool ViveControllerManager::isSupported() const { bool ViveControllerManager::isSupported() const {
#ifdef Q_OS_WIN
auto hmd = acquireOpenVrSystem(); auto hmd = acquireOpenVrSystem();
bool success = hmd != nullptr; bool success = hmd != nullptr;
releaseOpenVrSystem(); releaseOpenVrSystem();
return success; return success;
#else
return false;
#endif
} }
void ViveControllerManager::activate() { void ViveControllerManager::activate() {
InputPlugin::activate(); InputPlugin::activate();
#ifdef Q_OS_WIN
_container->addMenu(MENU_PATH); _container->addMenu(MENU_PATH);
_container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, RENDER_CONTROLLERS, _container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, RENDER_CONTROLLERS,
[this] (bool clicked) { this->setRenderControllers(clicked); }, [this] (bool clicked) { this->setRenderControllers(clicked); },
@ -72,8 +66,11 @@ void ViveControllerManager::activate() {
} }
Q_ASSERT(_hmd); Q_ASSERT(_hmd);
auto renderModels = vr::VRRenderModels();
vr::RenderModel_t model; vr::RenderModel_t model;
if (!_hmd->LoadRenderModel(CONTROLLER_MODEL_STRING.toStdString().c_str(), &model)) { /*
if (!_hmd->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) {
qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING); qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING);
} else { } else {
model::Mesh* mesh = new model::Mesh(); model::Mesh* mesh = new model::Mesh();
@ -118,7 +115,7 @@ void ViveControllerManager::activate() {
_modelLoaded = true; _modelLoaded = true;
_renderControllers = true; _renderControllers = true;
} }
#endif */
// unregister with UserInputMapper // unregister with UserInputMapper
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>(); auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
@ -129,7 +126,6 @@ void ViveControllerManager::activate() {
void ViveControllerManager::deactivate() { void ViveControllerManager::deactivate() {
InputPlugin::deactivate(); InputPlugin::deactivate();
#ifdef Q_OS_WIN
_container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS); _container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
_container->removeMenu(MENU_PATH); _container->removeMenu(MENU_PATH);
@ -139,7 +135,6 @@ void ViveControllerManager::deactivate() {
} }
_inputDevice->_poseStateMap.clear(); _inputDevice->_poseStateMap.clear();
#endif
// unregister with UserInputMapper // unregister with UserInputMapper
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>(); auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
@ -225,7 +220,6 @@ void ViveControllerManager::pluginUpdate(float deltaTime, bool jointsCaptured) {
} }
void ViveControllerManager::InputDevice::update(float deltaTime, bool jointsCaptured) { void ViveControllerManager::InputDevice::update(float deltaTime, bool jointsCaptured) {
#ifdef Q_OS_WIN
_poseStateMap.clear(); _poseStateMap.clear();
_buttonPressedMap.clear(); _buttonPressedMap.clear();
@ -276,7 +270,6 @@ void ViveControllerManager::InputDevice::update(float deltaTime, bool jointsCapt
} }
_trackedControllers = numTrackedControllers; _trackedControllers = numTrackedControllers;
#endif
} }
void ViveControllerManager::InputDevice::focusOutEvent() { void ViveControllerManager::InputDevice::focusOutEvent() {
@ -286,7 +279,6 @@ void ViveControllerManager::InputDevice::focusOutEvent() {
// These functions do translation from the Steam IDs to the standard controller IDs // These functions do translation from the Steam IDs to the standard controller IDs
void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool left) { void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool left) {
#ifdef Q_OS_WIN
//FIX ME? It enters here every frame: probably we want to enter only if an event occurs //FIX ME? It enters here every frame: probably we want to enter only if an event occurs
axis += vr::k_EButton_Axis0; axis += vr::k_EButton_Axis0;
using namespace controller; using namespace controller;
@ -296,12 +288,10 @@ void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x,
} else if (axis == vr::k_EButton_SteamVR_Trigger) { } else if (axis == vr::k_EButton_SteamVR_Trigger) {
_axisStateMap[left ? LT : RT] = x; _axisStateMap[left ? LT : RT] = x;
} }
#endif
} }
// These functions do translation from the Steam IDs to the standard controller IDs // These functions do translation from the Steam IDs to the standard controller IDs
void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool left) { void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool left) {
#ifdef Q_OS_WIN
if (!pressed) { if (!pressed) {
return; return;
} }
@ -319,7 +309,6 @@ void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool
//FIX ME: not able to ovrewrite the behaviour of this button //FIX ME: not able to ovrewrite the behaviour of this button
_buttonPressedMap.insert(left ? controller::LEFT_SECONDARY_THUMB : controller::RIGHT_SECONDARY_THUMB); _buttonPressedMap.insert(left ? controller::LEFT_SECONDARY_THUMB : controller::RIGHT_SECONDARY_THUMB);
} }
#endif
} }
void ViveControllerManager::InputDevice::handlePoseEvent(const mat4& mat, bool left) { void ViveControllerManager::InputDevice::handlePoseEvent(const mat4& mat, bool left) {

View file

@ -20,7 +20,7 @@
#include <model/Geometry.h> #include <model/Geometry.h>
#include <gpu/Texture.h> #include <gpu/Texture.h>
#include <controllers/InputDevice.h> #include <controllers/InputDevice.h>
#include "InputPlugin.h" #include <plugins/InputPlugin.h>
#include <RenderArgs.h> #include <RenderArgs.h>
#include <render/Scene.h> #include <render/Scene.h>

View file

@ -0,0 +1 @@
{}