Merge branch 'master' of https://github.com/highfidelity/hifi into orange

This commit is contained in:
samcake 2016-02-23 09:33:54 -08:00
commit 9d0803e6b8
24 changed files with 412 additions and 333 deletions

View file

@ -132,6 +132,7 @@ function maybeGoActive(event) {
}
}
var wasHmdActive = false;
var wasMouseCaptured = false;
function maybeGoAway() {
if (HMD.active !== wasHmdActive) {
wasHmdActive = !wasHmdActive;
@ -139,6 +140,17 @@ function maybeGoAway() {
goAway();
}
}
// If the mouse has gone from captured, to non-captured state,
// then it likely means the person is still in the HMD, but has
// tabbed away from the application (meaning they don't have mouse
// control) and they likely want to go into an away state
if (Reticle.mouseCaptured !== wasMouseCaptured) {
wasMouseCaptured = !wasMouseCaptured;
if (!wasMouseCaptured) {
goAway();
}
}
}
Script.update.connect(maybeGoAway);

View file

@ -1587,48 +1587,43 @@ function MyController(hand) {
}
ids.forEach(function(id) {
var props = Entities.getEntityProperties(id, ["boundingBox", "name"]);
if (props.name === 'pointer') {
return;
} else {
var entityMinPoint = props.boundingBox.brn;
var entityMaxPoint = props.boundingBox.tfl;
var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint);
var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint);
if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) {
// we haven't been touched before, but either right or left is touching us now
_this.allTouchedIDs[id] = true;
_this.startTouch(id);
} else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) {
// we have been touched before and are still being touched
// continue touch
_this.continueTouch(id);
} else if (_this.allTouchedIDs[id]) {
delete _this.allTouchedIDs[id];
_this.stopTouch(id);
} else {
//we are in another state
return;
}
}
var entityMinPoint = props.boundingBox.brn;
var entityMaxPoint = props.boundingBox.tfl;
var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint);
var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint);
if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) {
// we haven't been touched before, but either right or left is touching us now
_this.allTouchedIDs[id] = true;
_this.startTouch(id);
} else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) {
// we have been touched before and are still being touched
// continue touch
_this.continueTouch(id);
} else if (_this.allTouchedIDs[id]) {
delete _this.allTouchedIDs[id];
_this.stopTouch(id);
}
});
};
this.startTouch = function(entityID) {
this.callEntityMethodOnGrabbed("startTouch");
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(entityID, "startTouch", args);
};
this.continueTouch = function(entityID) {
this.callEntityMethodOnGrabbed("continueTouch");
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(entityID, "continueTouch", args);
};
this.stopTouch = function(entityID) {
this.callEntityMethodOnGrabbed("stopTouch");
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(entityID, "stopTouch", args);
};
this.release = function() {

View file

@ -38,6 +38,10 @@ var lightOverlayManager = new LightOverlayManager();
var cameraManager = new CameraManager();
var grid = Grid();
gridTool = GridTool({
horizontalGrid: grid
});
gridTool.setVisible(false);
var entityListTool = EntityListTool();
@ -341,7 +345,7 @@ var toolBar = (function() {
isActive = active;
if (!isActive) {
entityListTool.setVisible(false);
// gridTool.setVisible(false);
gridTool.setVisible(false);
grid.setEnabled(false);
propertiesTool.setVisible(false);
selectionManager.clearSelections();
@ -349,7 +353,7 @@ var toolBar = (function() {
} else {
hasShownPropertiesTool = false;
entityListTool.setVisible(true);
// gridTool.setVisible(true);
gridTool.setVisible(true);
grid.setEnabled(true);
propertiesTool.setVisible(true);
Window.setFocus();

View file

@ -33,8 +33,8 @@
elPosY.value = origin.y.toFixed(2);
}
if (data.minorGridWidth !== undefined) {
elMinorSpacing.value = data.minorGridWidth;
if (data.minorGridEvery !== undefined) {
elMinorSpacing.value = data.minorGridEvery;
}
if (data.majorGridEvery !== undefined) {
@ -60,7 +60,7 @@
origin: {
y: elPosY.value,
},
minorGridWidth: elMinorSpacing.value,
minorGridEvery: elMinorSpacing.value,
majorGridEvery: elMajorSpacing.value,
gridColor: gridColor,
colorIndex: gridColorIndex,
@ -132,21 +132,21 @@
<div id="horizontal-position" class="property-section">
<label>Position (Y Axis)</label>
<span>
<input type='number' id="horiz-y" class="number" value="0.0" step="0.1"></input>
<input type='number' id="horiz-y" class="number" step="0.1"></input>
</span>
</div>
<div class="property-section">
<label>Minor Grid Size</label>
<span>
<input type='number' id="minor-spacing" min="0" step="0.01", ></input>
<input type='number' id="minor-spacing" min="0.2" step="0.2"></input>
</span>
</div>
<div class="property-section">
<label>Major Grid Every</label>
<span>
<input type='number' id="major-spacing" min="2" step="1", ></input>
<input type='number' id="major-spacing" min="1" step="1", ></input>
</span>
</div>

View file

@ -12,24 +12,26 @@ Grid = function(opts) {
];
var colorIndex = 0;
var gridAlpha = 0.6;
var origin = { x: 0, y: 0, z: 0 };
var origin = { x: 0, y: +MyAvatar.getJointPosition('LeftToeBase').y.toFixed(1) + 0.1, z: 0 };
var scale = 500;
var minorGridEvery = 1.0;
var majorGridEvery = 5;
var minorGridWidth = 0.2;
var halfSize = 40;
var yOffset = 0.001;
var worldSize = 16384;
var snapToGrid = false;
var gridOverlay = Overlays.addOverlay("grid", {
position: { x: 0 , y: 0, z: 0 },
visible: true,
rotation: Quat.fromPitchYawRollDegrees(90, 0, 0),
dimensions: { x: scale, y: scale, z: scale },
position: origin,
visible: false,
drawInFront: false,
color: colors[0],
alpha: gridAlpha,
rotation: Quat.fromPitchYawRollDegrees(90, 0, 0),
minorGridWidth: 0.1,
majorGridEvery: 2,
minorGridEvery: minorGridEvery,
majorGridEvery: majorGridEvery,
});
that.visible = false;
@ -39,17 +41,13 @@ Grid = function(opts) {
return origin;
}
that.getMinorIncrement = function() { return minorGridWidth; };
that.getMajorIncrement = function() { return minorGridWidth * majorGridEvery; };
that.getMinorGridWidth = function() { return minorGridWidth; };
that.setMinorGridWidth = function(value) {
minorGridWidth = value;
that.getMinorIncrement = function() { return minorGridEvery; };
that.setMinorIncrement = function(value) {
minorGridEvery = value;
updateGrid();
};
that.getMajorGridEvery = function() { return majorGridEvery; };
that.setMajorGridEvery = function(value) {
}
that.getMajorIncrement = function() { return majorGridEvery; };
that.setMajorIncrement = function(value) {
majorGridEvery = value;
updateGrid();
};
@ -106,7 +104,7 @@ Grid = function(opts) {
dimensions = { x: 0, y: 0, z: 0 };
}
var spacing = majorOnly ? (minorGridWidth * majorGridEvery) : minorGridWidth;
var spacing = majorOnly ? majorGridEvery : minorGridEvery;
position = Vec3.subtract(position, origin);
@ -122,7 +120,7 @@ Grid = function(opts) {
return delta;
}
var spacing = majorOnly ? (minorGridWidth * majorGridEvery) : minorGridWidth;
var spacing = majorOnly ? majorGridEvery : minorGridEvery;
var snappedDelta = {
x: Math.round(delta.x / spacing) * spacing,
@ -135,9 +133,7 @@ Grid = function(opts) {
that.setPosition = function(newPosition, noUpdate) {
origin = Vec3.subtract(newPosition, { x: 0, y: yOffset, z: 0 });
origin.x = 0;
origin.z = 0;
origin = { x: 0, y: newPosition.y, z: 0 };
updateGrid();
if (!noUpdate) {
@ -149,7 +145,7 @@ Grid = function(opts) {
if (that.onUpdate) {
that.onUpdate({
origin: origin,
minorGridWidth: minorGridWidth,
minorGridEvery: minorGridEvery,
majorGridEvery: majorGridEvery,
gridSize: halfSize,
visible: that.visible,
@ -171,8 +167,8 @@ Grid = function(opts) {
that.setPosition(pos, true);
}
if (data.minorGridWidth) {
minorGridWidth = data.minorGridWidth;
if (data.minorGridEvery) {
minorGridEvery = data.minorGridEvery;
}
if (data.majorGridEvery) {
@ -191,20 +187,22 @@ Grid = function(opts) {
that.setVisible(data.visible, true);
}
updateGrid();
updateGrid(true);
}
function updateGrid() {
function updateGrid(noUpdate) {
Overlays.editOverlay(gridOverlay, {
position: { x: origin.y, y: origin.y, z: -origin.y },
position: { x: 0, y: origin.y, z: 0 },
visible: that.visible && that.enabled,
minorGridWidth: minorGridWidth,
minorGridEvery: minorGridEvery,
majorGridEvery: majorGridEvery,
color: colors[colorIndex],
alpha: gridAlpha,
});
that.emitUpdate();
if (!noUpdate) {
that.emitUpdate();
}
}
function cleanup() {
@ -247,7 +245,7 @@ GridTool = function(opts) {
} else if (data.type == "update") {
horizontalGrid.update(data);
for (var i = 0; i < listeners.length; i++) {
listeners[i](data);
listeners[i] && listeners[i](data);
}
} else if (data.type == "action") {
var action = data.action;

View file

@ -10,12 +10,19 @@ import "../js/Utils.js" as Utils
// windows will be childed.
FocusScope {
id: desktop
anchors.fill: parent;
objectName: "desktop"
// Allow the scale of the desktop to be changed without screwing up the size relative to the parent.
height: parent.height / scale
width: parent.width / scale
onHeightChanged: d.repositionAll();
onWidthChanged: d.repositionAll();
// Controls and windows can trigger this signal to ensure the desktop becomes visible
// when they're opened.
signal showDesktop();
// Allows QML/JS to find the desktop through the parent chain
property bool desktopRoot: true
@ -217,6 +224,8 @@ FocusScope {
}
reposition(targetWindow);
showDesktop();
}
function reposition(item) {
@ -314,7 +323,7 @@ FocusScope {
enabled: DebugQML
onTriggered: focusDebugger.visible = !focusDebugger.visible
}
}

View file

@ -1198,7 +1198,8 @@ void Application::initializeUi() {
// OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to
// support the window management and scripting proxies for VR use
offscreenUi->createDesktop(QString("hifi/Desktop.qml"));
connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);
// FIXME either expose so that dialogs can set this themselves or
// do better detection in the offscreen UI of what has focus
offscreenUi->setNavigationFocused(false);
@ -3906,16 +3907,8 @@ void Application::resetSensors(bool andReload) {
DependencyManager::get<Faceshift>()->reset();
DependencyManager::get<DdeFaceTracker>()->reset();
DependencyManager::get<EyeTracker>()->reset();
getActiveDisplayPlugin()->resetSensors();
QScreen* currentScreen = _window->windowHandle()->screen();
QWindow* mainWindow = _window->windowHandle();
QPoint windowCenter = mainWindow->geometry().center();
_glWidget->cursor().setPos(currentScreen, windowCenter);
getMyAvatar()->reset(andReload);
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "reset", Qt::QueuedConnection);
}
@ -5136,3 +5129,9 @@ void Application::readArgumentsFromLocalSocket() {
qApp->openUrl(QString::fromUtf8(message));
}
}
void Application::showDesktop() {
if (!_overlayConductor.getEnabled()) {
_overlayConductor.setEnabled(true);
}
}

View file

@ -280,6 +280,7 @@ public slots:
void runTests();
private slots:
void showDesktop();
void clearDomainOctreeDetails();
void idle(uint64_t now);
void aboutToQuit();

View file

@ -117,8 +117,8 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) {
static const glm::vec4 inputColor = { 0.3f, 1.0f, 0.3f, 1.0f };
static const glm::vec4 outputLeftColor = { 1.0f, 0.3f, 0.3f, 1.0f };
static const glm::vec4 outputRightColor = { 0.3f, 0.3f, 1.0f, 1.0f };
static const int gridRows = 2;
int gridCols = _framesPerScope;
static const int gridCols = 2;
int gridRows = _framesPerScope;
int x = (width - (int)SCOPE_WIDTH) / 2;
int y = (height - (int)SCOPE_HEIGHT) / 2;
@ -127,6 +127,12 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) {
gpu::Batch& batch = *renderArgs->_batch;
auto geometryCache = DependencyManager::get<GeometryCache>();
// Grid uses its own pipeline, so draw it before setting another
const float GRID_EDGE = 0.005f;
geometryCache->renderGrid(batch, glm::vec2(x, y), glm::vec2(x + w, y + h),
gridRows, gridCols, GRID_EDGE, gridColor, true, _audioScopeGrid);
geometryCache->useSimpleDrawPipeline(batch);
auto textureCache = DependencyManager::get<TextureCache>();
batch.setResourceTexture(0, textureCache->getWhiteTexture());
@ -139,7 +145,6 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) {
batch.setViewTransform(Transform());
geometryCache->renderQuad(batch, x, y, w, h, backgroundColor, _audioScopeBackground);
geometryCache->renderGrid(batch, x, y, w, h, gridRows, gridCols, gridColor, _audioScopeGrid);
renderLineStrip(batch, _inputID, inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput);
renderLineStrip(batch, _outputLeftID, outputLeftColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputLeft);
renderLineStrip(batch, _outputRightD, outputRightColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputRight);

View file

@ -101,9 +101,9 @@ public:
void handleLeaveEvent();
QPointF getMouseEventPosition(QMouseEvent* event);
bool shouldCaptureMouse() const;
private:
bool shouldCaptureMouse() const;
void displayOverlayTextureStereo(RenderArgs* renderArgs, float aspectRatio, float fov);
void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
@ -162,10 +162,13 @@ class ReticleInterface : public QObject {
Q_PROPERTY(bool visible READ getVisible WRITE setVisible)
Q_PROPERTY(float depth READ getDepth WRITE setDepth)
Q_PROPERTY(glm::vec2 maximumPosition READ getMaximumPosition)
Q_PROPERTY(bool mouseCaptured READ isMouseCaptured)
public:
ReticleInterface(ApplicationCompositor* outer) : QObject(outer), _compositor(outer) {}
Q_INVOKABLE bool isMouseCaptured() { return _compositor->shouldCaptureMouse(); }
Q_INVOKABLE bool getVisible() { return _compositor->getReticleVisible(); }
Q_INVOKABLE void setVisible(bool visible) { _compositor->setReticleVisible(visible); }

View file

@ -13,6 +13,8 @@
#include <QScriptValue>
#include <OctreeConstants.h>
#include <DependencyManager.h>
#include <GeometryCache.h>
#include <PathUtils.h>
@ -20,17 +22,28 @@
QString const Grid3DOverlay::TYPE = "grid";
const float DEFAULT_SCALE = 100.0f;
Grid3DOverlay::Grid3DOverlay() :
_minorGridWidth(1.0),
_majorGridEvery(5) {
Grid3DOverlay::Grid3DOverlay() {
setDimensions(DEFAULT_SCALE);
updateGrid();
}
Grid3DOverlay::Grid3DOverlay(const Grid3DOverlay* grid3DOverlay) :
Planar3DOverlay(grid3DOverlay),
_minorGridWidth(grid3DOverlay->_minorGridWidth),
_majorGridEvery(grid3DOverlay->_majorGridEvery)
_majorGridEvery(grid3DOverlay->_majorGridEvery),
_minorGridEvery(grid3DOverlay->_minorGridEvery)
{
updateGrid();
}
AABox Grid3DOverlay::getBounds() const {
if (_followCamera) {
// This is a UI element that should always be in view, lie to the octree to avoid culling
const AABox DOMAIN_BOX = AABox(glm::vec3(-TREE_SCALE / 2), TREE_SCALE);
return DOMAIN_BOX;
}
return Planar3DOverlay::getBounds();
}
void Grid3DOverlay::render(RenderArgs* args) {
@ -38,15 +51,8 @@ void Grid3DOverlay::render(RenderArgs* args) {
return; // do nothing if we're not visible
}
const int MINOR_GRID_DIVISIONS = 200;
const int MAJOR_GRID_DIVISIONS = 100;
const float MAX_COLOR = 255.0f;
// center the grid around the camera position on the plane
glm::vec3 rotated = glm::inverse(getRotation()) * args->_viewFrustum->getPosition();
float spacing = _minorGridWidth;
float alpha = getAlpha();
xColor color = getColor();
glm::vec4 gridColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
@ -54,72 +60,65 @@ void Grid3DOverlay::render(RenderArgs* args) {
auto batch = args->_batch;
if (batch) {
auto minCorner = glm::vec2(-0.5f, -0.5f);
auto maxCorner = glm::vec2(0.5f, 0.5f);
auto position = getPosition();
if (_followCamera) {
// Get the camera position rounded to the nearest major grid line
// This grid is for UI and should lie on worldlines
auto cameraPosition =
(float)_majorGridEvery * glm::round(args->_viewFrustum->getPosition() / (float)_majorGridEvery);
position += glm::vec3(cameraPosition.x, 0.0f, cameraPosition.z);
}
Transform transform;
transform.setRotation(getRotation());
transform.setScale(glm::vec3(getDimensions(), 1.0f));
transform.setTranslation(position);
batch->setModelTransform(transform);
// Minor grid
{
auto position = glm::vec3(_minorGridWidth * (floorf(rotated.x / spacing) - MINOR_GRID_DIVISIONS / 2),
spacing * (floorf(rotated.y / spacing) - MINOR_GRID_DIVISIONS / 2),
getPosition().z);
float scale = MINOR_GRID_DIVISIONS * spacing;
transform.setTranslation(position);
transform.setScale(scale);
batch->setModelTransform(transform);
DependencyManager::get<GeometryCache>()->renderGrid(*batch, MINOR_GRID_DIVISIONS, MINOR_GRID_DIVISIONS, gridColor);
}
// Major grid
{
spacing *= _majorGridEvery;
auto position = glm::vec3(spacing * (floorf(rotated.x / spacing) - MAJOR_GRID_DIVISIONS / 2),
spacing * (floorf(rotated.y / spacing) - MAJOR_GRID_DIVISIONS / 2),
getPosition().z);
float scale = MAJOR_GRID_DIVISIONS * spacing;
transform.setTranslation(position);
transform.setScale(scale);
// FIXME: THe line width of 4.0f is not supported anymore, we ll need a workaround
batch->setModelTransform(transform);
DependencyManager::get<GeometryCache>()->renderGrid(*batch, MAJOR_GRID_DIVISIONS, MAJOR_GRID_DIVISIONS, gridColor);
}
const float MINOR_GRID_EDGE = 0.0025f;
const float MAJOR_GRID_EDGE = 0.005f;
DependencyManager::get<GeometryCache>()->renderGrid(*batch, minCorner, maxCorner,
_minorGridRowDivisions, _minorGridColDivisions, MINOR_GRID_EDGE,
_majorGridRowDivisions, _majorGridColDivisions, MAJOR_GRID_EDGE,
gridColor, _drawInFront);
}
}
const render::ShapeKey Grid3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder();
if (getAlpha() != 1.0f) {
builder.withTranslucent();
}
return builder.build();
return render::ShapeKey::Builder().withOwnPipeline();
}
void Grid3DOverlay::setProperties(const QScriptValue& properties) {
Planar3DOverlay::setProperties(properties);
if (properties.property("minorGridWidth").isValid()) {
_minorGridWidth = properties.property("minorGridWidth").toVariant().toFloat();
if (properties.property("followCamera").isValid()) {
_followCamera = properties.property("followCamera").toVariant().toBool();
}
if (properties.property("majorGridEvery").isValid()) {
_majorGridEvery = properties.property("majorGridEvery").toVariant().toInt();
}
if (properties.property("minorGridEvery").isValid()) {
_minorGridEvery = properties.property("minorGridEvery").toVariant().toFloat();
}
updateGrid();
}
QScriptValue Grid3DOverlay::getProperty(const QString& property) {
if (property == "minorGridWidth") {
return _minorGridWidth;
if (property == "followCamera") {
return _followCamera;
}
if (property == "majorGridEvery") {
return _majorGridEvery;
}
if (property == "minorGridEvery") {
return _minorGridEvery;
}
return Planar3DOverlay::getProperty(property);
}
@ -128,3 +127,16 @@ Grid3DOverlay* Grid3DOverlay::createClone() const {
return new Grid3DOverlay(this);
}
void Grid3DOverlay::updateGrid() {
const int MAJOR_GRID_EVERY_MIN = 1;
const float MINOR_GRID_EVERY_MIN = 0.01f;
_majorGridEvery = std::max(_majorGridEvery, MAJOR_GRID_EVERY_MIN);
_minorGridEvery = std::max(_minorGridEvery, MINOR_GRID_EVERY_MIN);
_majorGridRowDivisions = getDimensions().x / _majorGridEvery;
_majorGridColDivisions = getDimensions().y / _majorGridEvery;
_minorGridRowDivisions = getDimensions().x / _minorGridEvery;
_minorGridColDivisions = getDimensions().y / _minorGridEvery;
}

View file

@ -24,6 +24,8 @@ public:
Grid3DOverlay();
Grid3DOverlay(const Grid3DOverlay* grid3DOverlay);
virtual AABox getBounds() const;
virtual void render(RenderArgs* args);
virtual const render::ShapeKey getShapeKey() override;
virtual void setProperties(const QScriptValue& properties);
@ -31,9 +33,21 @@ public:
virtual Grid3DOverlay* createClone() const;
// Grids are UI tools, and may not be intersected (pickable)
virtual bool findRayIntersection(const glm::vec3&, const glm::vec3&, float&, BoxFace&, glm::vec3&) { return false; }
private:
float _minorGridWidth;
int _majorGridEvery;
void updateGrid();
bool _followCamera { true };
int _majorGridEvery { 5 };
float _majorGridRowDivisions;
float _majorGridColDivisions;
float _minorGridEvery { 1.0f };
float _minorGridRowDivisions;
float _minorGridColDivisions;
};
#endif // hifi_Grid3DOverlay_h

View file

@ -20,7 +20,7 @@ public:
Planar3DOverlay();
Planar3DOverlay(const Planar3DOverlay* planar3DOverlay);
AABox getBounds() const;
virtual AABox getBounds() const;
glm::vec2 getDimensions() const { return _dimensions; }
void setDimensions(float value) { _dimensions = glm::vec2(value); }

View file

@ -279,9 +279,10 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
const QAudioFormat& desiredAudioFormat,
QAudioFormat& adjustedAudioFormat) {
// There had been a note here that 2khz was swapping channels. That doesn't seem to be happening
// any more for me. If it does, then we'll want to always resample.
if (!audioDevice.isFormatSupported(desiredAudioFormat)) {
// FIXME: directly using 24khz has a bug somewhere that causes channels to be swapped.
// Continue using our internal resampler, for now.
if (true || !audioDevice.isFormatSupported(desiredAudioFormat)) {
qCDebug(audioclient) << "The desired format for audio I/O is" << desiredAudioFormat;
qCDebug(audioclient, "The desired audio format is not supported by this device");
@ -289,7 +290,7 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
adjustedAudioFormat = desiredAudioFormat;
adjustedAudioFormat.setChannelCount(2);
if (audioDevice.isFormatSupported(adjustedAudioFormat)) {
if (false && audioDevice.isFormatSupported(adjustedAudioFormat)) {
return true;
} else {
adjustedAudioFormat.setChannelCount(1);

View file

@ -260,10 +260,22 @@ QNetworkReply* OBJReader::request(QUrl& url, bool isTest) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest netRequest(url);
QNetworkReply* netReply = isTest ? networkAccessManager.head(netRequest) : networkAccessManager.get(netRequest);
if (!qApp) {
return netReply;
}
QEventLoop loop; // Create an event loop that will quit when we get the finished signal
QObject::connect(netReply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec(); // Nothing is going to happen on this whole run thread until we get this
netReply->waitForReadyRead(-1); // so we might as well block this thread waiting for the response, rather than
bool aboutToQuit { false };
auto connection = QObject::connect(qApp, &QCoreApplication::aboutToQuit, [&] {
aboutToQuit = true;
});
static const int WAIT_TIMEOUT_MS = 500;
while (qApp && !aboutToQuit && !netReply->isReadable()) {
netReply->waitForReadyRead(WAIT_TIMEOUT_MS); // so we might as well block this thread waiting for the response, rather than
}
QObject::disconnect(connection);
return netReply; // trying to sync later on.
}

View file

@ -315,6 +315,8 @@ OffscreenQmlSurface::OffscreenQmlSurface() {
}
OffscreenQmlSurface::~OffscreenQmlSurface() {
QObject::disconnect(&_updateTimer);
QObject::disconnect(qApp);
_renderer->stop();
delete _rootItem;
delete _renderer;
@ -322,6 +324,10 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
delete _qmlEngine;
}
void OffscreenQmlSurface::onAboutToQuit() {
QObject::disconnect(&_updateTimer);
}
void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
_renderer = new OffscreenQmlRenderer(this, shareContext);
_renderer->_renderControl->_renderWindow = _proxyWindow;
@ -334,12 +340,9 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
// When Quick says there is a need to render, we will not render immediately. Instead,
// a timer with a small interval is used to get better performance.
_updateTimer.setInterval(MIN_TIMER_MS);
connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this]{
disconnect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
});
QObject::connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &OffscreenQmlSurface::onAboutToQuit);
_updateTimer.start();
_qmlComponent = new QQmlComponent(_qmlEngine);
_qmlEngine->rootContext()->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
}

View file

@ -74,6 +74,7 @@ signals:
public slots:
void requestUpdate();
void requestRender();
void onAboutToQuit();
private:
QObject* finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f);

View file

@ -0,0 +1,47 @@
<!
// Paint.slh
// libraries/gpu/src
//
// Created by Zach Pomerantz on 2/19/2016.
// Copyright 2016 High Fidelity, Inc.
//
// Fragment shader utility functions. Will fail compilation in vertex shaders.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
!>
<@if not GPU_PAINT_SLH@>
<@def GPU_PAINT_SLH@>
float paintStripe(float value, float offset, float scale, float edge) {
float width = fwidth(value);
float normalizedWidth = width * scale;
float x0 = (value + offset) * scale - normalizedWidth / 2;
float x1 = x0 + normalizedWidth;
float balance = 1.0 - edge;
float i0 = edge * floor(x0) + max(0.0, fract(x0) - balance);
float i1 = edge * floor(x1) + max(0.0, fract(x1) - balance);
float strip = (i1 - i0) / normalizedWidth;
return clamp(strip, 0.0, 1.0);
}
float paintGrid(vec2 value, vec2 offset, vec2 scale, vec2 edge) {
return max(
paintStripe(value.x, offset.x, scale.x, edge.x),
paintStripe(value.y, offset.y, scale.y, edge.y));
}
float paintGridMajor(vec2 value, vec2 offset, vec2 scale, vec2 edge) {
return paintGrid(value, offset, scale, edge);
}
float paintGridMajorMinor(vec2 value, vec4 offset, vec4 scale, vec4 edge) {
return max(
paintGrid(value, offset.xy, scale.xy, edge.xy),
paintGrid(value, offset.zw, scale.zw, edge.zw));
}
<@endif@>

View file

@ -22,17 +22,19 @@
#include "TextureCache.h"
#include "RenderUtilsLogging.h"
#include "standardTransformPNTC_vert.h"
#include "standardDrawTexture_frag.h"
#include "gpu/StandardShaderLib.h"
#include "model/TextureMap.h"
#include "standardTransformPNTC_vert.h"
#include "standardDrawTexture_frag.h"
#include "simple_vert.h"
#include "simple_textured_frag.h"
#include "simple_textured_emisive_frag.h"
#include "grid_frag.h"
//#define WANT_DEBUG
const int GeometryCache::UNKNOWN_ID = -1;
@ -564,186 +566,49 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch) {
renderWireShape(batch, Sphere);
}
void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
int majorRows, int majorCols, float majorEdge,
int minorRows, int minorCols, float minorEdge,
const glm::vec4& color, bool isLayered, int id) {
static const glm::vec2 MIN_TEX_COORD(0.0f, 0.0f);
static const glm::vec2 MAX_TEX_COORD(1.0f, 1.0f);
void GeometryCache::renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color) {
IntPair key(xDivisions, yDivisions);
Vec3Pair colorKey(glm::vec3(color.x, color.y, yDivisions), glm::vec3(color.z, color.y, xDivisions));
int vertices = (xDivisions + 1 + yDivisions + 1) * 2;
if (!_gridBuffers.contains(key)) {
auto verticesBuffer = std::make_shared<gpu::Buffer>();
float* vertexData = new float[vertices * 2];
float* vertex = vertexData;
for (int i = 0; i <= xDivisions; i++) {
float x = (float)i / xDivisions;
*(vertex++) = x;
*(vertex++) = 0.0f;
*(vertex++) = x;
*(vertex++) = 1.0f;
}
for (int i = 0; i <= yDivisions; i++) {
float y = (float)i / yDivisions;
*(vertex++) = 0.0f;
*(vertex++) = y;
*(vertex++) = 1.0f;
*(vertex++) = y;
}
verticesBuffer->append(sizeof(float) * vertices * 2, (gpu::Byte*) vertexData);
delete[] vertexData;
_gridBuffers[key] = verticesBuffer;
}
if (!_gridColors.contains(colorKey)) {
auto colorBuffer = std::make_shared<gpu::Buffer>();
_gridColors[colorKey] = colorBuffer;
int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
((int(color.y * 255.0f) & 0xFF) << 8) |
((int(color.z * 255.0f) & 0xFF) << 16) |
((int(color.w * 255.0f) & 0xFF) << 24);
int* colorData = new int[vertices];
int* colorDataAt = colorData;
for(int v = 0; v < vertices; v++) {
*(colorDataAt++) = compactColor;
}
colorBuffer->append(sizeof(int) * vertices, (gpu::Byte*) colorData);
delete[] colorData;
}
gpu::BufferPointer verticesBuffer = _gridBuffers[key];
gpu::BufferPointer colorBuffer = _gridColors[colorKey];
const int VERTICES_SLOT = 0;
const int COLOR_SLOT = 1;
auto streamFormat = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
batch.setInputFormat(streamFormat);
batch.setInputBuffer(VERTICES_SLOT, verticesView);
batch.setInputBuffer(COLOR_SLOT, colorView);
batch.draw(gpu::LINES, vertices, 0);
}
// TODO: why do we seem to create extra BatchItemDetails when we resize the window?? what's that??
void GeometryCache::renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id) {
#ifdef WANT_DEBUG
qCDebug(renderutils) << "GeometryCache::renderGrid(x["<<x<<"], "
"y["<<y<<"],"
"w["<<width<<"],"
"h["<<height<<"],"
"rows["<<rows<<"],"
"cols["<<cols<<"],"
" id:"<<id<<")...";
#endif
bool registered = (id != UNKNOWN_ID);
Vec3Pair key(glm::vec3(x, y, width), glm::vec3(height, rows, cols));
Vec3Pair colorKey(glm::vec3(color.x, color.y, rows), glm::vec3(color.z, color.y, cols));
Vec2FloatPair majorKey(glm::vec2(majorRows, majorCols), majorEdge);
Vec2FloatPair minorKey(glm::vec2(minorRows, minorCols), minorEdge);
Vec2FloatPairPair key(majorKey, minorKey);
int vertices = (cols + 1 + rows + 1) * 2;
if ((registered && (!_registeredAlternateGridBuffers.contains(id) || _lastRegisteredAlternateGridBuffers[id] != key))
|| (!registered && !_alternateGridBuffers.contains(key))) {
// Make the gridbuffer
if ((registered && (!_registeredGridBuffers.contains(id) || _lastRegisteredGridBuffer[id] != key)) ||
(!registered && !_gridBuffers.contains(key))) {
GridSchema gridSchema;
GridBuffer gridBuffer = std::make_shared<gpu::Buffer>(sizeof(GridSchema), (const gpu::Byte*) &gridSchema);
if (registered && _registeredAlternateGridBuffers.contains(id)) {
_registeredAlternateGridBuffers[id].reset();
#ifdef WANT_DEBUG
qCDebug(renderutils) << "renderGrid()... RELEASING REGISTERED VERTICES BUFFER";
#endif
if (registered && _registeredGridBuffers.contains(id)) {
gridBuffer = _registeredGridBuffers[id];
}
auto verticesBuffer = std::make_shared<gpu::Buffer>();
if (registered) {
_registeredAlternateGridBuffers[id] = verticesBuffer;
_lastRegisteredAlternateGridBuffers[id] = key;
_registeredGridBuffers[id] = gridBuffer;
_lastRegisteredGridBuffer[id] = key;
} else {
_alternateGridBuffers[key] = verticesBuffer;
_gridBuffers[key] = gridBuffer;
}
float* vertexData = new float[vertices * 2];
float* vertex = vertexData;
int dx = width / cols;
int dy = height / rows;
int tx = x;
int ty = y;
// Draw horizontal grid lines
for (int i = rows + 1; --i >= 0; ) {
*(vertex++) = x;
*(vertex++) = ty;
*(vertex++) = x + width;
*(vertex++) = ty;
ty += dy;
}
// Draw vertical grid lines
for (int i = cols + 1; --i >= 0; ) {
*(vertex++) = tx;
*(vertex++) = y;
*(vertex++) = tx;
*(vertex++) = y + height;
tx += dx;
}
verticesBuffer->append(sizeof(float) * vertices * 2, (gpu::Byte*) vertexData);
delete[] vertexData;
gridBuffer.edit<GridSchema>().period = glm::vec4(majorRows, majorCols, minorRows, minorCols);
gridBuffer.edit<GridSchema>().offset.x = -(majorEdge / majorRows) / 2;
gridBuffer.edit<GridSchema>().offset.y = -(majorEdge / majorCols) / 2;
gridBuffer.edit<GridSchema>().offset.z = -(minorEdge / minorRows) / 2;
gridBuffer.edit<GridSchema>().offset.w = -(minorEdge / minorCols) / 2;
gridBuffer.edit<GridSchema>().edge = glm::vec4(glm::vec2(majorEdge),
// If rows or columns are not set, do not draw minor gridlines
glm::vec2((minorRows != 0 && minorCols != 0) ? minorEdge : 0.0f));
}
if (!_gridColors.contains(colorKey)) {
auto colorBuffer = std::make_shared<gpu::Buffer>();
_gridColors[colorKey] = colorBuffer;
// Set the grid pipeline
useGridPipeline(batch, registered ? _registeredGridBuffers[id] : _gridBuffers[key], isLayered);
int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
((int(color.y * 255.0f) & 0xFF) << 8) |
((int(color.z * 255.0f) & 0xFF) << 16) |
((int(color.w * 255.0f) & 0xFF) << 24);
int* colorData = new int[vertices];
int* colorDataAt = colorData;
for(int v = 0; v < vertices; v++) {
*(colorDataAt++) = compactColor;
}
colorBuffer->append(sizeof(int) * vertices, (gpu::Byte*) colorData);
delete[] colorData;
}
gpu::BufferPointer verticesBuffer = registered ? _registeredAlternateGridBuffers[id] : _alternateGridBuffers[key];
gpu::BufferPointer colorBuffer = _gridColors[colorKey];
const int VERTICES_SLOT = 0;
const int COLOR_SLOT = 1;
auto streamFormat = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
batch.setInputFormat(streamFormat);
batch.setInputBuffer(VERTICES_SLOT, verticesView);
batch.setInputBuffer(COLOR_SLOT, colorView);
batch.draw(gpu::LINES, vertices, 0);
renderQuad(batch, minCorner, maxCorner, MIN_TEX_COORD, MAX_TEX_COORD, color, id);
}
void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, const glm::vec4& color) {
@ -1772,7 +1637,6 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
auto state = std::make_shared<gpu::State>();
// enable decal blend
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
@ -1792,6 +1656,30 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
}
}
void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered) {
if (!_gridPipeline) {
auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert));
auto ps = gpu::Shader::createPixel(std::string(grid_frag));
auto program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::makeProgram((*program));
_gridSlot = program->getBuffers().findLocation("gridBuffer");
auto stateLayered = std::make_shared<gpu::State>();
stateLayered->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
_gridPipelineLayered = gpu::Pipeline::create(program, stateLayered);
auto state = std::make_shared<gpu::State>(stateLayered->getValues());
const float DEPTH_BIAS = 0.001f;
state->setDepthBias(DEPTH_BIAS);
state->setDepthTest(true, false, gpu::LESS_EQUAL);
_gridPipeline = gpu::Pipeline::create(program, state);
}
gpu::PipelinePointer pipeline = isLayered ? _gridPipelineLayered : _gridPipeline;
batch.setPipeline(pipeline);
batch.setUniformBuffer(_gridSlot, gridBuffer);
}
class SimpleProgramKey {

View file

@ -31,8 +31,8 @@
class SimpleProgramKey;
typedef glm::vec3 Vec3Key;
typedef QPair<glm::vec2, float> Vec2FloatPair;
typedef QPair<Vec2FloatPair, Vec2FloatPair> Vec2FloatPairPair;
typedef QPair<glm::vec2, glm::vec2> Vec2Pair;
typedef QPair<Vec2Pair, Vec2Pair> Vec2PairPair;
typedef QPair<glm::vec3, glm::vec3> Vec3Pair;
@ -43,9 +43,10 @@ typedef QPair<Vec3Pair, Vec4Pair> Vec3PairVec4Pair;
typedef QPair<Vec4Pair, glm::vec4> Vec4PairVec4;
typedef QPair<Vec4Pair, Vec4Pair> Vec4PairVec4Pair;
inline uint qHash(const glm::vec2& v, uint seed) {
inline uint qHash(const Vec2FloatPairPair& v, uint seed) {
// multiply by prime numbers greater than the possible size
return qHash(v.x + 5009 * v.y, seed);
return qHash(v.first.first.x + 5009 * v.first.first.y + 5011 * v.first.second +
5021 * v.second.first.x + 5023 * v.second.first.y + 5039 * v.second.second);
}
inline uint qHash(const Vec2Pair& v, uint seed) {
@ -203,8 +204,14 @@ public:
void renderWireSphere(gpu::Batch& batch);
size_t getSphereTriangleCount();
void renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color);
void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id = UNKNOWN_ID);
void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
int majorRows, int majorCols, float majorEdge,
int minorRows, int minorCols, float minorEdge,
const glm::vec4& color, bool isLayered, int id = UNKNOWN_ID);
void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
int rows, int cols, float edge, const glm::vec4& color, bool isLayered, int id = UNKNOWN_ID) {
renderGrid(batch, minCorner, maxCorner, rows, cols, edge, 0, 0, 0.0f, color, isLayered, id);
}
void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);
@ -310,6 +317,19 @@ private:
gpu::BufferPointer _shapeVertices{ std::make_shared<gpu::Buffer>() };
gpu::BufferPointer _shapeIndices{ std::make_shared<gpu::Buffer>() };
class GridSchema {
public:
// data is arranged as majorRow, majorCol, minorRow, minorCol
glm::vec4 period;
glm::vec4 offset;
glm::vec4 edge;
};
using GridBuffer = gpu::BufferView;
void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered);
gpu::PipelinePointer _gridPipeline;
gpu::PipelinePointer _gridPipelineLayered;
int _gridSlot;
class BatchItemDetails {
public:
static int population;
@ -366,11 +386,9 @@ private:
QHash<Vec3PairVec2Pair, BatchItemDetails> _dashedLines;
QHash<int, BatchItemDetails> _registeredDashedLines;
QHash<IntPair, gpu::BufferPointer> _gridBuffers;
QHash<Vec3Pair, gpu::BufferPointer> _alternateGridBuffers;
QHash<int, gpu::BufferPointer> _registeredAlternateGridBuffers;
QHash<int, Vec3Pair> _lastRegisteredAlternateGridBuffers;
QHash<Vec3Pair, gpu::BufferPointer> _gridColors;
QHash<int, Vec2FloatPairPair> _lastRegisteredGridBuffer;
QHash<Vec2FloatPairPair, GridBuffer> _gridBuffers;
QHash<int, GridBuffer> _registeredGridBuffers;
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;

View file

@ -0,0 +1,44 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// grid.slf
// fragment shader
//
// Created by Zach Pomerantz on 2/16/2016.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Paint.slh@>
struct Grid {
vec4 period;
vec4 offset;
vec4 edge;
};
uniform gridBuffer { Grid grid; };
Grid getGrid() { return grid; };
in vec2 varTexCoord0;
in vec4 varColor;
out vec4 outFragColor;
void main(void) {
Grid grid = getGrid();
float alpha;
if (grid.edge.z == 0.0) {
alpha = paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy);
} else {
alpha = paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge);
}
if (alpha == 0.0) {
discard;
}
outFragColor = vec4(varColor.xyz, varColor.w * alpha);
}

View file

@ -144,7 +144,12 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
ScriptEngine::~ScriptEngine() {
qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename();
DependencyManager::get<ScriptEngines>()->removeScriptEngine(this);
auto scriptEngines = DependencyManager::get<ScriptEngines>();
if (scriptEngines) {
scriptEngines->removeScriptEngine(this);
} else {
qCWarning(scriptengine) << "Script destroyed after ScriptEngines!";
}
}
void ScriptEngine::disconnectNonEssentialSignals() {

View file

@ -112,6 +112,7 @@ void OffscreenUi::create(QOpenGLContext* context) {
}
void OffscreenUi::show(const QUrl& url, const QString& name, std::function<void(QQmlContext*, QObject*)> f) {
emit showDesktop();
QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name);
// First load?
if (!item) {
@ -127,6 +128,7 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<voi
QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name);
// Already loaded?
if (item) {
emit showDesktop();
item->setVisible(!item->isVisible());
return;
}
@ -134,6 +136,7 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<voi
load(url, f);
item = getRootItem()->findChild<QQuickItem*>(name);
if (item && !item->isVisible()) {
emit showDesktop();
item->setVisible(true);
}
}
@ -439,6 +442,8 @@ void OffscreenUi::createDesktop(const QUrl& url) {
new VrMenu(this);
new KeyboardFocusHack();
connect(_desktop, SIGNAL(showDesktop()), this, SLOT(showDesktop()));
}
QQuickItem* OffscreenUi::getDesktop() {

View file

@ -106,6 +106,9 @@ public:
// Compatibility with QInputDialog::getItem
static QString getItem(void *ignored, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
signals:
void showDesktop();
private:
QString fileDialog(const QVariantMap& properties);