mirror of
https://github.com/overte-org/overte.git
synced 2025-07-15 16:57:10 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into color
This commit is contained in:
commit
e4aab4bd97
60 changed files with 628 additions and 428 deletions
|
@ -226,7 +226,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
||||||
// if the allowed editors list is empty then everyone can adjust locks
|
// if the allowed editors list is empty then everyone can adjust locks
|
||||||
bool canAdjustLocks = allowedEditors.empty();
|
bool canAdjustLocks = allowedEditors.empty();
|
||||||
|
|
||||||
if (allowedEditors.contains(username)) {
|
if (allowedEditors.contains(username, Qt::CaseInsensitive)) {
|
||||||
// we have a non-empty allowed editors list - check if this user is verified to be in it
|
// we have a non-empty allowed editors list - check if this user is verified to be in it
|
||||||
if (!verifiedUsername) {
|
if (!verifiedUsername) {
|
||||||
if (!verifyUserSignature(username, usernameSignature, HifiSockAddr())) {
|
if (!verifyUserSignature(username, usernameSignature, HifiSockAddr())) {
|
||||||
|
|
|
@ -564,12 +564,12 @@ CameraTool = function(cameraManager) {
|
||||||
|
|
||||||
var ORIENTATION_OVERLAY_SIZE = 26;
|
var ORIENTATION_OVERLAY_SIZE = 26;
|
||||||
var ORIENTATION_OVERLAY_HALF_SIZE = ORIENTATION_OVERLAY_SIZE / 2;
|
var ORIENTATION_OVERLAY_HALF_SIZE = ORIENTATION_OVERLAY_SIZE / 2;
|
||||||
var ORIENTATION_OVERLAY_CUBE_SIZE = 10.5,
|
var ORIENTATION_OVERLAY_CUBE_SIZE = 10.5;
|
||||||
|
|
||||||
var ORIENTATION_OVERLAY_OFFSET = {
|
var ORIENTATION_OVERLAY_OFFSET = {
|
||||||
x: 30,
|
x: 30,
|
||||||
y: 30,
|
y: 30,
|
||||||
}
|
}
|
||||||
|
|
||||||
var UI_WIDTH = 70;
|
var UI_WIDTH = 70;
|
||||||
var UI_HEIGHT = 70;
|
var UI_HEIGHT = 70;
|
||||||
|
|
|
@ -6,7 +6,7 @@ SoundArray = function(audioOptions, autoUpdateAudioPosition) {
|
||||||
this.audioOptions = audioOptions !== undefined ? audioOptions : {};
|
this.audioOptions = audioOptions !== undefined ? audioOptions : {};
|
||||||
this.autoUpdateAudioPosition = autoUpdateAudioPosition !== undefined ? autoUpdateAudioPosition : false;
|
this.autoUpdateAudioPosition = autoUpdateAudioPosition !== undefined ? autoUpdateAudioPosition : false;
|
||||||
if (this.audioOptions.position === undefined) {
|
if (this.audioOptions.position === undefined) {
|
||||||
this.audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0}),
|
this.audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0});
|
||||||
}
|
}
|
||||||
if (this.audioOptions.volume === undefined) {
|
if (this.audioOptions.volume === undefined) {
|
||||||
this.audioOptions.volume = 1.0;
|
this.audioOptions.volume = 1.0;
|
||||||
|
|
|
@ -96,7 +96,8 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# link required hifi libraries
|
# link required hifi libraries
|
||||||
link_hifi_libraries(shared octree environment gpu procedural model render fbx networking model-networking entities avatars
|
link_hifi_libraries(shared octree environment gpu gl procedural model render
|
||||||
|
fbx networking model-networking entities avatars
|
||||||
audio audio-client animation script-engine physics
|
audio audio-client animation script-engine physics
|
||||||
render-utils entities-renderer ui auto-updater
|
render-utils entities-renderer ui auto-updater
|
||||||
plugins display-plugins input-plugins)
|
plugins display-plugins input-plugins)
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
#include <ObjectMotionState.h>
|
#include <ObjectMotionState.h>
|
||||||
#include <OctalCode.h>
|
#include <OctalCode.h>
|
||||||
#include <OctreeSceneStats.h>
|
#include <OctreeSceneStats.h>
|
||||||
#include <OffscreenGlCanvas.h>
|
#include <gl/OffscreenGlCanvas.h>
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <PhysicsEngine.h>
|
#include <PhysicsEngine.h>
|
||||||
|
@ -2756,7 +2756,6 @@ void Application::update(float deltaTime) {
|
||||||
|
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("physics");
|
PerformanceTimer perfTimer("physics");
|
||||||
myAvatar->relayDriveKeysToCharacterController();
|
|
||||||
|
|
||||||
static VectorOfMotionStates motionStates;
|
static VectorOfMotionStates motionStates;
|
||||||
_entitySimulation.getObjectsToDelete(motionStates);
|
_entitySimulation.getObjectsToDelete(motionStates);
|
||||||
|
@ -2783,6 +2782,8 @@ void Application::update(float deltaTime) {
|
||||||
avatarManager->getObjectsToChange(motionStates);
|
avatarManager->getObjectsToChange(motionStates);
|
||||||
_physicsEngine->changeObjects(motionStates);
|
_physicsEngine->changeObjects(motionStates);
|
||||||
|
|
||||||
|
myAvatar->prepareForPhysicsSimulation();
|
||||||
|
|
||||||
_entities.getTree()->withWriteLock([&] {
|
_entities.getTree()->withWriteLock([&] {
|
||||||
_physicsEngine->stepSimulation();
|
_physicsEngine->stepSimulation();
|
||||||
});
|
});
|
||||||
|
@ -2807,6 +2808,8 @@ void Application::update(float deltaTime) {
|
||||||
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
|
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
|
||||||
_entities.update(); // update the models...
|
_entities.update(); // update the models...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myAvatar->harvestResultsFromPhysicsSimulation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,8 @@ void MyAvatar::reset(bool andReload) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset dynamic state.
|
// Reset dynamic state.
|
||||||
_wasPushing = _isPushing = _isBraking = _billboardValid = _straighteningLean = false;
|
_wasPushing = _isPushing = _isBraking = _billboardValid = false;
|
||||||
|
_isFollowingHMD = false;
|
||||||
_skeletonModel.reset();
|
_skeletonModel.reset();
|
||||||
getHead()->reset();
|
getHead()->reset();
|
||||||
_targetVelocity = glm::vec3(0.0f);
|
_targetVelocity = glm::vec3(0.0f);
|
||||||
|
@ -304,7 +305,7 @@ glm::mat4 MyAvatar::getSensorToWorldMatrix() const {
|
||||||
|
|
||||||
// returns true if pos is OUTSIDE of the vertical capsule
|
// returns true if pos is OUTSIDE of the vertical capsule
|
||||||
// where the middle cylinder length is defined by capsuleLen and the radius by capsuleRad.
|
// where the middle cylinder length is defined by capsuleLen and the radius by capsuleRad.
|
||||||
static bool capsuleCheck(const glm::vec3& pos, float capsuleLen, float capsuleRad) {
|
static bool pointIsOutsideCapsule(const glm::vec3& pos, float capsuleLen, float capsuleRad) {
|
||||||
const float halfCapsuleLen = capsuleLen / 2.0f;
|
const float halfCapsuleLen = capsuleLen / 2.0f;
|
||||||
if (fabs(pos.y) <= halfCapsuleLen) {
|
if (fabs(pos.y) <= halfCapsuleLen) {
|
||||||
// cylinder check for middle capsule
|
// cylinder check for middle capsule
|
||||||
|
@ -325,6 +326,10 @@ static bool capsuleCheck(const glm::vec3& pos, float capsuleLen, float capsuleRa
|
||||||
// This can also update the avatar's position to follow the HMD
|
// This can also update the avatar's position to follow the HMD
|
||||||
// as it moves through the world.
|
// as it moves through the world.
|
||||||
void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
||||||
|
// update the sensorMatrices based on the new hmd pose
|
||||||
|
_hmdSensorMatrix = hmdSensorMatrix;
|
||||||
|
_hmdSensorPosition = extractTranslation(hmdSensorMatrix);
|
||||||
|
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
|
||||||
|
|
||||||
// calc deltaTime
|
// calc deltaTime
|
||||||
auto now = usecTimestampNow();
|
auto now = usecTimestampNow();
|
||||||
|
@ -334,11 +339,6 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
||||||
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
||||||
float deltaTime = glm::clamp((float)actualDeltaTime, 0.0f, BIGGEST_DELTA_TIME_SECS);
|
float deltaTime = glm::clamp((float)actualDeltaTime, 0.0f, BIGGEST_DELTA_TIME_SECS);
|
||||||
|
|
||||||
// update the sensorMatrices based on the new hmd pose
|
|
||||||
_hmdSensorMatrix = hmdSensorMatrix;
|
|
||||||
_hmdSensorPosition = extractTranslation(hmdSensorMatrix);
|
|
||||||
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
|
|
||||||
|
|
||||||
bool hmdIsAtRest = _hmdAtRestDetector.update(deltaTime, _hmdSensorPosition, _hmdSensorOrientation);
|
bool hmdIsAtRest = _hmdAtRestDetector.update(deltaTime, _hmdSensorPosition, _hmdSensorOrientation);
|
||||||
|
|
||||||
// It can be more accurate/smooth to use velocity rather than position,
|
// It can be more accurate/smooth to use velocity rather than position,
|
||||||
|
@ -360,58 +360,60 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
||||||
bool justStartedMoving = (_lastIsMoving != isMoving) && isMoving;
|
bool justStartedMoving = (_lastIsMoving != isMoving) && isMoving;
|
||||||
_lastIsMoving = isMoving;
|
_lastIsMoving = isMoving;
|
||||||
|
|
||||||
if (shouldBeginStraighteningLean() || hmdIsAtRest || justStartedMoving) {
|
if (shouldFollowHMD() || hmdIsAtRest || justStartedMoving) {
|
||||||
beginStraighteningLean();
|
beginFollowingHMD();
|
||||||
}
|
}
|
||||||
|
|
||||||
processStraighteningLean(deltaTime);
|
followHMD(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::beginStraighteningLean() {
|
glm::vec3 MyAvatar::getHMDCorrectionVelocity() const {
|
||||||
|
// TODO: impelement this
|
||||||
|
return Vectors::ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::beginFollowingHMD() {
|
||||||
// begin homing toward derived body position.
|
// begin homing toward derived body position.
|
||||||
if (!_straighteningLean) {
|
if (!_isFollowingHMD) {
|
||||||
_straighteningLean = true;
|
_isFollowingHMD = true;
|
||||||
_straighteningLeanAlpha = 0.0f;
|
_followHMDAlpha = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::shouldBeginStraighteningLean() const {
|
bool MyAvatar::shouldFollowHMD() const {
|
||||||
// define a vertical capsule
|
if (!_isFollowingHMD) {
|
||||||
const float STRAIGHTENING_LEAN_CAPSULE_RADIUS = 0.2f; // meters
|
// define a vertical capsule
|
||||||
const float STRAIGHTENING_LEAN_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters.
|
const float FOLLOW_HMD_CAPSULE_RADIUS = 0.2f; // meters
|
||||||
|
const float FOLLOW_HMD_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters.
|
||||||
// detect if the derived body position is outside of a capsule around the _bodySensorMatrix
|
|
||||||
auto newBodySensorMatrix = deriveBodyFromHMDSensor();
|
// detect if the derived body position is outside of a capsule around the _bodySensorMatrix
|
||||||
glm::vec3 diff = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix);
|
auto newBodySensorMatrix = deriveBodyFromHMDSensor();
|
||||||
bool isBodyPosOutsideCapsule = capsuleCheck(diff, STRAIGHTENING_LEAN_CAPSULE_LENGTH, STRAIGHTENING_LEAN_CAPSULE_RADIUS);
|
glm::vec3 localPoint = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix);
|
||||||
|
return pointIsOutsideCapsule(localPoint, FOLLOW_HMD_CAPSULE_LENGTH, FOLLOW_HMD_CAPSULE_RADIUS);
|
||||||
if (isBodyPosOutsideCapsule) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::processStraighteningLean(float deltaTime) {
|
void MyAvatar::followHMD(float deltaTime) {
|
||||||
if (_straighteningLean) {
|
if (_isFollowingHMD) {
|
||||||
|
|
||||||
const float STRAIGHTENING_LEAN_DURATION = 0.5f; // seconds
|
const float FOLLOW_HMD_DURATION = 0.5f; // seconds
|
||||||
|
|
||||||
auto newBodySensorMatrix = deriveBodyFromHMDSensor();
|
auto newBodySensorMatrix = deriveBodyFromHMDSensor();
|
||||||
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
||||||
glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix);
|
glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix);
|
||||||
glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
||||||
|
|
||||||
_straighteningLeanAlpha += (1.0f / STRAIGHTENING_LEAN_DURATION) * deltaTime;
|
_followHMDAlpha += (1.0f / FOLLOW_HMD_DURATION) * deltaTime;
|
||||||
|
|
||||||
if (_straighteningLeanAlpha >= 1.0f) {
|
if (_followHMDAlpha >= 1.0f) {
|
||||||
_straighteningLean = false;
|
_isFollowingHMD = false;
|
||||||
nextAttitude(worldBodyPos, worldBodyRot);
|
nextAttitude(worldBodyPos, worldBodyRot);
|
||||||
_bodySensorMatrix = newBodySensorMatrix;
|
_bodySensorMatrix = newBodySensorMatrix;
|
||||||
} else {
|
} else {
|
||||||
// interp position toward the desired pos
|
// interp position toward the desired pos
|
||||||
glm::vec3 pos = lerp(getPosition(), worldBodyPos, _straighteningLeanAlpha);
|
glm::vec3 pos = lerp(getPosition(), worldBodyPos, _followHMDAlpha);
|
||||||
glm::quat rot = glm::normalize(safeMix(getOrientation(), worldBodyRot, _straighteningLeanAlpha));
|
glm::quat rot = glm::normalize(safeMix(getOrientation(), worldBodyRot, _followHMDAlpha));
|
||||||
nextAttitude(pos, rot);
|
nextAttitude(pos, rot);
|
||||||
|
|
||||||
// interp sensor matrix toward desired
|
// interp sensor matrix toward desired
|
||||||
|
@ -419,8 +421,8 @@ void MyAvatar::processStraighteningLean(float deltaTime) {
|
||||||
glm::quat nextBodyRot = glm::normalize(glm::quat_cast(newBodySensorMatrix));
|
glm::quat nextBodyRot = glm::normalize(glm::quat_cast(newBodySensorMatrix));
|
||||||
glm::vec3 prevBodyPos = extractTranslation(_bodySensorMatrix);
|
glm::vec3 prevBodyPos = extractTranslation(_bodySensorMatrix);
|
||||||
glm::quat prevBodyRot = glm::normalize(glm::quat_cast(_bodySensorMatrix));
|
glm::quat prevBodyRot = glm::normalize(glm::quat_cast(_bodySensorMatrix));
|
||||||
pos = lerp(prevBodyPos, nextBodyPos, _straighteningLeanAlpha);
|
pos = lerp(prevBodyPos, nextBodyPos, _followHMDAlpha);
|
||||||
rot = glm::normalize(safeMix(prevBodyRot, nextBodyRot, _straighteningLeanAlpha));
|
rot = glm::normalize(safeMix(prevBodyRot, nextBodyRot, _followHMDAlpha));
|
||||||
_bodySensorMatrix = createMatFromQuatAndPos(rot, pos);
|
_bodySensorMatrix = createMatFromQuatAndPos(rot, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1274,6 +1276,23 @@ void MyAvatar::rebuildSkeletonBody() {
|
||||||
_characterController.setLocalBoundingBox(corner, scale);
|
_characterController.setLocalBoundingBox(corner, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::prepareForPhysicsSimulation() {
|
||||||
|
relayDriveKeysToCharacterController();
|
||||||
|
_characterController.setTargetVelocity(getTargetVelocity());
|
||||||
|
_characterController.setAvatarPositionAndOrientation(getPosition(), getOrientation());
|
||||||
|
_characterController.setHMDVelocity(getHMDCorrectionVelocity());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::harvestResultsFromPhysicsSimulation() {
|
||||||
|
glm::vec3 position = getPosition();
|
||||||
|
glm::quat orientation = getOrientation();
|
||||||
|
_characterController.getAvatarPositionAndOrientation(position, orientation);
|
||||||
|
nextAttitude(position, orientation);
|
||||||
|
setVelocity(_characterController.getLinearVelocity());
|
||||||
|
// TODO: harvest HMD shift here
|
||||||
|
//glm::vec3 hmdShift = _characterController.getHMDShift();
|
||||||
|
}
|
||||||
|
|
||||||
QString MyAvatar::getScriptedMotorFrame() const {
|
QString MyAvatar::getScriptedMotorFrame() const {
|
||||||
QString frame = "avatar";
|
QString frame = "avatar";
|
||||||
if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) {
|
if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) {
|
||||||
|
|
|
@ -12,12 +12,15 @@
|
||||||
#ifndef hifi_MyAvatar_h
|
#ifndef hifi_MyAvatar_h
|
||||||
#define hifi_MyAvatar_h
|
#define hifi_MyAvatar_h
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include <SettingHandle.h>
|
#include <SettingHandle.h>
|
||||||
#include <DynamicCharacterController.h>
|
|
||||||
#include <Rig.h>
|
#include <Rig.h>
|
||||||
|
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
#include "AtRestDetector.h"
|
#include "AtRestDetector.h"
|
||||||
|
#include "MyCharacterController.h"
|
||||||
|
|
||||||
|
|
||||||
class ModelItemID;
|
class ModelItemID;
|
||||||
|
|
||||||
|
@ -72,6 +75,8 @@ public:
|
||||||
// as it moves through the world.
|
// as it moves through the world.
|
||||||
void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix);
|
void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix);
|
||||||
|
|
||||||
|
glm::vec3 getHMDCorrectionVelocity() const;
|
||||||
|
|
||||||
// best called at end of main loop, just before rendering.
|
// best called at end of main loop, just before rendering.
|
||||||
// update sensor to world matrix from current body position and hmd sensor.
|
// update sensor to world matrix from current body position and hmd sensor.
|
||||||
// This is so the correct camera can be used for rendering.
|
// This is so the correct camera can be used for rendering.
|
||||||
|
@ -154,10 +159,12 @@ public:
|
||||||
|
|
||||||
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
|
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
|
||||||
|
|
||||||
DynamicCharacterController* getCharacterController() { return &_characterController; }
|
MyCharacterController* getCharacterController() { return &_characterController; }
|
||||||
|
|
||||||
|
void prepareForPhysicsSimulation();
|
||||||
|
void harvestResultsFromPhysicsSimulation();
|
||||||
|
|
||||||
const QString& getCollisionSoundURL() {return _collisionSoundURL; }
|
const QString& getCollisionSoundURL() { return _collisionSoundURL; }
|
||||||
void setCollisionSoundURL(const QString& url);
|
void setCollisionSoundURL(const QString& url);
|
||||||
|
|
||||||
void clearScriptableSettings();
|
void clearScriptableSettings();
|
||||||
|
@ -262,9 +269,9 @@ private:
|
||||||
const RecorderPointer getRecorder() const { return _recorder; }
|
const RecorderPointer getRecorder() const { return _recorder; }
|
||||||
const PlayerPointer getPlayer() const { return _player; }
|
const PlayerPointer getPlayer() const { return _player; }
|
||||||
|
|
||||||
void beginStraighteningLean();
|
void beginFollowingHMD();
|
||||||
bool shouldBeginStraighteningLean() const;
|
bool shouldFollowHMD() const;
|
||||||
void processStraighteningLean(float deltaTime);
|
void followHMD(float deltaTime);
|
||||||
|
|
||||||
bool cameraInsideHead() const;
|
bool cameraInsideHead() const;
|
||||||
|
|
||||||
|
@ -295,7 +302,7 @@ private:
|
||||||
quint32 _motionBehaviors;
|
quint32 _motionBehaviors;
|
||||||
QString _collisionSoundURL;
|
QString _collisionSoundURL;
|
||||||
|
|
||||||
DynamicCharacterController _characterController;
|
MyCharacterController _characterController;
|
||||||
|
|
||||||
AvatarWeakPointer _lookAtTargetAvatar;
|
AvatarWeakPointer _lookAtTargetAvatar;
|
||||||
glm::vec3 _targetAvatarPosition;
|
glm::vec3 _targetAvatarPosition;
|
||||||
|
@ -348,21 +355,21 @@ private:
|
||||||
RigPointer _rig;
|
RigPointer _rig;
|
||||||
bool _prevShouldDrawHead;
|
bool _prevShouldDrawHead;
|
||||||
|
|
||||||
bool _enableDebugDrawBindPose = false;
|
bool _enableDebugDrawBindPose { false };
|
||||||
bool _enableDebugDrawAnimPose = false;
|
bool _enableDebugDrawAnimPose { false };
|
||||||
AnimSkeleton::ConstPointer _debugDrawSkeleton = nullptr;
|
AnimSkeleton::ConstPointer _debugDrawSkeleton { nullptr };
|
||||||
|
|
||||||
AudioListenerMode _audioListenerMode;
|
AudioListenerMode _audioListenerMode;
|
||||||
glm::vec3 _customListenPosition;
|
glm::vec3 _customListenPosition;
|
||||||
glm::quat _customListenOrientation;
|
glm::quat _customListenOrientation;
|
||||||
|
|
||||||
bool _straighteningLean = false;
|
bool _isFollowingHMD { false };
|
||||||
float _straighteningLeanAlpha = 0.0f;
|
float _followHMDAlpha { 0.0f };
|
||||||
|
|
||||||
quint64 _lastUpdateFromHMDTime = usecTimestampNow();
|
quint64 _lastUpdateFromHMDTime { usecTimestampNow() };
|
||||||
AtRestDetector _hmdAtRestDetector;
|
AtRestDetector _hmdAtRestDetector;
|
||||||
glm::vec3 _lastPosition;
|
glm::vec3 _lastPosition;
|
||||||
bool _lastIsMoving = false;
|
bool _lastIsMoving { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||||
|
|
|
@ -1,13 +1,26 @@
|
||||||
|
//
|
||||||
|
// MyCharacterController.h
|
||||||
|
// interface/src/avatar
|
||||||
|
//
|
||||||
|
// Created by AndrewMeadows 2015.10.21
|
||||||
|
// 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 "MyCharacterController.h"
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btMultiSphereShape.h>
|
#include <BulletCollision/CollisionShapes/btMultiSphereShape.h>
|
||||||
#include <BulletDynamics/Dynamics/btRigidBody.h>
|
#include <BulletDynamics/Dynamics/btRigidBody.h>
|
||||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||||
#include <LinearMath/btDefaultMotionState.h>
|
#include <LinearMath/btDefaultMotionState.h>
|
||||||
|
|
||||||
|
#include <GLMHelpers.h>
|
||||||
|
#include <PhysicsLogging.h>
|
||||||
#include <PhysicsCollisionGroups.h>
|
#include <PhysicsCollisionGroups.h>
|
||||||
|
|
||||||
#include "BulletUtil.h"
|
#include "MyAvatar.h"
|
||||||
#include "DynamicCharacterController.h"
|
|
||||||
#include "PhysicsLogging.h"
|
|
||||||
|
|
||||||
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
|
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
|
||||||
const float DEFAULT_GRAVITY = -5.0f;
|
const float DEFAULT_GRAVITY = -5.0f;
|
||||||
|
@ -15,11 +28,6 @@ const float JUMP_SPEED = 3.5f;
|
||||||
|
|
||||||
const float MAX_FALL_HEIGHT = 20.0f;
|
const float MAX_FALL_HEIGHT = 20.0f;
|
||||||
|
|
||||||
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_UPDATE_SHAPE = 1U << 2;
|
|
||||||
const uint32_t PENDING_FLAG_JUMP = 1U << 3;
|
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -41,19 +49,18 @@ protected:
|
||||||
btRigidBody* _me;
|
btRigidBody* _me;
|
||||||
};
|
};
|
||||||
|
|
||||||
DynamicCharacterController::DynamicCharacterController(AvatarData* avatarData) {
|
MyCharacterController::MyCharacterController(MyAvatar* avatar) {
|
||||||
_halfHeight = 1.0f;
|
_halfHeight = 1.0f;
|
||||||
_shape = nullptr;
|
|
||||||
_rigidBody = nullptr;
|
|
||||||
|
|
||||||
assert(avatarData);
|
assert(avatar);
|
||||||
_avatarData = avatarData;
|
_avatar = avatar;
|
||||||
|
|
||||||
_enabled = false;
|
_enabled = false;
|
||||||
|
|
||||||
_floorDistance = MAX_FALL_HEIGHT;
|
_floorDistance = MAX_FALL_HEIGHT;
|
||||||
|
|
||||||
_walkVelocity.setValue(0.0f,0.0f,0.0f);
|
_walkVelocity.setValue(0.0f, 0.0f, 0.0f);
|
||||||
|
_hmdVelocity.setValue(0.0f, 0.0f, 0.0f);
|
||||||
_jumpSpeed = JUMP_SPEED;
|
_jumpSpeed = JUMP_SPEED;
|
||||||
_isOnGround = false;
|
_isOnGround = false;
|
||||||
_isJumping = false;
|
_isJumping = false;
|
||||||
|
@ -61,21 +68,16 @@ DynamicCharacterController::DynamicCharacterController(AvatarData* avatarData) {
|
||||||
_isHovering = true;
|
_isHovering = true;
|
||||||
_isPushingUp = false;
|
_isPushingUp = false;
|
||||||
_jumpToHoverStart = 0;
|
_jumpToHoverStart = 0;
|
||||||
|
_lastStepDuration = 0.0f;
|
||||||
|
|
||||||
_pendingFlags = PENDING_FLAG_UPDATE_SHAPE;
|
_pendingFlags = PENDING_FLAG_UPDATE_SHAPE;
|
||||||
updateShapeIfNecessary();
|
updateShapeIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicCharacterController::~DynamicCharacterController() {
|
MyCharacterController::~MyCharacterController() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
void MyCharacterController::preStep(btCollisionWorld* collisionWorld) {
|
||||||
void DynamicCharacterController::setWalkDirection(const btVector3& walkDirection) {
|
|
||||||
// do nothing -- walkVelocity is upated in preSimulation()
|
|
||||||
//_walkVelocity = walkDirection;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DynamicCharacterController::preStep(btCollisionWorld* collisionWorld) {
|
|
||||||
// trace a ray straight down to see if we're standing on the ground
|
// trace a ray straight down to see if we're standing on the ground
|
||||||
const btTransform& xform = _rigidBody->getWorldTransform();
|
const btTransform& xform = _rigidBody->getWorldTransform();
|
||||||
|
|
||||||
|
@ -96,7 +98,7 @@ void DynamicCharacterController::preStep(btCollisionWorld* collisionWorld) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
|
void MyCharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
|
||||||
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
|
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
|
||||||
btScalar actualSpeed = actualVelocity.length();
|
btScalar actualSpeed = actualVelocity.length();
|
||||||
|
|
||||||
|
@ -158,9 +160,20 @@ void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld, btScala
|
||||||
_rigidBody->setLinearVelocity(actualVelocity + tau * velocityCorrection);
|
_rigidBody->setLinearVelocity(actualVelocity + tau * velocityCorrection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rather than add _hmdVelocity to the velocity of the RigidBody, we explicitly teleport
|
||||||
|
// the RigidBody forward according to the formula: distance = rate * time
|
||||||
|
if (_hmdVelocity.length2() > 0.0f) {
|
||||||
|
btTransform bodyTransform = _rigidBody->getWorldTransform();
|
||||||
|
bodyTransform.setOrigin(bodyTransform.getOrigin() + dt * _hmdVelocity);
|
||||||
|
_rigidBody->setWorldTransform(bodyTransform);
|
||||||
|
}
|
||||||
|
// MyAvatar will ask us how far we stepped for HMD motion, which will depend on how
|
||||||
|
// much time has accumulated in _lastStepDuration.
|
||||||
|
_lastStepDuration += dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicCharacterController::jump() {
|
void MyCharacterController::jump() {
|
||||||
// check for case where user is holding down "jump" key...
|
// check for case where user is holding down "jump" key...
|
||||||
// we'll eventually tansition to "hover"
|
// we'll eventually tansition to "hover"
|
||||||
if (!_isJumping) {
|
if (!_isJumping) {
|
||||||
|
@ -178,12 +191,12 @@ void DynamicCharacterController::jump() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DynamicCharacterController::onGround() const {
|
bool MyCharacterController::onGround() const {
|
||||||
const btScalar FLOOR_PROXIMITY_THRESHOLD = 0.3f * _radius;
|
const btScalar FLOOR_PROXIMITY_THRESHOLD = 0.3f * _radius;
|
||||||
return _floorDistance < FLOOR_PROXIMITY_THRESHOLD;
|
return _floorDistance < FLOOR_PROXIMITY_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicCharacterController::setHovering(bool hover) {
|
void MyCharacterController::setHovering(bool hover) {
|
||||||
if (hover != _isHovering) {
|
if (hover != _isHovering) {
|
||||||
_isHovering = hover;
|
_isHovering = hover;
|
||||||
_isJumping = false;
|
_isJumping = false;
|
||||||
|
@ -198,7 +211,7 @@ void DynamicCharacterController::setHovering(bool hover) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicCharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) {
|
void MyCharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) {
|
||||||
_boxScale = scale;
|
_boxScale = scale;
|
||||||
|
|
||||||
float x = _boxScale.x;
|
float x = _boxScale.x;
|
||||||
|
@ -231,15 +244,7 @@ void DynamicCharacterController::setLocalBoundingBox(const glm::vec3& corner, co
|
||||||
_shapeLocalOffset = corner + 0.5f * _boxScale;
|
_shapeLocalOffset = corner + 0.5f * _boxScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DynamicCharacterController::needsRemoval() const {
|
void MyCharacterController::setEnabled(bool enabled) {
|
||||||
return (bool)(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DynamicCharacterController::needsAddition() const {
|
|
||||||
return (bool)(_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DynamicCharacterController::setEnabled(bool enabled) {
|
|
||||||
if (enabled != _enabled) {
|
if (enabled != _enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
// Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit.
|
// Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit.
|
||||||
|
@ -257,46 +262,9 @@ void DynamicCharacterController::setEnabled(bool enabled) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicCharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
void MyCharacterController::updateShapeIfNecessary() {
|
||||||
if (_dynamicsWorld != world) {
|
|
||||||
if (_dynamicsWorld) {
|
|
||||||
if (_rigidBody) {
|
|
||||||
_dynamicsWorld->removeRigidBody(_rigidBody);
|
|
||||||
_dynamicsWorld->removeAction(this);
|
|
||||||
}
|
|
||||||
_dynamicsWorld = nullptr;
|
|
||||||
}
|
|
||||||
if (world && _rigidBody) {
|
|
||||||
_dynamicsWorld = world;
|
|
||||||
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
|
||||||
_dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR);
|
|
||||||
_dynamicsWorld->addAction(this);
|
|
||||||
//reset(_dynamicsWorld);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_dynamicsWorld) {
|
|
||||||
if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
|
|
||||||
// shouldn't fall in here, but if we do make sure both ADD and REMOVE bits are still set
|
|
||||||
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
|
||||||
} else {
|
|
||||||
_pendingFlags &= ~PENDING_FLAG_ADD_TO_SIMULATION;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DynamicCharacterController::updateShapeIfNecessary() {
|
|
||||||
if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
|
if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
|
||||||
// make sure there is NO pending removal from simulation at this point
|
|
||||||
// (don't want to delete _rigidBody out from under the simulation)
|
|
||||||
assert(!(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION));
|
|
||||||
_pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE;
|
_pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE;
|
||||||
// delete shape and RigidBody
|
|
||||||
delete _rigidBody;
|
|
||||||
_rigidBody = nullptr;
|
|
||||||
delete _shape;
|
|
||||||
_shape = nullptr;
|
|
||||||
|
|
||||||
// compute new dimensions from avatar's bounding box
|
// compute new dimensions from avatar's bounding box
|
||||||
float x = _boxScale.x;
|
float x = _boxScale.x;
|
||||||
|
@ -310,19 +278,27 @@ void DynamicCharacterController::updateShapeIfNecessary() {
|
||||||
// NOTE: _shapeLocalOffset is already computed
|
// NOTE: _shapeLocalOffset is already computed
|
||||||
|
|
||||||
if (_radius > 0.0f) {
|
if (_radius > 0.0f) {
|
||||||
// create new shape
|
|
||||||
_shape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
|
|
||||||
|
|
||||||
// HACK: use some simple mass property defaults for now
|
// HACK: use some simple mass property defaults for now
|
||||||
float mass = 100.0f;
|
float mass = 100.0f;
|
||||||
btVector3 inertia(30.0f, 8.0f, 30.0f);
|
btVector3 inertia(30.0f, 8.0f, 30.0f);
|
||||||
|
|
||||||
// create new body
|
// create RigidBody if it doesn't exist
|
||||||
_rigidBody = new btRigidBody(mass, nullptr, _shape, inertia);
|
if (!_rigidBody) {
|
||||||
|
btCollisionShape* shape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
|
||||||
|
_rigidBody = new btRigidBody(mass, nullptr, shape, inertia);
|
||||||
|
} else {
|
||||||
|
btCollisionShape* shape = _rigidBody->getCollisionShape();
|
||||||
|
if (shape) {
|
||||||
|
delete shape;
|
||||||
|
}
|
||||||
|
shape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
|
||||||
|
_rigidBody->setCollisionShape(shape);
|
||||||
|
}
|
||||||
|
|
||||||
_rigidBody->setSleepingThresholds(0.0f, 0.0f);
|
_rigidBody->setSleepingThresholds(0.0f, 0.0f);
|
||||||
_rigidBody->setAngularFactor(0.0f);
|
_rigidBody->setAngularFactor(0.0f);
|
||||||
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
|
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()),
|
||||||
glmToBullet(_avatarData->getPosition())));
|
glmToBullet(_avatar->getPosition())));
|
||||||
if (_isHovering) {
|
if (_isHovering) {
|
||||||
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
||||||
} else {
|
} else {
|
||||||
|
@ -335,7 +311,7 @@ void DynamicCharacterController::updateShapeIfNecessary() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicCharacterController::updateUpAxis(const glm::quat& rotation) {
|
void MyCharacterController::updateUpAxis(const glm::quat& rotation) {
|
||||||
btVector3 oldUp = _currentUp;
|
btVector3 oldUp = _currentUp;
|
||||||
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
|
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
|
||||||
if (!_isHovering) {
|
if (!_isHovering) {
|
||||||
|
@ -346,24 +322,50 @@ void DynamicCharacterController::updateUpAxis(const glm::quat& rotation) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicCharacterController::preSimulation(btScalar timeStep) {
|
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::setHMDVelocity(const glm::vec3& velocity) {
|
||||||
|
_hmdVelocity = 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) {
|
if (_enabled && _dynamicsWorld) {
|
||||||
glm::quat rotation = _avatarData->getOrientation();
|
// slam body to where it is supposed to be
|
||||||
|
_rigidBody->setWorldTransform(_avatarBodyTransform);
|
||||||
// TODO: update gravity if up has changed
|
|
||||||
updateUpAxis(rotation);
|
|
||||||
|
|
||||||
glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset;
|
|
||||||
_rigidBody->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position)));
|
|
||||||
|
|
||||||
// the rotation is dictated by AvatarData
|
|
||||||
btTransform xform = _rigidBody->getWorldTransform();
|
|
||||||
xform.setRotation(glmToBullet(rotation));
|
|
||||||
_rigidBody->setWorldTransform(xform);
|
|
||||||
|
|
||||||
// scan for distant floor
|
// scan for distant floor
|
||||||
// rayStart is at center of bottom sphere
|
// rayStart is at center of bottom sphere
|
||||||
btVector3 rayStart = xform.getOrigin() - _halfHeight * _currentUp;
|
btVector3 rayStart = _avatarBodyTransform.getOrigin() - _halfHeight * _currentUp;
|
||||||
|
|
||||||
// rayEnd is straight down MAX_FALL_HEIGHT
|
// rayEnd is straight down MAX_FALL_HEIGHT
|
||||||
btScalar rayLength = _radius + MAX_FALL_HEIGHT;
|
btScalar rayLength = _radius + MAX_FALL_HEIGHT;
|
||||||
|
@ -388,8 +390,6 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) {
|
||||||
setHovering(true);
|
setHovering(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_walkVelocity = glmToBullet(_avatarData->getTargetVelocity());
|
|
||||||
|
|
||||||
if (_pendingFlags & PENDING_FLAG_JUMP) {
|
if (_pendingFlags & PENDING_FLAG_JUMP) {
|
||||||
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
||||||
if (onGround()) {
|
if (onGround()) {
|
||||||
|
@ -400,15 +400,9 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_lastStepDuration = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicCharacterController::postSimulation() {
|
void MyCharacterController::postSimulation() {
|
||||||
if (_enabled && _rigidBody) {
|
// postSimulation() exists for symmetry and just in case we need to do something here later
|
||||||
const btTransform& avatarTransform = _rigidBody->getWorldTransform();
|
|
||||||
glm::quat rotation = bulletToGLM(avatarTransform.getRotation());
|
|
||||||
glm::vec3 position = bulletToGLM(avatarTransform.getOrigin());
|
|
||||||
|
|
||||||
_avatarData->nextAttitude(position - rotation * _shapeLocalOffset, rotation);
|
|
||||||
_avatarData->setVelocity(bulletToGLM(_rigidBody->getLinearVelocity()));
|
|
||||||
}
|
|
||||||
}
|
}
|
106
interface/src/avatar/MyCharacterController.h
Normal file
106
interface/src/avatar/MyCharacterController.h
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
//
|
||||||
|
// MyCharacterController.h
|
||||||
|
// interface/src/avatar
|
||||||
|
//
|
||||||
|
// Created by AndrewMeadows 2015.10.21
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef hifi_MyCharacterController_h
|
||||||
|
#define hifi_MyCharacterController_h
|
||||||
|
|
||||||
|
#include <btBulletDynamicsCommon.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <BulletUtil.h>
|
||||||
|
#include <CharacterController.h>
|
||||||
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
|
class btCollisionShape;
|
||||||
|
class MyAvatar;
|
||||||
|
|
||||||
|
class MyCharacterController : public CharacterController {
|
||||||
|
public:
|
||||||
|
MyCharacterController(MyAvatar* avatar);
|
||||||
|
~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;
|
||||||
|
|
||||||
|
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 setHMDVelocity(const glm::vec3& velocity);
|
||||||
|
glm::vec3 getHMDShift() const { return _lastStepDuration * bulletToGLM(_hmdVelocity); }
|
||||||
|
|
||||||
|
glm::vec3 getLinearVelocity() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateUpAxis(const glm::quat& rotation);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
btVector3 _currentUp;
|
||||||
|
btVector3 _walkVelocity;
|
||||||
|
btVector3 _hmdVelocity;
|
||||||
|
btTransform _avatarBodyTransform;
|
||||||
|
|
||||||
|
glm::vec3 _shapeLocalOffset;
|
||||||
|
glm::vec3 _boxScale; // used to compute capsule shape
|
||||||
|
|
||||||
|
quint64 _jumpToHoverStart;
|
||||||
|
|
||||||
|
MyAvatar* _avatar { nullptr };
|
||||||
|
|
||||||
|
btScalar _halfHeight;
|
||||||
|
btScalar _radius;
|
||||||
|
|
||||||
|
btScalar _floorDistance;
|
||||||
|
|
||||||
|
btScalar _gravity;
|
||||||
|
|
||||||
|
btScalar _jumpSpeed;
|
||||||
|
btScalar _lastStepDuration;
|
||||||
|
|
||||||
|
bool _enabled;
|
||||||
|
bool _isOnGround;
|
||||||
|
bool _isJumping;
|
||||||
|
bool _isFalling;
|
||||||
|
bool _isHovering;
|
||||||
|
bool _isPushingUp;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_MyCharacterController_h
|
|
@ -106,8 +106,11 @@ void JSConsole::executeCommand(const QString& command) {
|
||||||
|
|
||||||
QScriptValue JSConsole::executeCommandInWatcher(const QString& command) {
|
QScriptValue JSConsole::executeCommandInWatcher(const QString& command) {
|
||||||
QScriptValue result;
|
QScriptValue result;
|
||||||
|
static const QString filename = "JSConcole";
|
||||||
QMetaObject::invokeMethod(_scriptEngine, "evaluate", Qt::ConnectionType::BlockingQueuedConnection,
|
QMetaObject::invokeMethod(_scriptEngine, "evaluate", Qt::ConnectionType::BlockingQueuedConnection,
|
||||||
Q_RETURN_ARG(QScriptValue, result), Q_ARG(const QString&, command));
|
Q_RETURN_ARG(QScriptValue, result),
|
||||||
|
Q_ARG(const QString&, command),
|
||||||
|
Q_ARG(const QString&, filename));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
#include <AbstractViewStateInterface.h>
|
#include <AbstractViewStateInterface.h>
|
||||||
|
|
||||||
#include <OffscreenQmlSurface.h>
|
#include <gl/OffscreenQmlSurface.h>
|
||||||
|
|
||||||
static const float DPI = 30.47f;
|
static const float DPI = 30.47f;
|
||||||
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
|
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
|
||||||
|
|
|
@ -366,7 +366,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
if (offsetLength > MIN_HIPS_OFFSET_LENGTH) {
|
if (offsetLength > MIN_HIPS_OFFSET_LENGTH) {
|
||||||
// but only if offset is long enough
|
// but only if offset is long enough
|
||||||
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
|
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
|
||||||
_relativePoses[0].trans = underPoses[0].trans + scaleFactor * _hipsOffset;
|
_relativePoses[_hipsIndex].trans = underPoses[_hipsIndex].trans + scaleFactor * _hipsOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
solveWithCyclicCoordinateDescent(targets);
|
solveWithCyclicCoordinateDescent(targets);
|
||||||
|
@ -758,8 +758,10 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
|
||||||
if (skeleton) {
|
if (skeleton) {
|
||||||
initConstraints();
|
initConstraints();
|
||||||
_headIndex = _skeleton->nameToJointIndex("Head");
|
_headIndex = _skeleton->nameToJointIndex("Head");
|
||||||
|
_hipsIndex = _skeleton->nameToJointIndex("Hips");
|
||||||
} else {
|
} else {
|
||||||
clearConstraints();
|
clearConstraints();
|
||||||
_headIndex = -1;
|
_headIndex = -1;
|
||||||
|
_hipsIndex = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ protected:
|
||||||
|
|
||||||
// experimental data for moving hips during IK
|
// experimental data for moving hips during IK
|
||||||
int _headIndex = -1;
|
int _headIndex = -1;
|
||||||
|
int _hipsIndex = -1;
|
||||||
glm::vec3 _hipsOffset = Vectors::ZERO;
|
glm::vec3 _hipsOffset = Vectors::ZERO;
|
||||||
|
|
||||||
// _maxTargetIndex is tracked to help optimize the recalculation of absolute poses
|
// _maxTargetIndex is tracked to help optimize the recalculation of absolute poses
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
set(TARGET_NAME display-plugins)
|
set(TARGET_NAME display-plugins)
|
||||||
setup_hifi_library(OpenGL)
|
setup_hifi_library(OpenGL)
|
||||||
link_hifi_libraries(shared plugins gpu render-utils)
|
link_hifi_libraries(shared plugins gpu gl)
|
||||||
|
|
||||||
target_opengl()
|
target_opengl()
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "gpu/GPUConfig.h"
|
#include <gl/Config.h>
|
||||||
#include "GLMHelpers.h"
|
#include <GLMHelpers.h>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
#include <GlWindow.h>
|
#include <gl/GlWindow.h>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
//
|
//
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#include "DisplayPlugin.h"
|
#include "DisplayPlugin.h"
|
||||||
#include "OglplusHelpers.h"
|
|
||||||
|
#include <QTimer>
|
||||||
|
#include <gl/OglplusHelpers.h>
|
||||||
|
|
||||||
class GlWindow;
|
class GlWindow;
|
||||||
class QOpenGLContext;
|
class QOpenGLContext;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QGLWidget>
|
#include <QGLWidget>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <GlWindow.h>
|
#include <gl/GlWindow.h>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
|
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <OglplusHelpers.h>
|
#include <gl/OglplusHelpers.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
|
|
||||||
#include "plugins/PluginContainer.h"
|
#include "plugins/PluginContainer.h"
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QGLWidget>
|
#include <QGLWidget>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <GlWindow.h>
|
#include <gl/GlWindow.h>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
|
|
||||||
#include <GlWindow.h>
|
#include <gl/GlWindow.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
#include <MatrixStack.h>
|
#include <MatrixStack.h>
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
|
|
||||||
#include <GlWindow.h>
|
#include <gl/GlWindow.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
#include <MatrixStack.h>
|
#include <MatrixStack.h>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
set(TARGET_NAME entities-renderer)
|
set(TARGET_NAME entities-renderer)
|
||||||
AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
|
AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
|
||||||
setup_hifi_library(Widgets Network Script)
|
setup_hifi_library(Widgets Network Script)
|
||||||
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils)
|
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils gl)
|
||||||
|
|
||||||
target_bullet()
|
target_bullet()
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ PolyLineEntityItem(entityItemID, properties) {
|
||||||
gpu::PipelinePointer RenderablePolyLineEntityItem::_pipeline;
|
gpu::PipelinePointer RenderablePolyLineEntityItem::_pipeline;
|
||||||
gpu::Stream::FormatPointer RenderablePolyLineEntityItem::_format;
|
gpu::Stream::FormatPointer RenderablePolyLineEntityItem::_format;
|
||||||
gpu::TexturePointer RenderablePolyLineEntityItem::_texture;
|
gpu::TexturePointer RenderablePolyLineEntityItem::_texture;
|
||||||
GLint RenderablePolyLineEntityItem::PAINTSTROKE_GPU_SLOT;
|
int32_t RenderablePolyLineEntityItem::PAINTSTROKE_GPU_SLOT;
|
||||||
|
|
||||||
void RenderablePolyLineEntityItem::createPipeline() {
|
void RenderablePolyLineEntityItem::createPipeline() {
|
||||||
static const int NORMAL_OFFSET = 12;
|
static const int NORMAL_OFFSET = 12;
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include "RenderableEntityItem.h"
|
#include "RenderableEntityItem.h"
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
#include <gpu/GPUConfig.h>
|
|
||||||
|
|
||||||
|
|
||||||
class RenderablePolyLineEntityItem : public PolyLineEntityItem {
|
class RenderablePolyLineEntityItem : public PolyLineEntityItem {
|
||||||
|
@ -34,7 +33,7 @@ public:
|
||||||
static gpu::PipelinePointer _pipeline;
|
static gpu::PipelinePointer _pipeline;
|
||||||
static gpu::Stream::FormatPointer _format;
|
static gpu::Stream::FormatPointer _format;
|
||||||
static gpu::TexturePointer _texture;
|
static gpu::TexturePointer _texture;
|
||||||
static GLint PAINTSTROKE_GPU_SLOT;
|
static int32_t PAINTSTROKE_GPU_SLOT;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void updateGeometry();
|
void updateGeometry();
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include <DeferredLightingEffect.h>
|
#include <DeferredLightingEffect.h>
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <OffscreenQmlSurface.h>
|
#include <gl/OffscreenQmlSurface.h>
|
||||||
#include <AbstractViewStateInterface.h>
|
#include <AbstractViewStateInterface.h>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
|
|
|
@ -1790,9 +1790,17 @@ const QByteArray EntityItem::getActionDataInternal() const {
|
||||||
const QByteArray EntityItem::getActionData() const {
|
const QByteArray EntityItem::getActionData() const {
|
||||||
QByteArray result;
|
QByteArray result;
|
||||||
assertUnlocked();
|
assertUnlocked();
|
||||||
withReadLock([&] {
|
|
||||||
result = getActionDataInternal();
|
if (_actionDataDirty) {
|
||||||
});
|
withWriteLock([&] {
|
||||||
|
getActionDataInternal();
|
||||||
|
result = _allActionsDataCache;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
withReadLock([&] {
|
||||||
|
result = _allActionsDataCache;
|
||||||
|
});
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
libraries/gl/CMakeLists.txt
Normal file
7
libraries/gl/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
set(TARGET_NAME gl)
|
||||||
|
setup_hifi_library(OpenGL Qml Quick)
|
||||||
|
link_hifi_libraries(shared)
|
||||||
|
|
||||||
|
target_glew()
|
||||||
|
target_opengl()
|
||||||
|
target_oglplus()
|
|
@ -8,9 +8,10 @@
|
||||||
|
|
||||||
#include "GlWindow.h"
|
#include "GlWindow.h"
|
||||||
|
|
||||||
#include <QOpenGLContext>
|
#include <QtGui/QOpenGLContext>
|
||||||
#include <QOpenGLDebugLogger>
|
#include <QtGui/QOpenGLDebugLogger>
|
||||||
#include <GLHelpers.h>
|
|
||||||
|
#include "GLHelpers.h"
|
||||||
|
|
||||||
GlWindow::GlWindow(QOpenGLContext* shareContext) : GlWindow(getDefaultOpenGlSurfaceFormat(), shareContext) {
|
GlWindow::GlWindow(QOpenGLContext* shareContext) : GlWindow(getDefaultOpenGlSurfaceFormat(), shareContext) {
|
||||||
}
|
}
|
|
@ -12,10 +12,11 @@
|
||||||
|
|
||||||
#include "OffscreenGlCanvas.h"
|
#include "OffscreenGlCanvas.h"
|
||||||
|
|
||||||
#include <GLHelpers.h>
|
#include <QtGui/QOffscreenSurface>
|
||||||
#include <QOpenGLDebugLogger>
|
#include <QtGui/QOpenGLDebugLogger>
|
||||||
#include <QOpenGLContext>
|
#include <QtGui/QOpenGLContext>
|
||||||
#include <QOffscreenSurface>
|
|
||||||
|
#include "GLHelpers.h"
|
||||||
|
|
||||||
OffscreenGlCanvas::OffscreenGlCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface){
|
OffscreenGlCanvas::OffscreenGlCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface){
|
||||||
}
|
}
|
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
#include "GLEscrow.h"
|
#include "GLEscrow.h"
|
||||||
#include "OffscreenGlCanvas.h"
|
#include "OffscreenGlCanvas.h"
|
||||||
#include "AbstractViewStateInterface.h"
|
|
||||||
|
|
||||||
// FIXME move to threaded rendering with Qt 5.5
|
// FIXME move to threaded rendering with Qt 5.5
|
||||||
// #define QML_THREADED
|
// #define QML_THREADED
|
||||||
|
@ -207,9 +206,7 @@ private:
|
||||||
qreal pixelRatio = 1.0;
|
qreal pixelRatio = 1.0;
|
||||||
if (_renderControl && _renderControl->_renderWindow) {
|
if (_renderControl && _renderControl->_renderWindow) {
|
||||||
pixelRatio = _renderControl->_renderWindow->devicePixelRatio();
|
pixelRatio = _renderControl->_renderWindow->devicePixelRatio();
|
||||||
} else {
|
}
|
||||||
pixelRatio = AbstractViewStateInterface::instance()->getDevicePixelRatio();
|
|
||||||
}
|
|
||||||
|
|
||||||
uvec2 newOffscreenSize = toGlm(newSize * pixelRatio);
|
uvec2 newOffscreenSize = toGlm(newSize * pixelRatio);
|
||||||
_textures.setSize(newOffscreenSize);
|
_textures.setSize(newOffscreenSize);
|
|
@ -1,7 +1,7 @@
|
||||||
set(TARGET_NAME gpu)
|
set(TARGET_NAME gpu)
|
||||||
AUTOSCRIBE_SHADER_LIB(gpu)
|
AUTOSCRIBE_SHADER_LIB(gpu)
|
||||||
setup_hifi_library()
|
setup_hifi_library()
|
||||||
link_hifi_libraries(shared)
|
link_hifi_libraries(shared gl)
|
||||||
|
|
||||||
target_glew()
|
target_glew()
|
||||||
target_opengl()
|
target_opengl()
|
|
@ -18,7 +18,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include "GPUConfig.h"
|
#include <gl/Config.h>
|
||||||
|
|
||||||
#include "Context.h"
|
#include "Context.h"
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,10 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
|
||||||
|
|
||||||
if (sixenseGetNumActiveControllers() == 0) {
|
if (sixenseGetNumActiveControllers() == 0) {
|
||||||
if (_hydrasConnected) {
|
if (_hydrasConnected) {
|
||||||
qCDebug(inputplugins, "hydra disconnected");
|
qCDebug(inputplugins) << "hydra disconnected" << _badDataCount;
|
||||||
|
if (_badDataCount++ < _allowedBadDataCount) { // gotta get some no-active in a row before we shut things down
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_hydrasConnected = false;
|
_hydrasConnected = false;
|
||||||
if (_deviceID != 0) {
|
if (_deviceID != 0) {
|
||||||
|
@ -181,6 +184,7 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
|
||||||
PerformanceTimer perfTimer("sixense");
|
PerformanceTimer perfTimer("sixense");
|
||||||
if (!_hydrasConnected) {
|
if (!_hydrasConnected) {
|
||||||
_hydrasConnected = true;
|
_hydrasConnected = true;
|
||||||
|
_badDataCount = 0;
|
||||||
registerToUserInputMapper(*userInputMapper);
|
registerToUserInputMapper(*userInputMapper);
|
||||||
assignDefaultInputMapping(*userInputMapper);
|
assignDefaultInputMapping(*userInputMapper);
|
||||||
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
|
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
|
||||||
|
@ -555,6 +559,7 @@ void SixenseManager::saveSettings() const {
|
||||||
settings.setVec3Value(QString("avatarPosition"), _avatarPosition);
|
settings.setVec3Value(QString("avatarPosition"), _avatarPosition);
|
||||||
settings.setQuatValue(QString("avatarRotation"), _avatarRotation);
|
settings.setQuatValue(QString("avatarRotation"), _avatarRotation);
|
||||||
settings.setValue(QString("reachLength"), QVariant(_reachLength));
|
settings.setValue(QString("reachLength"), QVariant(_reachLength));
|
||||||
|
settings.setValue(QString("allowedHydraFailures"), 120);
|
||||||
}
|
}
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
@ -567,6 +572,7 @@ void SixenseManager::loadSettings() {
|
||||||
settings.getVec3ValueIfValid(QString("avatarPosition"), _avatarPosition);
|
settings.getVec3ValueIfValid(QString("avatarPosition"), _avatarPosition);
|
||||||
settings.getQuatValueIfValid(QString("avatarRotation"), _avatarRotation);
|
settings.getQuatValueIfValid(QString("avatarRotation"), _avatarRotation);
|
||||||
settings.getFloatValueIfValid(QString("reachLength"), _reachLength);
|
settings.getFloatValueIfValid(QString("reachLength"), _reachLength);
|
||||||
|
_allowedBadDataCount = settings.value(QString("allowedHydraFailures"), 120).toInt();
|
||||||
}
|
}
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,8 @@ private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool _hydrasConnected;
|
bool _hydrasConnected;
|
||||||
|
int _badDataCount;
|
||||||
|
int _allowedBadDataCount;
|
||||||
|
|
||||||
static const QString NAME;
|
static const QString NAME;
|
||||||
static const QString HYDRA_ID_STRING;
|
static const QString HYDRA_ID_STRING;
|
||||||
|
|
52
libraries/physics/src/CharacterController.cpp
Normal file
52
libraries/physics/src/CharacterController.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
//
|
||||||
|
// CharacterControllerInterface.cpp
|
||||||
|
// libraries/physcis/src
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows 2015.10.21
|
||||||
|
// 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 "CharacterController.h"
|
||||||
|
|
||||||
|
#include "PhysicsCollisionGroups.h"
|
||||||
|
|
||||||
|
bool CharacterController::needsRemoval() const {
|
||||||
|
return (bool)(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CharacterController::needsAddition() const {
|
||||||
|
return (bool)(_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
||||||
|
if (_dynamicsWorld != world) {
|
||||||
|
if (_dynamicsWorld) {
|
||||||
|
if (_rigidBody) {
|
||||||
|
_dynamicsWorld->removeRigidBody(_rigidBody);
|
||||||
|
_dynamicsWorld->removeAction(this);
|
||||||
|
}
|
||||||
|
_dynamicsWorld = nullptr;
|
||||||
|
}
|
||||||
|
if (world && _rigidBody) {
|
||||||
|
_dynamicsWorld = world;
|
||||||
|
_pendingFlags &= ~PENDING_FLAG_JUMP;
|
||||||
|
_dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR);
|
||||||
|
_dynamicsWorld->addAction(this);
|
||||||
|
//reset(_dynamicsWorld);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_dynamicsWorld) {
|
||||||
|
if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
|
||||||
|
// shouldn't fall in here, but if we do make sure both ADD and REMOVE bits are still set
|
||||||
|
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||||
|
} else {
|
||||||
|
_pendingFlags &= ~PENDING_FLAG_ADD_TO_SIMULATION;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_pendingFlags &= ~PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
59
libraries/physics/src/CharacterController.h
Normal file
59
libraries/physics/src/CharacterController.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
//
|
||||||
|
// CharacterControllerInterface.h
|
||||||
|
// libraries/physcis/src
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows 2015.10.21
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_CharacterControllerInterface_h
|
||||||
|
#define hifi_CharacterControllerInterface_h
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <btBulletDynamicsCommon.h>
|
||||||
|
#include <BulletDynamics/Character/btCharacterControllerInterface.h>
|
||||||
|
|
||||||
|
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_UPDATE_SHAPE = 1U << 2;
|
||||||
|
const uint32_t PENDING_FLAG_JUMP = 1U << 3;
|
||||||
|
|
||||||
|
|
||||||
|
class btRigidBody;
|
||||||
|
class btCollisionWorld;
|
||||||
|
class btDynamicsWorld;
|
||||||
|
|
||||||
|
class CharacterController : public btCharacterControllerInterface {
|
||||||
|
public:
|
||||||
|
bool needsRemoval() const;
|
||||||
|
bool needsAddition() const;
|
||||||
|
void setDynamicsWorld(btDynamicsWorld* world);
|
||||||
|
btCollisionObject* getCollisionObject() { return _rigidBody; }
|
||||||
|
|
||||||
|
virtual void updateShapeIfNecessary() = 0;
|
||||||
|
virtual void preSimulation() = 0;
|
||||||
|
virtual void postSimulation() = 0;
|
||||||
|
|
||||||
|
virtual void setWalkDirection(const btVector3 &walkDirection) { assert(false); }
|
||||||
|
|
||||||
|
/* 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:
|
||||||
|
btDynamicsWorld* _dynamicsWorld { nullptr };
|
||||||
|
btRigidBody* _rigidBody { nullptr };
|
||||||
|
uint32_t _pendingFlags { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_CharacterControllerInterface_h
|
|
@ -1,95 +0,0 @@
|
||||||
#ifndef hifi_DynamicCharacterController_h
|
|
||||||
#define hifi_DynamicCharacterController_h
|
|
||||||
|
|
||||||
#include <btBulletDynamicsCommon.h>
|
|
||||||
#include <BulletDynamics/Character/btCharacterControllerInterface.h>
|
|
||||||
|
|
||||||
#include <AvatarData.h>
|
|
||||||
|
|
||||||
class btCollisionShape;
|
|
||||||
class btRigidBody;
|
|
||||||
class btCollisionWorld;
|
|
||||||
|
|
||||||
const int NUM_CHARACTER_CONTROLLER_RAYS = 2;
|
|
||||||
|
|
||||||
class DynamicCharacterController : public btCharacterControllerInterface
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
btScalar _halfHeight;
|
|
||||||
btScalar _radius;
|
|
||||||
btCollisionShape* _shape;
|
|
||||||
btRigidBody* _rigidBody;
|
|
||||||
|
|
||||||
btVector3 _currentUp;
|
|
||||||
|
|
||||||
btScalar _floorDistance;
|
|
||||||
|
|
||||||
btVector3 _walkVelocity;
|
|
||||||
btScalar _gravity;
|
|
||||||
|
|
||||||
glm::vec3 _shapeLocalOffset;
|
|
||||||
glm::vec3 _boxScale; // used to compute capsule shape
|
|
||||||
AvatarData* _avatarData = nullptr;
|
|
||||||
|
|
||||||
bool _enabled;
|
|
||||||
bool _isOnGround;
|
|
||||||
bool _isJumping;
|
|
||||||
bool _isFalling;
|
|
||||||
bool _isHovering;
|
|
||||||
bool _isPushingUp;
|
|
||||||
quint64 _jumpToHoverStart;
|
|
||||||
uint32_t _pendingFlags;
|
|
||||||
|
|
||||||
btDynamicsWorld* _dynamicsWorld = nullptr;
|
|
||||||
|
|
||||||
btScalar _jumpSpeed;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DynamicCharacterController(AvatarData* avatarData);
|
|
||||||
~DynamicCharacterController ();
|
|
||||||
|
|
||||||
virtual void setWalkDirection(const btVector3& walkDirection);
|
|
||||||
virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) { assert(false); }
|
|
||||||
|
|
||||||
// TODO: implement these when needed
|
|
||||||
virtual void reset(btCollisionWorld* collisionWorld) { }
|
|
||||||
virtual void warp(const btVector3& origin) { }
|
|
||||||
virtual void debugDraw(btIDebugDraw* debugDrawer) { }
|
|
||||||
virtual void setUpInterpolate(bool value) { }
|
|
||||||
|
|
||||||
btCollisionObject* getCollisionObject() { return _rigidBody; }
|
|
||||||
|
|
||||||
///btActionInterface interface
|
|
||||||
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTime) {
|
|
||||||
preStep(collisionWorld);
|
|
||||||
playerStep(collisionWorld, deltaTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void preStep(btCollisionWorld* collisionWorld);
|
|
||||||
virtual void playerStep(btCollisionWorld* collisionWorld, btScalar dt);
|
|
||||||
|
|
||||||
virtual bool canJump() const { assert(false); return false; } // never call this
|
|
||||||
virtual void jump(); // call this every frame the jump button is pressed
|
|
||||||
virtual bool onGround() const;
|
|
||||||
bool isHovering() const { return _isHovering; }
|
|
||||||
void setHovering(bool enabled);
|
|
||||||
|
|
||||||
bool needsRemoval() const;
|
|
||||||
bool needsAddition() const;
|
|
||||||
void setEnabled(bool enabled);
|
|
||||||
bool isEnabled() const { return _enabled && _dynamicsWorld; }
|
|
||||||
|
|
||||||
void setDynamicsWorld(btDynamicsWorld* world);
|
|
||||||
|
|
||||||
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
|
|
||||||
bool needsShapeUpdate() const;
|
|
||||||
void updateShapeIfNecessary();
|
|
||||||
|
|
||||||
void preSimulation(btScalar timeStep);
|
|
||||||
void postSimulation();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void updateUpAxis(const glm::quat& rotation);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_DynamicCharacterController_h
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <PhysicsCollisionGroups.h>
|
#include <PhysicsCollisionGroups.h>
|
||||||
|
|
||||||
|
#include "CharacterController.h"
|
||||||
#include "ObjectMotionState.h"
|
#include "ObjectMotionState.h"
|
||||||
#include "PhysicsEngine.h"
|
#include "PhysicsEngine.h"
|
||||||
#include "PhysicsHelpers.h"
|
#include "PhysicsHelpers.h"
|
||||||
|
@ -23,7 +24,7 @@ uint32_t PhysicsEngine::getNumSubsteps() {
|
||||||
|
|
||||||
PhysicsEngine::PhysicsEngine(const glm::vec3& offset) :
|
PhysicsEngine::PhysicsEngine(const glm::vec3& offset) :
|
||||||
_originOffset(offset),
|
_originOffset(offset),
|
||||||
_characterController(nullptr) {
|
_myAvatarController(nullptr) {
|
||||||
// build table of masks with their group as the key
|
// build table of masks with their group as the key
|
||||||
_collisionMasks.insert(btHashInt((int)COLLISION_GROUP_DEFAULT), COLLISION_MASK_DEFAULT);
|
_collisionMasks.insert(btHashInt((int)COLLISION_GROUP_DEFAULT), COLLISION_MASK_DEFAULT);
|
||||||
_collisionMasks.insert(btHashInt((int)COLLISION_GROUP_STATIC), COLLISION_MASK_STATIC);
|
_collisionMasks.insert(btHashInt((int)COLLISION_GROUP_STATIC), COLLISION_MASK_STATIC);
|
||||||
|
@ -38,8 +39,8 @@ PhysicsEngine::PhysicsEngine(const glm::vec3& offset) :
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicsEngine::~PhysicsEngine() {
|
PhysicsEngine::~PhysicsEngine() {
|
||||||
if (_characterController) {
|
if (_myAvatarController) {
|
||||||
_characterController->setDynamicsWorld(nullptr);
|
_myAvatarController->setDynamicsWorld(nullptr);
|
||||||
}
|
}
|
||||||
delete _collisionConfig;
|
delete _collisionConfig;
|
||||||
delete _collisionDispatcher;
|
delete _collisionDispatcher;
|
||||||
|
@ -239,16 +240,23 @@ void PhysicsEngine::stepSimulation() {
|
||||||
_clock.reset();
|
_clock.reset();
|
||||||
float timeStep = btMin(dt, MAX_TIMESTEP);
|
float timeStep = btMin(dt, MAX_TIMESTEP);
|
||||||
|
|
||||||
// TODO: move character->preSimulation() into relayIncomingChanges
|
if (_myAvatarController) {
|
||||||
if (_characterController) {
|
// ADEBUG TODO: move this stuff outside and in front of stepSimulation, because
|
||||||
if (_characterController->needsRemoval()) {
|
// the updateShapeIfNecessary() call needs info from MyAvatar and should
|
||||||
_characterController->setDynamicsWorld(nullptr);
|
// be done on the main thread during the pre-simulation stuff
|
||||||
|
if (_myAvatarController->needsRemoval()) {
|
||||||
|
_myAvatarController->setDynamicsWorld(nullptr);
|
||||||
|
|
||||||
|
// We must remove any existing contacts for the avatar so that any new contacts will have
|
||||||
|
// valid data. MyAvatar's RigidBody is the ONLY one in the simulation that does not yet
|
||||||
|
// have a MotionState so we pass nullptr to removeContacts().
|
||||||
|
removeContacts(nullptr);
|
||||||
}
|
}
|
||||||
_characterController->updateShapeIfNecessary();
|
_myAvatarController->updateShapeIfNecessary();
|
||||||
if (_characterController->needsAddition()) {
|
if (_myAvatarController->needsAddition()) {
|
||||||
_characterController->setDynamicsWorld(_dynamicsWorld);
|
_myAvatarController->setDynamicsWorld(_dynamicsWorld);
|
||||||
}
|
}
|
||||||
_characterController->preSimulation(timeStep);
|
_myAvatarController->preSimulation();
|
||||||
}
|
}
|
||||||
|
|
||||||
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, PHYSICS_ENGINE_MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, PHYSICS_ENGINE_MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||||
|
@ -257,8 +265,8 @@ void PhysicsEngine::stepSimulation() {
|
||||||
_numSubsteps += (uint32_t)numSubsteps;
|
_numSubsteps += (uint32_t)numSubsteps;
|
||||||
ObjectMotionState::setWorldSimulationStep(_numSubsteps);
|
ObjectMotionState::setWorldSimulationStep(_numSubsteps);
|
||||||
|
|
||||||
if (_characterController) {
|
if (_myAvatarController) {
|
||||||
_characterController->postSimulation();
|
_myAvatarController->postSimulation();
|
||||||
}
|
}
|
||||||
updateContactMap();
|
updateContactMap();
|
||||||
_hasOutgoingChanges = true;
|
_hasOutgoingChanges = true;
|
||||||
|
@ -268,7 +276,7 @@ void PhysicsEngine::stepSimulation() {
|
||||||
void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) {
|
void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) {
|
||||||
BT_PROFILE("ownershipInfection");
|
BT_PROFILE("ownershipInfection");
|
||||||
|
|
||||||
const btCollisionObject* characterObject = _characterController ? _characterController->getCollisionObject() : nullptr;
|
const btCollisionObject* characterObject = _myAvatarController ? _myAvatarController->getCollisionObject() : nullptr;
|
||||||
|
|
||||||
ObjectMotionState* motionStateA = static_cast<ObjectMotionState*>(objectA->getUserPointer());
|
ObjectMotionState* motionStateA = static_cast<ObjectMotionState*>(objectA->getUserPointer());
|
||||||
ObjectMotionState* motionStateB = static_cast<ObjectMotionState*>(objectB->getUserPointer());
|
ObjectMotionState* motionStateB = static_cast<ObjectMotionState*>(objectB->getUserPointer());
|
||||||
|
@ -431,15 +439,15 @@ void PhysicsEngine::bump(ObjectMotionState* motionState) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::setCharacterController(DynamicCharacterController* character) {
|
void PhysicsEngine::setCharacterController(CharacterController* character) {
|
||||||
if (_characterController != character) {
|
if (_myAvatarController != character) {
|
||||||
if (_characterController) {
|
if (_myAvatarController) {
|
||||||
// remove the character from the DynamicsWorld immediately
|
// remove the character from the DynamicsWorld immediately
|
||||||
_characterController->setDynamicsWorld(nullptr);
|
_myAvatarController->setDynamicsWorld(nullptr);
|
||||||
_characterController = nullptr;
|
_myAvatarController = nullptr;
|
||||||
}
|
}
|
||||||
// the character will be added to the DynamicsWorld later
|
// the character will be added to the DynamicsWorld later
|
||||||
_characterController = character;
|
_myAvatarController = character;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,14 @@
|
||||||
|
|
||||||
#include "BulletUtil.h"
|
#include "BulletUtil.h"
|
||||||
#include "ContactInfo.h"
|
#include "ContactInfo.h"
|
||||||
#include "DynamicCharacterController.h"
|
|
||||||
#include "ObjectMotionState.h"
|
#include "ObjectMotionState.h"
|
||||||
#include "ThreadSafeDynamicsWorld.h"
|
#include "ThreadSafeDynamicsWorld.h"
|
||||||
#include "ObjectAction.h"
|
#include "ObjectAction.h"
|
||||||
|
|
||||||
const float HALF_SIMULATION_EXTENT = 512.0f; // meters
|
const float HALF_SIMULATION_EXTENT = 512.0f; // meters
|
||||||
|
|
||||||
|
class CharacterController;
|
||||||
|
|
||||||
// simple class for keeping track of contacts
|
// simple class for keeping track of contacts
|
||||||
class ContactKey {
|
class ContactKey {
|
||||||
public:
|
public:
|
||||||
|
@ -87,7 +88,7 @@ public:
|
||||||
|
|
||||||
void removeRigidBody(btRigidBody* body);
|
void removeRigidBody(btRigidBody* body);
|
||||||
|
|
||||||
void setCharacterController(DynamicCharacterController* character);
|
void setCharacterController(CharacterController* character);
|
||||||
|
|
||||||
void dumpNextStats() { _dumpNextStats = true; }
|
void dumpNextStats() { _dumpNextStats = true; }
|
||||||
|
|
||||||
|
@ -117,7 +118,7 @@ private:
|
||||||
uint32_t _lastNumSubstepsAtUpdateInternal = 0;
|
uint32_t _lastNumSubstepsAtUpdateInternal = 0;
|
||||||
|
|
||||||
/// character collisions
|
/// character collisions
|
||||||
DynamicCharacterController* _characterController = NULL;
|
CharacterController* _myAvatarController;
|
||||||
|
|
||||||
bool _dumpNextStats = false;
|
bool _dumpNextStats = false;
|
||||||
bool _hasOutgoingChanges = false;
|
bool _hasOutgoingChanges = false;
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
#include <FSTReader.h>
|
#include <FSTReader.h>
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
|
|
||||||
#include <gpu/GLBackend.h>
|
|
||||||
|
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
#include "RenderUtilsLogging.h"
|
#include "RenderUtilsLogging.h"
|
||||||
|
|
||||||
|
@ -573,8 +571,8 @@ void GeometryCache::renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions
|
||||||
if (!_gridBuffers.contains(key)) {
|
if (!_gridBuffers.contains(key)) {
|
||||||
auto verticesBuffer = std::make_shared<gpu::Buffer>();
|
auto verticesBuffer = std::make_shared<gpu::Buffer>();
|
||||||
|
|
||||||
GLfloat* vertexData = new GLfloat[vertices * 2];
|
float* vertexData = new float[vertices * 2];
|
||||||
GLfloat* vertex = vertexData;
|
float* vertex = vertexData;
|
||||||
|
|
||||||
for (int i = 0; i <= xDivisions; i++) {
|
for (int i = 0; i <= xDivisions; i++) {
|
||||||
float x = (float)i / xDivisions;
|
float x = (float)i / xDivisions;
|
||||||
|
@ -595,7 +593,7 @@ void GeometryCache::renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions
|
||||||
*(vertex++) = y;
|
*(vertex++) = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
verticesBuffer->append(sizeof(GLfloat) * vertices * 2, (gpu::Byte*) vertexData);
|
verticesBuffer->append(sizeof(float) * vertices * 2, (gpu::Byte*) vertexData);
|
||||||
delete[] vertexData;
|
delete[] vertexData;
|
||||||
|
|
||||||
_gridBuffers[key] = verticesBuffer;
|
_gridBuffers[key] = verticesBuffer;
|
||||||
|
@ -674,8 +672,8 @@ void GeometryCache::renderGrid(gpu::Batch& batch, int x, int y, int width, int h
|
||||||
_alternateGridBuffers[key] = verticesBuffer;
|
_alternateGridBuffers[key] = verticesBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLfloat* vertexData = new GLfloat[vertices * 2];
|
float* vertexData = new float[vertices * 2];
|
||||||
GLfloat* vertex = vertexData;
|
float* vertex = vertexData;
|
||||||
|
|
||||||
int dx = width / cols;
|
int dx = width / cols;
|
||||||
int dy = height / rows;
|
int dy = height / rows;
|
||||||
|
@ -702,7 +700,7 @@ void GeometryCache::renderGrid(gpu::Batch& batch, int x, int y, int width, int h
|
||||||
tx += dx;
|
tx += dx;
|
||||||
}
|
}
|
||||||
|
|
||||||
verticesBuffer->append(sizeof(GLfloat) * vertices * 2, (gpu::Byte*) vertexData);
|
verticesBuffer->append(sizeof(float) * vertices * 2, (gpu::Byte*) vertexData);
|
||||||
delete[] vertexData;
|
delete[] vertexData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,8 +783,8 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, con
|
||||||
((int(color.z * 255.0f) & 0xFF) << 16) |
|
((int(color.z * 255.0f) & 0xFF) << 16) |
|
||||||
((int(color.w * 255.0f) & 0xFF) << 24);
|
((int(color.w * 255.0f) & 0xFF) << 24);
|
||||||
|
|
||||||
GLfloat* vertexData = new GLfloat[details.vertices * FLOATS_PER_VERTEX];
|
float* vertexData = new float[details.vertices * FLOATS_PER_VERTEX];
|
||||||
GLfloat* vertex = vertexData;
|
float* vertex = vertexData;
|
||||||
|
|
||||||
int* colorData = new int[details.vertices];
|
int* colorData = new int[details.vertices];
|
||||||
int* colorDataAt = colorData;
|
int* colorDataAt = colorData;
|
||||||
|
@ -798,7 +796,7 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, con
|
||||||
*(colorDataAt++) = compactColor;
|
*(colorDataAt++) = compactColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
details.verticesBuffer->append(sizeof(GLfloat) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData);
|
details.verticesBuffer->append(sizeof(float) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData);
|
||||||
details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData);
|
details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData);
|
||||||
delete[] vertexData;
|
delete[] vertexData;
|
||||||
delete[] colorData;
|
delete[] colorData;
|
||||||
|
@ -846,8 +844,8 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec3>& points, con
|
||||||
((int(color.z * 255.0f) & 0xFF) << 16) |
|
((int(color.z * 255.0f) & 0xFF) << 16) |
|
||||||
((int(color.w * 255.0f) & 0xFF) << 24);
|
((int(color.w * 255.0f) & 0xFF) << 24);
|
||||||
|
|
||||||
GLfloat* vertexData = new GLfloat[details.vertices * FLOATS_PER_VERTEX];
|
float* vertexData = new float[details.vertices * FLOATS_PER_VERTEX];
|
||||||
GLfloat* vertex = vertexData;
|
float* vertex = vertexData;
|
||||||
|
|
||||||
int* colorData = new int[details.vertices];
|
int* colorData = new int[details.vertices];
|
||||||
int* colorDataAt = colorData;
|
int* colorDataAt = colorData;
|
||||||
|
@ -860,7 +858,7 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec3>& points, con
|
||||||
*(colorDataAt++) = compactColor;
|
*(colorDataAt++) = compactColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
details.verticesBuffer->append(sizeof(GLfloat) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData);
|
details.verticesBuffer->append(sizeof(float) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData);
|
||||||
details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData);
|
details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData);
|
||||||
delete[] vertexData;
|
delete[] vertexData;
|
||||||
delete[] colorData;
|
delete[] colorData;
|
||||||
|
@ -912,8 +910,8 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec3>& points, con
|
||||||
((int(color.z * 255.0f) & 0xFF) << 16) |
|
((int(color.z * 255.0f) & 0xFF) << 16) |
|
||||||
((int(color.w * 255.0f) & 0xFF) << 24);
|
((int(color.w * 255.0f) & 0xFF) << 24);
|
||||||
|
|
||||||
GLfloat* vertexData = new GLfloat[details.vertices * FLOATS_PER_VERTEX];
|
float* vertexData = new float[details.vertices * FLOATS_PER_VERTEX];
|
||||||
GLfloat* vertex = vertexData;
|
float* vertex = vertexData;
|
||||||
|
|
||||||
int* colorData = new int[details.vertices];
|
int* colorData = new int[details.vertices];
|
||||||
int* colorDataAt = colorData;
|
int* colorDataAt = colorData;
|
||||||
|
@ -930,7 +928,7 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec3>& points, con
|
||||||
*(colorDataAt++) = compactColor;
|
*(colorDataAt++) = compactColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
details.verticesBuffer->append(sizeof(GLfloat) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData);
|
details.verticesBuffer->append(sizeof(float) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData);
|
||||||
details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData);
|
details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData);
|
||||||
delete[] vertexData;
|
delete[] vertexData;
|
||||||
delete[] colorData;
|
delete[] colorData;
|
||||||
|
@ -997,7 +995,7 @@ void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int
|
||||||
details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride);
|
details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride);
|
||||||
|
|
||||||
|
|
||||||
GLfloat vertexBuffer[NUM_FLOATS]; // only vertices, no normals because we're a 2D quad
|
float vertexBuffer[NUM_FLOATS]; // only vertices, no normals because we're a 2D quad
|
||||||
int vertexPoint = 0;
|
int vertexPoint = 0;
|
||||||
|
|
||||||
// Triangle strip points
|
// Triangle strip points
|
||||||
|
@ -1438,8 +1436,8 @@ void GeometryCache::renderDashedLine(gpu::Batch& batch, const glm::vec3& start,
|
||||||
int* colorData = new int[details.vertices];
|
int* colorData = new int[details.vertices];
|
||||||
int* colorDataAt = colorData;
|
int* colorDataAt = colorData;
|
||||||
|
|
||||||
GLfloat* vertexData = new GLfloat[details.vertices * FLOATS_PER_VERTEX];
|
float* vertexData = new float[details.vertices * FLOATS_PER_VERTEX];
|
||||||
GLfloat* vertex = vertexData;
|
float* vertex = vertexData;
|
||||||
|
|
||||||
glm::vec3 point = start;
|
glm::vec3 point = start;
|
||||||
*(vertex++) = point.x;
|
*(vertex++) = point.x;
|
||||||
|
@ -1465,7 +1463,7 @@ void GeometryCache::renderDashedLine(gpu::Batch& batch, const glm::vec3& start,
|
||||||
*(vertex++) = end.z;
|
*(vertex++) = end.z;
|
||||||
*(colorDataAt++) = compactColor;
|
*(colorDataAt++) = compactColor;
|
||||||
|
|
||||||
details.verticesBuffer->append(sizeof(GLfloat) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData);
|
details.verticesBuffer->append(sizeof(float) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData);
|
||||||
details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData);
|
details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData);
|
||||||
delete[] vertexData;
|
delete[] vertexData;
|
||||||
delete[] colorData;
|
delete[] colorData;
|
||||||
|
|
|
@ -79,11 +79,41 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) {
|
||||||
QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) {
|
QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) {
|
||||||
return engine->newQObject(in);
|
return engine->newQObject(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputController* &out) {
|
void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputController* &out) {
|
||||||
out = qobject_cast<AbstractInputController*>(object.toQObject());
|
out = qobject_cast<AbstractInputController*>(object.toQObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool hasCorrectSyntax(const QScriptProgram& program) {
|
||||||
|
const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode());
|
||||||
|
if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
|
||||||
|
const auto error = syntaxCheck.errorMessage();
|
||||||
|
const auto line = QString::number(syntaxCheck.errorLineNumber());
|
||||||
|
const auto column = QString::number(syntaxCheck.errorColumnNumber());
|
||||||
|
const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column);
|
||||||
|
qCWarning(scriptengine) << qPrintable(message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hadUncauchtExceptions(QScriptEngine& engine, const QString& fileName) {
|
||||||
|
if (engine.hasUncaughtException()) {
|
||||||
|
const auto backtrace = engine.uncaughtExceptionBacktrace();
|
||||||
|
const auto exception = engine.uncaughtException().toString();
|
||||||
|
const auto line = QString::number(engine.uncaughtExceptionLineNumber());
|
||||||
|
engine.clearExceptions();
|
||||||
|
|
||||||
|
auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line);
|
||||||
|
if (!backtrace.empty()) {
|
||||||
|
static const auto lineSeparator = "\n ";
|
||||||
|
message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator));
|
||||||
|
}
|
||||||
|
qCWarning(scriptengine) << qPrintable(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,
|
ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,
|
||||||
AbstractControllerScriptingInterface* controllerScriptingInterface, bool wantSignals) :
|
AbstractControllerScriptingInterface* controllerScriptingInterface, bool wantSignals) :
|
||||||
|
|
||||||
|
@ -95,9 +125,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
|
||||||
_wantSignals(wantSignals),
|
_wantSignals(wantSignals),
|
||||||
_controllerScriptingInterface(controllerScriptingInterface),
|
_controllerScriptingInterface(controllerScriptingInterface),
|
||||||
_fileNameString(fileNameString),
|
_fileNameString(fileNameString),
|
||||||
_quatLibrary(),
|
|
||||||
_vec3Library(),
|
|
||||||
_uuidLibrary(),
|
|
||||||
_isUserLoaded(false),
|
_isUserLoaded(false),
|
||||||
_isReloading(false),
|
_isReloading(false),
|
||||||
_arrayBufferClass(new ArrayBufferClass(this))
|
_arrayBufferClass(new ArrayBufferClass(this))
|
||||||
|
@ -508,26 +535,33 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
|
||||||
// Connect up ALL the handlers to the global entities object's signals.
|
// Connect up ALL the handlers to the global entities object's signals.
|
||||||
// (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.)
|
// (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.)
|
||||||
auto entities = DependencyManager::get<EntityScriptingInterface>();
|
auto entities = DependencyManager::get<EntityScriptingInterface>();
|
||||||
connect(entities.data(), &EntityScriptingInterface::deletingEntity, this,
|
connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) {
|
||||||
[=](const EntityItemID& entityID) {
|
_registeredHandlers.remove(entityID);
|
||||||
_registeredHandlers.remove(entityID);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Two common cases of event handler, differing only in argument signature.
|
// Two common cases of event handler, differing only in argument signature.
|
||||||
auto makeSingleEntityHandler = [=](const QString& eventName) -> std::function<void(const EntityItemID&)> {
|
using SingleEntityHandler = std::function<void(const EntityItemID&)>;
|
||||||
return [=](const EntityItemID& entityItemID) -> void {
|
auto makeSingleEntityHandler = [this](QString eventName) -> SingleEntityHandler {
|
||||||
generalHandler(entityItemID, eventName, [=]() -> QScriptValueList {
|
return [this, eventName](const EntityItemID& entityItemID) {
|
||||||
return QScriptValueList() << entityItemID.toScriptValue(this);
|
forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) });
|
||||||
});
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
auto makeMouseHandler = [=](const QString& eventName) -> std::function<void(const EntityItemID&, const MouseEvent&)> {
|
|
||||||
return [=](const EntityItemID& entityItemID, const MouseEvent& event) -> void {
|
using MouseHandler = std::function<void(const EntityItemID&, const MouseEvent&)>;
|
||||||
generalHandler(entityItemID, eventName, [=]() -> QScriptValueList {
|
auto makeMouseHandler = [this](QString eventName) -> MouseHandler {
|
||||||
return QScriptValueList() << entityItemID.toScriptValue(this) << event.toScriptValue(this);
|
return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) {
|
||||||
});
|
forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) });
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using CollisionHandler = std::function<void(const EntityItemID&, const EntityItemID&, const Collision&)>;
|
||||||
|
auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler {
|
||||||
|
return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) {
|
||||||
|
forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this),
|
||||||
|
collisionToScriptValue(this, collision) });
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity"));
|
connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity"));
|
||||||
connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity"));
|
connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity"));
|
||||||
|
|
||||||
|
@ -543,12 +577,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
|
||||||
connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity"));
|
connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity"));
|
||||||
connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity"));
|
connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity"));
|
||||||
|
|
||||||
connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this,
|
connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity"));
|
||||||
[=](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) {
|
|
||||||
generalHandler(idA, "collisionWithEntity", [=]() {
|
|
||||||
return QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (!_registeredHandlers.contains(entityID)) {
|
if (!_registeredHandlers.contains(entityID)) {
|
||||||
_registeredHandlers[entityID] = RegisteredEventHandlers();
|
_registeredHandlers[entityID] = RegisteredEventHandlers();
|
||||||
|
@ -558,7 +587,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) {
|
QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) {
|
||||||
if (_stoppingAllScripts) {
|
if (_stoppingAllScripts) {
|
||||||
return QScriptValue(); // bail early
|
return QScriptValue(); // bail early
|
||||||
}
|
}
|
||||||
|
@ -567,27 +596,30 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN
|
||||||
QScriptValue result;
|
QScriptValue result;
|
||||||
#ifdef THREAD_DEBUGGING
|
#ifdef THREAD_DEBUGGING
|
||||||
qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||||
"program:" << program << " fileName:" << fileName << "lineNumber:" << lineNumber;
|
"sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber;
|
||||||
#endif
|
#endif
|
||||||
QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection,
|
QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection,
|
||||||
Q_RETURN_ARG(QScriptValue, result),
|
Q_RETURN_ARG(QScriptValue, result),
|
||||||
Q_ARG(const QString&, program),
|
Q_ARG(const QString&, sourceCode),
|
||||||
Q_ARG(const QString&, fileName),
|
Q_ARG(const QString&, fileName),
|
||||||
Q_ARG(int, lineNumber));
|
Q_ARG(int, lineNumber));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check syntax
|
||||||
|
const QScriptProgram program(sourceCode, fileName, lineNumber);
|
||||||
|
if (!hasCorrectSyntax(program)) {
|
||||||
|
return QScriptValue();
|
||||||
|
}
|
||||||
|
|
||||||
_evaluatesPending++;
|
++_evaluatesPending;
|
||||||
QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber);
|
const auto result = QScriptEngine::evaluate(program);
|
||||||
if (hasUncaughtException()) {
|
--_evaluatesPending;
|
||||||
int line = uncaughtExceptionLineNumber();
|
|
||||||
qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << " : " << fileName << ") line" << line << ": " << result.toString();
|
const auto hadUncaughtException = hadUncauchtExceptions(*this, program.fileName());
|
||||||
}
|
|
||||||
_evaluatesPending--;
|
|
||||||
if (_wantSignals) {
|
if (_wantSignals) {
|
||||||
emit evaluationFinished(result, hasUncaughtException());
|
emit evaluationFinished(result, hadUncaughtException);
|
||||||
}
|
}
|
||||||
clearExceptions();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,7 +637,7 @@ void ScriptEngine::run() {
|
||||||
emit runningStateChanged();
|
emit runningStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue result = evaluate(_scriptContents);
|
QScriptValue result = evaluate(_scriptContents, _fileNameString);
|
||||||
|
|
||||||
QElapsedTimer startTime;
|
QElapsedTimer startTime;
|
||||||
startTime.start();
|
startTime.start();
|
||||||
|
@ -646,15 +678,6 @@ void ScriptEngine::run() {
|
||||||
qint64 now = usecTimestampNow();
|
qint64 now = usecTimestampNow();
|
||||||
float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND;
|
float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND;
|
||||||
|
|
||||||
if (hasUncaughtException()) {
|
|
||||||
int line = uncaughtExceptionLineNumber();
|
|
||||||
qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << uncaughtException().toString();
|
|
||||||
if (_wantSignals) {
|
|
||||||
emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString());
|
|
||||||
}
|
|
||||||
clearExceptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_isFinished) {
|
if (!_isFinished) {
|
||||||
if (_wantSignals) {
|
if (_wantSignals) {
|
||||||
emit update(deltaTime);
|
emit update(deltaTime);
|
||||||
|
@ -662,6 +685,9 @@ void ScriptEngine::run() {
|
||||||
}
|
}
|
||||||
lastUpdate = now;
|
lastUpdate = now;
|
||||||
|
|
||||||
|
if (hadUncauchtExceptions(*this, _fileNameString)) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stopAllTimers(); // make sure all our timers are stopped if the script is ending
|
stopAllTimers(); // make sure all our timers are stopped if the script is ending
|
||||||
|
@ -899,9 +925,9 @@ void ScriptEngine::load(const QString& loadFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
|
// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
|
||||||
void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) {
|
void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
qDebug() << "*** ERROR *** ScriptEngine::generalHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
|
qDebug() << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
|
||||||
assert(false);
|
assert(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -915,9 +941,8 @@ void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& e
|
||||||
}
|
}
|
||||||
QScriptValueList handlersForEvent = handlersOnEntity[eventName];
|
QScriptValueList handlersForEvent = handlersOnEntity[eventName];
|
||||||
if (!handlersForEvent.isEmpty()) {
|
if (!handlersForEvent.isEmpty()) {
|
||||||
QScriptValueList args = argGenerator();
|
|
||||||
for (int i = 0; i < handlersForEvent.count(); ++i) {
|
for (int i = 0; i < handlersForEvent.count(); ++i) {
|
||||||
handlersForEvent[i].call(QScriptValue(), args);
|
handlersForEvent[i].call(QScriptValue(), eventHanderArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -981,14 +1006,10 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
||||||
|
|
||||||
auto scriptCache = DependencyManager::get<ScriptCache>();
|
auto scriptCache = DependencyManager::get<ScriptCache>();
|
||||||
bool isFileUrl = isURL && scriptOrURL.startsWith("file://");
|
bool isFileUrl = isURL && scriptOrURL.startsWith("file://");
|
||||||
|
auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript");
|
||||||
|
|
||||||
// first check the syntax of the script contents
|
QScriptProgram program(contents, fileName);
|
||||||
QScriptSyntaxCheckResult syntaxCheck = QScriptEngine::checkSyntax(contents);
|
if (!hasCorrectSyntax(program)) {
|
||||||
if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
|
|
||||||
qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID;
|
|
||||||
qCDebug(scriptengine) << " " << syntaxCheck.errorMessage() << ":"
|
|
||||||
<< syntaxCheck.errorLineNumber() << syntaxCheck.errorColumnNumber();
|
|
||||||
qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL;
|
|
||||||
if (!isFileUrl) {
|
if (!isFileUrl) {
|
||||||
scriptCache->addScriptToBadScriptList(scriptOrURL);
|
scriptCache->addScriptToBadScriptList(scriptOrURL);
|
||||||
}
|
}
|
||||||
|
@ -1000,12 +1021,15 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptEngine sandbox;
|
QScriptEngine sandbox;
|
||||||
QScriptValue testConstructor = sandbox.evaluate(contents);
|
QScriptValue testConstructor = sandbox.evaluate(program);
|
||||||
|
if (hadUncauchtExceptions(sandbox, program.fileName())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!testConstructor.isFunction()) {
|
if (!testConstructor.isFunction()) {
|
||||||
qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID;
|
qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n"
|
||||||
qCDebug(scriptengine) << " NOT CONSTRUCTOR";
|
" NOT CONSTRUCTOR\n"
|
||||||
qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL;
|
" SCRIPT:" << scriptOrURL;
|
||||||
if (!isFileUrl) {
|
if (!isFileUrl) {
|
||||||
scriptCache->addScriptToBadScriptList(scriptOrURL);
|
scriptCache->addScriptToBadScriptList(scriptOrURL);
|
||||||
}
|
}
|
||||||
|
@ -1018,7 +1042,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
||||||
lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();
|
lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue entityScriptConstructor = evaluate(contents);
|
QScriptValue entityScriptConstructor = evaluate(contents, fileName);
|
||||||
QScriptValue entityScriptObject = entityScriptConstructor.construct();
|
QScriptValue entityScriptObject = entityScriptConstructor.construct();
|
||||||
EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified };
|
EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified };
|
||||||
_entityScripts[entityID] = newDetails;
|
_entityScripts[entityID] = newDetails;
|
||||||
|
|
|
@ -88,7 +88,7 @@ public:
|
||||||
Q_INVOKABLE void registerValue(const QString& valueName, QScriptValue value);
|
Q_INVOKABLE void registerValue(const QString& valueName, QScriptValue value);
|
||||||
|
|
||||||
/// evaluate some code in the context of the ScriptEngine and return the result
|
/// evaluate some code in the context of the ScriptEngine and return the result
|
||||||
Q_INVOKABLE QScriptValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1); // this is also used by the script tool widget
|
Q_INVOKABLE QScriptValue evaluate(const QString& program, const QString& fileName, int lineNumber = 1); // this is also used by the script tool widget
|
||||||
|
|
||||||
/// if the script engine is not already running, this will download the URL and start the process of seting it up
|
/// if the script engine is not already running, this will download the URL and start the process of seting it up
|
||||||
/// to run... NOTE - this is used by Application currently to load the url. We don't really want it to be exposed
|
/// to run... NOTE - this is used by Application currently to load the url. We don't really want it to be exposed
|
||||||
|
@ -181,7 +181,7 @@ private:
|
||||||
|
|
||||||
QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot);
|
QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot);
|
||||||
void stopTimer(QTimer* timer);
|
void stopTimer(QTimer* timer);
|
||||||
|
|
||||||
AbstractControllerScriptingInterface* _controllerScriptingInterface;
|
AbstractControllerScriptingInterface* _controllerScriptingInterface;
|
||||||
QString _fileNameString;
|
QString _fileNameString;
|
||||||
Quat _quatLibrary;
|
Quat _quatLibrary;
|
||||||
|
@ -193,7 +193,7 @@ private:
|
||||||
ArrayBufferClass* _arrayBufferClass;
|
ArrayBufferClass* _arrayBufferClass;
|
||||||
|
|
||||||
QHash<EntityItemID, RegisteredEventHandlers> _registeredHandlers;
|
QHash<EntityItemID, RegisteredEventHandlers> _registeredHandlers;
|
||||||
void generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator);
|
void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs);
|
||||||
Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success);
|
Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success);
|
||||||
|
|
||||||
static QSet<ScriptEngine*> _allKnownScriptEngines;
|
static QSet<ScriptEngine*> _allKnownScriptEngines;
|
||||||
|
|
|
@ -135,7 +135,7 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
|
||||||
prefixString.append(QString(" [%1]").arg(_targetName));
|
prefixString.append(QString(" [%1]").arg(_targetName));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString logMessage = QString("%1 %2").arg(prefixString, message);
|
QString logMessage = QString("%1 %2").arg(prefixString, message.split("\n").join("\n" + prefixString + " "));
|
||||||
fprintf(stdout, "%s\n", qPrintable(logMessage));
|
fprintf(stdout, "%s\n", qPrintable(logMessage));
|
||||||
return logMessage;
|
return logMessage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
class ReadWriteLockable {
|
class ReadWriteLockable {
|
||||||
public:
|
public:
|
||||||
template <typename F>
|
template <typename F>
|
||||||
bool withWriteLock(F f, bool require = true) {
|
bool withWriteLock(F f, bool require = true) const {
|
||||||
if (!require) {
|
if (!require) {
|
||||||
bool result = _lock.tryLockForWrite();
|
bool result = _lock.tryLockForWrite();
|
||||||
if (result) {
|
if (result) {
|
||||||
|
@ -22,7 +22,7 @@ public:
|
||||||
_lock.unlock();
|
_lock.unlock();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWriteLocker locker(&_lock);
|
QWriteLocker locker(&_lock);
|
||||||
f();
|
f();
|
||||||
|
@ -30,7 +30,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
bool withTryWriteLock(F f) {
|
bool withTryWriteLock(F f) const {
|
||||||
return withWriteLock(f, false);
|
return withWriteLock(f, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
set(TARGET_NAME ui)
|
set(TARGET_NAME ui)
|
||||||
setup_hifi_library(OpenGL Network Qml Quick Script XmlPatterns)
|
setup_hifi_library(OpenGL Network Qml Quick Script XmlPatterns)
|
||||||
link_hifi_libraries(render-utils shared)
|
link_hifi_libraries(shared networking gl)
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#ifndef hifi_OffscreenUi_h
|
#ifndef hifi_OffscreenUi_h
|
||||||
#define hifi_OffscreenUi_h
|
#define hifi_OffscreenUi_h
|
||||||
|
|
||||||
#include "OffscreenQmlSurface.h"
|
#include <gl/OffscreenQmlSurface.h>
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
|
|
|
@ -3,5 +3,5 @@ AUTOSCRIBE_SHADER_LIB(gpu model render-utils)
|
||||||
# This is not a testcase -- just set it up as a regular hifi project
|
# This is not a testcase -- just set it up as a regular hifi project
|
||||||
setup_hifi_project(Quick Gui OpenGL Script Widgets)
|
setup_hifi_project(Quick Gui OpenGL Script Widgets)
|
||||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||||
link_hifi_libraries(networking gpu procedural shared fbx model model-networking animation script-engine render-utils )
|
link_hifi_libraries(networking gl gpu procedural shared fbx model model-networking animation script-engine render-utils )
|
||||||
copy_dlls_beside_windows_executable()
|
copy_dlls_beside_windows_executable()
|
|
@ -6,8 +6,6 @@ setup_hifi_project(Quick Gui OpenGL)
|
||||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||||
|
|
||||||
# link in the shared libraries
|
# link in the shared libraries
|
||||||
link_hifi_libraries(render-utils gpu shared)
|
link_hifi_libraries(render-utils gl gpu shared)
|
||||||
|
|
||||||
message(${PROJECT_BINARY_DIR})
|
|
||||||
|
|
||||||
copy_dlls_beside_windows_executable()
|
copy_dlls_beside_windows_executable()
|
||||||
|
|
|
@ -8,8 +8,8 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||||
#include_oglplus()
|
#include_oglplus()
|
||||||
|
|
||||||
# link in the shared libraries
|
# link in the shared libraries
|
||||||
link_hifi_libraries(shared octree environment gpu model render fbx networking entities
|
link_hifi_libraries(shared octree environment gl gpu model render fbx networking entities
|
||||||
script-engine physics
|
script-engine physics
|
||||||
render-utils entities-renderer)
|
render-utils entities-renderer)
|
||||||
|
|
||||||
include_directories("${PROJECT_BINARY_DIR}/../../libraries/gpu/")
|
include_directories("${PROJECT_BINARY_DIR}/../../libraries/gpu/")
|
||||||
|
@ -17,6 +17,4 @@ include_directories("${PROJECT_BINARY_DIR}/../../libraries/render-utils/")
|
||||||
include_directories("${PROJECT_BINARY_DIR}/../../libraries/entities-renderer/")
|
include_directories("${PROJECT_BINARY_DIR}/../../libraries/entities-renderer/")
|
||||||
include_directories("${PROJECT_BINARY_DIR}/../../libraries/model/")
|
include_directories("${PROJECT_BINARY_DIR}/../../libraries/model/")
|
||||||
|
|
||||||
message(${PROJECT_BINARY_DIR})
|
|
||||||
|
|
||||||
copy_dlls_beside_windows_executable()
|
copy_dlls_beside_windows_executable()
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
|
||||||
#include <GLHelpers.h>
|
#include <gl/GLHelpers.h>
|
||||||
|
|
||||||
#include "../model/Skybox_vert.h"
|
#include "../model/Skybox_vert.h"
|
||||||
#include "../model/Skybox_frag.h"
|
#include "../model/Skybox_frag.h"
|
||||||
|
|
|
@ -11,6 +11,6 @@ if (WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# link in the shared libraries
|
# link in the shared libraries
|
||||||
link_hifi_libraries(ui render-utils gpu shared)
|
link_hifi_libraries(shared networking gl gpu ui)
|
||||||
|
|
||||||
copy_dlls_beside_windows_executable()
|
copy_dlls_beside_windows_executable()
|
||||||
|
|
Loading…
Reference in a new issue