mirror of
https://github.com/overte-org/overte.git
synced 2025-04-11 01:42:11 +02:00
merge from master
This commit is contained in:
commit
58172cfbd4
27 changed files with 405 additions and 186 deletions
39
.clang-format
Normal file
39
.clang-format
Normal file
|
@ -0,0 +1,39 @@
|
|||
Language: Cpp
|
||||
Standard: Cpp11
|
||||
BasedOnStyle: "Chromium"
|
||||
ColumnLimit: 128
|
||||
IndentWidth: 4
|
||||
UseTab: Never
|
||||
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterEnum: true
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyNamespace: true
|
||||
|
||||
|
||||
AccessModifierOffset: -4
|
||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
IndentCaseLabels: true
|
||||
ReflowComments: false
|
||||
Cpp11BracedListStyle: false
|
||||
ContinuationIndentWidth: 4
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
CompactNamespaces: true
|
||||
SortIncludes: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
PenaltyBreakBeforeFirstCallParameter: 1000
|
||||
|
|
@ -118,6 +118,7 @@ macro(AUTOSCRIBE_SHADER_LIB)
|
|||
foreach(SHADER_FILE ${SHADER_SOURCE_FILES})
|
||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
||||
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
||||
set_property(SOURCE ${AUTOSCRIBE_GENERATED_FILE} PROPERTY SKIP_AUTOMOC ON)
|
||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
|
||||
endforeach()
|
||||
#message(${TARGET_NAME} ${AUTOSCRIBE_SHADER_SRC})
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
#
|
||||
|
||||
function(set_from_env _RESULT_NAME _ENV_VAR_NAME _DEFAULT_VALUE)
|
||||
if ("$ENV{${_ENV_VAR_NAME}}" STREQUAL "")
|
||||
set (${_RESULT_NAME} ${_DEFAULT_VALUE} PARENT_SCOPE)
|
||||
else()
|
||||
set (${_RESULT_NAME} $ENV{${_ENV_VAR_NAME}} PARENT_SCOPE)
|
||||
if (NOT DEFINED ${_RESULT_NAME})
|
||||
if ("$ENV{${_ENV_VAR_NAME}}" STREQUAL "")
|
||||
set (${_RESULT_NAME} ${_DEFAULT_VALUE} PARENT_SCOPE)
|
||||
else()
|
||||
set (${_RESULT_NAME} $ENV{${_ENV_VAR_NAME}} PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
function shouldRaiseKeyboard() {
|
||||
var nodeName = document.activeElement.nodeName;
|
||||
var nodeType = document.activeElement.type;
|
||||
if (nodeName === "INPUT" && ["email", "number", "password", "tel", "text", "url"].indexOf(nodeType) !== -1
|
||||
if (nodeName === "INPUT" && ["email", "number", "password", "tel", "text", "url", "search"].indexOf(nodeType) !== -1
|
||||
|| document.activeElement.nodeName === "TEXTAREA") {
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
@ -13,6 +13,7 @@ import "."
|
|||
|
||||
Rectangle {
|
||||
id: keyboardBase
|
||||
objectName: "keyboard"
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
@ -27,6 +28,8 @@ Rectangle {
|
|||
|
||||
readonly property int mirrorTextHeight: keyboardRowHeight
|
||||
|
||||
property bool password: false
|
||||
property alias mirroredText: mirrorText.text
|
||||
property bool showMirrorText: true
|
||||
readonly property int raisedHeight: 200
|
||||
|
||||
|
@ -112,16 +115,20 @@ Rectangle {
|
|||
color: "#252525"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
TextEdit {
|
||||
TextInput {
|
||||
id: mirrorText
|
||||
visible: showMirrorText
|
||||
size: 13.5
|
||||
FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; }
|
||||
font.family: ralewaySemiBold.name
|
||||
font.pointSize: 13.5
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
color: "#FFFFFF";
|
||||
anchors.fill: parent
|
||||
wrapMode: Text.WordWrap
|
||||
readOnly: false // we need to leave this property read-only to allow control to accept QKeyEvent
|
||||
readOnly: false // we need this to allow control to accept QKeyEvent
|
||||
selectByMouse: false
|
||||
echoMode: password ? TextInput.Password : TextInput.Normal
|
||||
|
||||
Keys.onPressed: {
|
||||
if (event.key == Qt.Key_Return || event.key == Qt.Key_Space) {
|
||||
|
|
|
@ -207,6 +207,17 @@
|
|||
#if defined(Q_OS_WIN)
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
#ifdef DEBUG_EVENT_QUEUE
|
||||
// This is a HACK that uses private headers included with the qt source distrubution.
|
||||
// To use this feature you need to add these directores to your include path:
|
||||
// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1/QtCore
|
||||
// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1
|
||||
#define QT_BOOTSTRAPPED
|
||||
#include <private/qthread_p.h>
|
||||
#include <private/qobject_p.h>
|
||||
#undef QT_BOOTSTRAPPED
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
}
|
||||
|
@ -264,9 +275,7 @@ private:
|
|||
switch ((int)event->type()) {
|
||||
case ApplicationEvent::Render:
|
||||
render();
|
||||
// Ensure we never back up the render events. Each render should be triggered only in response
|
||||
// to the NEXT render event after the last render occured
|
||||
QCoreApplication::removePostedEvents(this, ApplicationEvent::Render);
|
||||
qApp->_pendingRenderEvent.store(false);
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
@ -2712,9 +2721,14 @@ bool Application::importFromZIP(const QString& filePath) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
void Application::onPresent(quint32 frameCount) {
|
||||
postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority);
|
||||
if (_renderEventHandler && !isAboutToQuit()) {
|
||||
bool expected = false;
|
||||
if (_pendingIdleEvent.compare_exchange_strong(expected, true)) {
|
||||
postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority);
|
||||
}
|
||||
expected = false;
|
||||
if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEvent.compare_exchange_strong(expected, true)) {
|
||||
postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render));
|
||||
}
|
||||
}
|
||||
|
@ -2781,7 +2795,26 @@ bool Application::handleFileOpenEvent(QFileOpenEvent* fileEvent) {
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_EVENT_QUEUE
|
||||
static int getEventQueueSize(QThread* thread) {
|
||||
auto threadData = QThreadData::get2(thread);
|
||||
QMutexLocker locker(&threadData->postEventList.mutex);
|
||||
return threadData->postEventList.size();
|
||||
}
|
||||
|
||||
static void dumpEventQueue(QThread* thread) {
|
||||
auto threadData = QThreadData::get2(thread);
|
||||
QMutexLocker locker(&threadData->postEventList.mutex);
|
||||
qDebug() << "AJT: event list, size =" << threadData->postEventList.size();
|
||||
for (auto& postEvent : threadData->postEventList) {
|
||||
QEvent::Type type = (postEvent.event ? postEvent.event->type() : QEvent::None);
|
||||
qDebug() << "AJT: " << type;
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_EVENT_QUEUE
|
||||
|
||||
bool Application::event(QEvent* event) {
|
||||
|
||||
if (!Menu::getInstance()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2801,8 +2834,18 @@ bool Application::event(QEvent* event) {
|
|||
// see (windowMinimizedChanged)
|
||||
case ApplicationEvent::Idle:
|
||||
idle();
|
||||
// Don't process extra idle events that arrived in the event queue while we were doing this idle
|
||||
QCoreApplication::removePostedEvents(this, ApplicationEvent::Idle);
|
||||
|
||||
#ifdef DEBUG_EVENT_QUEUE
|
||||
{
|
||||
int count = getEventQueueSize(QThread::currentThread());
|
||||
if (count > 400) {
|
||||
dumpEventQueue(QThread::currentThread());
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_EVENT_QUEUE
|
||||
|
||||
_pendingIdleEvent.store(false);
|
||||
|
||||
return true;
|
||||
|
||||
case QEvent::MouseMove:
|
||||
|
@ -7203,7 +7246,7 @@ void Application::updateDisplayMode() {
|
|||
_offscreenContext->makeCurrent();
|
||||
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
|
||||
_displayPlugin = newDisplayPlugin;
|
||||
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent);
|
||||
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection);
|
||||
auto desktop = offscreenUi->getDesktop();
|
||||
if (desktop) {
|
||||
desktop->setProperty("repositionLocked", wasRepositionLocked);
|
||||
|
|
|
@ -717,5 +717,8 @@ private:
|
|||
LaserPointerManager _laserPointerManager;
|
||||
|
||||
friend class RenderEventHandler;
|
||||
|
||||
std::atomic<bool> _pendingIdleEvent { false };
|
||||
std::atomic<bool> _pendingRenderEvent { false };
|
||||
};
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -72,6 +72,12 @@ void Application::paintGL() {
|
|||
{
|
||||
QMutexLocker viewLocker(&_renderArgsMutex);
|
||||
renderArgs = _appRenderArgs._renderArgs;
|
||||
|
||||
// don't render if there is no context.
|
||||
if (!_appRenderArgs._renderArgs._context) {
|
||||
return;
|
||||
}
|
||||
|
||||
HMDSensorPose = _appRenderArgs._headPose;
|
||||
eyeToWorld = _appRenderArgs._eyeToWorld;
|
||||
sensorToWorld = _appRenderArgs._sensorToWorld;
|
||||
|
|
|
@ -15,13 +15,14 @@
|
|||
#include "RayPickScriptingInterface.h"
|
||||
|
||||
LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates,
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) :
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) :
|
||||
_renderingEnabled(enabled),
|
||||
_renderStates(renderStates),
|
||||
_defaultRenderStates(defaultRenderStates),
|
||||
_faceAvatar(faceAvatar),
|
||||
_centerEndY(centerEndY),
|
||||
_lockEnd(lockEnd),
|
||||
_distanceScaleEnd(distanceScaleEnd),
|
||||
_rayPickUID(DependencyManager::get<RayPickScriptingInterface>()->createRayPick(rayProps))
|
||||
{
|
||||
|
||||
|
@ -90,6 +91,10 @@ void LaserPointer::editRenderState(const std::string& state, const QVariant& sta
|
|||
updateRenderStateOverlay(_renderStates[state].getStartID(), startProps);
|
||||
updateRenderStateOverlay(_renderStates[state].getPathID(), pathProps);
|
||||
updateRenderStateOverlay(_renderStates[state].getEndID(), endProps);
|
||||
QVariant endDim = endProps.toMap()["dimensions"];
|
||||
if (endDim.isValid()) {
|
||||
_renderStates[state].setEndDim(vec3FromVariant(endDim));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -158,10 +163,14 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
|
|||
if (!renderState.getEndID().isNull()) {
|
||||
QVariantMap endProps;
|
||||
glm::quat faceAvatarRotation = DependencyManager::get<AvatarManager>()->getMyAvatar()->getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f)));
|
||||
glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value);
|
||||
if (_distanceScaleEnd) {
|
||||
dim = renderState.getEndDim() * glm::distance(pickRay.origin, endVec) * DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale();
|
||||
endProps.insert("dimensions", vec3toVariant(dim));
|
||||
}
|
||||
if (_centerEndY) {
|
||||
endProps.insert("position", end);
|
||||
} else {
|
||||
glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value);
|
||||
glm::vec3 currentUpVector = faceAvatarRotation * Vectors::UP;
|
||||
endProps.insert("position", vec3toVariant(endVec + glm::vec3(currentUpVector.x * 0.5f * dim.y, currentUpVector.y * 0.5f * dim.y, currentUpVector.z * 0.5f * dim.y)));
|
||||
}
|
||||
|
@ -248,6 +257,7 @@ RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, cons
|
|||
_pathIgnoreRays = qApp->getOverlays().getProperty(_pathID, "ignoreRayIntersection").value.toBool();
|
||||
}
|
||||
if (!_endID.isNull()) {
|
||||
_endDim = vec3FromVariant(qApp->getOverlays().getProperty(_endID, "dimensions").value);
|
||||
_endIgnoreRays = qApp->getOverlays().getProperty(_endID, "ignoreRayIntersection").value.toBool();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ public:
|
|||
const bool& doesPathIgnoreRays() const { return _pathIgnoreRays; }
|
||||
const bool& doesEndIgnoreRays() const { return _endIgnoreRays; }
|
||||
|
||||
void setEndDim(const glm::vec3& endDim) { _endDim = endDim; }
|
||||
const glm::vec3& getEndDim() const { return _endDim; }
|
||||
|
||||
void deleteOverlays();
|
||||
|
||||
private:
|
||||
|
@ -43,6 +46,8 @@ private:
|
|||
bool _startIgnoreRays;
|
||||
bool _pathIgnoreRays;
|
||||
bool _endIgnoreRays;
|
||||
|
||||
glm::vec3 _endDim;
|
||||
};
|
||||
|
||||
|
||||
|
@ -55,7 +60,7 @@ public:
|
|||
typedef std::unordered_map<std::string, std::pair<float, RenderState>> DefaultRenderStateMap;
|
||||
|
||||
LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates,
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled);
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled);
|
||||
~LaserPointer();
|
||||
|
||||
QUuid getRayUID() { return _rayPickUID; }
|
||||
|
@ -85,6 +90,7 @@ private:
|
|||
bool _faceAvatar;
|
||||
bool _centerEndY;
|
||||
bool _lockEnd;
|
||||
bool _distanceScaleEnd;
|
||||
std::pair<QUuid, bool> _objectLockEnd { std::pair<QUuid, bool>(QUuid(), false)};
|
||||
|
||||
const QUuid _rayPickUID;
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
#include "LaserPointerManager.h"
|
||||
|
||||
QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates,
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) {
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) {
|
||||
QUuid result;
|
||||
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, distanceScaleEnd, enabled);
|
||||
if (!laserPointer->getRayUID().isNull()) {
|
||||
result = QUuid::createUuid();
|
||||
withWriteLock([&] { _laserPointers[result] = laserPointer; });
|
||||
|
|
|
@ -25,7 +25,8 @@ class LaserPointerManager : protected ReadWriteLockable {
|
|||
|
||||
public:
|
||||
QUuid createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates,
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled);
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled);
|
||||
|
||||
void removeLaserPointer(const QUuid& uid);
|
||||
void enableLaserPointer(const QUuid& uid) const;
|
||||
void disableLaserPointer(const QUuid& uid) const;
|
||||
|
|
|
@ -41,6 +41,11 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert
|
|||
lockEnd = propertyMap["lockEnd"].toBool();
|
||||
}
|
||||
|
||||
bool distanceScaleEnd = false;
|
||||
if (propertyMap["distanceScaleEnd"].isValid()) {
|
||||
distanceScaleEnd = propertyMap["distanceScaleEnd"].toBool();
|
||||
}
|
||||
|
||||
bool enabled = false;
|
||||
if (propertyMap["enabled"].isValid()) {
|
||||
enabled = propertyMap["enabled"].toBool();
|
||||
|
@ -75,7 +80,7 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert
|
|||
}
|
||||
}
|
||||
|
||||
return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled);
|
||||
return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled);
|
||||
}
|
||||
|
||||
void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const {
|
||||
|
|
|
@ -135,6 +135,7 @@ static const int32_t exp2Table[1 << EXP2_TABBITS][3] = {
|
|||
|
||||
static const int IEEE754_FABS_MASK = 0x7fffffff;
|
||||
static const int IEEE754_MANT_BITS = 23;
|
||||
static const int IEEE754_EXPN_BITS = 8;
|
||||
static const int IEEE754_EXPN_BIAS = 127;
|
||||
|
||||
//
|
||||
|
@ -152,7 +153,7 @@ static inline int32_t peaklog2(float* input) {
|
|||
|
||||
// split into e and x - 1.0
|
||||
int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM;
|
||||
int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff;
|
||||
int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff;
|
||||
|
||||
// saturate
|
||||
if (e > 31) {
|
||||
|
@ -191,7 +192,7 @@ static inline int32_t peaklog2(float* input0, float* input1) {
|
|||
|
||||
// split into e and x - 1.0
|
||||
int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM;
|
||||
int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff;
|
||||
int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff;
|
||||
|
||||
// saturate
|
||||
if (e > 31) {
|
||||
|
@ -234,7 +235,7 @@ static inline int32_t peaklog2(float* input0, float* input1, float* input2, floa
|
|||
|
||||
// split into e and x - 1.0
|
||||
int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM;
|
||||
int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff;
|
||||
int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff;
|
||||
|
||||
// saturate
|
||||
if (e > 31) {
|
||||
|
@ -259,30 +260,30 @@ static inline int32_t peaklog2(float* input0, float* input1, float* input2, floa
|
|||
// Count Leading Zeros
|
||||
// Emulates the CLZ (ARM) and LZCNT (x86) instruction
|
||||
//
|
||||
static inline int CLZ(uint32_t x) {
|
||||
static inline int CLZ(uint32_t u) {
|
||||
|
||||
if (x == 0) {
|
||||
if (u == 0) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
int e = 0;
|
||||
if (x < 0x00010000) {
|
||||
x <<= 16;
|
||||
if (u < 0x00010000) {
|
||||
u <<= 16;
|
||||
e += 16;
|
||||
}
|
||||
if (x < 0x01000000) {
|
||||
x <<= 8;
|
||||
if (u < 0x01000000) {
|
||||
u <<= 8;
|
||||
e += 8;
|
||||
}
|
||||
if (x < 0x10000000) {
|
||||
x <<= 4;
|
||||
if (u < 0x10000000) {
|
||||
u <<= 4;
|
||||
e += 4;
|
||||
}
|
||||
if (x < 0x40000000) {
|
||||
x <<= 2;
|
||||
if (u < 0x40000000) {
|
||||
u <<= 2;
|
||||
e += 2;
|
||||
}
|
||||
if (x < 0x80000000) {
|
||||
if (u < 0x80000000) {
|
||||
e += 1;
|
||||
}
|
||||
return e;
|
||||
|
@ -290,19 +291,19 @@ static inline int CLZ(uint32_t x) {
|
|||
|
||||
//
|
||||
// Compute -log2(x) for x=[0,1] in Q31, result in Q26
|
||||
// x = 0 returns 0x7fffffff
|
||||
// x < 0 undefined
|
||||
// x <= 0 returns 0x7fffffff
|
||||
//
|
||||
static inline int32_t fixlog2(int32_t x) {
|
||||
|
||||
if (x == 0) {
|
||||
if (x <= 0) {
|
||||
return 0x7fffffff;
|
||||
}
|
||||
|
||||
// split into e and x - 1.0
|
||||
int e = CLZ((uint32_t)x);
|
||||
x <<= e; // normalize to [0x80000000, 0xffffffff]
|
||||
x &= 0x7fffffff; // x - 1.0
|
||||
uint32_t u = (uint32_t)x;
|
||||
int e = CLZ(u);
|
||||
u <<= e; // normalize to [0x80000000, 0xffffffff]
|
||||
x = u & 0x7fffffff; // x - 1.0
|
||||
|
||||
int k = x >> (31 - LOG2_TABBITS);
|
||||
|
||||
|
@ -320,13 +321,18 @@ static inline int32_t fixlog2(int32_t x) {
|
|||
|
||||
//
|
||||
// Compute exp2(-x) for x=[0,32] in Q26, result in Q31
|
||||
// x < 0 undefined
|
||||
// x <= 0 returns 0x7fffffff
|
||||
//
|
||||
static inline int32_t fixexp2(int32_t x) {
|
||||
|
||||
if (x <= 0) {
|
||||
return 0x7fffffff;
|
||||
}
|
||||
|
||||
// split into e and 1.0 - x
|
||||
int e = x >> LOG2_FRACBITS;
|
||||
x = ~(x << LOG2_INTBITS) & 0x7fffffff;
|
||||
uint32_t u = (uint32_t)x;
|
||||
int e = u >> LOG2_FRACBITS;
|
||||
x = ~(u << LOG2_INTBITS) & 0x7fffffff;
|
||||
|
||||
int k = x >> (31 - EXP2_TABBITS);
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ class MonoDCBlock {
|
|||
public:
|
||||
void process(int32_t& x) {
|
||||
|
||||
x <<= 15; // scale to Q30
|
||||
x *= (1 << 15); // scale to Q30
|
||||
x -= _dcOffset; // remove DC
|
||||
_dcOffset += x >> 13; // pole = (1.0 - 2^-13) = 0.9999
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ class StereoDCBlock {
|
|||
public:
|
||||
void process(int32_t& x0, int32_t& x1) {
|
||||
|
||||
x0 <<= 15;
|
||||
x1 <<= 15;
|
||||
x0 *= (1 << 15);
|
||||
x1 *= (1 << 15);
|
||||
|
||||
x0 -= _dcOffset[0];
|
||||
x1 -= _dcOffset[1];
|
||||
|
@ -71,10 +71,10 @@ class QuadDCBlock {
|
|||
public:
|
||||
void process(int32_t& x0, int32_t& x1, int32_t& x2, int32_t& x3) {
|
||||
|
||||
x0 <<= 15;
|
||||
x1 <<= 15;
|
||||
x2 <<= 15;
|
||||
x3 <<= 15;
|
||||
x0 *= (1 << 15);
|
||||
x1 *= (1 << 15);
|
||||
x2 *= (1 << 15);
|
||||
x3 *= (1 << 15);
|
||||
|
||||
x0 -= _dcOffset[0];
|
||||
x1 -= _dcOffset[1];
|
||||
|
@ -100,10 +100,10 @@ protected:
|
|||
int _histogram[NHIST] = {};
|
||||
|
||||
// peakhold
|
||||
int32_t _holdMin = 0x7fffffff;
|
||||
int32_t _holdInc = 0x7fffffff;
|
||||
uint32_t _holdMin = 0x7fffffff;
|
||||
uint32_t _holdInc = 0x7fffffff;
|
||||
uint32_t _holdMax = 0x7fffffff;
|
||||
int32_t _holdRel = 0x7fffffff;
|
||||
uint32_t _holdRel = 0x7fffffff;
|
||||
int32_t _holdPeak = 0x7fffffff;
|
||||
|
||||
// hysteresis
|
||||
|
@ -177,18 +177,23 @@ void GateImpl::setThreshold(float threshold) {
|
|||
void GateImpl::setHold(float hold) {
|
||||
|
||||
const double RELEASE = 100.0; // release = 100ms
|
||||
const double PROGHOLD = 0.100; // progressive hold = 100ms
|
||||
const double PROGHOLD = 100.0; // progressive hold = 100ms
|
||||
|
||||
// pure hold = 1 to 1000ms
|
||||
hold = MAX(hold, 1.0f);
|
||||
hold = MIN(hold, 1000.0f);
|
||||
|
||||
// compute final tc
|
||||
_holdMin = msToTc(RELEASE, _sampleRate);
|
||||
|
||||
_holdInc = (int32_t)((_holdMin - 0x7fffffff) / (PROGHOLD * _sampleRate));
|
||||
_holdInc = MIN(_holdInc, -1); // prevent 0 on long releases
|
||||
|
||||
_holdMax = 0x7fffffff - (uint32_t)(_holdInc * (double)hold/1000.0 * _sampleRate);
|
||||
// compute tc increment, to progress from 0x7fffffff to _holdMin in PROGHOLD ms
|
||||
double progSamples = PROGHOLD/1000.0 * _sampleRate;
|
||||
_holdInc = (uint32_t)((0x7fffffff - _holdMin) / progSamples);
|
||||
_holdInc = MAX(_holdInc, 1); // prevent 0 on long releases
|
||||
|
||||
// compute initial tc, to progress from _holdMax to 0x7fffffff in hold ms
|
||||
double holdSamples = (double)hold/1000.0 * _sampleRate;
|
||||
_holdMax = 0x7fffffff + (uint32_t)(_holdInc * holdSamples);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -318,8 +323,6 @@ void GateImpl::processHistogram(int numFrames) {
|
|||
|
||||
// smooth threshold update
|
||||
_threshAdapt = threshold + MULQ31((_threshAdapt - threshold), tcThreshold);
|
||||
|
||||
//printf("threshold = %0.1f\n", (_threshAdapt - (LOG2_HEADROOM_Q15 << LOG2_FRACBITS)) * -6.02f / (1 << LOG2_FRACBITS));
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -336,10 +339,8 @@ int32_t GateImpl::peakhold(int32_t peak) {
|
|||
// (_holdRel > _holdMin) progressive hold
|
||||
// (_holdRel = _holdMin) release
|
||||
|
||||
_holdRel += _holdInc; // update progressive hold
|
||||
_holdRel = MAX((uint32_t)_holdRel, (uint32_t)_holdMin); // saturate at final value
|
||||
|
||||
int32_t tc = MIN((uint32_t)_holdRel, 0x7fffffff);
|
||||
_holdRel -= _holdInc; // update progressive hold
|
||||
int32_t tc = MIN(MAX(_holdRel, _holdMin), 0x7fffffff); // saturate to [_holdMin, 0x7fffffff]
|
||||
peak += MULQ31((_holdPeak - peak), tc); // apply release
|
||||
|
||||
} else {
|
||||
|
|
|
@ -46,6 +46,10 @@ static const int STATS_FOR_STATS_PACKET_WINDOW_SECONDS = 30;
|
|||
// _currentJitterBufferFrames is updated with the time-weighted avg and the running time-weighted avg is reset.
|
||||
static const quint64 FRAMES_AVAILABLE_STAT_WINDOW_USECS = 10 * USECS_PER_SECOND;
|
||||
|
||||
// When the audio codec is switched, temporary codec mismatch is expected due to packets in-flight.
|
||||
// A SelectedAudioFormat packet is not sent until this threshold is exceeded.
|
||||
static const int MAX_MISMATCHED_AUDIO_CODEC_COUNT = 10;
|
||||
|
||||
InboundAudioStream::InboundAudioStream(int numChannels, int numFrames, int numBlocks, int numStaticJitterBlocks) :
|
||||
_ringBuffer(numChannels * numFrames, numBlocks),
|
||||
_numChannels(numChannels),
|
||||
|
@ -153,6 +157,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
|||
// If we recieved a SilentAudioFrame from our sender, we might want to drop
|
||||
// some of the samples in order to catch up to our desired jitter buffer size.
|
||||
writeDroppableSilentFrames(networkFrames);
|
||||
|
||||
} else {
|
||||
// note: PCM and no codec are identical
|
||||
bool selectedPCM = _selectedCodecName == "pcm" || _selectedCodecName == "";
|
||||
|
@ -160,20 +165,33 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
|||
if (codecInPacket == _selectedCodecName || (packetPCM && selectedPCM)) {
|
||||
auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead());
|
||||
parseAudioData(message.getType(), afterProperties);
|
||||
_mismatchedAudioCodecCount = 0;
|
||||
|
||||
} else {
|
||||
qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket << "writing silence";
|
||||
_mismatchedAudioCodecCount++;
|
||||
qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket;
|
||||
|
||||
// Since the data in the stream is using a codec that we aren't prepared for,
|
||||
// we need to let the codec know that we don't have data for it, this will
|
||||
// allow the codec to interpolate missing data and produce a fade to silence.
|
||||
lostAudioData(1);
|
||||
|
||||
// inform others of the mismatch
|
||||
auto sendingNode = DependencyManager::get<NodeList>()->nodeWithUUID(message.getSourceID());
|
||||
if (sendingNode) {
|
||||
emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket);
|
||||
if (packetPCM) {
|
||||
// If there are PCM packets in-flight after the codec is changed, use them.
|
||||
auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead());
|
||||
_ringBuffer.writeData(afterProperties.data(), afterProperties.size());
|
||||
} else {
|
||||
// Since the data in the stream is using a codec that we aren't prepared for,
|
||||
// we need to let the codec know that we don't have data for it, this will
|
||||
// allow the codec to interpolate missing data and produce a fade to silence.
|
||||
lostAudioData(1);
|
||||
}
|
||||
|
||||
if (_mismatchedAudioCodecCount > MAX_MISMATCHED_AUDIO_CODEC_COUNT) {
|
||||
_mismatchedAudioCodecCount = 0;
|
||||
|
||||
// inform others of the mismatch
|
||||
auto sendingNode = DependencyManager::get<NodeList>()->nodeWithUUID(message.getSourceID());
|
||||
if (sendingNode) {
|
||||
emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket);
|
||||
qDebug(audio) << "Codec mismatch threshold exceeded, SelectedAudioFormat(" << _selectedCodecName << " ) sent";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -186,6 +186,7 @@ protected:
|
|||
CodecPluginPointer _codec;
|
||||
QString _selectedCodecName;
|
||||
Decoder* _decoder { nullptr };
|
||||
int _mismatchedAudioCodecCount { 0 };
|
||||
};
|
||||
|
||||
float calculateRepeatedFrameFadeFactor(int indexOfRepeat);
|
||||
|
|
|
@ -983,6 +983,9 @@ public:
|
|||
glm::vec2 dstCoord;
|
||||
glm::ivec2 srcPixel;
|
||||
for (int y = 0; y < faceWidth; ++y) {
|
||||
QRgb* destScanLineBegin = reinterpret_cast<QRgb*>( image.scanLine(y) );
|
||||
QRgb* destPixelIterator = destScanLineBegin;
|
||||
|
||||
dstCoord.y = 1.0f - (y + 0.5f) * dstInvSize.y; // Fill cube face images from top to bottom
|
||||
for (int x = 0; x < faceWidth; ++x) {
|
||||
dstCoord.x = (x + 0.5f) * dstInvSize.x;
|
||||
|
@ -995,13 +998,19 @@ public:
|
|||
srcPixel.y = floor((1.0f - srcCoord.y) * srcFaceHeight);
|
||||
|
||||
if (((uint32)srcPixel.x < (uint32)source.width()) && ((uint32)srcPixel.y < (uint32)source.height())) {
|
||||
image.setPixel(x, y, source.pixel(QPoint(srcPixel.x, srcPixel.y)));
|
||||
// We can't directly use the pixel() method because that launches a pixel color conversion to output
|
||||
// a correct RGBA8 color. But in our case we may have stored HDR values encoded in a RGB30 format which
|
||||
// are not convertible by Qt. The same goes with the setPixel method, by the way.
|
||||
const QRgb* sourcePixelIterator = reinterpret_cast<const QRgb*>(source.scanLine(srcPixel.y));
|
||||
sourcePixelIterator += srcPixel.x;
|
||||
*destPixelIterator = *sourcePixelIterator;
|
||||
|
||||
// Keep for debug, this is showing the dir as a color
|
||||
// glm::u8vec4 rgba((xyzDir.x + 1.0)*0.5 * 256, (xyzDir.y + 1.0)*0.5 * 256, (xyzDir.z + 1.0)*0.5 * 256, 256);
|
||||
// unsigned int val = 0xff000000 | (rgba.r) | (rgba.g << 8) | (rgba.b << 16);
|
||||
// image.setPixel(x, y, val);
|
||||
// *destPixelIterator = val;
|
||||
}
|
||||
++destPixelIterator;
|
||||
}
|
||||
}
|
||||
return image;
|
||||
|
@ -1192,6 +1201,10 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage&
|
|||
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
||||
QImage image = processSourceImage(srcImage, true);
|
||||
|
||||
if (image.format() != QIMAGE_HDR_FORMAT) {
|
||||
image = convertToHDRFormat(image, HDR_FORMAT);
|
||||
}
|
||||
|
||||
gpu::Element formatMip;
|
||||
gpu::Element formatGPU;
|
||||
if (isCubeTexturesCompressionEnabled()) {
|
||||
|
@ -1229,13 +1242,6 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage&
|
|||
faces.push_back(faceImage);
|
||||
}
|
||||
}
|
||||
|
||||
if (image.format() != QIMAGE_HDR_FORMAT) {
|
||||
for (auto& face : faces) {
|
||||
face = convertToHDRFormat(face, HDR_FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
qCDebug(imagelogging) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str());
|
||||
return nullptr;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <gl/Context.h>
|
||||
#include <shared/ReadWriteLockable.h>
|
||||
|
||||
#include "types/FileTypeProfile.h"
|
||||
#include "types/HFWebEngineProfile.h"
|
||||
|
@ -52,6 +53,53 @@ Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml")
|
|||
Q_LOGGING_CATEGORY(trace_render_qml_gl, "trace.render.qml.gl")
|
||||
Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
|
||||
|
||||
|
||||
class OffscreenQmlWhitelist : public Dependency, private ReadWriteLockable {
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
|
||||
void addWhitelistContextHandler(const std::initializer_list<QUrl>& urls, const QmlContextCallback& callback) {
|
||||
withWriteLock([&] {
|
||||
for (const auto& url : urls) {
|
||||
_callbacks[url].push_back(callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QList<QmlContextCallback> getCallbacksForUrl(const QUrl& url) const {
|
||||
return resultWithReadLock<QList<QmlContextCallback>>([&] {
|
||||
QList<QmlContextCallback> result;
|
||||
auto itr = _callbacks.find(url);
|
||||
if (_callbacks.end() != itr) {
|
||||
result = *itr;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
QHash<QUrl, QList<QmlContextCallback>> _callbacks;
|
||||
};
|
||||
|
||||
QSharedPointer<OffscreenQmlWhitelist> getQmlWhitelist() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
DependencyManager::set<OffscreenQmlWhitelist>();
|
||||
});
|
||||
|
||||
return DependencyManager::get<OffscreenQmlWhitelist>();
|
||||
}
|
||||
|
||||
|
||||
void OffscreenQmlSurface::addWhitelistContextHandler(const std::initializer_list<QUrl>& urls, const QmlContextCallback& callback) {
|
||||
getQmlWhitelist()->addWhitelistContextHandler(urls, callback);
|
||||
}
|
||||
|
||||
|
||||
QmlContextCallback OffscreenQmlSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QObject*) {};
|
||||
|
||||
struct TextureSet {
|
||||
// The number of surfaces with this size
|
||||
size_t count { 0 };
|
||||
|
@ -640,18 +688,26 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
|
|||
_qmlContext->setBaseUrl(baseUrl);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> onQmlLoadedCallback) {
|
||||
void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextCallback& onQmlLoadedCallback) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
qCWarning(uiLogging) << "Called load on a non-surface thread";
|
||||
}
|
||||
// Synchronous loading may take a while; restart the deadlock timer
|
||||
QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection);
|
||||
|
||||
// Get any whitelist functionality
|
||||
QList<QmlContextCallback> callbacks = getQmlWhitelist()->getCallbacksForUrl(qmlSource);
|
||||
// If we have whitelisted content, we must load a new context
|
||||
createNewContext |= !callbacks.empty();
|
||||
callbacks.push_back(onQmlLoadedCallback);
|
||||
|
||||
QQmlContext* targetContext = _qmlContext;
|
||||
if (_rootItem && createNewContext) {
|
||||
targetContext = new QQmlContext(targetContext);
|
||||
}
|
||||
|
||||
|
||||
// FIXME eliminate loading of relative file paths for QML
|
||||
QUrl finalQmlSource = qmlSource;
|
||||
if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) {
|
||||
finalQmlSource = _qmlContext->resolvedUrl(qmlSource);
|
||||
|
@ -659,29 +715,32 @@ void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std
|
|||
|
||||
auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous);
|
||||
if (qmlComponent->isLoading()) {
|
||||
connect(qmlComponent, &QQmlComponent::statusChanged, this,
|
||||
[this, qmlComponent, targetContext, onQmlLoadedCallback](QQmlComponent::Status) {
|
||||
finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback);
|
||||
connect(qmlComponent, &QQmlComponent::statusChanged, this, [=](QQmlComponent::Status) {
|
||||
finishQmlLoad(qmlComponent, targetContext, callbacks);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback);
|
||||
finishQmlLoad(qmlComponent, targetContext, callbacks);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> onQmlLoadedCallback) {
|
||||
void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback) {
|
||||
load(qmlSource, true, onQmlLoadedCallback);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> onQmlLoadedCallback) {
|
||||
void OffscreenQmlSurface::load(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback) {
|
||||
load(qmlSource, false, onQmlLoadedCallback);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::load(const QString& qmlSourceFile, const QmlContextCallback& onQmlLoadedCallback) {
|
||||
return load(QUrl(qmlSourceFile), onQmlLoadedCallback);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::clearCache() {
|
||||
_qmlContext->engine()->clearComponentCache();
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> onQmlLoadedCallback) {
|
||||
void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QList<QmlContextCallback>& callbacks) {
|
||||
disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0);
|
||||
if (qmlComponent->isError()) {
|
||||
for (const auto& error : qmlComponent->errors()) {
|
||||
|
@ -716,7 +775,9 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext
|
|||
// Make sure we will call callback for this codepath
|
||||
// Call this before qmlComponent->completeCreate() otherwise ghost window appears
|
||||
if (newItem && _rootItem) {
|
||||
onQmlLoadedCallback(qmlContext, newObject);
|
||||
for (const auto& callback : callbacks) {
|
||||
callback(qmlContext, newObject);
|
||||
}
|
||||
}
|
||||
|
||||
QObject* eventBridge = qmlContext->contextProperty("eventBridge").value<QObject*>();
|
||||
|
@ -751,8 +812,11 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext
|
|||
_rootItem = newItem;
|
||||
_rootItem->setParentItem(_quickWindow->contentItem());
|
||||
_rootItem->setSize(_quickWindow->renderTargetSize());
|
||||
|
||||
// Call this callback after rootitem is set, otherwise VrMenu wont work
|
||||
onQmlLoadedCallback(qmlContext, newObject);
|
||||
for (const auto& callback : callbacks) {
|
||||
callback(qmlContext, newObject);
|
||||
}
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::updateQuick() {
|
||||
|
@ -1018,6 +1082,32 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid
|
|||
}
|
||||
}
|
||||
|
||||
static void forEachKeyboard(QQuickItem* item, std::function<void(QQuickItem*)> function) {
|
||||
QObject* itemObject = item;
|
||||
while (itemObject) {
|
||||
if (itemObject->parent()) {
|
||||
itemObject = itemObject->parent();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto keyboards = itemObject->findChildren<QObject*>("keyboard");
|
||||
|
||||
for (auto keyboardObject : keyboards) {
|
||||
auto keyboard = qobject_cast<QQuickItem*>(keyboardObject);
|
||||
if (keyboard == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (function) {
|
||||
function(keyboard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const int TEXTINPUT_PASSWORD = 2;
|
||||
|
||||
void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric) {
|
||||
#if Q_OS_ANDROID
|
||||
return;
|
||||
|
@ -1030,6 +1120,26 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n
|
|||
// if HMD is being worn, allow keyboard to open. allow it to close, HMD or not.
|
||||
if (!raised || qApp->property(hifi::properties::HMD).toBool()) {
|
||||
QQuickItem* item = dynamic_cast<QQuickItem*>(object);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto echoMode = item->property("echoMode");
|
||||
bool isPasswordField = echoMode.isValid() && echoMode.toInt() == TEXTINPUT_PASSWORD;
|
||||
|
||||
// we need to somehow pass 'isPasswordField' to visible keyboard so it will change its 'mirror text' to asterixes
|
||||
// the issue in some cases there might be more than one keyboard in object tree and it is hard to understand which one is being used at the moment
|
||||
// unfortunately attempts to check for visibility failed becuase visibility is not updated yet. So... I don't see other way than just update properties for all the keyboards
|
||||
forEachKeyboard(item, [&](QQuickItem* keyboard) {
|
||||
keyboard->setProperty("mirroredText", QVariant::fromValue(QString("")));
|
||||
keyboard->setProperty("password", isPasswordField);
|
||||
});
|
||||
|
||||
// for future probably makes sense to consider one of the following:
|
||||
// 1. make keyboard a singleton, which will be dynamically re-parented before showing
|
||||
// 2. track currently visible keyboard somewhere, allow to subscribe for this signal
|
||||
// any of above should also eliminate need in duplicated properties and code below
|
||||
|
||||
while (item) {
|
||||
// Numeric value may be set in parameter from HTML UI; for QML UI, detect numeric fields here.
|
||||
numeric = numeric || QString(item->metaObject()->className()).left(7) == "SpinBox";
|
||||
|
|
|
@ -35,12 +35,18 @@ class QQuickItem;
|
|||
// one copy in flight, and one copy being used by the receiver
|
||||
#define GPU_RESOURCE_BUFFER_SIZE 3
|
||||
|
||||
using QmlContextCallback = std::function<void(QQmlContext*, QObject*)>;
|
||||
|
||||
class OffscreenQmlSurface : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged)
|
||||
public:
|
||||
static void setSharedContext(QOpenGLContext* context);
|
||||
|
||||
static QmlContextCallback DEFAULT_CONTEXT_CALLBACK;
|
||||
static void addWhitelistContextHandler(const std::initializer_list<QUrl>& urls, const QmlContextCallback& callback);
|
||||
static void addWhitelistContextHandler(const QUrl& url, const QmlContextCallback& callback) { addWhitelistContextHandler({ { url } }, callback); };
|
||||
|
||||
OffscreenQmlSurface();
|
||||
virtual ~OffscreenQmlSurface();
|
||||
|
||||
|
@ -50,12 +56,10 @@ public:
|
|||
void resize(const QSize& size, bool forceResize = false);
|
||||
QSize size() const;
|
||||
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> onQmlLoadedCallback = [](QQmlContext*, QObject*) {});
|
||||
Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> onQmlLoadedCallback = [](QQmlContext*, QObject*) {});
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> onQmlLoadedCallback = [](QQmlContext*, QObject*) {});
|
||||
Q_INVOKABLE void load(const QString& qmlSourceFile, std::function<void(QQmlContext*, QObject*)> onQmlLoadedCallback = [](QQmlContext*, QObject*) {}) {
|
||||
return load(QUrl(qmlSourceFile), onQmlLoadedCallback);
|
||||
}
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QString& qmlSourceFile, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
void clearCache();
|
||||
void setMaxFps(uint8_t maxFps) { _maxFps = maxFps; }
|
||||
// Optional values for event handling
|
||||
|
@ -120,7 +124,7 @@ protected:
|
|||
private:
|
||||
static QOpenGLContext* getSharedContext();
|
||||
|
||||
void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> onQmlLoadedCallback);
|
||||
void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QList<QmlContextCallback>& callbacks);
|
||||
QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject);
|
||||
void setupFbo();
|
||||
bool allowNewFrame(uint8_t fps);
|
||||
|
|
|
@ -53,4 +53,8 @@ ScriptDiscoveryService.clearDebugWindow.connect(function() {
|
|||
window.clearDebugWindow();
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
window.close();
|
||||
})
|
||||
|
||||
}());
|
||||
|
|
|
@ -23,6 +23,8 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
(function() {
|
||||
var PICK_WITH_HAND_RAY = true;
|
||||
|
||||
var SEARCH_SPHERE_SIZE = 0.0132;
|
||||
var dim = {x: SEARCH_SPHERE_SIZE, y: SEARCH_SPHERE_SIZE, z: SEARCH_SPHERE_SIZE};
|
||||
var halfPath = {
|
||||
type: "line3d",
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
|
@ -37,6 +39,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
var halfEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -58,6 +61,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
var fullEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -135,10 +139,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
100);
|
||||
|
||||
this.updateLaserPointer = function(controllerData) {
|
||||
var SEARCH_SPHERE_SIZE = 0.011;
|
||||
var MIN_SPHERE_SIZE = 0.0005;
|
||||
var radius = Math.max(1.2 * SEARCH_SPHERE_SIZE * this.intersectionDistance, MIN_SPHERE_SIZE) * MyAvatar.sensorToWorldScale;
|
||||
var dim = {x: radius, y: radius, z: radius};
|
||||
var mode = "hold";
|
||||
if (!this.distanceHolding && !this.distanceRotating) {
|
||||
if (controllerData.triggerClicks[this.hand]) {
|
||||
|
@ -150,16 +150,10 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
|
||||
var laserPointerID = PICK_WITH_HAND_RAY ? this.laserPointer : this.headLaserPointer;
|
||||
if (mode === "full") {
|
||||
var fullEndToEdit = PICK_WITH_HAND_RAY ? this.fullEnd : fullEnd;
|
||||
fullEndToEdit.dimensions = dim;
|
||||
LaserPointers.editRenderState(laserPointerID, mode, { path: fullPath, end: fullEndToEdit });
|
||||
this.contextOverlayTimer = false;
|
||||
this.destroyContextOverlay();
|
||||
} else if (mode === "half") {
|
||||
var halfEndToEdit = PICK_WITH_HAND_RAY ? this.halfEnd : halfEnd;
|
||||
halfEndToEdit.dimensions = dim;
|
||||
LaserPointers.editRenderState(laserPointerID, mode, {path: halfPath, end: halfEndToEdit});
|
||||
}
|
||||
|
||||
LaserPointers.enableLaserPointer(laserPointerID);
|
||||
LaserPointers.setRenderState(laserPointerID, mode);
|
||||
if (this.distanceHolding || this.distanceRotating) {
|
||||
|
@ -577,8 +571,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
LaserPointers.removeLaserPointer(this.laserPointer);
|
||||
};
|
||||
|
||||
this.halfEnd = halfEnd;
|
||||
this.fullEnd = fullEnd;
|
||||
this.laserPointer = LaserPointers.createLaserPointer({
|
||||
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||
|
@ -586,6 +578,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
distanceScaleEnd: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
});
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
Script.include("/~/system/libraries/controllers.js");
|
||||
|
||||
(function() {
|
||||
var SEARCH_SPHERE_SIZE = 0.0132;
|
||||
var dim = {x: SEARCH_SPHERE_SIZE, y: SEARCH_SPHERE_SIZE, z: SEARCH_SPHERE_SIZE};
|
||||
var halfPath = {
|
||||
type: "line3d",
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
|
@ -30,6 +32,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
var halfEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -51,6 +54,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
var fullEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -107,10 +111,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
|
||||
this.updateLaserPointer = function(controllerData) {
|
||||
var SEARCH_SPHERE_SIZE = 0.011;
|
||||
var MIN_SPHERE_SIZE = 0.0005;
|
||||
var radius = Math.max(1.2 * SEARCH_SPHERE_SIZE * this.intersectionDistance, MIN_SPHERE_SIZE);
|
||||
var dim = {x: radius, y: radius, z: radius};
|
||||
var mode = "none";
|
||||
if (controllerData.triggerClicks[this.hand]) {
|
||||
mode = "full";
|
||||
|
@ -118,18 +118,8 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
mode = "half";
|
||||
}
|
||||
|
||||
var laserPointerID = this.laserPointer;
|
||||
if (mode === "full") {
|
||||
var fullEndToEdit = this.fullEnd;
|
||||
fullEndToEdit.dimensions = dim;
|
||||
LaserPointers.editRenderState(laserPointerID, mode, {path: fullPath, end: fullEndToEdit});
|
||||
} else if (mode === "half") {
|
||||
var halfEndToEdit = this.halfEnd;
|
||||
halfEndToEdit.dimensions = dim;
|
||||
LaserPointers.editRenderState(laserPointerID, mode, {path: halfPath, end: halfEndToEdit});
|
||||
}
|
||||
LaserPointers.enableLaserPointer(laserPointerID);
|
||||
LaserPointers.setRenderState(laserPointerID, mode);
|
||||
LaserPointers.enableLaserPointer(this.laserPointer);
|
||||
LaserPointers.setRenderState(this.laserPointer, mode);
|
||||
};
|
||||
|
||||
this.laserPointerOff = function() {
|
||||
|
@ -192,8 +182,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
return makeRunningValues(true, [this.targetEntityID], []);
|
||||
};
|
||||
|
||||
this.halfEnd = halfEnd;
|
||||
this.fullEnd = fullEnd;
|
||||
this.laserPointer = LaserPointers.createLaserPointer({
|
||||
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||
|
@ -201,6 +189,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
distanceScaleEnd: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
});
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
(function() {
|
||||
Script.include("/~/system/libraries/controllers.js");
|
||||
var ControllerDispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
var END_RADIUS = 0.005;
|
||||
var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS };
|
||||
var halfPath = {
|
||||
type: "line3d",
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
|
@ -36,6 +38,7 @@
|
|||
};
|
||||
var halfEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -57,6 +60,7 @@
|
|||
};
|
||||
var fullEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -126,17 +130,6 @@
|
|||
};
|
||||
|
||||
this.updateLaserPointer = function(controllerData) {
|
||||
var RADIUS = 0.005;
|
||||
var dim = { x: RADIUS, y: RADIUS, z: RADIUS };
|
||||
|
||||
if (this.mode === "full") {
|
||||
this.fullEnd.dimensions = dim;
|
||||
LaserPointers.editRenderState(this.laserPointer, this.mode, {path: fullPath, end: this.fullEnd});
|
||||
} else if (this.mode === "half") {
|
||||
this.halfEnd.dimensions = dim;
|
||||
LaserPointers.editRenderState(this.laserPointer, this.mode, {path: halfPath, end: this.halfEnd});
|
||||
}
|
||||
|
||||
LaserPointers.enableLaserPointer(this.laserPointer);
|
||||
LaserPointers.setRenderState(this.laserPointer, this.mode);
|
||||
};
|
||||
|
@ -212,8 +205,6 @@
|
|||
LaserPointers.removeLaserPointer(this.laserPointer);
|
||||
};
|
||||
|
||||
this.halfEnd = halfEnd;
|
||||
this.fullEnd = fullEnd;
|
||||
this.laserPointer = LaserPointers.createLaserPointer({
|
||||
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_HUD,
|
||||
|
|
|
@ -18,6 +18,8 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
Script.include("/~/system/libraries/utils.js");
|
||||
|
||||
(function () {
|
||||
var END_RADIUS = 0.005;
|
||||
var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS };
|
||||
var halfPath = {
|
||||
type: "line3d",
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
|
@ -32,6 +34,7 @@ Script.include("/~/system/libraries/utils.js");
|
|||
};
|
||||
var halfEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -53,6 +56,7 @@ Script.include("/~/system/libraries/utils.js");
|
|||
};
|
||||
var fullEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -121,17 +125,6 @@ Script.include("/~/system/libraries/utils.js");
|
|||
};
|
||||
|
||||
this.updateLaserPointer = function(controllerData) {
|
||||
var RADIUS = 0.005;
|
||||
var dim = { x: RADIUS, y: RADIUS, z: RADIUS };
|
||||
|
||||
if (this.mode === "full") {
|
||||
this.fullEnd.dimensions = dim;
|
||||
LaserPointers.editRenderState(this.laserPointer, this.mode, {path: fullPath, end: this.fullEnd});
|
||||
} else if (this.mode === "half") {
|
||||
this.halfEnd.dimensions = dim;
|
||||
LaserPointers.editRenderState(this.laserPointer, this.mode, {path: halfPath, end: this.halfEnd});
|
||||
}
|
||||
|
||||
LaserPointers.enableLaserPointer(this.laserPointer);
|
||||
LaserPointers.setRenderState(this.laserPointer, this.mode);
|
||||
|
||||
|
@ -237,10 +230,6 @@ Script.include("/~/system/libraries/utils.js");
|
|||
LaserPointers.removeLaserPointer(this.laserPointer);
|
||||
};
|
||||
|
||||
|
||||
this.halfEnd = halfEnd;
|
||||
this.fullEnd = fullEnd;
|
||||
|
||||
this.laserPointer = LaserPointers.createLaserPointer({
|
||||
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||
|
|
|
@ -17,6 +17,8 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
|
||||
(function() {
|
||||
var TouchEventUtils = Script.require("/~/system/libraries/touchEventUtils.js");
|
||||
var END_RADIUS = 0.005;
|
||||
var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS };
|
||||
var halfPath = {
|
||||
type: "line3d",
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
|
@ -31,6 +33,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
var halfEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -52,6 +55,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
var fullEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -171,17 +175,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
|
||||
this.updateLaserPointer = function(controllerData) {
|
||||
var RADIUS = 0.005;
|
||||
var dim = { x: RADIUS, y: RADIUS, z: RADIUS };
|
||||
|
||||
if (this.mode === "full") {
|
||||
this.fullEnd.dimensions = dim;
|
||||
LaserPointers.editRenderState(this.laserPointer, this.mode, {path: fullPath, end: this.fullEnd});
|
||||
} else if (this.mode === "half") {
|
||||
this.halfEnd.dimensions = dim;
|
||||
LaserPointers.editRenderState(this.laserPointer, this.mode, {path: halfPath, end: this.halfEnd});
|
||||
}
|
||||
|
||||
LaserPointers.enableLaserPointer(this.laserPointer);
|
||||
LaserPointers.setRenderState(this.laserPointer, this.mode);
|
||||
|
||||
|
@ -371,8 +364,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
LaserPointers.removeLaserPointer(this.laserPointer);
|
||||
};
|
||||
|
||||
this.halfEnd = halfEnd;
|
||||
this.fullEnd = fullEnd;
|
||||
this.laserPointer = LaserPointers.createLaserPointer({
|
||||
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_OVERLAYS,
|
||||
|
|
|
@ -17,6 +17,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
Script.include("/~/system/libraries/controllers.js");
|
||||
|
||||
(function() {
|
||||
var END_RADIUS = 0.005;
|
||||
var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS };
|
||||
var halfPath = {
|
||||
type: "line3d",
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
|
@ -31,6 +33,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
var halfEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -52,6 +55,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
var fullEnd = {
|
||||
type: "sphere",
|
||||
dimensions: dim,
|
||||
solid: true,
|
||||
color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
|
@ -366,17 +370,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
|
||||
this.updateLaserPointer = function(controllerData) {
|
||||
var RADIUS = 0.005;
|
||||
var dim = { x: RADIUS, y: RADIUS, z: RADIUS };
|
||||
|
||||
if (this.mode === "full") {
|
||||
fullEnd.dimensions = dim;
|
||||
LaserPointers.editRenderState(this.laserPointer, this.mode, {path: fullPath, end: fullEnd});
|
||||
} else if (this.mode === "half") {
|
||||
halfEnd.dimensions = dim;
|
||||
LaserPointers.editRenderState(this.laserPointer, this.mode, {path: halfPath, end: halfEnd});
|
||||
}
|
||||
|
||||
LaserPointers.enableLaserPointer(this.laserPointer);
|
||||
LaserPointers.setRenderState(this.laserPointer, this.mode);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue