mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 20:16:16 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into game-render-interface
This commit is contained in:
commit
b5c942f7f6
51 changed files with 496 additions and 241 deletions
|
@ -49,9 +49,14 @@ ScrollingWindow {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
ApplicationInterface.uploadRequest.connect(uploadClicked);
|
ApplicationInterface.uploadRequest.connect(uploadClicked);
|
||||||
assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError);
|
assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError);
|
||||||
|
assetMappingsModel.autoRefreshEnabled = true;
|
||||||
|
|
||||||
reload();
|
reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onDestruction: {
|
||||||
|
assetMappingsModel.autoRefreshEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
function doDeleteFile(path) {
|
function doDeleteFile(path) {
|
||||||
console.log("Deleting " + path);
|
console.log("Deleting " + path);
|
||||||
|
@ -146,7 +151,6 @@ ScrollingWindow {
|
||||||
|
|
||||||
function reload() {
|
function reload() {
|
||||||
Assets.mappingModel.refresh();
|
Assets.mappingModel.refresh();
|
||||||
treeView.selection.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGetMappingsError(errorString) {
|
function handleGetMappingsError(errorString) {
|
||||||
|
@ -502,16 +506,6 @@ ScrollingWindow {
|
||||||
onClicked: root.deleteFile()
|
onClicked: root.deleteFile()
|
||||||
enabled: treeView.selection.hasSelection
|
enabled: treeView.selection.hasSelection
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiControls.GlyphButton {
|
|
||||||
|
|
||||||
glyph: hifi.glyphs.reload
|
|
||||||
color: hifi.buttons.black
|
|
||||||
colorScheme: root.colorScheme
|
|
||||||
width: hifi.dimensions.controlLineHeight
|
|
||||||
|
|
||||||
onClicked: root.reload()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,7 +745,7 @@ ScrollingWindow {
|
||||||
var path = assetProxyModel.data(index, 0x100);
|
var path = assetProxyModel.data(index, 0x100);
|
||||||
mappings.push(path);
|
mappings.push(path);
|
||||||
}
|
}
|
||||||
print("Setting baking enabled:" + mappings + checked);
|
print("Setting baking enabled:" + mappings + " " + checked);
|
||||||
Assets.setBakingEnabled(mappings, checked, function() {
|
Assets.setBakingEnabled(mappings, checked, function() {
|
||||||
reload();
|
reload();
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,9 +49,15 @@ Rectangle {
|
||||||
isHMD = HMD.active;
|
isHMD = HMD.active;
|
||||||
ApplicationInterface.uploadRequest.connect(uploadClicked);
|
ApplicationInterface.uploadRequest.connect(uploadClicked);
|
||||||
assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError);
|
assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError);
|
||||||
|
assetMappingsModel.autoRefreshEnabled = true;
|
||||||
|
|
||||||
reload();
|
reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onDestruction: {
|
||||||
|
assetMappingsModel.autoRefreshEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
function doDeleteFile(path) {
|
function doDeleteFile(path) {
|
||||||
console.log("Deleting " + path);
|
console.log("Deleting " + path);
|
||||||
|
|
||||||
|
@ -145,7 +151,6 @@ Rectangle {
|
||||||
|
|
||||||
function reload() {
|
function reload() {
|
||||||
Assets.mappingModel.refresh();
|
Assets.mappingModel.refresh();
|
||||||
treeView.selection.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGetMappingsError(errorString) {
|
function handleGetMappingsError(errorString) {
|
||||||
|
@ -502,16 +507,6 @@ Rectangle {
|
||||||
onClicked: root.deleteFile()
|
onClicked: root.deleteFile()
|
||||||
enabled: treeView.selection.hasSelection
|
enabled: treeView.selection.hasSelection
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiControls.GlyphButton {
|
|
||||||
|
|
||||||
glyph: hifi.glyphs.reload
|
|
||||||
color: hifi.buttons.black
|
|
||||||
colorScheme: root.colorScheme
|
|
||||||
width: hifi.dimensions.controlLineHeight
|
|
||||||
|
|
||||||
onClicked: root.reload()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,7 +743,7 @@ Rectangle {
|
||||||
var path = assetProxyModel.data(index, 0x100);
|
var path = assetProxyModel.data(index, 0x100);
|
||||||
mappings.push(path);
|
mappings.push(path);
|
||||||
}
|
}
|
||||||
print("Setting baking enabled:" + mappings + checked);
|
print("Setting baking enabled:" + mappings + " " + checked);
|
||||||
Assets.setBakingEnabled(mappings, checked, function() {
|
Assets.setBakingEnabled(mappings, checked, function() {
|
||||||
reload();
|
reload();
|
||||||
});
|
});
|
||||||
|
|
|
@ -2196,6 +2196,14 @@ float MyAvatar::getDomainMaxScale() {
|
||||||
return _domainMaximumScale;
|
return _domainMaximumScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setGravity(float gravity) {
|
||||||
|
_characterController.setGravity(gravity);
|
||||||
|
}
|
||||||
|
|
||||||
|
float MyAvatar::getGravity() {
|
||||||
|
return _characterController.getGravity();
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::increaseSize() {
|
void MyAvatar::increaseSize() {
|
||||||
// make sure we're starting from an allowable scale
|
// make sure we're starting from an allowable scale
|
||||||
clampTargetScaleToDomainLimits();
|
clampTargetScaleToDomainLimits();
|
||||||
|
|
|
@ -152,7 +152,7 @@ class MyAvatar : public Avatar {
|
||||||
|
|
||||||
Q_PROPERTY(float userHeight READ getUserHeight WRITE setUserHeight)
|
Q_PROPERTY(float userHeight READ getUserHeight WRITE setUserHeight)
|
||||||
Q_PROPERTY(float userEyeHeight READ getUserEyeHeight)
|
Q_PROPERTY(float userEyeHeight READ getUserEyeHeight)
|
||||||
|
|
||||||
const QString DOMINANT_LEFT_HAND = "left";
|
const QString DOMINANT_LEFT_HAND = "left";
|
||||||
const QString DOMINANT_RIGHT_HAND = "right";
|
const QString DOMINANT_RIGHT_HAND = "right";
|
||||||
|
|
||||||
|
@ -551,6 +551,9 @@ public slots:
|
||||||
float getDomainMinScale();
|
float getDomainMinScale();
|
||||||
float getDomainMaxScale();
|
float getDomainMaxScale();
|
||||||
|
|
||||||
|
void setGravity(float gravity);
|
||||||
|
float getGravity();
|
||||||
|
|
||||||
void goToLocation(const glm::vec3& newPosition,
|
void goToLocation(const glm::vec3& newPosition,
|
||||||
bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(),
|
bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(),
|
||||||
bool shouldFaceLocation = false);
|
bool shouldFaceLocation = false);
|
||||||
|
|
|
@ -92,8 +92,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const bool defaultState) {
|
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) {
|
||||||
PickRay pickRay = qApp->getRayPickManager().getPickRay(_rayPickUID);
|
|
||||||
if (!renderState.getStartID().isNull()) {
|
if (!renderState.getStartID().isNull()) {
|
||||||
QVariantMap startProps;
|
QVariantMap startProps;
|
||||||
startProps.insert("position", vec3toVariant(pickRay.origin));
|
startProps.insert("position", vec3toVariant(pickRay.origin));
|
||||||
|
@ -185,12 +184,14 @@ void LaserPointer::disableRenderState(const RenderState& renderState) {
|
||||||
|
|
||||||
void LaserPointer::update() {
|
void LaserPointer::update() {
|
||||||
RayPickResult prevRayPickResult = DependencyManager::get<RayPickScriptingInterface>()->getPrevRayPickResult(_rayPickUID);
|
RayPickResult prevRayPickResult = DependencyManager::get<RayPickScriptingInterface>()->getPrevRayPickResult(_rayPickUID);
|
||||||
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && prevRayPickResult.type != IntersectionType::NONE) {
|
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() &&
|
||||||
updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, prevRayPickResult.distance, prevRayPickResult.objectID, false);
|
(prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) {
|
||||||
|
float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance;
|
||||||
|
updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false);
|
||||||
disableRenderState(_defaultRenderStates[_currentRenderState].second);
|
disableRenderState(_defaultRenderStates[_currentRenderState].second);
|
||||||
} else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
|
} else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
|
||||||
disableRenderState(_renderStates[_currentRenderState]);
|
disableRenderState(_renderStates[_currentRenderState]);
|
||||||
updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), true);
|
updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), prevRayPickResult.searchRay, true);
|
||||||
} else if (!_currentRenderState.empty()) {
|
} else if (!_currentRenderState.empty()) {
|
||||||
disableRenderState(_renderStates[_currentRenderState]);
|
disableRenderState(_renderStates[_currentRenderState]);
|
||||||
disableRenderState(_defaultRenderStates[_currentRenderState].second);
|
disableRenderState(_defaultRenderStates[_currentRenderState].second);
|
||||||
|
|
|
@ -65,6 +65,7 @@ public:
|
||||||
void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps);
|
void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps);
|
||||||
|
|
||||||
void setPrecisionPicking(const bool precisionPicking) { DependencyManager::get<RayPickScriptingInterface>()->setPrecisionPicking(_rayPickUID, precisionPicking); }
|
void setPrecisionPicking(const bool precisionPicking) { DependencyManager::get<RayPickScriptingInterface>()->setPrecisionPicking(_rayPickUID, precisionPicking); }
|
||||||
|
void setLaserLength(const float laserLength) { _laserLength = laserLength; }
|
||||||
void setIgnoreEntities(const QScriptValue& ignoreEntities) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreEntities(_rayPickUID, ignoreEntities); }
|
void setIgnoreEntities(const QScriptValue& ignoreEntities) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreEntities(_rayPickUID, ignoreEntities); }
|
||||||
void setIncludeEntities(const QScriptValue& includeEntities) { DependencyManager::get<RayPickScriptingInterface>()->setIncludeEntities(_rayPickUID, includeEntities); }
|
void setIncludeEntities(const QScriptValue& includeEntities) { DependencyManager::get<RayPickScriptingInterface>()->setIncludeEntities(_rayPickUID, includeEntities); }
|
||||||
void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreOverlays(_rayPickUID, ignoreOverlays); }
|
void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreOverlays(_rayPickUID, ignoreOverlays); }
|
||||||
|
@ -78,6 +79,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _renderingEnabled;
|
bool _renderingEnabled;
|
||||||
|
float _laserLength { 0.0f };
|
||||||
std::string _currentRenderState { "" };
|
std::string _currentRenderState { "" };
|
||||||
RenderStateMap _renderStates;
|
RenderStateMap _renderStates;
|
||||||
DefaultRenderStateMap _defaultRenderStates;
|
DefaultRenderStateMap _defaultRenderStates;
|
||||||
|
@ -89,7 +91,7 @@ private:
|
||||||
QUuid _rayPickUID;
|
QUuid _rayPickUID;
|
||||||
|
|
||||||
void updateRenderStateOverlay(const OverlayID& id, const QVariant& props);
|
void updateRenderStateOverlay(const OverlayID& id, const QVariant& props);
|
||||||
void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const bool defaultState);
|
void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState);
|
||||||
void disableRenderState(const RenderState& renderState);
|
void disableRenderState(const RenderState& renderState);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,17 +14,19 @@ QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const La
|
||||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) {
|
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) {
|
||||||
std::shared_ptr<LaserPointer> laserPointer = std::make_shared<LaserPointer>(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled);
|
std::shared_ptr<LaserPointer> laserPointer = std::make_shared<LaserPointer>(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled);
|
||||||
if (!laserPointer->getRayUID().isNull()) {
|
if (!laserPointer->getRayUID().isNull()) {
|
||||||
QWriteLocker lock(&_addLock);
|
QWriteLocker containsLock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_laserPointersToAdd.push(std::pair<QUuid, std::shared_ptr<LaserPointer>>(id, laserPointer));
|
_laserPointers[id] = laserPointer;
|
||||||
|
_laserPointerLocks[id] = std::make_shared<QReadWriteLock>();
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::removeLaserPointer(const QUuid uid) {
|
void LaserPointerManager::removeLaserPointer(const QUuid uid) {
|
||||||
QWriteLocker lock(&_removeLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
_laserPointersToRemove.push(uid);
|
_laserPointers.remove(uid);
|
||||||
|
_laserPointerLocks.remove(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::enableLaserPointer(const QUuid uid) {
|
void LaserPointerManager::enableLaserPointer(const QUuid uid) {
|
||||||
|
@ -69,32 +71,12 @@ const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::update() {
|
void LaserPointerManager::update() {
|
||||||
|
QReadLocker lock(&_containsLock);
|
||||||
for (QUuid& uid : _laserPointers.keys()) {
|
for (QUuid& uid : _laserPointers.keys()) {
|
||||||
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
|
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
|
||||||
QReadLocker laserLock(_laserPointerLocks[uid].get());
|
QReadLocker laserLock(_laserPointerLocks[uid].get());
|
||||||
_laserPointers[uid]->update();
|
_laserPointers[uid]->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
QWriteLocker containsLock(&_containsLock);
|
|
||||||
{
|
|
||||||
QWriteLocker lock(&_addLock);
|
|
||||||
while (!_laserPointersToAdd.empty()) {
|
|
||||||
std::pair<QUuid, std::shared_ptr<LaserPointer>> laserPointerToAdd = _laserPointersToAdd.front();
|
|
||||||
_laserPointersToAdd.pop();
|
|
||||||
_laserPointers[laserPointerToAdd.first] = laserPointerToAdd.second;
|
|
||||||
_laserPointerLocks[laserPointerToAdd.first] = std::make_shared<QReadWriteLock>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
QWriteLocker lock(&_removeLock);
|
|
||||||
while (!_laserPointersToRemove.empty()) {
|
|
||||||
QUuid uid = _laserPointersToRemove.front();
|
|
||||||
_laserPointersToRemove.pop();
|
|
||||||
_laserPointers.remove(uid);
|
|
||||||
_laserPointerLocks.remove(uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
|
void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
|
||||||
|
@ -105,6 +87,14 @@ void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LaserPointerManager::setLaserLength(QUuid uid, const float laserLength) {
|
||||||
|
QReadLocker lock(&_containsLock);
|
||||||
|
if (_laserPointers.contains(uid)) {
|
||||||
|
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
||||||
|
_laserPointers[uid]->setLaserLength(laserLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
|
void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
if (_laserPointers.contains(uid)) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ public:
|
||||||
const RayPickResult getPrevRayPickResult(const QUuid uid);
|
const RayPickResult getPrevRayPickResult(const QUuid uid);
|
||||||
|
|
||||||
void setPrecisionPicking(QUuid uid, const bool precisionPicking);
|
void setPrecisionPicking(QUuid uid, const bool precisionPicking);
|
||||||
|
void setLaserLength(QUuid uid, const float laserLength);
|
||||||
void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities);
|
void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities);
|
||||||
void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities);
|
void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities);
|
||||||
void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays);
|
void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays);
|
||||||
|
@ -46,10 +47,6 @@ public:
|
||||||
private:
|
private:
|
||||||
QHash<QUuid, std::shared_ptr<LaserPointer>> _laserPointers;
|
QHash<QUuid, std::shared_ptr<LaserPointer>> _laserPointers;
|
||||||
QHash<QUuid, std::shared_ptr<QReadWriteLock>> _laserPointerLocks;
|
QHash<QUuid, std::shared_ptr<QReadWriteLock>> _laserPointerLocks;
|
||||||
QReadWriteLock _addLock;
|
|
||||||
std::queue<std::pair<QUuid, std::shared_ptr<LaserPointer>>> _laserPointersToAdd;
|
|
||||||
QReadWriteLock _removeLock;
|
|
||||||
std::queue<QUuid> _laserPointersToRemove;
|
|
||||||
QReadWriteLock _containsLock;
|
QReadWriteLock _containsLock;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,6 +31,7 @@ public slots:
|
||||||
Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); }
|
Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); }
|
||||||
|
|
||||||
Q_INVOKABLE void setPrecisionPicking(QUuid uid, const bool precisionPicking) { qApp->getLaserPointerManager().setPrecisionPicking(uid, precisionPicking); }
|
Q_INVOKABLE void setPrecisionPicking(QUuid uid, const bool precisionPicking) { qApp->getLaserPointerManager().setPrecisionPicking(uid, precisionPicking); }
|
||||||
|
Q_INVOKABLE void setLaserLength(QUuid uid, const float laserLength) { qApp->getLaserPointerManager().setLaserLength(uid, laserLength); }
|
||||||
Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { qApp->getLaserPointerManager().setIgnoreEntities(uid, ignoreEntities); }
|
Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { qApp->getLaserPointerManager().setIgnoreEntities(uid, ignoreEntities); }
|
||||||
Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { qApp->getLaserPointerManager().setIncludeEntities(uid, includeEntities); }
|
Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { qApp->getLaserPointerManager().setIncludeEntities(uid, includeEntities); }
|
||||||
Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { qApp->getLaserPointerManager().setIgnoreOverlays(uid, ignoreOverlays); }
|
Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { qApp->getLaserPointerManager().setIgnoreOverlays(uid, ignoreOverlays); }
|
||||||
|
|
|
@ -70,6 +70,9 @@ public:
|
||||||
if (doesPickNonCollidable()) {
|
if (doesPickNonCollidable()) {
|
||||||
toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE);
|
toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE);
|
||||||
}
|
}
|
||||||
|
if (doesPickCourse()) {
|
||||||
|
toReturn |= getBitMask(PICK_COURSE);
|
||||||
|
}
|
||||||
return Flags(toReturn);
|
return Flags(toReturn);
|
||||||
}
|
}
|
||||||
Flags getOverlayFlags() const {
|
Flags getOverlayFlags() const {
|
||||||
|
@ -80,6 +83,9 @@ public:
|
||||||
if (doesPickNonCollidable()) {
|
if (doesPickNonCollidable()) {
|
||||||
toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE);
|
toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE);
|
||||||
}
|
}
|
||||||
|
if (doesPickCourse()) {
|
||||||
|
toReturn |= getBitMask(PICK_COURSE);
|
||||||
|
}
|
||||||
return Flags(toReturn);
|
return Flags(toReturn);
|
||||||
}
|
}
|
||||||
Flags getAvatarFlags() const { return Flags(getBitMask(PICK_AVATARS)); }
|
Flags getAvatarFlags() const { return Flags(getBitMask(PICK_AVATARS)); }
|
||||||
|
|
|
@ -38,11 +38,12 @@ void RayPickManager::cacheResult(const bool intersects, const RayPickResult& res
|
||||||
res = resTemp;
|
res = resTemp;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cache[ray][mask] = RayPickResult();
|
cache[ray][mask] = RayPickResult(res.searchRay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::update() {
|
void RayPickManager::update() {
|
||||||
|
QReadLocker lock(&_containsLock);
|
||||||
RayPickCache results;
|
RayPickCache results;
|
||||||
for (auto& uid : _rayPicks.keys()) {
|
for (auto& uid : _rayPicks.keys()) {
|
||||||
std::shared_ptr<RayPick> rayPick = _rayPicks[uid];
|
std::shared_ptr<RayPick> rayPick = _rayPicks[uid];
|
||||||
|
@ -58,7 +59,7 @@ void RayPickManager::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<glm::vec3, glm::vec3> rayKey = QPair<glm::vec3, glm::vec3>(ray.origin, ray.direction);
|
QPair<glm::vec3, glm::vec3> rayKey = QPair<glm::vec3, glm::vec3>(ray.origin, ray.direction);
|
||||||
RayPickResult res;
|
RayPickResult res = RayPickResult(ray);
|
||||||
|
|
||||||
if (rayPick->getFilter().doesPickEntities()) {
|
if (rayPick->getFilter().doesPickEntities()) {
|
||||||
RayToEntityIntersectionResult entityRes;
|
RayToEntityIntersectionResult entityRes;
|
||||||
|
@ -73,7 +74,7 @@ void RayPickManager::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromCache) {
|
if (!fromCache) {
|
||||||
cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal),
|
cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, ray, entityRes.surfaceNormal),
|
||||||
entityMask, res, rayKey, results);
|
entityMask, res, rayKey, results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +92,7 @@ void RayPickManager::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromCache) {
|
if (!fromCache) {
|
||||||
cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal),
|
cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, ray, overlayRes.surfaceNormal),
|
||||||
overlayMask, res, rayKey, results);
|
overlayMask, res, rayKey, results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,7 @@ void RayPickManager::update() {
|
||||||
RayPickFilter::Flags avatarMask = rayPick->getFilter().getAvatarFlags();
|
RayPickFilter::Flags avatarMask = rayPick->getFilter().getAvatarFlags();
|
||||||
if (!checkAndCompareCachedResults(rayKey, results, res, avatarMask)) {
|
if (!checkAndCompareCachedResults(rayKey, results, res, avatarMask)) {
|
||||||
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(ray, rayPick->getIncludeAvatars(), rayPick->getIgnoreAvatars());
|
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(ray, rayPick->getIncludeAvatars(), rayPick->getIgnoreAvatars());
|
||||||
cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection), avatarMask, res, rayKey, results);
|
cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, ray), avatarMask, res, rayKey, results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +110,7 @@ void RayPickManager::update() {
|
||||||
RayPickFilter::Flags hudMask = rayPick->getFilter().getHUDFlags();
|
RayPickFilter::Flags hudMask = rayPick->getFilter().getHUDFlags();
|
||||||
if (!checkAndCompareCachedResults(rayKey, results, res, hudMask)) {
|
if (!checkAndCompareCachedResults(rayKey, results, res, hudMask)) {
|
||||||
glm::vec3 hudRes = DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(ray.origin, ray.direction);
|
glm::vec3 hudRes = DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(ray.origin, ray.direction);
|
||||||
cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes), hudMask, res, rayKey, results);
|
cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes, ray), hudMask, res, rayKey, results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,56 +118,39 @@ void RayPickManager::update() {
|
||||||
if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) {
|
if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) {
|
||||||
rayPick->setRayPickResult(res);
|
rayPick->setRayPickResult(res);
|
||||||
} else {
|
} else {
|
||||||
rayPick->setRayPickResult(RayPickResult());
|
rayPick->setRayPickResult(RayPickResult(ray));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QWriteLocker containsLock(&_containsLock);
|
|
||||||
{
|
|
||||||
QWriteLocker lock(&_addLock);
|
|
||||||
while (!_rayPicksToAdd.empty()) {
|
|
||||||
std::pair<QUuid, std::shared_ptr<RayPick>> rayPickToAdd = _rayPicksToAdd.front();
|
|
||||||
_rayPicksToAdd.pop();
|
|
||||||
_rayPicks[rayPickToAdd.first] = rayPickToAdd.second;
|
|
||||||
_rayPickLocks[rayPickToAdd.first] = std::make_shared<QReadWriteLock>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
QWriteLocker lock(&_removeLock);
|
|
||||||
while (!_rayPicksToRemove.empty()) {
|
|
||||||
QUuid uid = _rayPicksToRemove.front();
|
|
||||||
_rayPicksToRemove.pop();
|
|
||||||
_rayPicks.remove(uid);
|
|
||||||
_rayPickLocks.remove(uid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
||||||
QWriteLocker lock(&_addLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_rayPicksToAdd.push(std::pair<QUuid, std::shared_ptr<RayPick>>(id, std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled)));
|
_rayPicks[id] = std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled);
|
||||||
|
_rayPickLocks[id] = std::make_shared<QReadWriteLock>();
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid RayPickManager::createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
QUuid RayPickManager::createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
||||||
QWriteLocker lock(&_addLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_rayPicksToAdd.push(std::pair<QUuid, std::shared_ptr<RayPick>>(id, std::make_shared<MouseRayPick>(filter, maxDistance, enabled)));
|
_rayPicks[id] = std::make_shared<MouseRayPick>(filter, maxDistance, enabled);
|
||||||
|
_rayPickLocks[id] = std::make_shared<QReadWriteLock>();
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
||||||
QWriteLocker lock(&_addLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_rayPicksToAdd.push(std::pair<QUuid, std::shared_ptr<RayPick>>(id, std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled)));
|
_rayPicks[id] = std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled);
|
||||||
|
_rayPickLocks[id] = std::make_shared<QReadWriteLock>();
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::removeRayPick(const QUuid uid) {
|
void RayPickManager::removeRayPick(const QUuid uid) {
|
||||||
QWriteLocker lock(&_removeLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
_rayPicksToRemove.push(uid);
|
_rayPicks.remove(uid);
|
||||||
|
_rayPickLocks.remove(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::enableRayPick(const QUuid uid) {
|
void RayPickManager::enableRayPick(const QUuid uid) {
|
||||||
|
@ -185,18 +169,6 @@ void RayPickManager::disableRayPick(const QUuid uid) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PickRay RayPickManager::getPickRay(const QUuid uid) {
|
|
||||||
QReadLocker containsLock(&_containsLock);
|
|
||||||
if (_rayPicks.contains(uid)) {
|
|
||||||
bool valid;
|
|
||||||
PickRay pickRay = _rayPicks[uid]->getPickRay(valid);
|
|
||||||
if (valid) {
|
|
||||||
return pickRay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PickRay();
|
|
||||||
}
|
|
||||||
|
|
||||||
const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) {
|
const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
if (_rayPicks.contains(uid)) {
|
||||||
|
|
|
@ -28,7 +28,6 @@ class RayPickManager {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void update();
|
void update();
|
||||||
const PickRay getPickRay(const QUuid uid);
|
|
||||||
|
|
||||||
QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled);
|
QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled);
|
||||||
QUuid createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled);
|
QUuid createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled);
|
||||||
|
@ -49,10 +48,6 @@ public:
|
||||||
private:
|
private:
|
||||||
QHash<QUuid, std::shared_ptr<RayPick>> _rayPicks;
|
QHash<QUuid, std::shared_ptr<RayPick>> _rayPicks;
|
||||||
QHash<QUuid, std::shared_ptr<QReadWriteLock>> _rayPickLocks;
|
QHash<QUuid, std::shared_ptr<QReadWriteLock>> _rayPickLocks;
|
||||||
QReadWriteLock _addLock;
|
|
||||||
std::queue<std::pair<QUuid, std::shared_ptr<RayPick>>> _rayPicksToAdd;
|
|
||||||
QReadWriteLock _removeLock;
|
|
||||||
std::queue<QUuid> _rayPicksToRemove;
|
|
||||||
QReadWriteLock _containsLock;
|
QReadWriteLock _containsLock;
|
||||||
|
|
||||||
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayPickFilter::Flags, RayPickResult>> RayPickCache;
|
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayPickFilter::Flags, RayPickResult>> RayPickCache;
|
||||||
|
|
|
@ -19,8 +19,13 @@
|
||||||
#include <AssetUpload.h>
|
#include <AssetUpload.h>
|
||||||
#include <MappingRequest.h>
|
#include <MappingRequest.h>
|
||||||
#include <NetworkLogging.h>
|
#include <NetworkLogging.h>
|
||||||
|
#include <NodeList.h>
|
||||||
#include <OffscreenUi.h>
|
#include <OffscreenUi.h>
|
||||||
|
|
||||||
|
static const int AUTO_REFRESH_INTERVAL = 1000;
|
||||||
|
|
||||||
|
int assetMappingModelMetatypeId = qRegisterMetaType<AssetMappingModel*>("AssetMappingModel*");
|
||||||
|
|
||||||
AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() {
|
AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() {
|
||||||
_proxyModel.setSourceModel(&_assetMappingModel);
|
_proxyModel.setSourceModel(&_assetMappingModel);
|
||||||
_proxyModel.setSortRole(Qt::DisplayRole);
|
_proxyModel.setSortRole(Qt::DisplayRole);
|
||||||
|
@ -189,6 +194,29 @@ void AssetMappingsScriptingInterface::setBakingEnabled(QStringList paths, bool e
|
||||||
|
|
||||||
AssetMappingModel::AssetMappingModel() {
|
AssetMappingModel::AssetMappingModel() {
|
||||||
setupRoles();
|
setupRoles();
|
||||||
|
|
||||||
|
connect(&_autoRefreshTimer, &QTimer::timeout, this, [this] {
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
auto assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
if (assetServer) {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_autoRefreshTimer.setInterval(AUTO_REFRESH_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetMappingModel::isAutoRefreshEnabled() {
|
||||||
|
return _autoRefreshTimer.isActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetMappingModel::setAutoRefreshEnabled(bool enabled) {
|
||||||
|
if (enabled != _autoRefreshTimer.isActive()) {
|
||||||
|
if (enabled) {
|
||||||
|
_autoRefreshTimer.start();
|
||||||
|
} else {
|
||||||
|
_autoRefreshTimer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssetMappingModel::isKnownFolder(QString path) const {
|
bool AssetMappingModel::isKnownFolder(QString path) const {
|
||||||
|
@ -205,10 +233,7 @@ bool AssetMappingModel::isKnownFolder(QString path) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int assetMappingModelMetatypeId = qRegisterMetaType<AssetMappingModel*>("AssetMappingModel*");
|
|
||||||
|
|
||||||
void AssetMappingModel::refresh() {
|
void AssetMappingModel::refresh() {
|
||||||
qDebug() << "Refreshing asset mapping model";
|
|
||||||
auto assetClient = DependencyManager::get<AssetClient>();
|
auto assetClient = DependencyManager::get<AssetClient>();
|
||||||
auto request = assetClient->createGetAllMappingsRequest();
|
auto request = assetClient->createGetAllMappingsRequest();
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,16 @@
|
||||||
|
|
||||||
class AssetMappingModel : public QStandardItemModel {
|
class AssetMappingModel : public QStandardItemModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(bool autoRefreshEnabled READ isAutoRefreshEnabled WRITE setAutoRefreshEnabled)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AssetMappingModel();
|
AssetMappingModel();
|
||||||
|
|
||||||
Q_INVOKABLE void refresh();
|
Q_INVOKABLE void refresh();
|
||||||
|
|
||||||
|
bool isAutoRefreshEnabled();
|
||||||
|
void setAutoRefreshEnabled(bool enabled);
|
||||||
|
|
||||||
bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }
|
bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }
|
||||||
bool isKnownFolder(QString path) const;
|
bool isKnownFolder(QString path) const;
|
||||||
|
|
||||||
|
@ -44,6 +49,7 @@ private:
|
||||||
void setupRoles();
|
void setupRoles();
|
||||||
|
|
||||||
QHash<QString, QStandardItem*> _pathToItemMap;
|
QHash<QString, QStandardItem*> _pathToItemMap;
|
||||||
|
QTimer _autoRefreshTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(AssetMappingModel*)
|
Q_DECLARE_METATYPE(AssetMappingModel*)
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
#include <EntityTreeRenderer.h>
|
#include <EntityTreeRenderer.h>
|
||||||
#include <NetworkingConstants.h>
|
#include <NetworkingConstants.h>
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
static const float CONTEXT_OVERLAY_TABLET_OFFSET = 30.0f; // Degrees
|
static const float CONTEXT_OVERLAY_TABLET_OFFSET = 30.0f; // Degrees
|
||||||
static const float CONTEXT_OVERLAY_TABLET_ORIENTATION = 210.0f; // Degrees
|
static const float CONTEXT_OVERLAY_TABLET_ORIENTATION = 210.0f; // Degrees
|
||||||
static const float CONTEXT_OVERLAY_TABLET_DISTANCE = 0.65F; // Meters
|
static const float CONTEXT_OVERLAY_TABLET_DISTANCE = 0.65F; // Meters
|
||||||
|
@ -38,11 +42,6 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
||||||
_entityPropertyFlags += PROP_DIMENSIONS;
|
_entityPropertyFlags += PROP_DIMENSIONS;
|
||||||
_entityPropertyFlags += PROP_REGISTRATION_POINT;
|
_entityPropertyFlags += PROP_REGISTRATION_POINT;
|
||||||
|
|
||||||
// initially, set _enabled to match the switch. Later we enable/disable via the getter/setters
|
|
||||||
// if we are in edit or pal (for instance). Note this is temporary, as we expect to enable this all
|
|
||||||
// the time after getting edge highlighting, etc...
|
|
||||||
_enabled = _settingSwitch.get();
|
|
||||||
|
|
||||||
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>().data();
|
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>().data();
|
||||||
connect(entityTreeRenderer, SIGNAL(mousePressOnEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(createOrDestroyContextOverlay(const EntityItemID&, const PointerEvent&)));
|
connect(entityTreeRenderer, SIGNAL(mousePressOnEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(createOrDestroyContextOverlay(const EntityItemID&, const PointerEvent&)));
|
||||||
connect(entityTreeRenderer, SIGNAL(hoverEnterEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverEnterEntity(const EntityItemID&, const PointerEvent&)));
|
connect(entityTreeRenderer, SIGNAL(hoverEnterEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverEnterEntity(const EntityItemID&, const PointerEvent&)));
|
||||||
|
@ -65,40 +64,36 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
||||||
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandler, &SelectionToSceneHandler::selectedItemsListChanged);
|
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandler, &SelectionToSceneHandler::selectedItemsListChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const uint32_t MOUSE_HW_ID = 0;
|
||||||
static const uint32_t LEFT_HAND_HW_ID = 1;
|
static const uint32_t LEFT_HAND_HW_ID = 1;
|
||||||
static const xColor CONTEXT_OVERLAY_COLOR = { 255, 255, 255 };
|
static const xColor CONTEXT_OVERLAY_COLOR = { 255, 255, 255 };
|
||||||
static const float CONTEXT_OVERLAY_INSIDE_DISTANCE = 1.0f; // in meters
|
static const float CONTEXT_OVERLAY_INSIDE_DISTANCE = 1.0f; // in meters
|
||||||
static const float CONTEXT_OVERLAY_CLOSE_DISTANCE = 1.5f; // in meters
|
static const float CONTEXT_OVERLAY_SIZE = 0.09f; // in meters, same x and y dims
|
||||||
static const float CONTEXT_OVERLAY_CLOSE_SIZE = 0.12f; // in meters, same x and y dims
|
static const float CONTEXT_OVERLAY_OFFSET_DISTANCE = 0.1f;
|
||||||
static const float CONTEXT_OVERLAY_FAR_SIZE = 0.08f; // in meters, same x and y dims
|
static const float CONTEXT_OVERLAY_OFFSET_ANGLE = 5.0f;
|
||||||
static const float CONTEXT_OVERLAY_CLOSE_OFFSET_ANGLE = 20.0f;
|
|
||||||
static const float CONTEXT_OVERLAY_UNHOVERED_ALPHA = 0.85f;
|
static const float CONTEXT_OVERLAY_UNHOVERED_ALPHA = 0.85f;
|
||||||
static const float CONTEXT_OVERLAY_HOVERED_ALPHA = 1.0f;
|
static const float CONTEXT_OVERLAY_HOVERED_ALPHA = 1.0f;
|
||||||
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMIN = 0.6f;
|
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMIN = 0.6f;
|
||||||
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMAX = 1.0f;
|
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMAX = 1.0f;
|
||||||
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEPERIOD = 1.0f;
|
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEPERIOD = 1.0f;
|
||||||
static const float CONTEXT_OVERLAY_UNHOVERED_COLORPULSE = 1.0f;
|
static const float CONTEXT_OVERLAY_UNHOVERED_COLORPULSE = 1.0f;
|
||||||
static const float CONTEXT_OVERLAY_FAR_OFFSET = 0.1f;
|
|
||||||
|
|
||||||
void ContextOverlayInterface::setEnabled(bool enabled) {
|
void ContextOverlayInterface::setEnabled(bool enabled) {
|
||||||
// only enable/disable if the setting in 'on'. If it is 'off',
|
_enabled = enabled;
|
||||||
// make sure _enabled is always false.
|
|
||||||
if (_settingSwitch.get()) {
|
|
||||||
_enabled = enabled;
|
|
||||||
} else {
|
|
||||||
_enabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
|
bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||||
if (_enabled && event.getButton() == PointerEvent::SecondaryButton) {
|
if (_enabled && event.getButton() == PointerEvent::SecondaryButton) {
|
||||||
if (contextOverlayFilterPassed(entityItemID)) {
|
if (contextOverlayFilterPassed(entityItemID)) {
|
||||||
|
if (event.getID() == MOUSE_HW_ID) {
|
||||||
|
enableEntityHighlight(entityItemID);
|
||||||
|
}
|
||||||
|
|
||||||
qCDebug(context_overlay) << "Creating Context Overlay on top of entity with ID: " << entityItemID;
|
qCDebug(context_overlay) << "Creating Context Overlay on top of entity with ID: " << entityItemID;
|
||||||
|
|
||||||
// Add all necessary variables to the stack
|
// Add all necessary variables to the stack
|
||||||
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityItemID, _entityPropertyFlags);
|
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityItemID, _entityPropertyFlags);
|
||||||
glm::vec3 cameraPosition = qApp->getCamera().getPosition();
|
glm::vec3 cameraPosition = qApp->getCamera().getPosition();
|
||||||
float distanceFromCameraToEntity = glm::distance(entityProperties.getPosition(), cameraPosition);
|
|
||||||
glm::vec3 entityDimensions = entityProperties.getDimensions();
|
glm::vec3 entityDimensions = entityProperties.getDimensions();
|
||||||
glm::vec3 entityPosition = entityProperties.getPosition();
|
glm::vec3 entityPosition = entityProperties.getPosition();
|
||||||
glm::vec3 contextOverlayPosition = entityProperties.getPosition();
|
glm::vec3 contextOverlayPosition = entityProperties.getPosition();
|
||||||
|
@ -131,27 +126,22 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID&
|
||||||
// If the camera is inside the box...
|
// If the camera is inside the box...
|
||||||
// ...position the Context Overlay 1 meter in front of the camera.
|
// ...position the Context Overlay 1 meter in front of the camera.
|
||||||
contextOverlayPosition = cameraPosition + CONTEXT_OVERLAY_INSIDE_DISTANCE * (qApp->getCamera().getOrientation() * Vectors::FRONT);
|
contextOverlayPosition = cameraPosition + CONTEXT_OVERLAY_INSIDE_DISTANCE * (qApp->getCamera().getOrientation() * Vectors::FRONT);
|
||||||
contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_CLOSE_SIZE, CONTEXT_OVERLAY_CLOSE_SIZE) * glm::distance(contextOverlayPosition, cameraPosition);
|
contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_SIZE, CONTEXT_OVERLAY_SIZE) * glm::distance(contextOverlayPosition, cameraPosition);
|
||||||
} else if (distanceFromCameraToEntity < CONTEXT_OVERLAY_CLOSE_DISTANCE) {
|
|
||||||
// Else if the entity is too close to the camera...
|
|
||||||
// ...rotate the Context Overlay to the right of the entity.
|
|
||||||
// This makes it easy to inspect things you're holding.
|
|
||||||
float offsetAngle = -CONTEXT_OVERLAY_CLOSE_OFFSET_ANGLE;
|
|
||||||
if (event.getID() == LEFT_HAND_HW_ID) {
|
|
||||||
offsetAngle *= -1;
|
|
||||||
}
|
|
||||||
contextOverlayPosition = (glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f))) * (entityPosition - cameraPosition)) + cameraPosition;
|
|
||||||
contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_CLOSE_SIZE, CONTEXT_OVERLAY_CLOSE_SIZE) * glm::distance(contextOverlayPosition, cameraPosition);
|
|
||||||
} else {
|
} else {
|
||||||
// Else, place the Context Overlay some offset away from the entity's bounding
|
// Rotate the Context Overlay some number of degrees offset from the entity
|
||||||
// box in the direction of the camera.
|
// along the line cast from your head to the entity's bounding box.
|
||||||
glm::vec3 direction = glm::normalize(entityPosition - cameraPosition);
|
glm::vec3 direction = glm::normalize(entityPosition - cameraPosition);
|
||||||
float distance;
|
float distance;
|
||||||
BoxFace face;
|
BoxFace face;
|
||||||
glm::vec3 normal;
|
glm::vec3 normal;
|
||||||
boundingBox.findRayIntersection(cameraPosition, direction, distance, face, normal);
|
boundingBox.findRayIntersection(cameraPosition, direction, distance, face, normal);
|
||||||
contextOverlayPosition = (cameraPosition + direction * distance) - direction * CONTEXT_OVERLAY_FAR_OFFSET;
|
float offsetAngle = -CONTEXT_OVERLAY_OFFSET_ANGLE;
|
||||||
contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_FAR_SIZE, CONTEXT_OVERLAY_FAR_SIZE) * glm::distance(contextOverlayPosition, cameraPosition);
|
if (event.getID() == LEFT_HAND_HW_ID) {
|
||||||
|
offsetAngle *= -1;
|
||||||
|
}
|
||||||
|
contextOverlayPosition = (glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f)))) *
|
||||||
|
((cameraPosition + direction * (distance - CONTEXT_OVERLAY_OFFSET_DISTANCE)));
|
||||||
|
contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_SIZE, CONTEXT_OVERLAY_SIZE) * glm::distance(contextOverlayPosition, cameraPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, setup and draw the Context Overlay
|
// Finally, setup and draw the Context Overlay
|
||||||
|
@ -176,6 +166,7 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID&
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!_currentEntityWithContextOverlay.isNull()) {
|
if (!_currentEntityWithContextOverlay.isNull()) {
|
||||||
|
disableEntityHighlight(_currentEntityWithContextOverlay);
|
||||||
return destroyContextOverlay(_currentEntityWithContextOverlay, event);
|
return destroyContextOverlay(_currentEntityWithContextOverlay, event);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -237,13 +228,13 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveOverlay(const OverlayID&
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextOverlayInterface::contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event) {
|
void ContextOverlayInterface::contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event) {
|
||||||
if (contextOverlayFilterPassed(entityID)) {
|
if (contextOverlayFilterPassed(entityID) && _enabled && event.getID() != MOUSE_HW_ID) {
|
||||||
enableEntityHighlight(entityID);
|
enableEntityHighlight(entityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event) {
|
void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event) {
|
||||||
if (_currentEntityWithContextOverlay != entityID) {
|
if (_currentEntityWithContextOverlay != entityID && _enabled && event.getID() != MOUSE_HW_ID) {
|
||||||
disableEntityHighlight(entityID);
|
disableEntityHighlight(entityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,8 +76,6 @@ private:
|
||||||
|
|
||||||
bool _isInMarketplaceInspectionMode { false };
|
bool _isInMarketplaceInspectionMode { false };
|
||||||
|
|
||||||
Setting::Handle<bool> _settingSwitch { "inspectionMode", false };
|
|
||||||
|
|
||||||
void openMarketplace();
|
void openMarketplace();
|
||||||
void enableEntityHighlight(const EntityItemID& entityItemID);
|
void enableEntityHighlight(const EntityItemID& entityItemID);
|
||||||
void disableEntityHighlight(const EntityItemID& entityItemID);
|
void disableEntityHighlight(const EntityItemID& entityItemID);
|
||||||
|
|
|
@ -222,6 +222,16 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
|
||||||
_renderablesToUpdate.insert({ entityId, renderable });
|
_renderablesToUpdate.insert({ entityId, renderable });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Looping over all the entity renderers is likely to be a bottleneck in the future
|
||||||
|
// Currently, this is necessary because the model entity loading logic requires constant polling
|
||||||
|
// This was working fine because the entity server used to send repeated updates as your view changed,
|
||||||
|
// but with the improved entity server logic (PR 11141), updateInScene (below) would not be triggered enough
|
||||||
|
for (const auto& entry : _entitiesInScene) {
|
||||||
|
const auto& renderable = entry.second;
|
||||||
|
if (renderable) {
|
||||||
|
renderable->update(scene, transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!_renderablesToUpdate.empty()) {
|
if (!_renderablesToUpdate.empty()) {
|
||||||
for (const auto& entry : _renderablesToUpdate) {
|
for (const auto& entry : _renderablesToUpdate) {
|
||||||
const auto& renderable = entry.second;
|
const auto& renderable = entry.second;
|
||||||
|
|
|
@ -291,6 +291,18 @@ void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& trans
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityRenderer::update(const ScenePointer& scene, Transaction& transaction) {
|
||||||
|
if (!isValidRenderItem()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needsUpdate()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
doUpdate(scene, transaction, _entity);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Internal methods
|
// Internal methods
|
||||||
//
|
//
|
||||||
|
@ -304,6 +316,11 @@ bool EntityRenderer::needsRenderUpdate() const {
|
||||||
return needsRenderUpdateFromEntity(_entity);
|
return needsRenderUpdateFromEntity(_entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if the item needs to have update called
|
||||||
|
bool EntityRenderer::needsUpdate() const {
|
||||||
|
return needsUpdateFromEntity(_entity);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns true if the item in question needs to have updateInScene called because of changes in the entity
|
// Returns true if the item in question needs to have updateInScene called because of changes in the entity
|
||||||
bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity) const {
|
bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity) const {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
|
@ -49,6 +49,8 @@ public:
|
||||||
virtual bool addToScene(const ScenePointer& scene, Transaction& transaction) final;
|
virtual bool addToScene(const ScenePointer& scene, Transaction& transaction) final;
|
||||||
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction);
|
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction);
|
||||||
|
|
||||||
|
virtual void update(const ScenePointer& scene, Transaction& transaction);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }
|
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }
|
||||||
virtual void onAddToScene(const EntityItemPointer& entity);
|
virtual void onAddToScene(const EntityItemPointer& entity);
|
||||||
|
@ -71,6 +73,12 @@ protected:
|
||||||
// Returns true if the item in question needs to have updateInScene called because of changes in the entity
|
// Returns true if the item in question needs to have updateInScene called because of changes in the entity
|
||||||
virtual bool needsRenderUpdateFromEntity(const EntityItemPointer& entity) const;
|
virtual bool needsRenderUpdateFromEntity(const EntityItemPointer& entity) const;
|
||||||
|
|
||||||
|
// Returns true if the item in question needs to have update called
|
||||||
|
virtual bool needsUpdate() const;
|
||||||
|
|
||||||
|
// Returns true if the item in question needs to have update called because of changes in the entity
|
||||||
|
virtual bool needsUpdateFromEntity(const EntityItemPointer& entity) const { return false; }
|
||||||
|
|
||||||
// Will be called on the main thread from updateInScene. This can be used to fetch things like
|
// Will be called on the main thread from updateInScene. This can be used to fetch things like
|
||||||
// network textures or model geometry from resource caches
|
// network textures or model geometry from resource caches
|
||||||
virtual void doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) { }
|
virtual void doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) { }
|
||||||
|
@ -80,6 +88,8 @@ protected:
|
||||||
// data in this method if using multi-threaded rendering
|
// data in this method if using multi-threaded rendering
|
||||||
virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity);
|
virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity);
|
||||||
|
|
||||||
|
virtual void doUpdate(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) { }
|
||||||
|
|
||||||
// Called by the `render` method after `needsRenderUpdate`
|
// Called by the `render` method after `needsRenderUpdate`
|
||||||
virtual void doRender(RenderArgs* args) = 0;
|
virtual void doRender(RenderArgs* args) = 0;
|
||||||
|
|
||||||
|
@ -148,6 +158,15 @@ protected:
|
||||||
onRemoveFromSceneTyped(_typedEntity);
|
onRemoveFromSceneTyped(_typedEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using Parent::needsUpdateFromEntity;
|
||||||
|
// Returns true if the item in question needs to have update called because of changes in the entity
|
||||||
|
virtual bool needsUpdateFromEntity(const EntityItemPointer& entity) const override final {
|
||||||
|
if (Parent::needsUpdateFromEntity(entity)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return needsUpdateFromTypedEntity(_typedEntity);
|
||||||
|
}
|
||||||
|
|
||||||
using Parent::needsRenderUpdateFromEntity;
|
using Parent::needsRenderUpdateFromEntity;
|
||||||
// Returns true if the item in question needs to have updateInScene called because of changes in the entity
|
// Returns true if the item in question needs to have updateInScene called because of changes in the entity
|
||||||
virtual bool needsRenderUpdateFromEntity(const EntityItemPointer& entity) const override final {
|
virtual bool needsRenderUpdateFromEntity(const EntityItemPointer& entity) const override final {
|
||||||
|
@ -162,6 +181,11 @@ protected:
|
||||||
doRenderUpdateSynchronousTyped(scene, transaction, _typedEntity);
|
doRenderUpdateSynchronousTyped(scene, transaction, _typedEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void doUpdate(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) override final {
|
||||||
|
Parent::doUpdate(scene, transaction, entity);
|
||||||
|
doUpdateTyped(scene, transaction, _typedEntity);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity) override final {
|
virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity) override final {
|
||||||
Parent::doRenderUpdateAsynchronous(entity);
|
Parent::doRenderUpdateAsynchronous(entity);
|
||||||
doRenderUpdateAsynchronousTyped(_typedEntity);
|
doRenderUpdateAsynchronousTyped(_typedEntity);
|
||||||
|
@ -170,6 +194,8 @@ protected:
|
||||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { return false; }
|
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { return false; }
|
||||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { }
|
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { }
|
||||||
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { }
|
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { }
|
||||||
|
virtual bool needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const { return false; }
|
||||||
|
virtual void doUpdateTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { }
|
||||||
virtual void onAddToSceneTyped(const TypedEntityPointer& entity) { }
|
virtual void onAddToSceneTyped(const TypedEntityPointer& entity) { }
|
||||||
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) { }
|
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) { }
|
||||||
|
|
||||||
|
|
|
@ -904,7 +904,7 @@ using namespace render;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
|
||||||
ItemKey ModelEntityRenderer::getKey() {
|
ItemKey ModelEntityRenderer::getKey() {
|
||||||
return ItemKey::Builder::opaqueShape().withTypeMeta();
|
return ItemKey::Builder().withTypeMeta();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
|
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
|
||||||
|
@ -1026,12 +1026,16 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
||||||
entity->copyAnimationJointDataToModel();
|
entity->copyAnimationJointDataToModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelEntityRenderer::needsRenderUpdate() const {
|
bool ModelEntityRenderer::needsUpdate() const {
|
||||||
ModelPointer model;
|
ModelPointer model;
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
model = _model;
|
model = _model;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (_modelJustLoaded) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (model) {
|
if (model) {
|
||||||
if (_needsJointSimulation || _moving || _animating) {
|
if (_needsJointSimulation || _moving || _animating) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1057,10 +1061,10 @@ bool ModelEntityRenderer::needsRenderUpdate() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Parent::needsRenderUpdate();
|
return Parent::needsUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
bool ModelEntityRenderer::needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||||
if (resultWithReadLock<bool>([&] {
|
if (resultWithReadLock<bool>([&] {
|
||||||
if (entity->hasModel() != _hasModel) {
|
if (entity->hasModel() != _hasModel) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1122,7 +1126,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
void ModelEntityRenderer::doUpdateTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||||
if (_hasModel != entity->hasModel()) {
|
if (_hasModel != entity->hasModel()) {
|
||||||
_hasModel = entity->hasModel();
|
_hasModel = entity->hasModel();
|
||||||
}
|
}
|
||||||
|
@ -1148,9 +1152,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_modelJustLoaded = false;
|
||||||
// Check for addition
|
// Check for addition
|
||||||
if (_hasModel && !(bool)_model) {
|
if (_hasModel && !(bool)_model) {
|
||||||
model = std::make_shared<Model>(nullptr, entity.get());
|
model = std::make_shared<Model>(nullptr, entity.get());
|
||||||
|
connect(model.get(), &Model::setURLFinished, this, &ModelEntityRenderer::handleModelLoaded);
|
||||||
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
|
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
|
||||||
model->init();
|
model->init();
|
||||||
entity->setModel(model);
|
entity->setModel(model);
|
||||||
|
@ -1175,8 +1181,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
|
properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
|
||||||
auto extents = model->getMeshExtents();
|
auto extents = model->getMeshExtents();
|
||||||
properties.setDimensions(extents.maximum - extents.minimum);
|
properties.setDimensions(extents.maximum - extents.minimum);
|
||||||
qCDebug(entitiesrenderer) << "Autoresizing"
|
qCDebug(entitiesrenderer) << "Autoresizing"
|
||||||
<< (!entity->getName().isEmpty() ? entity->getName() : entity->getModelURL())
|
<< (!entity->getName().isEmpty() ? entity->getName() : entity->getModelURL())
|
||||||
<< "from mesh extents";
|
<< "from mesh extents";
|
||||||
|
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity",
|
QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity",
|
||||||
|
@ -1203,7 +1209,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
entity->updateModelBounds();
|
entity->updateModelBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (model->isVisible() != _visible) {
|
if (model->isVisible() != _visible) {
|
||||||
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
||||||
// the renderable item. As it stands now the model checks it's visible/invisible state
|
// the renderable item. As it stands now the model checks it's visible/invisible state
|
||||||
|
@ -1234,7 +1239,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (_animating) {
|
if (_animating) {
|
||||||
if (!jointsMapped()) {
|
if (!jointsMapped()) {
|
||||||
mapJoints(entity, model->getJointNames());
|
mapJoints(entity, model->getJointNames());
|
||||||
|
@ -1243,6 +1247,12 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelEntityRenderer::handleModelLoaded(bool success) {
|
||||||
|
if (success) {
|
||||||
|
_modelJustLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
|
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
|
||||||
void ModelEntityRenderer::doRender(RenderArgs* args) {
|
void ModelEntityRenderer::doRender(RenderArgs* args) {
|
||||||
PROFILE_RANGE(render_detail, "MetaModelRender");
|
PROFILE_RANGE(render_detail, "MetaModelRender");
|
||||||
|
|
|
@ -138,10 +138,10 @@ protected:
|
||||||
virtual ItemKey getKey() override;
|
virtual ItemKey getKey() override;
|
||||||
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override;
|
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override;
|
||||||
|
|
||||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
virtual bool needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
||||||
virtual bool needsRenderUpdate() const override;
|
virtual bool needsUpdate() const override;
|
||||||
virtual void doRender(RenderArgs* args) override;
|
virtual void doRender(RenderArgs* args) override;
|
||||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
virtual void doUpdateTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void animate(const TypedEntityPointer& entity);
|
void animate(const TypedEntityPointer& entity);
|
||||||
|
@ -151,6 +151,7 @@ private:
|
||||||
// Transparency is handled in ModelMeshPartPayload
|
// Transparency is handled in ModelMeshPartPayload
|
||||||
virtual bool isTransparent() const override { return false; }
|
virtual bool isTransparent() const override { return false; }
|
||||||
|
|
||||||
|
bool _modelJustLoaded { false };
|
||||||
bool _hasModel { false };
|
bool _hasModel { false };
|
||||||
::ModelPointer _model;
|
::ModelPointer _model;
|
||||||
GeometryResource::Pointer _compoundShapeResource;
|
GeometryResource::Pointer _compoundShapeResource;
|
||||||
|
@ -178,6 +179,9 @@ private:
|
||||||
bool _animating { false };
|
bool _animating { false };
|
||||||
uint64_t _lastAnimated { 0 };
|
uint64_t _lastAnimated { 0 };
|
||||||
float _currentFrame { 0 };
|
float _currentFrame { 0 };
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleModelLoaded(bool success);
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace
|
} } // namespace
|
||||||
|
|
|
@ -102,7 +102,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
|
||||||
glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
|
glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
|
||||||
transformToTopLeft.setRotation(orientation);
|
transformToTopLeft.setRotation(orientation);
|
||||||
}
|
}
|
||||||
transformToTopLeft.postTranslate(glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left
|
transformToTopLeft.postTranslate(dimensions * glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left
|
||||||
transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed
|
transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed
|
||||||
|
|
||||||
batch.setModelTransform(transformToTopLeft);
|
batch.setModelTransform(transformToTopLeft);
|
||||||
|
|
|
@ -140,6 +140,11 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
|
||||||
_webSurface->resize(QSize(windowSize.x, windowSize.y));
|
_webSurface->resize(QSize(windowSize.x, windowSize.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||||
|
Parent::doRenderUpdateAsynchronousTyped(entity);
|
||||||
|
_modelTransform.postScale(entity->getDimensions());
|
||||||
|
}
|
||||||
|
|
||||||
void WebEntityRenderer::doRender(RenderArgs* args) {
|
void WebEntityRenderer::doRender(RenderArgs* args) {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
_lastRenderTime = usecTimestampNow();
|
_lastRenderTime = usecTimestampNow();
|
||||||
|
|
|
@ -29,6 +29,7 @@ protected:
|
||||||
virtual bool needsRenderUpdate() const override;
|
virtual bool needsRenderUpdate() const override;
|
||||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
||||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||||
|
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
||||||
virtual void doRender(RenderArgs* args) override;
|
virtual void doRender(RenderArgs* args) override;
|
||||||
virtual bool isTransparent() const override;
|
virtual bool isTransparent() const override;
|
||||||
|
|
||||||
|
|
|
@ -464,7 +464,7 @@ void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) {
|
||||||
_resource = resource;
|
_resource = resource;
|
||||||
if (_resource) {
|
if (_resource) {
|
||||||
if (_resource->isLoaded()) {
|
if (_resource->isLoaded()) {
|
||||||
_geometryRef = std::make_shared<Geometry>(*_resource);
|
resourceFinished(true);
|
||||||
} else {
|
} else {
|
||||||
startWatching();
|
startWatching();
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
||||||
_dynamicsWorld->addRigidBody(_rigidBody, collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR);
|
_dynamicsWorld->addRigidBody(_rigidBody, collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR);
|
||||||
_dynamicsWorld->addAction(this);
|
_dynamicsWorld->addAction(this);
|
||||||
// restore gravity settings because adding an object to the world overwrites its gravity setting
|
// restore gravity settings because adding an object to the world overwrites its gravity setting
|
||||||
_rigidBody->setGravity(_gravity * _currentUp);
|
_rigidBody->setGravity(_currentGravity * _currentUp);
|
||||||
btCollisionShape* shape = _rigidBody->getCollisionShape();
|
btCollisionShape* shape = _rigidBody->getCollisionShape();
|
||||||
assert(shape && shape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE);
|
assert(shape && shape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE);
|
||||||
_ghost.setCharacterShape(static_cast<btConvexHullShape*>(shape));
|
_ghost.setCharacterShape(static_cast<btConvexHullShape*>(shape));
|
||||||
|
@ -302,7 +302,7 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar
|
||||||
// add minimum velocity to counteract gravity's displacement during one step
|
// add minimum velocity to counteract gravity's displacement during one step
|
||||||
// Note: the 0.5 factor comes from the fact that we really want the
|
// Note: the 0.5 factor comes from the fact that we really want the
|
||||||
// average velocity contribution from gravity during the step
|
// average velocity contribution from gravity during the step
|
||||||
stepUpSpeed -= 0.5f * _gravity * timeToStep; // remember: _gravity is negative scalar
|
stepUpSpeed -= 0.5f * _currentGravity * timeToStep; // remember: _gravity is negative scalar
|
||||||
|
|
||||||
btScalar vDotUp = velocity.dot(_currentUp);
|
btScalar vDotUp = velocity.dot(_currentUp);
|
||||||
if (vDotUp < stepUpSpeed) {
|
if (vDotUp < stepUpSpeed) {
|
||||||
|
@ -351,6 +351,28 @@ static const char* stateToStr(CharacterController::State state) {
|
||||||
}
|
}
|
||||||
#endif // #ifdef DEBUG_STATE_CHANGE
|
#endif // #ifdef DEBUG_STATE_CHANGE
|
||||||
|
|
||||||
|
void CharacterController::updateCurrentGravity() {
|
||||||
|
int16_t collisionGroup = computeCollisionGroup();
|
||||||
|
if (_state == State::Hover || collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||||
|
_currentGravity = 0.0f;
|
||||||
|
} else {
|
||||||
|
_currentGravity = _gravity;
|
||||||
|
}
|
||||||
|
if (_rigidBody) {
|
||||||
|
_rigidBody->setGravity(_currentGravity * _currentUp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CharacterController::setGravity(float gravity) {
|
||||||
|
_gravity = gravity;
|
||||||
|
updateCurrentGravity();
|
||||||
|
}
|
||||||
|
|
||||||
|
float CharacterController::getGravity() {
|
||||||
|
return _gravity;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_STATE_CHANGE
|
#ifdef DEBUG_STATE_CHANGE
|
||||||
void CharacterController::setState(State desiredState, const char* reason) {
|
void CharacterController::setState(State desiredState, const char* reason) {
|
||||||
#else
|
#else
|
||||||
|
@ -365,19 +387,7 @@ void CharacterController::setState(State desiredState) {
|
||||||
qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "from" << stateToStr(_state) << "," << reason;
|
qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "from" << stateToStr(_state) << "," << reason;
|
||||||
#endif
|
#endif
|
||||||
_state = desiredState;
|
_state = desiredState;
|
||||||
updateGravity();
|
updateCurrentGravity();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CharacterController::updateGravity() {
|
|
||||||
int16_t collisionGroup = computeCollisionGroup();
|
|
||||||
if (_state == State::Hover || collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
|
||||||
_gravity = 0.0f;
|
|
||||||
} else {
|
|
||||||
_gravity = DEFAULT_AVATAR_GRAVITY;
|
|
||||||
}
|
|
||||||
if (_rigidBody) {
|
|
||||||
_rigidBody->setGravity(_gravity * _currentUp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,14 +446,14 @@ void CharacterController::handleChangedCollisionGroup() {
|
||||||
_dynamicsWorld->addRigidBody(_rigidBody, collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR);
|
_dynamicsWorld->addRigidBody(_rigidBody, collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR);
|
||||||
}
|
}
|
||||||
_pendingFlags &= ~PENDING_FLAG_UPDATE_COLLISION_GROUP;
|
_pendingFlags &= ~PENDING_FLAG_UPDATE_COLLISION_GROUP;
|
||||||
updateGravity();
|
updateCurrentGravity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::updateUpAxis(const glm::quat& rotation) {
|
void CharacterController::updateUpAxis(const glm::quat& rotation) {
|
||||||
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
|
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
|
||||||
if (_rigidBody) {
|
if (_rigidBody) {
|
||||||
_rigidBody->setGravity(_gravity * _currentUp);
|
_rigidBody->setGravity(_currentGravity * _currentUp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "BulletUtil.h"
|
#include "BulletUtil.h"
|
||||||
#include "CharacterGhostObject.h"
|
#include "CharacterGhostObject.h"
|
||||||
|
#include "AvatarConstants.h"
|
||||||
|
|
||||||
const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0;
|
const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0;
|
||||||
const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1;
|
const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1;
|
||||||
|
@ -42,15 +43,18 @@ const btScalar MAX_CHARACTER_MOTOR_TIMESCALE = 60.0f; // one minute
|
||||||
const btScalar MIN_CHARACTER_MOTOR_TIMESCALE = 0.05f;
|
const btScalar MIN_CHARACTER_MOTOR_TIMESCALE = 0.05f;
|
||||||
|
|
||||||
class CharacterController : public btCharacterControllerInterface {
|
class CharacterController : public btCharacterControllerInterface {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CharacterController();
|
CharacterController();
|
||||||
virtual ~CharacterController();
|
virtual ~CharacterController();
|
||||||
|
|
||||||
bool needsRemoval() const;
|
bool needsRemoval() const;
|
||||||
bool needsAddition() const;
|
bool needsAddition() const;
|
||||||
virtual void setDynamicsWorld(btDynamicsWorld* world);
|
virtual void setDynamicsWorld(btDynamicsWorld* world);
|
||||||
btCollisionObject* getCollisionObject() { return _rigidBody; }
|
btCollisionObject* getCollisionObject() { return _rigidBody; }
|
||||||
|
|
||||||
|
void setGravity(float gravity);
|
||||||
|
float getGravity();
|
||||||
|
|
||||||
virtual void updateShapeIfNecessary() = 0;
|
virtual void updateShapeIfNecessary() = 0;
|
||||||
|
|
||||||
// overrides from btCharacterControllerInterface
|
// overrides from btCharacterControllerInterface
|
||||||
|
@ -131,7 +135,7 @@ protected:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
virtual void updateMassProperties() = 0;
|
virtual void updateMassProperties() = 0;
|
||||||
void updateGravity();
|
void updateCurrentGravity();
|
||||||
void updateUpAxis(const glm::quat& rotation);
|
void updateUpAxis(const glm::quat& rotation);
|
||||||
bool checkForSupport(btCollisionWorld* collisionWorld);
|
bool checkForSupport(btCollisionWorld* collisionWorld);
|
||||||
|
|
||||||
|
@ -184,7 +188,8 @@ protected:
|
||||||
bool _stepUpEnabled { true };
|
bool _stepUpEnabled { true };
|
||||||
bool _hasSupport;
|
bool _hasSupport;
|
||||||
|
|
||||||
btScalar _gravity { 0.0f };
|
btScalar _currentGravity { 0.0f };
|
||||||
|
btScalar _gravity { DEFAULT_AVATAR_GRAVITY };
|
||||||
|
|
||||||
btScalar _followTime;
|
btScalar _followTime;
|
||||||
btVector3 _followLinearDisplacement;
|
btVector3 _followLinearDisplacement;
|
||||||
|
|
|
@ -321,17 +321,25 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
|
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
|
||||||
_meshIndex(_meshIndex),
|
_meshIndex(meshIndex),
|
||||||
_shapeID(shapeIndex) {
|
_shapeID(shapeIndex) {
|
||||||
|
|
||||||
assert(model && model->isLoaded());
|
assert(model && model->isLoaded());
|
||||||
_model = model;
|
_model = model;
|
||||||
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex);
|
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex);
|
||||||
|
const Model::MeshState& state = model->getMeshState(_meshIndex);
|
||||||
|
|
||||||
updateMeshPart(modelMesh, partIndex);
|
updateMeshPart(modelMesh, partIndex);
|
||||||
|
computeAdjustedLocalBound(state.clusterMatrices);
|
||||||
|
|
||||||
updateTransform(transform, offsetTransform);
|
updateTransform(transform, offsetTransform);
|
||||||
|
Transform renderTransform = transform;
|
||||||
|
if (state.clusterMatrices.size() == 1) {
|
||||||
|
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
|
||||||
|
}
|
||||||
|
updateTransformForSkinnedMesh(renderTransform, transform, state.clusterBuffer);
|
||||||
|
|
||||||
initCache();
|
initCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -209,11 +209,6 @@ void Model::updateRenderItems() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 scale = getScale();
|
|
||||||
if (_collisionGeometry) {
|
|
||||||
// _collisionGeometry is already scaled
|
|
||||||
scale = glm::vec3(1.0f);
|
|
||||||
}
|
|
||||||
_needsUpdateClusterMatrices = true;
|
_needsUpdateClusterMatrices = true;
|
||||||
_renderItemsNeedUpdate = false;
|
_renderItemsNeedUpdate = false;
|
||||||
|
|
||||||
|
@ -221,7 +216,7 @@ void Model::updateRenderItems() {
|
||||||
// the application will ensure only the last lambda is actually invoked.
|
// the application will ensure only the last lambda is actually invoked.
|
||||||
void* key = (void*)this;
|
void* key = (void*)this;
|
||||||
std::weak_ptr<Model> weakSelf = shared_from_this();
|
std::weak_ptr<Model> weakSelf = shared_from_this();
|
||||||
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf, scale]() {
|
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() {
|
||||||
|
|
||||||
// do nothing, if the model has already been destroyed.
|
// do nothing, if the model has already been destroyed.
|
||||||
auto self = weakSelf.lock();
|
auto self = weakSelf.lock();
|
||||||
|
@ -1220,6 +1215,7 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::createRenderItemSet() {
|
void Model::createRenderItemSet() {
|
||||||
|
updateClusterMatrices();
|
||||||
if (_collisionGeometry) {
|
if (_collisionGeometry) {
|
||||||
if (_collisionRenderItems.empty()) {
|
if (_collisionRenderItems.empty()) {
|
||||||
createCollisionRenderItemSet();
|
createCollisionRenderItemSet();
|
||||||
|
@ -1270,7 +1266,6 @@ void Model::createVisibleRenderItemSet() {
|
||||||
shapeID++;
|
shapeID++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
computeMeshPartLocalBounds();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::createCollisionRenderItemSet() {
|
void Model::createCollisionRenderItemSet() {
|
||||||
|
|
|
@ -81,10 +81,10 @@ public:
|
||||||
float getColorB() const { return color.b; }
|
float getColorB() const { return color.b; }
|
||||||
|
|
||||||
glm::vec3 color{ 1.f, 0.7f, 0.2f };
|
glm::vec3 color{ 1.f, 0.7f, 0.2f };
|
||||||
float width{ 3.f };
|
float width{ 2.0f };
|
||||||
float intensity{ 1.f };
|
float intensity{ 0.9f };
|
||||||
float fillOpacityUnoccluded{ 0.35f };
|
float fillOpacityUnoccluded{ 0.0f };
|
||||||
float fillOpacityOccluded{ 0.1f };
|
float fillOpacityOccluded{ 0.0f };
|
||||||
bool glow{ false };
|
bool glow{ false };
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
layout(location = 0) in vec4 inColor;
|
in vec4 _color;
|
||||||
|
in float distanceFromCenter;
|
||||||
|
|
||||||
out vec4 _fragColor;
|
out vec4 _fragColor;
|
||||||
|
|
||||||
|
@ -17,10 +18,10 @@ void main(void) {
|
||||||
// The incoming value actually ranges from -1 to 1, so modify it
|
// The incoming value actually ranges from -1 to 1, so modify it
|
||||||
// so that it goes from 0 -> 1 -> 0 with the solid alpha being at
|
// so that it goes from 0 -> 1 -> 0 with the solid alpha being at
|
||||||
// the center of the line
|
// the center of the line
|
||||||
float alpha = 1.0 - abs(inColor.a);
|
float alpha = 1.0 - abs(distanceFromCenter);
|
||||||
|
|
||||||
// Convert from a linear alpha curve to a sharp peaked one
|
// Convert from a linear alpha curve to a sharp peaked one
|
||||||
alpha = pow(alpha, 10);
|
alpha = _color.a * pow(alpha, 10);
|
||||||
|
|
||||||
// Drop everything where the curve falls off to nearly nothing
|
// Drop everything where the curve falls off to nearly nothing
|
||||||
if (alpha <= 0.05) {
|
if (alpha <= 0.05) {
|
||||||
|
@ -28,6 +29,5 @@ void main(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit the color
|
// Emit the color
|
||||||
_fragColor = vec4(inColor.rgb, alpha);
|
_fragColor = vec4(_color.rgb, alpha);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@ layout(std140) uniform lineData {
|
||||||
vec4 color;
|
vec4 color;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(location = 0) out vec4 _color;
|
out vec4 _color;
|
||||||
|
// the distance from the center in 'quad space'
|
||||||
|
out float distanceFromCenter;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
_color = color;
|
_color = color;
|
||||||
|
@ -45,11 +47,10 @@ void main(void) {
|
||||||
// Add or subtract the orthogonal vector based on a different vertex ID
|
// Add or subtract the orthogonal vector based on a different vertex ID
|
||||||
// calculation
|
// calculation
|
||||||
if (gl_VertexID < 2) {
|
if (gl_VertexID < 2) {
|
||||||
// Use the alpha channel to store the distance from the center in 'quad space'
|
distanceFromCenter = -1.0;
|
||||||
_color.a = -1.0;
|
|
||||||
eye.xyz -= orthogonal;
|
eye.xyz -= orthogonal;
|
||||||
} else {
|
} else {
|
||||||
_color.a = 1.0;
|
distanceFromCenter = 1.0;
|
||||||
eye.xyz += orthogonal;
|
eye.xyz += orthogonal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ void main(void) {
|
||||||
max(0, 1.0 - shininess / 128.0),
|
max(0, 1.0 - shininess / 128.0),
|
||||||
DEFAULT_METALLIC,
|
DEFAULT_METALLIC,
|
||||||
specular,
|
specular,
|
||||||
specular);
|
vec3(clamp(emissiveAmount, 0.0, 1.0)));
|
||||||
} else {
|
} else {
|
||||||
packDeferredFragment(
|
packDeferredFragment(
|
||||||
normal,
|
normal,
|
||||||
|
|
|
@ -77,13 +77,13 @@ QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEve
|
||||||
normal.setProperty("x", event._normal.x);
|
normal.setProperty("x", event._normal.x);
|
||||||
normal.setProperty("y", event._normal.y);
|
normal.setProperty("y", event._normal.y);
|
||||||
normal.setProperty("z", event._normal.z);
|
normal.setProperty("z", event._normal.z);
|
||||||
obj.setProperty("pos3D", normal);
|
obj.setProperty("normal", normal);
|
||||||
|
|
||||||
QScriptValue direction = engine->newObject();
|
QScriptValue direction = engine->newObject();
|
||||||
direction.setProperty("x", event._direction.x);
|
direction.setProperty("x", event._direction.x);
|
||||||
direction.setProperty("y", event._direction.y);
|
direction.setProperty("y", event._direction.y);
|
||||||
direction.setProperty("z", event._direction.z);
|
direction.setProperty("z", event._direction.z);
|
||||||
obj.setProperty("pos3D", direction);
|
obj.setProperty("direction", direction);
|
||||||
|
|
||||||
bool isPrimaryButton = false;
|
bool isPrimaryButton = false;
|
||||||
bool isSecondaryButton = false;
|
bool isSecondaryButton = false;
|
||||||
|
|
|
@ -762,6 +762,8 @@ QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResu
|
||||||
QScriptValue intersection = vec3toScriptValue(engine, rayPickResult.intersection);
|
QScriptValue intersection = vec3toScriptValue(engine, rayPickResult.intersection);
|
||||||
obj.setProperty("intersection", intersection);
|
obj.setProperty("intersection", intersection);
|
||||||
obj.setProperty("intersects", rayPickResult.type != NONE);
|
obj.setProperty("intersects", rayPickResult.type != NONE);
|
||||||
|
QScriptValue searchRay = pickRayToScriptValue(engine, rayPickResult.searchRay);
|
||||||
|
obj.setProperty("searchRay", searchRay);
|
||||||
QScriptValue surfaceNormal = vec3toScriptValue(engine, rayPickResult.surfaceNormal);
|
QScriptValue surfaceNormal = vec3toScriptValue(engine, rayPickResult.surfaceNormal);
|
||||||
obj.setProperty("surfaceNormal", surfaceNormal);
|
obj.setProperty("surfaceNormal", surfaceNormal);
|
||||||
return obj;
|
return obj;
|
||||||
|
|
|
@ -137,7 +137,7 @@ QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay)
|
||||||
void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay);
|
void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay);
|
||||||
|
|
||||||
enum IntersectionType {
|
enum IntersectionType {
|
||||||
NONE,
|
NONE = 0,
|
||||||
ENTITY,
|
ENTITY,
|
||||||
OVERLAY,
|
OVERLAY,
|
||||||
AVATAR,
|
AVATAR,
|
||||||
|
@ -147,12 +147,14 @@ enum IntersectionType {
|
||||||
class RayPickResult {
|
class RayPickResult {
|
||||||
public:
|
public:
|
||||||
RayPickResult() {}
|
RayPickResult() {}
|
||||||
RayPickResult(const IntersectionType type, const QUuid& objectID, const float distance, const glm::vec3& intersection, const glm::vec3& surfaceNormal = glm::vec3(NAN)) :
|
RayPickResult(const PickRay& searchRay) : searchRay(searchRay) {}
|
||||||
type(type), objectID(objectID), distance(distance), intersection(intersection), surfaceNormal(surfaceNormal) {}
|
RayPickResult(const IntersectionType type, const QUuid& objectID, const float distance, const glm::vec3& intersection, const PickRay& searchRay, const glm::vec3& surfaceNormal = glm::vec3(NAN)) :
|
||||||
|
type(type), objectID(objectID), distance(distance), intersection(intersection), searchRay(searchRay), surfaceNormal(surfaceNormal) {}
|
||||||
IntersectionType type { NONE };
|
IntersectionType type { NONE };
|
||||||
QUuid objectID { 0 };
|
QUuid objectID;
|
||||||
float distance { FLT_MAX };
|
float distance { FLT_MAX };
|
||||||
glm::vec3 intersection { NAN };
|
glm::vec3 intersection { NAN };
|
||||||
|
PickRay searchRay;
|
||||||
glm::vec3 surfaceNormal { NAN };
|
glm::vec3 surfaceNormal { NAN };
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(RayPickResult)
|
Q_DECLARE_METATYPE(RayPickResult)
|
||||||
|
|
|
@ -211,12 +211,12 @@ class UrlHandler : public QObject {
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE bool canHandleUrl(const QString& url) {
|
Q_INVOKABLE bool canHandleUrl(const QString& url) {
|
||||||
static auto handler = dynamic_cast<AbstractUriHandler*>(qApp);
|
static auto handler = dynamic_cast<AbstractUriHandler*>(qApp);
|
||||||
return handler->canAcceptURL(url);
|
return handler && handler->canAcceptURL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_INVOKABLE bool handleUrl(const QString& url) {
|
Q_INVOKABLE bool handleUrl(const QString& url) {
|
||||||
static auto handler = dynamic_cast<AbstractUriHandler*>(qApp);
|
static auto handler = dynamic_cast<AbstractUriHandler*>(qApp);
|
||||||
return handler->acceptURL(url);
|
return handler && handler->acceptURL(url);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info)
|
||||||
|
|
||||||
// During the period in which we have HFC commerce in the system, but not applied everywhere:
|
// During the period in which we have HFC commerce in the system, but not applied everywhere:
|
||||||
const QString tokenStringCommerce{ "Chrome/48.0 (HighFidelityInterface WithHFC)" };
|
const QString tokenStringCommerce{ "Chrome/48.0 (HighFidelityInterface WithHFC)" };
|
||||||
static Setting::Handle<bool> _settingSwitch{ "inspectionMode", false };
|
static Setting::Handle<bool> _settingSwitch{ "commerce", false };
|
||||||
bool isMoney = _settingSwitch.get();
|
bool isMoney = _settingSwitch.get();
|
||||||
|
|
||||||
const QString tokenString = !isAuthable ? tokenStringMobile : (isMoney ? tokenStringCommerce : tokenStringMetaverse);
|
const QString tokenString = !isAuthable ? tokenStringMobile : (isMoney ? tokenStringCommerce : tokenStringMetaverse);
|
||||||
|
|
45
scripts/developer/tests/gravityScript.js
Normal file
45
scripts/developer/tests/gravityScript.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
//
|
||||||
|
// Gravity Script 1.0
|
||||||
|
// ************
|
||||||
|
//
|
||||||
|
// Created by Cain Kilgore on 9/14/2017
|
||||||
|
|
||||||
|
// Javascript for the Gravity Modifier Implementation to test
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
function menuParameters(menuNameSelection, menuItemNameSelection) {
|
||||||
|
Menu.addMenuItem({
|
||||||
|
menuName: menuNameSelection,
|
||||||
|
menuItemName: menuItemNameSelection,
|
||||||
|
isCheckable: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupMenu() {
|
||||||
|
if (!Menu.menuExists("Gravity")) {
|
||||||
|
Menu.addMenu("Gravity");
|
||||||
|
for (var i = -5; i <= 5; i++) {
|
||||||
|
menuParameters("Gravity", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function menuItemEvent(menuItem) {
|
||||||
|
for (var i = -5; i <= 5; i++) {
|
||||||
|
if (menuItem == i) {
|
||||||
|
MyAvatar.setGravity(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onScriptEnding() {
|
||||||
|
Menu.removeMenu("Gravity");
|
||||||
|
}
|
||||||
|
|
||||||
|
setupMenu();
|
||||||
|
Menu.menuItemEvent.connect(menuItemEvent);
|
||||||
|
Script.scriptEnding.connect(onScriptEnding);
|
|
@ -131,7 +131,7 @@
|
||||||
var button;
|
var button;
|
||||||
var buttonName = "WALLET";
|
var buttonName = "WALLET";
|
||||||
var tablet = null;
|
var tablet = null;
|
||||||
var walletEnabled = Settings.getValue("inspectionMode", false);
|
var walletEnabled = Settings.getValue("commerce", false);
|
||||||
function startup() {
|
function startup() {
|
||||||
if (walletEnabled) {
|
if (walletEnabled) {
|
||||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
|
|
@ -148,7 +148,9 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
if (mode === "full") {
|
if (mode === "full") {
|
||||||
var fullEndToEdit = PICK_WITH_HAND_RAY ? this.fullEnd : fullEnd;
|
var fullEndToEdit = PICK_WITH_HAND_RAY ? this.fullEnd : fullEnd;
|
||||||
fullEndToEdit.dimensions = dim;
|
fullEndToEdit.dimensions = dim;
|
||||||
LaserPointers.editRenderState(laserPointerID, mode, {path: fullPath, end: fullEndToEdit});
|
LaserPointers.editRenderState(laserPointerID, mode, { path: fullPath, end: fullEndToEdit });
|
||||||
|
this.contextOverlayTimer = false;
|
||||||
|
this.destroyContextOverlay();
|
||||||
} else if (mode === "half") {
|
} else if (mode === "half") {
|
||||||
var halfEndToEdit = PICK_WITH_HAND_RAY ? this.halfEnd : halfEnd;
|
var halfEndToEdit = PICK_WITH_HAND_RAY ? this.halfEnd : halfEnd;
|
||||||
halfEndToEdit.dimensions = dim;
|
halfEndToEdit.dimensions = dim;
|
||||||
|
|
|
@ -44,10 +44,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
||||||
return (this.hand === RIGHT_HAND) ? leftNearParentingGrabEntity : rightNearParentingGrabEntity;
|
return (this.hand === RIGHT_HAND) ? leftNearParentingGrabEntity : rightNearParentingGrabEntity;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.otherHandIsParent = function(props) {
|
|
||||||
return this.getOtherModule().thisHandIsParent(props);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.thisHandIsParent = function(props) {
|
this.thisHandIsParent = function(props) {
|
||||||
if (props.parentID !== MyAvatar.sessionUUID && props.parentID !== AVATAR_SELF_ID) {
|
if (props.parentID !== MyAvatar.sessionUUID && props.parentID !== AVATAR_SELF_ID) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -99,12 +95,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
||||||
// this should never happen, but if it does, don't set previous parent to be this hand.
|
// this should never happen, but if it does, don't set previous parent to be this hand.
|
||||||
// this.previousParentID[targetProps.id] = NULL;
|
// this.previousParentID[targetProps.id] = NULL;
|
||||||
// this.previousParentJointIndex[targetProps.id] = -1;
|
// this.previousParentJointIndex[targetProps.id] = -1;
|
||||||
} else if (this.otherHandIsParent(targetProps)) {
|
|
||||||
// the other hand is parent. Steal the object and information
|
|
||||||
var otherModule = this.getOtherModule();
|
|
||||||
this.previousParentID[targetProps.id] = otherModule.previousParentID[targetProps.id];
|
|
||||||
this.previousParentJointIndex[targetProps.id] = otherModule.previousParentJointIndex[targetProps.id];
|
|
||||||
otherModule.endNearParentingGrabEntity();
|
|
||||||
} else {
|
} else {
|
||||||
this.previousParentID[targetProps.id] = targetProps.parentID;
|
this.previousParentID[targetProps.id] = targetProps.parentID;
|
||||||
this.previousParentJointIndex[targetProps.id] = targetProps.parentJointIndex;
|
this.previousParentJointIndex[targetProps.id] = targetProps.parentJointIndex;
|
||||||
|
|
|
@ -298,6 +298,9 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
var intersection = controllerData.rayPicks[this.hand];
|
var intersection = controllerData.rayPicks[this.hand];
|
||||||
var offOverlay = (intersection.type !== RayPick.INTERSECTED_OVERLAY);
|
var offOverlay = (intersection.type !== RayPick.INTERSECTED_OVERLAY);
|
||||||
var triggerOff = (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE);
|
var triggerOff = (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE);
|
||||||
|
if (triggerOff) {
|
||||||
|
this.deleteContextOverlay();
|
||||||
|
}
|
||||||
var grabbingOverlay = this.grabModuleWantsNearbyOverlay(controllerData);
|
var grabbingOverlay = this.grabModuleWantsNearbyOverlay(controllerData);
|
||||||
return offOverlay || grabbingOverlay || triggerOff;
|
return offOverlay || grabbingOverlay || triggerOff;
|
||||||
};
|
};
|
||||||
|
@ -308,7 +311,6 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
this.laserPressExit();
|
this.laserPressExit();
|
||||||
this.laserPressingTarget = false;
|
this.laserPressingTarget = false;
|
||||||
}
|
}
|
||||||
this.deleteContextOverlay();
|
|
||||||
this.relinquishTouchFocus();
|
this.relinquishTouchFocus();
|
||||||
this.reset();
|
this.reset();
|
||||||
this.updateLaserPointer();
|
this.updateLaserPointer();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// handControllerGrab.js
|
// scaleAvatar.js
|
||||||
//
|
//
|
||||||
// Created by Dante Ruiz on 9/11/17
|
// Created by Dante Ruiz on 9/11/17
|
||||||
//
|
//
|
||||||
|
@ -80,4 +80,5 @@
|
||||||
dispatcherUtils.disableDispatcherModule("LeftScaleAvatar");
|
dispatcherUtils.disableDispatcherModule("LeftScaleAvatar");
|
||||||
dispatcherUtils.disableDispatcherModule("RightScaleAvatar");
|
dispatcherUtils.disableDispatcherModule("RightScaleAvatar");
|
||||||
};
|
};
|
||||||
|
Script.scriptEnding.connect(this.cleanup);
|
||||||
})();
|
})();
|
||||||
|
|
106
scripts/system/controllers/controllerModules/scaleEntity.js
Normal file
106
scripts/system/controllers/controllerModules/scaleEntity.js
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
// scaleEntity.js
|
||||||
|
//
|
||||||
|
// Created by Dante Ruiz on 9/18/17
|
||||||
|
//
|
||||||
|
// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
/* global Script, Vec3, MyAvatar, RIGHT_HAND */
|
||||||
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
|
|
||||||
|
function ScaleEntity(hand) {
|
||||||
|
this.hand = hand;
|
||||||
|
this.grabbedThingID = false;
|
||||||
|
this.scalingStartDistance = false;
|
||||||
|
this.scalingStartDimensions = false;
|
||||||
|
|
||||||
|
this.parameters = dispatcherUtils.makeDispatcherModuleParameters(
|
||||||
|
120,
|
||||||
|
this.hand === RIGHT_HAND ? ["rightHandTrigger"] : ["leftHandTrigger"],
|
||||||
|
[],
|
||||||
|
100
|
||||||
|
);
|
||||||
|
|
||||||
|
this.otherHand = function() {
|
||||||
|
return this.hand === dispatcherUtils.RIGHT_HAND ? dispatcherUtils.LEFT_HAND : dispatcherUtils.RIGHT_HAND;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.otherModule = function() {
|
||||||
|
return this.hand === dispatcherUtils.RIGHT_HAND ? leftScaleEntity : rightScaleEntity;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.bumperPressed = function(controllerData) {
|
||||||
|
return ( controllerData.secondaryValues[this.hand] > dispatcherUtils.BUMPER_ON_VALUE);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getTargetProps = function(controllerData) {
|
||||||
|
// nearbyEntityProperties is already sorted by length from controller
|
||||||
|
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
|
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
||||||
|
var props = nearbyEntityProperties[i];
|
||||||
|
var handPosition = controllerData.controllerLocations[this.hand].position;
|
||||||
|
var distance = Vec3.distance(props.position, handPosition);
|
||||||
|
if (distance > dispatcherUtils.NEAR_GRAB_RADIUS * sensorScaleFactor) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((dispatcherUtils.entityIsGrabbable(props) ||
|
||||||
|
dispatcherUtils.propsArePhysical(props)) && !props.locked) {
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isReady = function(controllerData) {
|
||||||
|
var otherModule = this.otherModule();
|
||||||
|
if (this.bumperPressed(controllerData) && otherModule.bumperPressed(controllerData)) {
|
||||||
|
var thisHandTargetProps = this.getTargetProps(controllerData);
|
||||||
|
var otherHandTargetProps = otherModule.getTargetProps(controllerData);
|
||||||
|
if (thisHandTargetProps && otherHandTargetProps) {
|
||||||
|
if (thisHandTargetProps.id === otherHandTargetProps.id) {
|
||||||
|
this.grabbedThingID = thisHandTargetProps.id;
|
||||||
|
this.scalingStartDistance = Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position,
|
||||||
|
controllerData.controllerLocations[this.otherHand()].position));
|
||||||
|
this.scalingStartDimensions = thisHandTargetProps.dimensions;
|
||||||
|
return dispatcherUtils.makeRunningValues(true, [], []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dispatcherUtils.makeRunningValues(false, [], []);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.run = function(controllerData) {
|
||||||
|
var otherModule = this.otherModule();
|
||||||
|
if (this.bumperPressed(controllerData) && otherModule.bumperPressed(controllerData)) {
|
||||||
|
if (this.hand === dispatcherUtils.RIGHT_HAND) {
|
||||||
|
var scalingCurrentDistance =
|
||||||
|
Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position,
|
||||||
|
controllerData.controllerLocations[this.otherHand()].position));
|
||||||
|
var currentRescale = scalingCurrentDistance / this.scalingStartDistance;
|
||||||
|
var newDimensions = Vec3.multiply(currentRescale, this.scalingStartDimensions);
|
||||||
|
Entities.editEntity(this.grabbedThingID, { dimensions: newDimensions });
|
||||||
|
}
|
||||||
|
return dispatcherUtils.makeRunningValues(true, [], []);
|
||||||
|
}
|
||||||
|
return dispatcherUtils.makeRunningValues(false, [], []);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var leftScaleEntity = new ScaleEntity(dispatcherUtils.LEFT_HAND);
|
||||||
|
var rightScaleEntity = new ScaleEntity(dispatcherUtils.RIGHT_HAND);
|
||||||
|
|
||||||
|
dispatcherUtils.enableDispatcherModule("LeftScaleEntity", leftScaleEntity);
|
||||||
|
dispatcherUtils.enableDispatcherModule("RightScaleEntity", rightScaleEntity);
|
||||||
|
|
||||||
|
this.cleanup = function() {
|
||||||
|
dispatcherUtils.disableDispatcherModule("LeftScaleEntity");
|
||||||
|
dispatcherUtils.disableDispatcherModule("RightScaleEntity");
|
||||||
|
};
|
||||||
|
Script.scriptEnding.connect(this.cleanup);
|
||||||
|
})();
|
|
@ -29,7 +29,8 @@ var CONTOLLER_SCRIPTS = [
|
||||||
"controllerModules/disableOtherModule.js",
|
"controllerModules/disableOtherModule.js",
|
||||||
"controllerModules/farTrigger.js",
|
"controllerModules/farTrigger.js",
|
||||||
"controllerModules/teleport.js",
|
"controllerModules/teleport.js",
|
||||||
"controllerModules/scaleAvatar.js"
|
"controllerModules/scaleAvatar.js",
|
||||||
|
"controllerModules/scaleEntity.js"
|
||||||
];
|
];
|
||||||
|
|
||||||
var DEBUG_MENU_ITEM = "Debug defaultScripts.js";
|
var DEBUG_MENU_ITEM = "Debug defaultScripts.js";
|
||||||
|
|
|
@ -450,7 +450,7 @@
|
||||||
var parsedJsonMessage = JSON.parse(message);
|
var parsedJsonMessage = JSON.parse(message);
|
||||||
|
|
||||||
if (parsedJsonMessage.type === "marketplaces") {
|
if (parsedJsonMessage.type === "marketplaces") {
|
||||||
if (parsedJsonMessage.action === "inspectionModeSetting") {
|
if (parsedJsonMessage.action === "commerceSetting") {
|
||||||
confirmAllPurchases = !!parsedJsonMessage.data;
|
confirmAllPurchases = !!parsedJsonMessage.data;
|
||||||
injectCode();
|
injectCode();
|
||||||
}
|
}
|
||||||
|
@ -458,7 +458,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Request inspection mode setting
|
// Request commerce setting
|
||||||
// Code is injected into the webpage after the setting comes back.
|
// Code is injected into the webpage after the setting comes back.
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "REQUEST_SETTING"
|
type: "REQUEST_SETTING"
|
||||||
|
|
|
@ -319,7 +319,11 @@ if (typeof module !== 'undefined') {
|
||||||
LEFT_HAND: LEFT_HAND,
|
LEFT_HAND: LEFT_HAND,
|
||||||
RIGHT_HAND: RIGHT_HAND,
|
RIGHT_HAND: RIGHT_HAND,
|
||||||
BUMPER_ON_VALUE: BUMPER_ON_VALUE,
|
BUMPER_ON_VALUE: BUMPER_ON_VALUE,
|
||||||
|
propsArePhysical: propsArePhysical,
|
||||||
|
entityIsGrabbable: entityIsGrabbable,
|
||||||
|
NEAR_GRAB_RADIUS: NEAR_GRAB_RADIUS,
|
||||||
projectOntoOverlayXYPlane: projectOntoOverlayXYPlane,
|
projectOntoOverlayXYPlane: projectOntoOverlayXYPlane,
|
||||||
projectOntoEntityXYPlane: projectOntoEntityXYPlane
|
projectOntoEntityXYPlane: projectOntoEntityXYPlane
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,8 +138,8 @@
|
||||||
} else if (parsedJsonMessage.type === "REQUEST_SETTING") {
|
} else if (parsedJsonMessage.type === "REQUEST_SETTING") {
|
||||||
tablet.emitScriptEvent(JSON.stringify({
|
tablet.emitScriptEvent(JSON.stringify({
|
||||||
type: "marketplaces",
|
type: "marketplaces",
|
||||||
action: "inspectionModeSetting",
|
action: "commerceSetting",
|
||||||
data: Settings.getValue("inspectionMode", false)
|
data: Settings.getValue("commerce", false)
|
||||||
}));
|
}));
|
||||||
} else if (parsedJsonMessage.type === "PURCHASES") {
|
} else if (parsedJsonMessage.type === "PURCHASES") {
|
||||||
tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH);
|
tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH);
|
||||||
|
|
|
@ -12,7 +12,7 @@ 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(shared networking model fbx ktx image octree gl gpu gpu-gl render model-networking networking render-utils entities entities-renderer animation audio avatars script-engine physics procedural midi)
|
link_hifi_libraries(shared networking model fbx ktx image octree gl gpu gpu-gl render model-networking networking render-utils entities entities-renderer animation audio avatars script-engine physics procedural midi ui)
|
||||||
|
|
||||||
package_libraries_for_deployment()
|
package_libraries_for_deployment()
|
||||||
|
|
||||||
|
|
|
@ -42,11 +42,15 @@
|
||||||
#include <LogHandler.h>
|
#include <LogHandler.h>
|
||||||
#include <AssetClient.h>
|
#include <AssetClient.h>
|
||||||
|
|
||||||
|
#include <gl/OffscreenGLCanvas.h>
|
||||||
|
|
||||||
#include <gpu/gl/GLBackend.h>
|
#include <gpu/gl/GLBackend.h>
|
||||||
#include <gpu/gl/GLFramebuffer.h>
|
#include <gpu/gl/GLFramebuffer.h>
|
||||||
#include <gpu/gl/GLTexture.h>
|
#include <gpu/gl/GLTexture.h>
|
||||||
#include <gpu/StandardShaderLib.h>
|
#include <gpu/StandardShaderLib.h>
|
||||||
|
|
||||||
|
#include <ui/OffscreenQmlSurface.h>
|
||||||
|
|
||||||
#include <AnimationCache.h>
|
#include <AnimationCache.h>
|
||||||
#include <SimpleEntitySimulation.h>
|
#include <SimpleEntitySimulation.h>
|
||||||
#include <EntityDynamicInterface.h>
|
#include <EntityDynamicInterface.h>
|
||||||
|
@ -427,6 +431,10 @@ namespace render {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OffscreenGLCanvas* _chromiumShareContext{ nullptr };
|
||||||
|
Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context);
|
||||||
|
|
||||||
|
|
||||||
// Create a simple OpenGL window that renders text in various ways
|
// Create a simple OpenGL window that renders text in various ways
|
||||||
class QTestWindow : public QWindow, public AbstractViewStateInterface {
|
class QTestWindow : public QWindow, public AbstractViewStateInterface {
|
||||||
|
|
||||||
|
@ -506,8 +514,6 @@ public:
|
||||||
AbstractViewStateInterface::setInstance(this);
|
AbstractViewStateInterface::setInstance(this);
|
||||||
_octree = DependencyManager::set<EntityTreeRenderer>(false, this, nullptr);
|
_octree = DependencyManager::set<EntityTreeRenderer>(false, this, nullptr);
|
||||||
_octree->init();
|
_octree->init();
|
||||||
// Prevent web entities from rendering
|
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, WebEntityItem::factory);
|
|
||||||
|
|
||||||
DependencyManager::set<ParentFinder>(_octree->getTree());
|
DependencyManager::set<ParentFinder>(_octree->getTree());
|
||||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
@ -535,6 +541,23 @@ public:
|
||||||
_renderThread.initialize(this, _initContext);
|
_renderThread.initialize(this, _initContext);
|
||||||
_initContext.makeCurrent();
|
_initContext.makeCurrent();
|
||||||
|
|
||||||
|
if (nsightActive()) {
|
||||||
|
// Prevent web entities from rendering
|
||||||
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, WebEntityItem::factory);
|
||||||
|
} else {
|
||||||
|
_chromiumShareContext = new OffscreenGLCanvas();
|
||||||
|
_chromiumShareContext->setObjectName("ChromiumShareContext");
|
||||||
|
_chromiumShareContext->create(_initContext.qglContext());
|
||||||
|
_chromiumShareContext->makeCurrent();
|
||||||
|
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
|
||||||
|
|
||||||
|
// Make sure all QML surfaces share the main thread GL context
|
||||||
|
OffscreenQmlSurface::setSharedContext(_initContext.qglContext());
|
||||||
|
|
||||||
|
_initContext.makeCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// FIXME use a wait condition
|
// FIXME use a wait condition
|
||||||
QThread::msleep(1000);
|
QThread::msleep(1000);
|
||||||
_renderThread.submitFrame(gpu::FramePointer());
|
_renderThread.submitFrame(gpu::FramePointer());
|
||||||
|
@ -679,6 +702,7 @@ private:
|
||||||
_renderCount = _renderThread._presentCount.load();
|
_renderCount = _renderThread._presentCount.load();
|
||||||
update();
|
update();
|
||||||
|
|
||||||
|
_initContext.makeCurrent();
|
||||||
RenderArgs renderArgs(_renderThread._gpuContext, DEFAULT_OCTREE_SIZE_SCALE,
|
RenderArgs renderArgs(_renderThread._gpuContext, DEFAULT_OCTREE_SIZE_SCALE,
|
||||||
0, RenderArgs::DEFAULT_RENDER_MODE,
|
0, RenderArgs::DEFAULT_RENDER_MODE,
|
||||||
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
||||||
|
|
Loading…
Reference in a new issue