Merge branch 'master' of https://github.com/highfidelity/hifi into expose-anim-vars

This commit is contained in:
Howard Stearns 2015-10-29 08:25:41 -07:00
commit d79d0bc5c5
66 changed files with 730 additions and 544 deletions

View file

@ -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())) {

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -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();
} }
} }

View file

@ -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) {

View file

@ -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.
@ -166,10 +171,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();
@ -274,9 +281,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;
@ -307,7 +314,7 @@ private:
quint32 _motionBehaviors; quint32 _motionBehaviors;
QString _collisionSoundURL; QString _collisionSoundURL;
DynamicCharacterController _characterController; MyCharacterController _characterController;
AvatarWeakPointer _lookAtTargetAvatar; AvatarWeakPointer _lookAtTargetAvatar;
glm::vec3 _targetAvatarPosition; glm::vec3 _targetAvatarPosition;
@ -360,21 +367,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);

View file

@ -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()));
}
} }

View 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

View file

@ -117,8 +117,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
Rig::HeadParameters headParams; Rig::HeadParameters headParams;
headParams.modelRotation = getRotation();
headParams.modelTranslation = getTranslation();
headParams.enableLean = qApp->getAvatarUpdater()->isHMDMode(); headParams.enableLean = qApp->getAvatarUpdater()->isHMDMode();
headParams.leanSideways = head->getFinalLeanSideways(); headParams.leanSideways = head->getFinalLeanSideways();
headParams.leanForward = head->getFinalLeanForward(); headParams.leanForward = head->getFinalLeanForward();
@ -152,19 +150,13 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
headParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame(); headParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame();
} }
headParams.eyeLookAt = head->getLookAtPosition();
headParams.eyeSaccade = head->getSaccade();
headParams.leanJointIndex = geometry.leanJointIndex; headParams.leanJointIndex = geometry.leanJointIndex;
headParams.neckJointIndex = geometry.neckJointIndex; headParams.neckJointIndex = geometry.neckJointIndex;
headParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
headParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
headParams.isTalking = head->getTimeWithoutTalking() <= 1.5f; headParams.isTalking = head->getTimeWithoutTalking() <= 1.5f;
_rig->updateFromHeadParameters(headParams, deltaTime); _rig->updateFromHeadParameters(headParams, deltaTime);
Rig::HandParameters handParams; Rig::HandParameters handParams;
const PalmData* leftPalm = getPalmWithIndex(myAvatar->getHand(), LEFT_HAND_INDEX); const PalmData* leftPalm = getPalmWithIndex(myAvatar->getHand(), LEFT_HAND_INDEX);
if (leftPalm && leftPalm->isActive()) { if (leftPalm && leftPalm->isActive()) {
handParams.isLeftEnabled = true; handParams.isLeftEnabled = true;
@ -188,8 +180,28 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
_rig->updateFromHandParameters(handParams, deltaTime); _rig->updateFromHandParameters(handParams, deltaTime);
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation()); _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation());
// evaluate AnimGraph animation and update jointStates.
Model::updateRig(deltaTime, parentTransform);
Rig::EyeParameters eyeParams;
eyeParams.worldHeadOrientation = headParams.worldHeadOrientation;
eyeParams.eyeLookAt = head->getLookAtPosition();
eyeParams.eyeSaccade = head->getSaccade();
eyeParams.modelRotation = getRotation();
eyeParams.modelTranslation = getTranslation();
eyeParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
_rig->updateFromEyeParameters(eyeParams);
// rebuild the jointState transform for the eyes only. Must be after updateRig.
_rig->updateJointState(eyeParams.leftEyeJointIndex, parentTransform);
_rig->updateJointState(eyeParams.rightEyeJointIndex, parentTransform);
} else { } else {
Model::updateRig(deltaTime, parentTransform);
// This is a little more work than we really want. // This is a little more work than we really want.
// //
// Other avatars joint, including their eyes, should already be set just like any other joints // Other avatars joint, including their eyes, should already be set just like any other joints
@ -206,11 +218,17 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
head->setBasePitch(glm::degrees(-eulers.x)); head->setBasePitch(glm::degrees(-eulers.x));
head->setBaseYaw(glm::degrees(eulers.y)); head->setBaseYaw(glm::degrees(eulers.y));
head->setBaseRoll(glm::degrees(-eulers.z)); head->setBaseRoll(glm::degrees(-eulers.z));
_rig->updateEyeJoints(geometry.leftEyeJointIndex, geometry.rightEyeJointIndex,
getTranslation(), getRotation(), Rig::EyeParameters eyeParams;
head->getFinalOrientationInWorldFrame(), head->getCorrectedLookAtPosition()); eyeParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame();
eyeParams.eyeLookAt = head->getCorrectedLookAtPosition();
eyeParams.eyeSaccade = glm::vec3();
eyeParams.modelRotation = getRotation();
eyeParams.modelTranslation = getTranslation();
eyeParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
_rig->updateFromEyeParameters(eyeParams);
} }
Model::updateRig(deltaTime, parentTransform);
} }
void SkeletonModel::updateAttitude() { void SkeletonModel::updateAttitude() {

View file

@ -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;
} }

View file

@ -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;

View file

@ -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;
} }
} }

View file

@ -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

View file

@ -23,34 +23,6 @@
#include "AnimSkeleton.h" #include "AnimSkeleton.h"
#include "IKTarget.h" #include "IKTarget.h"
void Rig::HeadParameters::dump() const {
qCDebug(animation, "HeadParameters =");
qCDebug(animation, " leanSideways = %0.5f", (double)leanSideways);
qCDebug(animation, " leanForward = %0.5f", (double)leanForward);
qCDebug(animation, " torsoTwist = %0.5f", (double)torsoTwist);
glm::vec3 axis = glm::axis(localHeadOrientation);
float theta = glm::angle(localHeadOrientation);
qCDebug(animation, " localHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
axis = glm::axis(worldHeadOrientation);
theta = glm::angle(worldHeadOrientation);
qCDebug(animation, " localHead pitch = %.5f, yaw = %.5f, roll = %.5f", (double)localHeadPitch, (double)localHeadYaw, (double)localHeadRoll);
qCDebug(animation, " localHeadPosition = (%.5f, %.5f, %.5f)", (double)localHeadPosition.x, (double)localHeadPosition.y, (double)localHeadPosition.z);
qCDebug(animation, " isInHMD = %s", isInHMD ? "true" : "false");
qCDebug(animation, " worldHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
axis = glm::axis(modelRotation);
theta = glm::angle(modelRotation);
qCDebug(animation, " modelRotation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
qCDebug(animation, " modelTranslation = (%.5f, %.5f, %.5f)", (double)modelTranslation.x, (double)modelTranslation.y, (double)modelTranslation.z);
qCDebug(animation, " eyeLookAt = (%.5f, %.5f, %.5f)", (double)eyeLookAt.x, (double)eyeLookAt.y, (double)eyeLookAt.z);
qCDebug(animation, " eyeSaccade = (%.5f, %.5f, %.5f)", (double)eyeSaccade.x, (double)eyeSaccade.y, (double)eyeSaccade.z);
qCDebug(animation, " leanJointIndex = %.d", leanJointIndex);
qCDebug(animation, " neckJointIndex = %.d", neckJointIndex);
qCDebug(animation, " leftEyeJointIndex = %.d", leftEyeJointIndex);
qCDebug(animation, " rightEyeJointIndex = %.d", rightEyeJointIndex);
qCDebug(animation, " isTalking = %s", isTalking ? "true" : "false");
}
void insertSorted(QList<AnimationHandlePointer>& handles, const AnimationHandlePointer& handle) { void insertSorted(QList<AnimationHandlePointer>& handles, const AnimationHandlePointer& handle) {
for (QList<AnimationHandlePointer>::iterator it = handles.begin(); it != handles.end(); it++) { for (QList<AnimationHandlePointer>::iterator it = handles.begin(); it != handles.end(); it++) {
if (handle->getPriority() > (*it)->getPriority()) { if (handle->getPriority() > (*it)->getPriority()) {
@ -1045,8 +1017,6 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
_animVars.unset("lean"); _animVars.unset("lean");
} }
updateNeckJoint(params.neckJointIndex, params); updateNeckJoint(params.neckJointIndex, params);
updateEyeJoints(params.leftEyeJointIndex, params.rightEyeJointIndex, params.modelTranslation, params.modelRotation,
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
if (_enableAnimGraph) { if (_enableAnimGraph) {
_animVars.set("isTalking", params.isTalking); _animVars.set("isTalking", params.isTalking);
@ -1054,6 +1024,13 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
} }
} }
void Rig::updateFromEyeParameters(const EyeParameters& params) {
updateEyeJoint(params.leftEyeJointIndex, params.modelTranslation, params.modelRotation,
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
updateEyeJoint(params.rightEyeJointIndex, params.modelTranslation, params.modelRotation,
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
}
static const glm::vec3 X_AXIS(1.0f, 0.0f, 0.0f); static const glm::vec3 X_AXIS(1.0f, 0.0f, 0.0f);
static const glm::vec3 Y_AXIS(0.0f, 1.0f, 0.0f); static const glm::vec3 Y_AXIS(0.0f, 1.0f, 0.0f);
static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f); static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f);
@ -1209,12 +1186,6 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
} }
} }
void Rig::updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation,
const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) {
updateEyeJoint(leftEyeIndex, modelTranslation, modelRotation, worldHeadOrientation, lookAtSpot, saccade);
updateEyeJoint(rightEyeIndex, modelTranslation, modelRotation, worldHeadOrientation, lookAtSpot, saccade);
}
void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) { void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) {
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
auto& state = _jointStates[index]; auto& state = _jointStates[index];

View file

@ -65,24 +65,26 @@ public:
float leanForward = 0.0f; // degrees float leanForward = 0.0f; // degrees
float torsoTwist = 0.0f; // degrees float torsoTwist = 0.0f; // degrees
bool enableLean = false; bool enableLean = false;
glm::quat modelRotation = glm::quat(); glm::quat worldHeadOrientation = glm::quat();
glm::quat localHeadOrientation = glm::quat(); glm::quat localHeadOrientation = glm::quat();
float localHeadPitch = 0.0f; // degrees float localHeadPitch = 0.0f; // degrees
float localHeadYaw = 0.0f; // degrees float localHeadYaw = 0.0f; // degrees
float localHeadRoll = 0.0f; // degrees float localHeadRoll = 0.0f; // degrees
glm::vec3 localHeadPosition = glm::vec3(); glm::vec3 localHeadPosition = glm::vec3();
bool isInHMD = false; bool isInHMD = false;
int leanJointIndex = -1;
int neckJointIndex = -1;
bool isTalking = false;
};
struct EyeParameters {
glm::quat worldHeadOrientation = glm::quat(); glm::quat worldHeadOrientation = glm::quat();
glm::vec3 eyeLookAt = glm::vec3(); // world space glm::vec3 eyeLookAt = glm::vec3(); // world space
glm::vec3 eyeSaccade = glm::vec3(); // world space glm::vec3 eyeSaccade = glm::vec3(); // world space
glm::vec3 modelTranslation = glm::vec3(); glm::vec3 modelTranslation = glm::vec3();
int leanJointIndex = -1; glm::quat modelRotation = glm::quat();
int neckJointIndex = -1;
int leftEyeJointIndex = -1; int leftEyeJointIndex = -1;
int rightEyeJointIndex = -1; int rightEyeJointIndex = -1;
bool isTalking = false;
void dump() const;
}; };
struct HandParameters { struct HandParameters {
@ -193,9 +195,7 @@ public:
bool getEnableAnimGraph() const { return _enableAnimGraph; } bool getEnableAnimGraph() const { return _enableAnimGraph; }
void updateFromHeadParameters(const HeadParameters& params, float dt); void updateFromHeadParameters(const HeadParameters& params, float dt);
void updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation, void updateFromEyeParameters(const EyeParameters& params);
const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade = glm::vec3(0.0f));
void updateFromHandParameters(const HandParameters& params, float dt); void updateFromHandParameters(const HandParameters& params, float dt);
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,

View file

@ -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()

View file

@ -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>

View file

@ -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>

View file

@ -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;

View file

@ -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"

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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()

View file

@ -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;

View file

@ -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();

View file

@ -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>

View file

@ -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;
} }

View file

@ -64,7 +64,7 @@ Extents FBXGeometry::getUnscaledMeshExtents() const {
glm::vec3 minimum = glm::vec3(offset * glm::vec4(extents.minimum, 1.0f)); glm::vec3 minimum = glm::vec3(offset * glm::vec4(extents.minimum, 1.0f));
glm::vec3 maximum = glm::vec3(offset * glm::vec4(extents.maximum, 1.0f)); glm::vec3 maximum = glm::vec3(offset * glm::vec4(extents.maximum, 1.0f));
Extents scaledExtents = { minimum, maximum }; Extents scaledExtents = { minimum, maximum };
return scaledExtents; return scaledExtents;
} }
@ -73,7 +73,7 @@ bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
if (!getUnscaledMeshExtents().containsPoint(point)) { if (!getUnscaledMeshExtents().containsPoint(point)) {
return false; return false;
} }
auto checkEachPrimitive = [=](FBXMesh& mesh, QVector<int> indices, int primitiveSize) -> bool { auto checkEachPrimitive = [=](FBXMesh& mesh, QVector<int> indices, int primitiveSize) -> bool {
// Check whether the point is "behind" all the primitives. // Check whether the point is "behind" all the primitives.
for (int j = 0; j < indices.size(); j += primitiveSize) { for (int j = 0; j < indices.size(); j += primitiveSize) {
@ -87,11 +87,11 @@ bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
} }
return true; return true;
}; };
// Check that the point is contained in at least one convex mesh. // Check that the point is contained in at least one convex mesh.
for (auto mesh : meshes) { for (auto mesh : meshes) {
bool insideMesh = true; bool insideMesh = true;
// To be considered inside a convex mesh, // To be considered inside a convex mesh,
// the point needs to be "behind" all the primitives respective planes. // the point needs to be "behind" all the primitives respective planes.
for (auto part : mesh.parts) { for (auto part : mesh.parts) {
@ -108,7 +108,7 @@ bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
return true; return true;
} }
} }
// It wasn't in any mesh, return false. // It wasn't in any mesh, return false.
return false; return false;
} }
@ -194,7 +194,7 @@ public:
glm::vec3 rotationMax; // radians glm::vec3 rotationMax; // radians
}; };
glm::mat4 getGlobalTransform(const QMultiHash<QString, QString>& _connectionParentMap, glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParentMap,
const QHash<QString, FBXModel>& models, QString nodeID, bool mixamoHack) { const QHash<QString, FBXModel>& models, QString nodeID, bool mixamoHack) {
glm::mat4 globalTransform; glm::mat4 globalTransform;
while (!nodeID.isNull()) { while (!nodeID.isNull()) {
@ -228,12 +228,12 @@ void printNode(const FBXNode& node, int indentLevel) {
int indentLength = 2; int indentLength = 2;
QByteArray spaces(indentLevel * indentLength, ' '); QByteArray spaces(indentLevel * indentLength, ' ');
QDebug nodeDebug = qDebug(modelformat); QDebug nodeDebug = qDebug(modelformat);
nodeDebug.nospace() << spaces.data() << node.name.data() << ": "; nodeDebug.nospace() << spaces.data() << node.name.data() << ": ";
foreach (const QVariant& property, node.properties) { foreach (const QVariant& property, node.properties) {
nodeDebug << property; nodeDebug << property;
} }
foreach (const FBXNode& child, node.children) { foreach (const FBXNode& child, node.children) {
printNode(child, indentLevel + 1); printNode(child, indentLevel + 1);
} }
@ -246,7 +246,7 @@ public:
glm::mat4 transformLink; glm::mat4 transformLink;
}; };
void appendModelIDs(const QString& parentID, const QMultiHash<QString, QString>& connectionChildMap, void appendModelIDs(const QString& parentID, const QMultiMap<QString, QString>& connectionChildMap,
QHash<QString, FBXModel>& models, QSet<QString>& remainingModels, QVector<QString>& modelIDs) { QHash<QString, FBXModel>& models, QSet<QString>& remainingModels, QVector<QString>& modelIDs) {
if (remainingModels.contains(parentID)) { if (remainingModels.contains(parentID)) {
modelIDs.append(parentID); modelIDs.append(parentID);
@ -331,7 +331,7 @@ void addBlendshapes(const ExtractedBlendshape& extracted, const QList<WeightedIn
} }
} }
QString getTopModelID(const QMultiHash<QString, QString>& connectionParentMap, QString getTopModelID(const QMultiMap<QString, QString>& connectionParentMap,
const QHash<QString, FBXModel>& models, const QString& modelID) { const QHash<QString, FBXModel>& models, const QString& modelID) {
QString topID = modelID; QString topID = modelID;
forever { forever {
@ -342,7 +342,7 @@ QString getTopModelID(const QMultiHash<QString, QString>& connectionParentMap,
} }
} }
return topID; return topID;
outerContinue: ; outerContinue: ;
} }
} }
@ -361,7 +361,7 @@ public:
}; };
bool checkMaterialsHaveTextures(const QHash<QString, FBXMaterial>& materials, bool checkMaterialsHaveTextures(const QHash<QString, FBXMaterial>& materials,
const QHash<QString, QByteArray>& textureFilenames, const QMultiHash<QString, QString>& _connectionChildMap) { const QHash<QString, QByteArray>& textureFilenames, const QMultiMap<QString, QString>& _connectionChildMap) {
foreach (const QString& materialID, materials.keys()) { foreach (const QString& materialID, materials.keys()) {
foreach (const QString& childID, _connectionChildMap.values(materialID)) { foreach (const QString& childID, _connectionChildMap.values(materialID)) {
if (textureFilenames.contains(childID)) { if (textureFilenames.contains(childID)) {
@ -443,8 +443,8 @@ QByteArray fileOnUrl(const QByteArray& filenameString, const QString& url) {
} }
FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) { FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) {
const FBXNode& node = _fbxNode; const FBXNode& node = _fbxNode;
QHash<QString, ExtractedMesh> meshes; QMap<QString, ExtractedMesh> meshes;
QHash<QString, QString> modelIDsToNames; QHash<QString, QString> modelIDsToNames;
QHash<QString, int> meshIDsToMeshIndices; QHash<QString, int> meshIDsToMeshIndices;
QHash<QString, QString> ooChildToParent; QHash<QString, QString> ooChildToParent;
@ -497,7 +497,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
QVector<QString> humanIKJointIDs(humanIKJointNames.size()); QVector<QString> humanIKJointIDs(humanIKJointNames.size());
QVariantHash blendshapeMappings = mapping.value("bs").toHash(); QVariantHash blendshapeMappings = mapping.value("bs").toHash();
QMultiHash<QByteArray, WeightedIndex> blendshapeIndices; QMultiHash<QByteArray, WeightedIndex> blendshapeIndices;
for (int i = 0;; i++) { for (int i = 0;; i++) {
QByteArray blendshapeName = FACESHIFT_BLENDSHAPES[i]; QByteArray blendshapeName = FACESHIFT_BLENDSHAPES[i];
@ -527,7 +527,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
QString hifiGlobalNodeID; QString hifiGlobalNodeID;
unsigned int meshIndex = 0; unsigned int meshIndex = 0;
foreach (const FBXNode& child, node.children) { foreach (const FBXNode& child, node.children) {
if (child.name == "FBXHeaderExtension") { if (child.name == "FBXHeaderExtension") {
foreach (const FBXNode& object, child.children) { foreach (const FBXNode& object, child.children) {
if (object.name == "SceneInfo") { if (object.name == "SceneInfo") {
@ -537,7 +537,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
if (subsubobject.name == "Author") { if (subsubobject.name == "Author") {
geometry.author = subsubobject.properties.at(0).toString(); geometry.author = subsubobject.properties.at(0).toString();
} }
} }
} else if (subobject.name == "Properties70") { } else if (subobject.name == "Properties70") {
foreach (const FBXNode& subsubobject, subobject.children) { foreach (const FBXNode& subsubobject, subobject.children) {
if (subsubobject.name == "P" && subsubobject.properties.size() >= 5 && if (subsubobject.name == "P" && subsubobject.properties.size() >= 5 &&
@ -620,7 +620,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
if (humanIKJointIndex != -1) { if (humanIKJointIndex != -1) {
humanIKJointIDs[humanIKJointIndex] = getID(object.properties); humanIKJointIDs[humanIKJointIndex] = getID(object.properties);
} }
glm::vec3 translation; glm::vec3 translation;
// NOTE: the euler angles as supplied by the FBX file are in degrees // NOTE: the euler angles as supplied by the FBX file are in degrees
glm::vec3 rotationOffset; glm::vec3 rotationOffset;
@ -709,7 +709,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
// it's a mesh as well as a model // it's a mesh as well as a model
mesh = &meshes[getID(object.properties)]; mesh = &meshes[getID(object.properties)];
*mesh = extractMesh(object, meshIndex); *mesh = extractMesh(object, meshIndex);
} else if (subobject.name == "Shape") { } else if (subobject.name == "Shape") {
ExtractedBlendshape blendshape = { subobject.properties.at(0).toString(), ExtractedBlendshape blendshape = { subobject.properties.at(0).toString(),
extractBlendshape(subobject) }; extractBlendshape(subobject) };
@ -720,7 +720,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
QString attributetype = subobject.properties.at(0).toString(); QString attributetype = subobject.properties.at(0).toString();
if (!attributetype.empty()) { if (!attributetype.empty()) {
if (attributetype == "Light") { if (attributetype == "Light") {
QString lightprop; QString lightprop;
foreach (const QVariant& vprop, subobject.properties) { foreach (const QVariant& vprop, subobject.properties) {
lightprop = vprop.toString(); lightprop = vprop.toString();
} }
@ -731,23 +731,23 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
} else { } else {
QString whatisthat = subobject.name; QString whatisthat = subobject.name;
if (whatisthat == "Shape") { if (whatisthat == "Shape") {
} }
} }
#endif #endif
} }
// add the blendshapes included in the model, if any // add the blendshapes included in the model, if any
if (mesh) { if (mesh) {
foreach (const ExtractedBlendshape& extracted, blendshapes) { foreach (const ExtractedBlendshape& extracted, blendshapes) {
addBlendshapes(extracted, blendshapeIndices.values(extracted.id.toLatin1()), *mesh); addBlendshapes(extracted, blendshapeIndices.values(extracted.id.toLatin1()), *mesh);
} }
} }
// see FBX documentation, http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html // see FBX documentation, http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html
model.translation = translation; model.translation = translation;
model.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot); model.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot);
model.preRotation = glm::quat(glm::radians(preRotation)); model.preRotation = glm::quat(glm::radians(preRotation));
model.rotation = glm::quat(glm::radians(rotation)); model.rotation = glm::quat(glm::radians(rotation));
model.postRotation = glm::quat(glm::radians(postRotation)); model.postRotation = glm::quat(glm::radians(postRotation));
@ -862,7 +862,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
if (subobject.name == "RelativeFilename") { if (subobject.name == "RelativeFilename") {
filename = subobject.properties.at(0).toByteArray(); filename = subobject.properties.at(0).toByteArray();
filename = fileOnUrl(filename, url); filename = fileOnUrl(filename, url);
} else if (subobject.name == "Content" && !subobject.properties.isEmpty()) { } else if (subobject.name == "Content" && !subobject.properties.isEmpty()) {
content = subobject.properties.at(0).toByteArray(); content = subobject.properties.at(0).toByteArray();
} }
@ -905,10 +905,10 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
} else if (property.properties.at(0) == "Emissive") { } else if (property.properties.at(0) == "Emissive") {
material.emissiveColor = getVec3(property.properties, index); material.emissiveColor = getVec3(property.properties, index);
} else if (property.properties.at(0) == "Shininess") { } else if (property.properties.at(0) == "Shininess") {
material.shininess = property.properties.at(index).value<double>(); material.shininess = property.properties.at(index).value<double>();
} else if (property.properties.at(0) == "Opacity") { } else if (property.properties.at(0) == "Opacity") {
material.opacity = property.properties.at(index).value<double>(); material.opacity = property.properties.at(index).value<double>();
} }
@ -1001,7 +1001,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
} }
} }
animationCurves.insert(getID(object.properties), curve); animationCurves.insert(getID(object.properties), curve);
} }
#if defined(DEBUG_FBXREADER) #if defined(DEBUG_FBXREADER)
else { else {
@ -1013,7 +1013,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
} else { } else {
unknown++; unknown++;
} }
} }
#endif #endif
} }
} else if (child.name == "Connections") { } else if (child.name == "Connections") {
@ -1041,14 +1041,14 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (type.contains("transparentcolor")) { // it should be TransparentColor... } else if (type.contains("transparentcolor")) { // it should be TransparentColor...
// THis is how Maya assign a texture that affect diffuse color AND transparency ? // THis is how Maya assign a texture that affect diffuse color AND transparency ?
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (type.contains("bump")) { } else if (type.contains("bump")) {
bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (type.contains("normal")) { } else if (type.contains("normal")) {
normalTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); normalTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (type.contains("specular") || type.contains("reflection")) { } else if (type.contains("specular") || type.contains("reflection")) {
specularTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); specularTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (type == "lcl rotation") { } else if (type == "lcl rotation") {
localRotations.insert(getID(connection.properties, 2), getID(connection.properties, 1)); localRotations.insert(getID(connection.properties, 2), getID(connection.properties, 1));
@ -1097,7 +1097,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
} else { } else {
unknown++; unknown++;
} }
} }
#endif #endif
} }
@ -1142,7 +1142,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
} }
} }
outerBreak: outerBreak:
// make sure the parent is in the child map // make sure the parent is in the child map
QString parent = _connectionParentMap.value(model.key()); QString parent = _connectionParentMap.value(model.key());
if (!_connectionChildMap.contains(parent, model.key())) { if (!_connectionChildMap.contains(parent, model.key())) {
@ -1172,7 +1172,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
frame.translations.resize(modelIDs.size()); frame.translations.resize(modelIDs.size());
geometry.animationFrames.append(frame); geometry.animationFrames.append(frame);
} }
// convert the models to joints // convert the models to joints
QVariantList freeJoints = mapping.values("freeJoint"); QVariantList freeJoints = mapping.values("freeJoint");
geometry.hasSkeletonJoints = false; geometry.hasSkeletonJoints = false;
@ -1181,7 +1181,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
FBXJoint joint; FBXJoint joint;
joint.isFree = freeJoints.contains(model.name); joint.isFree = freeJoints.contains(model.name);
joint.parentIndex = model.parentIndex; joint.parentIndex = model.parentIndex;
// get the indices of all ancestors starting with the first free one (if any) // get the indices of all ancestors starting with the first free one (if any)
int jointIndex = geometry.joints.size(); int jointIndex = geometry.joints.size();
joint.freeLineage.append(jointIndex); joint.freeLineage.append(jointIndex);
@ -1203,7 +1203,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
joint.rotationMax = model.rotationMax; joint.rotationMax = model.rotationMax;
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation; glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
if (joint.parentIndex == -1) { if (joint.parentIndex == -1) {
joint.transform = geometry.offset * glm::translate(joint.translation) * joint.preTransform * joint.transform = geometry.offset * glm::translate(joint.translation) * joint.preTransform *
glm::mat4_cast(combinedRotation) * joint.postTransform; glm::mat4_cast(combinedRotation) * joint.postTransform;
joint.inverseDefaultRotation = glm::inverse(combinedRotation); joint.inverseDefaultRotation = glm::inverse(combinedRotation);
joint.distanceToParent = 0.0f; joint.distanceToParent = 0.0f;
@ -1272,11 +1272,11 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
geometry.rightHandJointIndex = modelIDs.indexOf(jointRightHandID); geometry.rightHandJointIndex = modelIDs.indexOf(jointRightHandID);
geometry.leftToeJointIndex = modelIDs.indexOf(jointLeftToeID); geometry.leftToeJointIndex = modelIDs.indexOf(jointLeftToeID);
geometry.rightToeJointIndex = modelIDs.indexOf(jointRightToeID); geometry.rightToeJointIndex = modelIDs.indexOf(jointRightToeID);
foreach (const QString& id, humanIKJointIDs) { foreach (const QString& id, humanIKJointIDs) {
geometry.humanIKJointIndices.append(modelIDs.indexOf(id)); geometry.humanIKJointIndices.append(modelIDs.indexOf(id));
} }
// extract the translation component of the neck transform // extract the translation component of the neck transform
if (geometry.neckJointIndex != -1) { if (geometry.neckJointIndex != -1) {
const glm::mat4& transform = geometry.joints.at(geometry.neckJointIndex).transform; const glm::mat4& transform = geometry.joints.at(geometry.neckJointIndex).transform;
@ -1285,7 +1285,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
geometry.bindExtents.reset(); geometry.bindExtents.reset();
geometry.meshExtents.reset(); geometry.meshExtents.reset();
// Create the Material Library // Create the Material Library
consolidateFBXMaterials(); consolidateFBXMaterials();
geometry.materials = _fbxMaterials; geometry.materials = _fbxMaterials;
@ -1293,9 +1293,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
// see if any materials have texture children // see if any materials have texture children
bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilenames, _connectionChildMap); bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilenames, _connectionChildMap);
for (QHash<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) { for (QMap<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
ExtractedMesh& extracted = it.value(); ExtractedMesh& extracted = it.value();
extracted.mesh.meshExtents.reset(); extracted.mesh.meshExtents.reset();
// accumulate local transforms // accumulate local transforms
@ -1335,7 +1335,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
} }
materialIndex++; materialIndex++;
} else if (_textureFilenames.contains(childID)) { } else if (_textureFilenames.contains(childID)) {
FBXTexture texture = getTexture(childID); FBXTexture texture = getTexture(childID);
for (int j = 0; j < extracted.partMaterialTextures.size(); j++) { for (int j = 0; j < extracted.partMaterialTextures.size(); j++) {
@ -1360,7 +1360,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
setTangents(extracted.mesh, part.quadIndices.at(i + 2), part.quadIndices.at(i + 3)); setTangents(extracted.mesh, part.quadIndices.at(i + 2), part.quadIndices.at(i + 3));
setTangents(extracted.mesh, part.quadIndices.at(i + 3), part.quadIndices.at(i)); setTangents(extracted.mesh, part.quadIndices.at(i + 3), part.quadIndices.at(i));
} }
// <= size - 3 in order to prevent overflowing triangleIndices when (i % 3) != 0 // <= size - 3 in order to prevent overflowing triangleIndices when (i % 3) != 0
// This is most likely evidence of a further problem in extractMesh() // This is most likely evidence of a further problem in extractMesh()
for (int i = 0; i <= part.triangleIndices.size() - 3; i += 3) { for (int i = 0; i <= part.triangleIndices.size() - 3; i += 3) {
setTangents(extracted.mesh, part.triangleIndices.at(i), part.triangleIndices.at(i + 1)); setTangents(extracted.mesh, part.triangleIndices.at(i), part.triangleIndices.at(i + 1));
@ -1500,7 +1500,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
glm::vec4& weights = extracted.mesh.clusterWeights[i]; glm::vec4& weights = extracted.mesh.clusterWeights[i];
float total = weights.x + weights.y + weights.z + weights.w; float total = weights.x + weights.y + weights.z + weights.w;
if (total != 1.0f && total != 0.0f) { if (total != 1.0f && total != 0.0f) {
weights /= total; weights /= total;
} }
} }
} else { } else {
@ -1573,7 +1573,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
avgRadius += glm::length(offset - projection * axis); avgRadius += glm::length(offset - projection * axis);
} }
avgRadius /= (float)points.size(); avgRadius /= (float)points.size();
// compute endpoints of capsule in joint-frame // compute endpoints of capsule in joint-frame
glm::vec3 capsuleBegin = avgPoint; glm::vec3 capsuleBegin = avgPoint;
glm::vec3 capsuleEnd = avgPoint; glm::vec3 capsuleEnd = avgPoint;
@ -1594,27 +1594,27 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
joint.shapeInfo.radius = avgRadius; joint.shapeInfo.radius = avgRadius;
} }
geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString()); geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());
// Add sitting points // Add sitting points
QVariantHash sittingPoints = mapping.value("sit").toHash(); QVariantHash sittingPoints = mapping.value("sit").toHash();
for (QVariantHash::const_iterator it = sittingPoints.constBegin(); it != sittingPoints.constEnd(); it++) { for (QVariantHash::const_iterator it = sittingPoints.constBegin(); it != sittingPoints.constEnd(); it++) {
SittingPoint sittingPoint; SittingPoint sittingPoint;
sittingPoint.name = it.key(); sittingPoint.name = it.key();
QVariantList properties = it->toList(); QVariantList properties = it->toList();
sittingPoint.position = parseVec3(properties.at(0).toString()); sittingPoint.position = parseVec3(properties.at(0).toString());
sittingPoint.rotation = glm::quat(glm::radians(parseVec3(properties.at(1).toString()))); sittingPoint.rotation = glm::quat(glm::radians(parseVec3(properties.at(1).toString())));
geometry.sittingPoints.append(sittingPoint); geometry.sittingPoints.append(sittingPoint);
} }
// attempt to map any meshes to a named model // attempt to map any meshes to a named model
for (QHash<QString, int>::const_iterator m = meshIDsToMeshIndices.constBegin(); for (QHash<QString, int>::const_iterator m = meshIDsToMeshIndices.constBegin();
m != meshIDsToMeshIndices.constEnd(); m++) { m != meshIDsToMeshIndices.constEnd(); m++) {
const QString& meshID = m.key(); const QString& meshID = m.key();
int meshIndex = m.value(); int meshIndex = m.value();
if (ooChildToParent.contains(meshID)) { if (ooChildToParent.contains(meshID)) {
const QString& modelID = ooChildToParent.value(meshID); const QString& modelID = ooChildToParent.value(meshID);
if (modelIDsToNames.contains(modelID)) { if (modelIDsToNames.contains(modelID)) {
@ -1623,7 +1623,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
} }
} }
} }
return geometryPtr; return geometryPtr;
} }
@ -1641,5 +1641,3 @@ FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QStri
return reader.extractFBXGeometry(mapping, url); return reader.extractFBXGeometry(mapping, url);
} }

View file

@ -413,8 +413,8 @@ public:
float _lightmapOffset = 0.0f; float _lightmapOffset = 0.0f;
float _lightmapLevel; float _lightmapLevel;
QMultiHash<QString, QString> _connectionParentMap; QMultiMap<QString, QString> _connectionParentMap;
QMultiHash<QString, QString> _connectionChildMap; QMultiMap<QString, QString> _connectionChildMap;
static glm::vec3 getVec3(const QVariantList& properties, int index); static glm::vec3 getVec3(const QVariantList& properties, int index);
static QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector); static QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector);

View 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()

View file

@ -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) {
} }

View file

@ -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){
} }

View file

@ -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);

View file

@ -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()

View file

@ -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"

View file

@ -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();
} }

View file

@ -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;

View 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;
}
}

View 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

View file

@ -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

View file

@ -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;
} }
} }

View file

@ -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;

View file

@ -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;

View file

@ -229,7 +229,7 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locati
void MeshPartPayload::render(RenderArgs* args) const { void MeshPartPayload::render(RenderArgs* args) const {
PerformanceTimer perfTimer("MeshPartPayload::render"); PerformanceTimer perfTimer("MeshPartPayload::render");
if (!model->_readyWhenAdded) { if (!model->_readyWhenAdded || !model->_isVisible) {
return; // bail asap return; // bail asap
} }

View file

@ -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 hadUncaughtExceptions(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))
@ -531,26 +558,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"));
@ -566,12 +600,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();
@ -581,7 +610,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
} }
@ -590,27 +619,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 = hadUncaughtExceptions(*this, program.fileName());
}
_evaluatesPending--;
if (_wantSignals) { if (_wantSignals) {
emit evaluationFinished(result, hasUncaughtException()); emit evaluationFinished(result, hadUncaughtException);
} }
clearExceptions();
return result; return result;
} }
@ -628,7 +660,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();
@ -669,15 +701,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);
@ -685,6 +708,8 @@ void ScriptEngine::run() {
} }
lastUpdate = now; lastUpdate = now;
// Debug and clear exceptions
hadUncaughtExceptions(*this, _fileNameString);
} }
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
@ -943,9 +968,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 ;
} }
@ -958,9 +983,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);
} }
} }
} }
@ -1024,14 +1048,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);
} }
@ -1043,12 +1063,15 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
} }
QScriptEngine sandbox; QScriptEngine sandbox;
QScriptValue testConstructor = sandbox.evaluate(contents); QScriptValue testConstructor = sandbox.evaluate(program);
if (hadUncaughtExceptions(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);
} }
@ -1061,7 +1084,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;

View file

@ -89,7 +89,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
@ -185,7 +185,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;
@ -197,7 +197,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;

View file

@ -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;
} }

View file

@ -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);
} }

View file

@ -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)

View file

@ -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>

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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"

View file

@ -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()