Merge branch 'master' of github.com:highfidelity/hifi into fix/light-intensity

This commit is contained in:
Zach Pomerantz 2016-02-24 16:24:09 -08:00
commit c2ed5e5474
109 changed files with 3032 additions and 714 deletions

View file

@ -564,7 +564,7 @@ function MyController(hand) {
"additiveBlending": 0,
"textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png"
}
this.particleBeamObject = Entities.addEntity(particleBeamPropertiesObject);
};
@ -1588,7 +1588,9 @@ function MyController(hand) {
ids.forEach(function(id) {
var props = Entities.getEntityProperties(id, ["boundingBox", "name"]);
if (props.name === 'pointer') {
if (!props ||
!props.boundingBox ||
props.name === 'pointer') {
return;
}
var entityMinPoint = props.boundingBox.brn;

47
examples/depthReticle.js Normal file
View file

@ -0,0 +1,47 @@
// depthReticle.js
// examples
//
// Created by Brad Hefta-Gaub on 2/23/16.
// Copyright 2016 High Fidelity, Inc.
//
// When used in HMD, this script will make the reticle depth track to any clickable item in view.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var APPARENT_2D_OVERLAY_DEPTH = 1.0;
var APPARENT_MAXIMUM_DEPTH = 100.0; // this is a depth at which things all seem sufficiently distant
var lastDepthCheckTime = 0;
Script.update.connect(function(deltaTime) {
var TIME_BETWEEN_DEPTH_CHECKS = 100;
var timeSinceLastDepthCheck = Date.now() - lastDepthCheckTime;
if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) {
var reticlePosition = Reticle.position;
// first check the 2D Overlays
if (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(reticlePosition)) {
Reticle.setDepth(APPARENT_2D_OVERLAY_DEPTH);
} else {
var pickRay = Camera.computePickRay(reticlePosition.x, reticlePosition.y);
// Then check the 3D overlays
var result = Overlays.findRayIntersection(pickRay);
if (!result.intersects) {
// finally check the entities
result = Entities.findRayIntersection(pickRay, true);
}
// If either the overlays or entities intersect, then set the reticle depth to
// the distance of intersection
if (result.intersects) {
Reticle.setDepth(result.distance);
} else {
// if nothing intersects... set the depth to some sufficiently large depth
Reticle.setDepth(APPARENT_MAXIMUM_DEPTH);
}
}
}
});

View file

@ -75,8 +75,7 @@
function createEmitNumberPropertyUpdateFunction(propertyName, decimals) {
decimals = decimals == undefined ? 4 : decimals;
return function() {
var value = +this.value;
value = +value.toFixed(decimals);
var value = parseFloat(this.value).toFixed(decimals);
EventBridge.emitWebEvent(
'{ "type":"update", "properties":{"' + propertyName + '":' + value + '}}'

View file

@ -32,11 +32,9 @@ ParticleExplorerTool = function() {
that.destroyWebView = function() {
if (!that.webView) {
print("EBL CAN'ZT CLOSE WEB VIEW- IT DOESNT EXISTS!")
return;
}
print("EBL CLOSING WEB VIEW")
that.webView.close();
that.webView = null;
that.activeParticleEntity = 0;

View file

@ -0,0 +1,101 @@
//
// particleOrientationTest.js
// examples/tests
//
// Created by Piper.Peppercorn.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var emitterBone = 'Head'
var particleEntities = [];
function emitter(jointName) {
var jointID = MyAvatar.jointNames.indexOf(jointName);
var newEmitter = Entities.addEntity({
name: 'particleEmitter ' + jointName,
type: 'ParticleEffect',
emitterShouldTrail: true,
textures: 'https://dl.dropboxusercontent.com/u/96759331/ParticleTest.png',
position: Vec3.sum(MyAvatar.getAbsoluteJointRotationInObjectFrame(jointID), MyAvatar.position),
parentJointIndex: jointID,
position: MyAvatar.getJointPosition(jointName),
color: {
red: 255,
green: 255,
blue: 255
},
isEmitting: 1,
maxParticles: 1,
lifespan: 2.0
,
emitRate: 1,
emitSpeed: 0.0,
speedSpread: 0.0,
/*
emitOrientation: {
x: -0.7035577893257141,
y: -0.000015259007341228426,
z: -0.000015259007341228426,
w: 1.7106381058692932
},
*/
emitOrientation: {
x:0,
y: 0,
z: 0,
w: Math.PI
},
emitRadiusStart: 0,
polarStart: 0,
polarFinish: 0,
azimuthFinish: 3.1415927410125732,
emitAcceleration: {
x: 0,
y: 0,
z: 0
},
accelerationSpread: {
x: 0,
y: 0,
z: 0
},
particleRadius: 2.0,
radiusSpread: 1.0,
radiusStart: 2.0,
radiusFinish: 2.0,
colorSpread: {
red: 0,
green: 0,
blue: 0
},
colorStart: {
red: 255,
green: 255,
blue: 255
},
colorFinish: {
red: 255,
green: 255,
blue: 255
},
alpha: 1,
alphaSpread: 0,
alphaStart: 1,
alphaFinish: 1
});
return newEmitter;
}
Script.scriptEnding.connect(function() {
for (var i = 0; i < particleEntities.length; i++) {
// Fixes a crash on shutdown:
Entities.editEntity(particleEntities[i], { parentID: '' });
Entities.deleteEntity(particleEntities[i]);
}
});
particleEntities.push(emitter(emitterBone));

View file

@ -9,11 +9,6 @@
"Enabled": {
"enabled": true
}
},
"Antialiasing": {
"Enabled": {
"enabled": true
}
}
}
}

Binary file not shown.

View file

@ -0,0 +1,93 @@
Copyright (c) 2009, Mark Simonson (http://www.ms-studio.com, mark@marksimonson.com),
with Reserved Font Name Anonymous Pro.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

View file

@ -0,0 +1,94 @@
Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
with Reserved Font Name < Fira >,
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,94 @@
Copyright (c) 2010, Matt McInerney (matt@pixelspread.com),
Copyright (c) 2011, Pablo Impallari (www.impallari.com|impallari@gmail.com),
Copyright (c) 2011, Rodrigo Fuenzalida (www.rfuenzalida.com|hello@rfuenzalida.com), with Reserved Font Name Raleway
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

View file

@ -5,6 +5,8 @@ import QtQuick.Controls 1.2
Item {
anchors.fill: parent
anchors.leftMargin: 300
objectName: "StatsItem"
Hifi.Stats {
id: root
objectName: "Stats"
@ -27,6 +29,7 @@ Item {
MouseArea {
anchors.fill: parent
onClicked: { root.expanded = !root.expanded; }
hoverEnabled: true
}
Column {
@ -83,6 +86,7 @@ Item {
MouseArea {
anchors.fill: parent
onClicked: { root.expanded = !root.expanded; }
hoverEnabled: true
}
Column {
id: pingCol
@ -123,6 +127,7 @@ Item {
MouseArea {
anchors.fill: parent
onClicked: { root.expanded = !root.expanded; }
hoverEnabled: true
}
Column {
id: geoCol
@ -172,6 +177,7 @@ Item {
MouseArea {
anchors.fill: parent
onClicked: { root.expanded = !root.expanded; }
hoverEnabled: true
}
Column {
id: octreeCol
@ -186,42 +192,29 @@ Item {
color: root.fontColor;
font.pixelSize: root.fontSize
visible: root.expanded;
text: "\tItems Rendered Opaque: " + root.opaqueRendered +
" / Translucent: " + root.translucentRendered +
" / Shadow: " + root.shadowRendered +
" / Other: " + root.otherRendered;
text: "Items rendered / considered: " +
root.itemRendered + " / " + root.itemConsidered;
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
visible: root.expanded;
text: "\tOpaque considered: " + root.opaqueConsidered +
" / Out of view: " + root.opaqueOutOfView +
" / Too small: " + root.opaqueTooSmall;
text: " out of view: " + root.itemOutOfView +
" too small: " + root.itemTooSmall;
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
visible: root.expanded;
text: "\tShadow considered: " + root.shadowConsidered +
" / Out of view: " + root.shadowOutOfView +
" / Too small: " + root.shadowTooSmall;
text: "Shadows rendered / considered: " +
root.shadowRendered + " / " + root.shadowConsidered;
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
visible: root.expanded;
text: "\tTranslucent considered: " + root.translucentConsidered +
" / Out of view: " + root.translucentOutOfView +
" / Too small: " + root.translucentTooSmall;
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
visible: root.expanded;
text: "\tOther considered: " + root.otherConsidered +
" / Out of view: " + root.otherOutOfView +
" / Too small: " + root.otherTooSmall;
text: " out of view: " + root.shadowOutOfView +
" too small: " + root.shadowTooSmall;
}
Text {
color: root.fontColor;

View file

@ -20,8 +20,10 @@ Windows.Window {
property string newTabSource
property alias tabView: tabView
onParentChanged: {
x = 120;
y = 120;
if (parent) {
x = 120;
y = 120;
}
}
Settings {

View file

@ -0,0 +1,54 @@
//
// Button.qml
//
// Created by David Rowe on 16 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4 as Original
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
Original.Button {
id: button
property int color: 0
width: 120
height: 30
style: ButtonStyle {
background: Rectangle {
radius: hifi.buttons.radius
gradient: Gradient {
GradientStop {
position: 0.2
color: enabled
? (!pressed && button.color != hifi.buttons.black || (!hovered || pressed) && button.color == hifi.buttons.black
? hifi.buttons.colorStart[button.color] : hifi.buttons.colorFinish[button.color])
: hifi.buttons.colorStart[hifi.buttons.white]
}
GradientStop {
position: 1.0
color: enabled
? ((!hovered || pressed) && button.color != hifi.buttons.black || !pressed && button.color == hifi.buttons.black
? hifi.buttons.colorFinish[button.color] : hifi.buttons.colorStart[button.color])
: hifi.buttons.colorFinish[hifi.buttons.white]
}
}
}
label: RalewayBold {
font.capitalization: Font.AllUppercase
color: enabled ? hifi.buttons.textColor[button.color] : hifi.colors.lightGrayText
size: hifi.fontSizes.buttonLabel
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: control.text
}
}
}

View file

@ -0,0 +1,65 @@
//
// StaticSection.qml
//
// Created by David Rowe on 16 Feb 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
//
import QtQuick 2.5
import "../styles-uit"
Column {
property string name: "Static Section"
property bool hasSeparator: false
spacing: hifi.dimensions.contentSpacing.y
anchors {
left: parent.left
leftMargin: hifi.dimensions.contentMargin.x
right: parent.right
rightMargin: hifi.dimensions.contentMargin.x
}
VerticalSpacer { }
Item {
visible: hasSeparator
anchors.top: sectionName.top
Rectangle {
width: frame.width
height: 1
color: hifi.colors.baseGrayShadow
x: -hifi.dimensions.contentMargin.x
anchors.bottom: highlight.top
}
Rectangle {
id: highlight
width: frame.width
height: 1
color: hifi.colors.baseGrayHighlight
x: -hifi.dimensions.contentMargin.x
anchors.bottom: parent.top
}
}
RalewayRegular {
id: sectionName
text: parent.name
size: hifi.fontSizes.sectionName
font.capitalization: Font.AllUppercase
color: hifi.colors.lightGrayText
verticalAlignment: Text.AlignBottom
height: {
if (hasSeparator) {
hifi.dimensions.contentMargin.y
}
}
}
}

View file

@ -0,0 +1,181 @@
//
// Table.qml
//
// Created by David Rowe on 18 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
TableView {
id: tableView
property var tableModel: ListModel { }
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
model: tableModel
TableViewColumn {
role: "name"
}
anchors { left: parent.left; right: parent.right }
headerVisible: false
headerDelegate: Item { } // Fix OSX QML bug that displays scrollbar starting too low.
// Use rectangle to draw border with rounded corners.
frameVisible: false
Rectangle {
color: "#00000000"
anchors { fill: parent; margins: -2 }
radius: hifi.dimensions.borderRadius
border.color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
border.width: 2
}
anchors.margins: 2 // Shrink TableView to lie within border.
backgroundVisible: true
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
style: TableViewStyle {
// Needed in order for rows to keep displaying rows after end of table entries.
backgroundColor: parent.isLightColorScheme ? hifi.colors.tableRowLightEven : hifi.colors.tableRowDarkEven
alternateBackgroundColor: parent.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
handle: Item {
id: scrollbarHandle
implicitWidth: 6
Rectangle {
anchors {
fill: parent
leftMargin: 2 // Move it right
rightMargin: -2 // ""
topMargin: 3 // Shrink vertically
bottomMargin: 3 // ""
}
radius: 3
color: hifi.colors.tableScrollHandle
}
}
scrollBarBackground: Item {
implicitWidth: 10
Rectangle {
anchors {
fill: parent
margins: -1 // Expand
}
color: hifi.colors.baseGrayHighlight
}
Rectangle {
anchors {
fill: parent
margins: 1 // Shrink
}
radius: 4
color: hifi.colors.tableScrollBackground
}
}
incrementControl: Item {
visible: false
}
decrementControl: Item {
visible: false
}
}
rowDelegate: Rectangle {
height: (styleData.selected ? 1.8 : 1) * hifi.dimensions.tableRowHeight
color: styleData.selected
? hifi.colors.primaryHighlight
: tableView.isLightColorScheme
? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd)
: (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd)
}
itemDelegate: Item {
anchors {
left: parent ? parent.left : undefined
leftMargin: hifi.dimensions.tablePadding
right: parent ? parent.right : undefined
rightMargin: hifi.dimensions.tablePadding
}
FiraSansSemiBold {
id: textItem
text: styleData.value
size: hifi.fontSizes.tableText
color: colorScheme == hifi.colorSchemes.light
? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight)
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
anchors {
left: parent.left
right: parent.right
top: parent.top
topMargin: 3
}
// FIXME: Put reload item in tableModel passed in from RunningScripts.
HiFiGlyphs {
id: reloadButton
text: hifi.glyphs.reloadSmall
color: parent.color
anchors {
top: parent.top
right: stopButton.left
verticalCenter: parent.verticalCenter
}
MouseArea {
anchors { fill: parent; margins: -2 }
onClicked: reloadScript(model.url)
}
}
// FIXME: Put stop item in tableModel passed in from RunningScripts.
HiFiGlyphs {
id: stopButton
text: hifi.glyphs.closeSmall
color: parent.color
anchors {
top: parent.top
right: parent.right
verticalCenter: parent.verticalCenter
}
MouseArea {
anchors { fill: parent; margins: -2 }
onClicked: stopScript(model.url)
}
}
}
// FIXME: Automatically use aux. information from tableModel
FiraSansSemiBold {
text: tableModel.get(styleData.row) ? tableModel.get(styleData.row).url : ""
elide: Text.ElideMiddle
size: hifi.fontSizes.tableText
color: colorScheme == hifi.colorSchemes.light
? (styleData.selected ? hifi.colors.black : hifi.colors.lightGray)
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
anchors {
top: textItem.bottom
left: parent.left
right: parent.right
}
visible: styleData.selected
}
}
}

View file

@ -0,0 +1,25 @@
//
// TextEdit.qml
//
// Created by Bradley Austin Davis on 24 Apr 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
TextEdit {
property real size: 32
FontLoader { id: ralewaySemibold; source: "../../fonts/Raleway-Semibold.ttf"; }
font.family: ralewaySemibold.name
font.pointSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
}

View file

@ -0,0 +1,59 @@
//
// TextField.qml
//
// Created by David Rowe on 17 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
TextField {
id: textField
property int colorScheme: hifi.colorSchemes.light
property string label: ""
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
font.family: firaSansSemiBold.name
font.pixelSize: hifi.fontSizes.textFieldInput
height: implicitHeight + 4 // Make surrounding box higher so that highlight is vertically centered.
placeholderText: textField.label // Instead of separate label (see below).
style: TextFieldStyle {
textColor: textField.colorScheme == hifi.colorSchemes.light
? (textField.focus ? hifi.colors.black : hifi.colors.lightGray)
: (textField.focus ? hifi.colors.white : hifi.colors.lightGrayText)
background: Rectangle {
color: textField.colorScheme == hifi.colorSchemes.light
? (textField.focus ? hifi.colors.white : hifi.colors.lightGray)
: (textField.focus ? hifi.colors.black : hifi.colors.baseGrayShadow)
border.color: hifi.colors.primaryHighlight
border.width: textField.focus ? 1 : 0
}
placeholderTextColor: hifi.colors.lightGray
selectedTextColor: hifi.colors.black
selectionColor: hifi.colors.primaryHighlight
padding.left: hifi.dimensions.textPadding
padding.right: hifi.dimensions.textPadding
}
/*
// Separate label instead of placeholderText.
RalewaySemibold {
text: textField.label
size: hifi.fontSizes.inputLabel
color: hifi.colors.lightGrayText
anchors.left: parent.left
anchors.bottom: parent.top
anchors.bottomMargin: 4
visible: label != ""
}
*/
}

View file

@ -0,0 +1,147 @@
//
// Table.qml
//
// Created by David Rowe on 17 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
TreeView {
id: treeView
property var treeModel: ListModel { }
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
model: treeModel
TableViewColumn {
role: "display";
}
anchors { left: parent.left; right: parent.right }
headerVisible: false
headerDelegate: Item { } // Fix OSX QML bug that displays scrollbar starting too low.
// Use rectangle to draw border with rounded corners.
frameVisible: false
Rectangle {
color: "#00000000"
anchors.fill: parent
radius: hifi.dimensions.borderRadius
border.color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
border.width: 2
anchors.margins: -2
}
anchors.margins: 2 // Shrink TreeView to lie within border.
backgroundVisible: true
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
style: TreeViewStyle {
// Needed in order for rows to keep displaying rows after end of table entries.
backgroundColor: parent.isLightColorScheme ? hifi.colors.tableRowLightEven : hifi.colors.tableRowDarkEven
alternateBackgroundColor: parent.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
branchDelegate: HiFiGlyphs {
text: styleData.isExpanded ? hifi.glyphs.disclosureCollapse : hifi.glyphs.disclosureExpand
size: hifi.fontSizes.tableText * 2.5 // tableText is in points; proportionately scale to pixels
color: colorScheme == hifi.colorSchemes.light
? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight)
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
anchors {
left: parent ? parent.left : undefined
leftMargin: hifi.dimensions.tablePadding / 2
}
}
handle: Item {
id: scrollbarHandle
implicitWidth: 6
Rectangle {
anchors {
fill: parent
leftMargin: 2 // Move it right
rightMargin: -2 // ""
topMargin: 3 // Shrink vertically
bottomMargin: 3 // ""
}
radius: 3
color: hifi.colors.tableScrollHandle
}
}
scrollBarBackground: Item {
implicitWidth: 10
Rectangle {
anchors {
fill: parent
margins: -1 // Expand
}
color: hifi.colors.baseGrayHighlight
}
Rectangle {
anchors {
fill: parent
margins: 1 // Shrink
}
radius: 4
color: hifi.colors.tableScrollBackground
}
}
incrementControl: Item {
visible: false
}
decrementControl: Item {
visible: false
}
}
rowDelegate: Rectangle {
height: hifi.dimensions.tableRowHeight
color: styleData.selected
? hifi.colors.primaryHighlight
: treeView.isLightColorScheme
? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd)
: (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd)
}
itemDelegate: FiraSansSemiBold {
anchors {
left: parent ? parent.left : undefined
leftMargin: (2 + styleData.depth) * hifi.dimensions.tablePadding
right: parent ? parent.right : undefined
rightMargin: hifi.dimensions.tablePadding
verticalCenter: parent ? parent.verticalCenter : undefined
}
text: styleData.value
size: hifi.fontSizes.tableText
color: colorScheme == hifi.colorSchemes.light
? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight)
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
}
onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index)
onActivated: {
var path = scriptsModel.data(index, 0x100)
if (path) {
loadScript(path)
}
}
}

View file

@ -0,0 +1,18 @@
//
// VerticalSpacer.qml
//
// Created by David Rowe on 16 Feb 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
//
import QtQuick 2.5
import "../styles-uit"
Item {
width: 1 // Must be non-zero
height: hifi.dimensions.contentSpacing.y
}

View file

@ -1,21 +1,33 @@
//
// Desktop.qml
//
// Created by Bradley Austin Davis on 15 Apr 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs;
import "../dialogs"
import "../menus"
import "../js/Utils.js" as Utils
// This is our primary 'desktop' object to which all VR dialogs and
// windows will be childed.
// This is our primary 'desktop' object to which all VR dialogs and windows are childed.
FocusScope {
id: desktop
anchors.fill: parent;
objectName: "desktop"
anchors.fill: parent
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
@ -148,12 +160,12 @@ FocusScope {
}
Component.onCompleted: {
offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged);
//offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged);
focusHack.start();
}
function onWindowFocusChanged() {
console.log("Focus item is " + offscreenWindow.activeFocusItem);
//console.log("Focus item is " + offscreenWindow.activeFocusItem);
// FIXME this needs more testing before it can go into production
// and I already cant produce any way to have a modal dialog lose focus
@ -217,6 +229,8 @@ FocusScope {
}
reposition(targetWindow);
showDesktop();
}
function reposition(item) {
@ -304,6 +318,7 @@ FocusScope {
Rectangle {
id: focusDebugger;
objectName: "focusDebugger"
z: 9999; visible: false; color: "red"
ColorAnimation on color { from: "#7fffff00"; to: "#7f0000ff"; duration: 1000; loops: 9999 }
}
@ -314,8 +329,5 @@ FocusScope {
enabled: DebugQML
onTriggered: focusDebugger.visible = !focusDebugger.visible
}
}

View file

@ -1,7 +1,18 @@
//
// FocusHack.qml
//
// Created by Bradley Austin Davis on 21 Jan 2015
// 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
//
import QtQuick 2.5
FocusScope {
id: root
objectName: "FocusHack"
TextInput {
id: textInput;
@ -21,6 +32,3 @@ FocusScope {
focusTimer.running = true;
}
}

View file

@ -1,13 +1,23 @@
//
// Desktop.qml
//
// Created by Bradley Austin Davis on 25 Apr 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.2
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import "../controls"
import "../styles"
import "../windows"
import "../controls-uit"
import "../styles-uit"
import "../windows-uit"
import "messageDialog"
// FIXME respect default button functionality
ModalWindow {
id: root
HifiConstants { id: hifi }
@ -32,96 +42,91 @@ ModalWindow {
property alias detailedText: detailedText.text
property alias text: mainTextContainer.text
property alias informativeText: informativeTextContainer.text
onIconChanged: iconHolder.updateIcon();
onIconChanged: updateIcon();
property int buttons: OriginalDialogs.StandardButton.Ok
property int icon: OriginalDialogs.StandardIcon.NoIcon
property string iconText: ""
property int defaultButton: OriginalDialogs.StandardButton.NoButton;
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
focus: defaultButton === OriginalDialogs.StandardButton.NoButton
Rectangle {
function updateIcon() {
if (!root) {
return;
}
switch (root.icon) {
case OriginalDialogs.StandardIcon.Information:
iconText = "\uF05A";
break;
case OriginalDialogs.StandardIcon.Question:
iconText = "\uF059"
break;
case OriginalDialogs.StandardIcon.Warning:
iconText = "\uF071"
break;
case OriginalDialogs.StandardIcon.Critical:
iconText = "\uF057"
break;
default:
iconText = ""
}
}
Item {
id: messageBox
clip: true
anchors.fill: parent
radius: 4
color: "white"
width: pane.width
height: pane.height
QtObject {
id: d
readonly property real spacing: hifi.layout.spacing
readonly property real outerSpacing: hifi.layout.spacing * 2
readonly property real spacing: hifi.dimensions.contentSpacing.x
readonly property real outerSpacing: hifi.dimensions.contentSpacing.y
readonly property int minWidth: 480
readonly property int maxWdith: 1280
readonly property int minHeight: 160
readonly property int minHeight: 120
readonly property int maxHeight: 720
function resize() {
var targetWidth = iconHolder.width + mainTextContainer.width + d.spacing * 6
var targetHeight = mainTextContainer.implicitHeight + informativeTextContainer.implicitHeight + d.spacing * 8 + buttons.height + details.height
var targetWidth = mainTextContainer.width
var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y
+ (informativeTextContainer.text != "" ? informativeTextContainer.contentHeight + 3 * hifi.dimensions.contentSpacing.y : 0)
+ buttons.height
+ (content.state === "expanded" ? details.implicitHeight + hifi.dimensions.contentSpacing.y : 0)
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth)
root.height = (targetHeight < d.minHeight) ? d.minHeight: ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)
}
}
FontAwesome {
id: iconHolder
size: 48
anchors {
left: parent.left
top: parent.top
margins: d.spacing * 2
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
style: Text.Outline; styleColor: "black"
Component.onCompleted: updateIcon();
function updateIcon() {
if (!root) {
return;
}
switch (root.icon) {
case OriginalDialogs.StandardIcon.Information:
text = "\uF05A";
color = "blue";
break;
case OriginalDialogs.StandardIcon.Question:
text = "\uF059"
color = "blue";
break;
case OriginalDialogs.StandardIcon.Warning:
text = "\uF071"
color = "yellow";
break;
case OriginalDialogs.StandardIcon.Critical:
text = "\uF057"
color = "red"
break;
default:
text = ""
}
visible = (text != "");
}
}
Text {
RalewaySemibold {
id: mainTextContainer
onHeightChanged: d.resize(); onWidthChanged: d.resize();
wrapMode: Text.WordWrap
font { pointSize: 14; weight: Font.Bold }
anchors { left: iconHolder.right; top: parent.top; margins: d.spacing * 2 }
size: hifi.fontSizes.menuItem
color: hifi.colors.baseGrayHighlight
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
}
lineHeight: 2
lineHeightMode: Text.ProportionalHeight
}
Text {
RalewaySemibold {
id: informativeTextContainer
onHeightChanged: d.resize(); onWidthChanged: d.resize();
wrapMode: Text.WordWrap
font.pointSize: 11
anchors { top: mainTextContainer.bottom; right: parent.right; left: iconHolder.right; margins: d.spacing * 2 }
size: hifi.fontSizes.menuItem
color: hifi.colors.baseGrayHighlight
anchors {
top: mainTextContainer.bottom
left: parent.left
right: parent.right
margins: 0
topMargin: text != "" ? hifi.dimensions.contentSpacing.y : 0
}
}
Flow {
@ -130,29 +135,35 @@ ModalWindow {
spacing: d.spacing
onHeightChanged: d.resize(); onWidthChanged: d.resize();
layoutDirection: Qt.RightToLeft
anchors { bottom: details.top; right: parent.right; margins: d.spacing * 2; bottomMargin: 0 }
MessageDialogButton { dialog: root; text: qsTr("OK"); button: OriginalDialogs.StandardButton.Ok; }
MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.StandardButton.Open; }
MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.StandardButton.Save; }
MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.StandardButton.SaveAll; }
MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.StandardButton.Retry; }
MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.StandardButton.Ignore; }
MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.StandardButton.Apply; }
MessageDialogButton { dialog: root; text: qsTr("Yes"); button: OriginalDialogs.StandardButton.Yes; }
MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.StandardButton.YesToAll; }
MessageDialogButton { dialog: root; text: qsTr("No"); button: OriginalDialogs.StandardButton.No; }
MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.StandardButton.NoToAll; }
MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.StandardButton.Discard; }
MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.StandardButton.Reset; }
MessageDialogButton { dialog: root; text: qsTr("Restore Defaults"); button: OriginalDialogs.StandardButton.RestoreDefaults; }
MessageDialogButton { dialog: root; text: qsTr("Cancel"); button: OriginalDialogs.StandardButton.Cancel; }
MessageDialogButton { dialog: root; text: qsTr("Abort"); button: OriginalDialogs.StandardButton.Abort; }
anchors {
top: informativeTextContainer.text == "" ? mainTextContainer.bottom : informativeTextContainer.bottom
horizontalCenter: parent.horizontalCenter
margins: 0
topMargin: 2 * hifi.dimensions.contentSpacing.y
}
MessageDialogButton { dialog: root; text: qsTr("Close"); button: OriginalDialogs.StandardButton.Close; }
MessageDialogButton { dialog: root; text: qsTr("Abort"); button: OriginalDialogs.StandardButton.Abort; }
MessageDialogButton { dialog: root; text: qsTr("Cancel"); button: OriginalDialogs.StandardButton.Cancel; }
MessageDialogButton { dialog: root; text: qsTr("Restore Defaults"); button: OriginalDialogs.StandardButton.RestoreDefaults; }
MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.StandardButton.Reset; }
MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.StandardButton.Discard; }
MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.StandardButton.NoToAll; }
MessageDialogButton { dialog: root; text: qsTr("No"); button: OriginalDialogs.StandardButton.No; }
MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.StandardButton.YesToAll; }
MessageDialogButton { dialog: root; text: qsTr("Yes"); button: OriginalDialogs.StandardButton.Yes; }
MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.StandardButton.Apply; }
MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.StandardButton.Ignore; }
MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.StandardButton.Retry; }
MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.StandardButton.SaveAll; }
MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.StandardButton.Save; }
MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.StandardButton.Open; }
MessageDialogButton { dialog: root; text: qsTr("OK"); button: OriginalDialogs.StandardButton.Ok; }
Button {
id: moreButton
text: qsTr("Show Details...")
onClicked: { content.state = (content.state === "" ? "expanded" : "")
}
width: 160
onClicked: { content.state = (content.state === "" ? "expanded" : "") }
visible: detailedText && detailedText.length > 0
}
MessageDialogButton { dialog: root; text: qsTr("Help"); button: OriginalDialogs.StandardButton.Help; }
@ -161,10 +172,16 @@ ModalWindow {
Item {
id: details
width: parent.width
implicitHeight: detailedText.implicitHeight + root.spacing
implicitHeight: detailedText.implicitHeight
height: 0
clip: true
anchors { bottom: parent.bottom; left: parent.left; right: parent.right; margins: d.spacing * 2 }
anchors {
top: buttons.bottom
left: parent.left;
right: parent.right;
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
}
Flickable {
id: flickable
contentHeight: detailedText.height
@ -173,10 +190,13 @@ ModalWindow {
anchors.bottomMargin: root.outerSpacing
TextEdit {
id: detailedText
size: hifi.fontSizes.menuItem
color: hifi.colors.baseGrayHighlight
width: details.width
wrapMode: Text.WordWrap
readOnly: true
selectByMouse: true
anchors.margins: 0
}
}
}
@ -190,6 +210,7 @@ ModalWindow {
}
]
Component.onCompleted: updateIcon();
onStateChanged: d.resize()
}

View file

@ -1,11 +1,24 @@
//
// MessageDialogButton.qml
//
// Created by Bradley Austin Davis on 29 Jan 2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import "../../controls-uit"
Button {
property var dialog;
property int button: StandardButton.NoButton;
color: dialog.defaultButton === button ? hifi.buttons.blue : hifi.buttons.white
focus: dialog.defaultButton === button
onClicked: dialog.click(button)
visible: dialog.buttons & button

View file

@ -8,6 +8,16 @@ import ".."
Desktop {
id: desktop
MouseArea {
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
scrollGestureEnabled: false // we don't need/want these
onEntered: ApplicationCompositor.reticleOverDesktop = true
onExited: ApplicationCompositor.reticleOverDesktop = false
acceptedButtons: Qt.NoButton
}
Component.onCompleted: {
WebEngine.settings.javascriptCanOpenWindows = true;
WebEngine.settings.javascriptCanAccessClipboard = false;

View file

@ -1,11 +1,21 @@
//
// RunningScripts.qml
//
// Created by Bradley Austin Davis on 12 Jan 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import Qt.labs.settings 1.0
import "../../styles" as Hifi
import "../../controls" as HifiControls
import "../../windows"
import "../../styles-uit"
import "../../controls-uit" as HifiControls
import "../../windows-uit"
Window {
id: root
@ -15,6 +25,9 @@ Window {
destroyOnInvisible: true
x: 40; y: 40
implicitWidth: 384; implicitHeight: 640
minSize: Qt.vector2d(200, 300)
HifiConstants { id: hifi }
property var scripts: ScriptDiscoveryService;
property var scriptsModel: scripts.scriptsModelFilter
@ -33,6 +46,11 @@ Window {
Component.onCompleted: updateRunningScripts()
function setDefaultFocus() {
// Work around FocusScope of scrollable window.
filterEdit.forceActiveFocus();
}
function updateRunningScripts() {
var runningScripts = ScriptDiscoveryService.getRunning();
runningScriptsModel.clear()
@ -66,126 +84,50 @@ Window {
scripts.stopAllScripts();
}
Rectangle {
color: "white"
anchors.fill: parent
Column {
width: pane.contentWidth
Item {
anchors { fill: parent; margins: 8 }
Text {
id: title
font.bold: true
font.pointSize: 16
color: "#0e7077"
text: "Currently Running"
}
HifiControls.StaticSection {
name: "Currently Running"
Row {
id: allButtons
anchors.top: title.bottom
anchors.topMargin: 8
spacing: 8
Button { text: "Reload all"; onClicked: reloadAll() }
Button { text: "Stop all"; onClicked: stopAll() }
}
spacing: hifi.dimensions.contentSpacing.x
ScrollView {
onActiveFocusChanged: if (activeFocus && listView.currentItem) { listView.currentItem.forceActiveFocus(); }
anchors {
top: allButtons.bottom;
left: parent.left;
right: parent.right;
topMargin: 8
bottom: row1.top
bottomMargin: 8
HifiControls.Button {
text: "Reload all"
color: hifi.buttons.black
onClicked: reloadAll()
}
ListView {
id: listView
clip: true
anchors { fill: parent; margins: 0 }
model: runningScriptsModel
delegate: FocusScope {
id: scope
anchors { left: parent.left; right: parent.right }
height: scriptName.height + 12 + (ListView.isCurrentItem ? scriptName.height + 6 : 0)
Keys.onDownPressed: listView.incrementCurrentIndex()
Keys.onUpPressed: listView.decrementCurrentIndex()
Rectangle {
id: rectangle
anchors.fill: parent
clip: true
radius: 3
color: scope.ListView.isCurrentItem ? "#79f" :
index % 2 ? "#ddd" : "#eee"
Text {
id: scriptName
anchors { left: parent.left; leftMargin: 4; top: parent.top; topMargin:6 }
text: name
}
Text {
id: scriptUrl
anchors { left: scriptName.left; right: parent.right; rightMargin: 4; top: scriptName.bottom; topMargin: 6 }
text: url
elide: Text.ElideMiddle
}
MouseArea {
anchors.fill: parent
onClicked: { listView.currentIndex = index; scope.forceActiveFocus(); }
}
Row {
anchors.verticalCenter: scriptName.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 4
spacing: 4
HifiControls.FontAwesome {
text: "\uf021"; size: scriptName.height;
MouseArea {
anchors { fill: parent; margins: -2; }
onClicked: reloadScript(model.url)
}
}
HifiControls.FontAwesome {
size: scriptName.height; text: "\uf00d"
MouseArea {
anchors { fill: parent; margins: -2; }
onClicked: stopScript(model.url)
}
}
}
}
}
HifiControls.Button {
text: "Stop all"
color: hifi.buttons.red
onClicked: stopAll()
}
}
Text {
id: loadLabel
text: "Load Scripts"
font.bold: true
font.pointSize: 16
color: "#0e7077"
HifiControls.Table {
tableModel: runningScriptsModel
height: 185
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: filterEdit.top
anchors.bottomMargin: 8
anchors.right: parent.right
}
}
HifiControls.StaticSection {
name: "Load Scripts"
hasSeparator: true
Row {
id: row1
spacing: 8
anchors.bottom: filterEdit.top
anchors.bottomMargin: 8
spacing: hifi.dimensions.contentSpacing.x
anchors.right: parent.right
Button {
text: "from URL";
onClicked: fromUrlTimer.running = true;
HifiControls.Button {
text: "from URL"
color: hifi.buttons.black
height: 26
onClicked: fromUrlTimer.running = true
// For some reason trigginer an API that enters
// an internal event loop directly from the button clicked
@ -203,9 +145,11 @@ Window {
}
}
Button {
HifiControls.Button {
text: "from Disk"
onClicked: fromDiskTimer.running = true;
color: hifi.buttons.black
height: 26
onClicked: fromDiskTimer.running = true
Timer {
id: fromDiskTimer
@ -221,66 +165,32 @@ Window {
id: filterEdit
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: treeView.top
anchors.bottomMargin: 8
placeholderText: "filter"
focus: true
colorScheme: hifi.colorSchemes.dark
//placeholderText: "filter"
label: "Filter"
onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i")
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
}
TreeView {
HifiControls.Tree {
id: treeView
height: 128
anchors.bottom: loadButton.top
anchors.bottomMargin: 8
height: 155
treeModel: scriptsModel
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.right: parent.right
headerVisible: false
// FIXME doesn't work?
onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index)
// FIXME not triggered by double click?
onActivated: {
var path = scriptsModel.data(index, 0x100)
if (path) {
loadScript(path)
}
}
model: scriptsModel
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: treeView.foo();
}
function foo() {
var localRect = Qt.rect(0, 0, width, height);
var rect = desktop.mapFromItem(treeView, 0, 0, width, height)
console.log("Local Rect " + localRect)
console.log("Rect " + rect)
console.log("Desktop size " + Qt.size(desktop.width, desktop.height));
}
TableViewColumn {
title: "Name";
role: "display";
// delegate: Text {
// text: styleData.value
// renderType: Text.QtRendering
// elite: styleData.elideMode
// }
}
}
HifiControls.TextField {
id: selectedScript
readOnly: true
anchors.left: parent.left
anchors.right: loadButton.left
anchors.rightMargin: 8
anchors.bottom: loadButton.bottom
anchors.top: loadButton.top
anchors.right: parent.right
anchors.rightMargin: loadButton.width + hifi.dimensions.contentSpacing.x
colorScheme: hifi.colorSchemes.dark
readOnly: true
Connections {
target: treeView
onCurrentIndexChanged: {
@ -290,19 +200,28 @@ Window {
} else {
selectedScript.text = ""
}
}
}
}
Button {
id: loadButton
anchors.bottom: parent.bottom
Item {
// Take the loadButton out of the column flow.
id: loadButtonContainer
anchors.top: selectedScript.top
anchors.right: parent.right
text: "Load"
enabled: selectedScript.text != ""
onClicked: root.loadScript(selectedScript.text)
HifiControls.Button {
id: loadButton
anchors.right: parent.right
text: "Load"
color: hifi.buttons.blue
enabled: selectedScript.text != ""
onClicked: root.loadScript(selectedScript.text)
}
}
HifiControls.VerticalSpacer { }
}
}
}

View file

@ -6,9 +6,11 @@ import "."
Item {
id: root
anchors.fill: parent
objectName: "MouseMenuHandlerItem"
MouseArea {
id: menuRoot;
objectName: "MouseMenuHandlerMouseArea"
anchors.fill: parent
enabled: d.topMenu !== null
onClicked: {

View file

@ -0,0 +1,23 @@
//
// AnonymousProRegular.qml
//
// Created by David Rowe on 12 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: anonymousProRegular; source: "../../fonts/AnonymousPro-Regular.ttf"; }
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: anonymousProRegular.name
}

View file

@ -0,0 +1,23 @@
//
// FiraSansSemiBold.qml
//
// Created by David Rowe on 12 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: firaSansSemiBold.name
}

View file

@ -0,0 +1,26 @@
//
// FontAwesome.qml
//
// Created by Bradley Austin Davis on 24 Apr 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; }
property int size: 32
width: size
height: size
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: iconFont.name
}

View file

@ -0,0 +1,25 @@
//
// HiFiGlyphs.qml
//
// Created by David Rowe on 12 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: hiFiGlyphs; source: "../../fonts/hifi-glyphs.ttf"; }
property int size: 32
font.pixelSize: size
width: size
height: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: hiFiGlyphs.name
}

View file

@ -0,0 +1,134 @@
//
// HiFiConstants.qml
//
// Created by Bradley Austin Davis on 28 Apr 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Window 2.2
Item {
readonly property alias colors: colors
readonly property alias colorSchemes: colorSchemes
readonly property alias dimensions: dimensions
readonly property alias fontSizes: fontSizes
readonly property alias glyphs: glyphs
readonly property alias buttons: buttons
readonly property alias effects: effects
Item {
id: colors
// Base colors
readonly property color baseGray: "#404040"
readonly property color darkGray: "#121212"
readonly property color baseGrayShadow: "#252525"
readonly property color baseGrayHighlight: "#575757"
readonly property color lightGray: "#6a6a6a"
readonly property color lightGrayText: "#afafaf"
readonly property color faintGray: "#e3e3e3"
readonly property color primaryHighlight: "#00b4ef"
readonly property color blueAccent: "#1080b8"
readonly property color redHighlight: "#e2334d"
readonly property color redAccent: "#b70a37"
readonly property color greenHighlight: "#1ac567"
readonly property color greenShadow: "#2c8e72"
// Semitransparent
readonly property color darkGray30: "#4d121212"
readonly property color darkGray0: "#00121212"
readonly property color baseGrayShadow60: "#99252525"
readonly property color baseGrayHighlight40: "#66575757"
readonly property color baseGrayHighlight15: "#26575757"
readonly property color lightGrayText80: "#ccafafaf"
readonly property color faintGray50: "#80e3e3e3"
// Other colors
readonly property color white: "#ffffff"
readonly property color black: "#000000"
// Semitransparent
readonly property color white50: "#80ffffff"
readonly property color white30: "#4dffffff"
readonly property color white25: "#40ffffff"
// Control specific colors
readonly property color tableRowLightOdd: white50
readonly property color tableRowLightEven: "#1a575757"
readonly property color tableRowDarkOdd: "#80393939"
readonly property color tableRowDarkEven: "#a6181818"
readonly property color tableScrollHandle: "#707070"
readonly property color tableScrollBackground: "#323232"
}
Item {
id: colorSchemes
readonly property int light: 0
readonly property int dark: 1
}
Item {
id: dimensions
readonly property bool largeScreen: Screen.width >= 1920 && Screen.height >= 1080
readonly property real borderRadius: largeScreen ? 7.5 : 5.0
readonly property real borderWidth: largeScreen ? 2 : 1
readonly property vector2d contentMargin: Qt.vector2d(12, 24)
readonly property vector2d contentSpacing: Qt.vector2d(8, 12)
readonly property real textPadding: 8
readonly property real tablePadding: 12
readonly property real tableRowHeight: largeScreen ? 26 : 23
readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30)
readonly property real modalDialogTitleHeight: 40
}
Item {
id: fontSizes // In pixels
readonly property real overlayTitle: dimensions.largeScreen? 18 : 14
readonly property real tabName: dimensions.largeScreen? 12 : 10
readonly property real sectionName: dimensions.largeScreen? 12 : 10
readonly property real inputLabel: dimensions.largeScreen? 14 : 10
readonly property real textFieldInput: dimensions.largeScreen? 15 : 12
readonly property real tableText: dimensions.largeScreen? 15 : 12
readonly property real buttonLabel: dimensions.largeScreen? 13 : 9
readonly property real iconButton: dimensions.largeScreen? 13 : 9
readonly property real listItem: dimensions.largeScreen? 15 : 11
readonly property real tabularData: dimensions.largeScreen? 15 : 11
readonly property real logs: dimensions.largeScreen? 16 : 12
readonly property real code: dimensions.largeScreen? 16 : 12
readonly property real rootMenu: dimensions.largeScreen? 15 : 11
readonly property real menuItem: dimensions.largeScreen? 15 : 11
readonly property real shortcutText: dimensions.largeScreen? 13 : 9
}
Item {
id: glyphs
readonly property string close: "w"
readonly property string closeInverted: "x"
readonly property string closeSmall: "C"
readonly property string disclosureCollapse: "Z"
readonly property string disclosureExpand: "B"
readonly property string pin: "y"
readonly property string pinInverted: "z"
readonly property string reloadSmall: "a"
readonly property string resizeHandle: "A"
}
Item {
id: buttons
readonly property int white: 0
readonly property int blue: 1
readonly property int red: 2
readonly property int black: 3
readonly property var textColor: [ colors.darkGray, colors.white, colors.white, colors.white ]
readonly property var colorStart: [ "#ffffff", "#00b4ef", "#d42043", "#343434" ]
readonly property var colorFinish: [ "#afafaf", "#1080b8", "#94132e", "#000000" ]
readonly property int radius: 5
}
QtObject {
id: effects
readonly property int fadeInDuration: 300
}
}

View file

@ -0,0 +1,24 @@
//
// RalewayBold.qml
//
// Created by David Rowe on 12 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: ralewayBold; source: "../../fonts/Raleway-Bold.ttf"; }
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: ralewayBold.name
font.bold: true // Font seems to need this in order to display bold.
}

View file

@ -0,0 +1,23 @@
//
// RalewayLight.qml
//
// Created by David Rowe on 12 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: ralewayLight; source: "../../fonts/Raleway-Light.ttf"; }
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: ralewayLight.name
}

View file

@ -0,0 +1,23 @@
//
// RalewayRegular.qml
//
// Created by David Rowe on 12 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: ralewayRegular; source: "../../fonts/Raleway-Regular.ttf"; }
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: ralewayRegular.name
}

View file

@ -0,0 +1,23 @@
//
// RalewaySemibold.qml
//
// Created by David Rowe on 12 Feb 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: ralewaySemibold; source: "../../fonts/Raleway-Semibold.ttf"; }
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: ralewaySemibold.name
}

View file

@ -0,0 +1,111 @@
//
// DefaultFrame.qml
//
// Created by Bradley Austin Davis on 12 Jan 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
//
import QtQuick 2.5
import QtGraphicalEffects 1.0
import "."
import "../styles-uit"
Frame {
HifiConstants { id: hifi }
Rectangle {
// Dialog frame
id: frameContent
anchors {
topMargin: -frameMarginTop
leftMargin: -frameMarginLeft
rightMargin: -frameMarginRight
bottomMargin: -frameMarginBottom
}
anchors.fill: parent
color: hifi.colors.baseGrayHighlight40
border {
width: hifi.dimensions.borderWidth
color: hifi.colors.faintGray50
}
radius: hifi.dimensions.borderRadius
// Allow dragging of the window
MouseArea {
anchors.fill: parent
drag.target: window
}
Row {
id: controlsRow
anchors {
right: parent.right;
top: parent.top;
topMargin: frameMargin + 1 // Move down a little to visually align with the title
rightMargin: frameMarginRight;
}
spacing: iconSize / 4
HiFiGlyphs {
// "Pin" button
visible: false
text: (frame.pinned && !pinClickArea.containsMouse) || (!frame.pinned && pinClickArea.containsMouse) ? hifi.glyphs.pinInverted : hifi.glyphs.pin
color: pinClickArea.containsMouse && !pinClickArea.pressed ? hifi.colors.redHighlight : hifi.colors.white
size: iconSize
MouseArea {
id: pinClickArea
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
onClicked: { frame.pin(); mouse.accepted = false; }
}
}
HiFiGlyphs {
// "Close" button
visible: window ? window.closable : false
text: closeClickArea.containsPress ? hifi.glyphs.closeInverted : hifi.glyphs.close
color: closeClickArea.containsMouse ? hifi.colors.redHighlight : hifi.colors.white
size: iconSize
MouseArea {
id: closeClickArea
anchors.fill: parent
hoverEnabled: true
onClicked: window.visible = false;
}
}
}
RalewayRegular {
// Title
id: titleText
anchors {
left: parent.left
leftMargin: frameMarginLeft + hifi.dimensions.contentMargin.x
right: controlsRow.left
rightMargin: iconSize
top: parent.top
topMargin: frameMargin
}
text: window ? window.title : ""
color: hifi.colors.white
size: hifi.fontSizes.overlayTitle
}
DropShadow {
source: titleText
anchors.fill: titleText
horizontalOffset: 1
verticalOffset: 1
samples: 2
color: hifi.colors.baseGrayShadow60
visible: (window && window.focus)
cached: true
}
}
}

View file

@ -0,0 +1,60 @@
//
// Fadable.qml
//
// Created by Bradley Austin Davis on 15 Jan 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtGraphicalEffects 1.0
import "../styles-uit"
// Enable window visibility transitions
FocusScope {
id: root
HifiConstants { id: hifi }
Component.onCompleted: {
fadeTargetProperty = visible ? 1.0 : 0.0
}
// The target property to animate, usually scale or opacity
property alias fadeTargetProperty: root.opacity
// always start the property at 0 to enable fade in on creation
fadeTargetProperty: 0
// DO NOT set visible to false or when derived types override it it
// will short circuit the fade in on initial visibility
// visible: false <--- NO
// Some dialogs should be destroyed when they become
// invisible, so handle that
onVisibleChanged: {
// If someone directly set the visibility to false
// toggle it back on and use the targetVisible flag to transition
// via fading.
if ((!visible && fadeTargetProperty != 0.0) || (visible && fadeTargetProperty == 0.0)) {
var target = visible;
visible = !visible;
fadeTargetProperty = target ? 1.0 : 0.0;
return;
}
}
// The actual animator
Behavior on fadeTargetProperty {
NumberAnimation {
duration: hifi.effects.fadeInDuration
easing.type: Easing.InOutCubic
}
}
// Once we're transparent, disable the dialog's visibility
onFadeTargetPropertyChanged: {
visible = (fadeTargetProperty != 0.0);
}
}

View file

@ -0,0 +1,133 @@
//
// Frame.qml
//
// Created by Bradley Austin Davis on 12 Jan 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
//
import QtQuick 2.5
import QtGraphicalEffects 1.0
import "../styles-uit"
import "../js/Utils.js" as Utils
Item {
id: frame
HifiConstants { id: hifi }
default property var decoration
readonly property int iconSize: 22
readonly property int frameMargin: 9
readonly property int frameMarginLeft: frameMargin
readonly property int frameMarginRight: frameMargin
readonly property int frameMarginTop: 2 * frameMargin + iconSize
readonly property int frameMarginBottom: iconSize + 11
// Frames always fill their parents, but their decorations may extend
// beyond the window via negative margin sizes
anchors.fill: parent
children: [
focusShadow,
decoration,
sizeOutline,
debugZ,
sizeDrag
]
Text {
id: debugZ
visible: DebugQML
text: window ? "Z: " + window.z : ""
y: window ? window.height + 4 : 0
}
function deltaSize(dx, dy) {
var newSize = Qt.vector2d(window.width + dx, window.height + dy);
newSize = Utils.clampVector(newSize, window.minSize, window.maxSize);
window.width = newSize.x
window.height = newSize.y
}
RadialGradient {
id: focusShadow
width: 1.66 * window.width
height: 1.66 * window.height
x: (window.width - width) / 2
y: window.height / 2 - 0.375 * height
// FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX.
// Check again when have a later version of QtQuick.
visible: window && window.focus && pane.visible && Qt.platform.os != "osx"
gradient: Gradient {
// GradientStop position 0.5 is at full circumference of circle that fits inside the square.
GradientStop { position: 0.0; color: "#ff000000" } // black, 100% opacity
GradientStop { position: 0.333; color: "#1f000000" } // black, 12% opacity
GradientStop { position: 0.5; color: "#00000000" } // black, 0% opacity
GradientStop { position: 1.0; color: "#00000000" }
}
cached: true
}
Rectangle {
id: sizeOutline
x: -frameMarginLeft
y: -frameMarginTop
width: window ? window.width + frameMarginLeft + frameMarginRight : 0
height: window ? window.height + frameMarginTop + frameMarginBottom : 0
color: hifi.colors.baseGrayHighlight15
border.width: 3
border.color: hifi.colors.white50
radius: hifi.dimensions.borderRadius
visible: window ? !pane.visible : false
}
MouseArea {
// Resize handle
id: sizeDrag
width: iconSize
height: iconSize
enabled: window ? window.resizable : false
hoverEnabled: true
x: window ? window.width + frameMarginRight - iconSize : 0
y: window ? window.height + 4 : 0
property vector2d pressOrigin
property vector2d sizeOrigin
property bool hid: false
onPressed: {
//console.log("Pressed on size")
pressOrigin = Qt.vector2d(mouseX, mouseY)
sizeOrigin = Qt.vector2d(window.content.width, window.content.height)
hid = false;
}
onReleased: {
if (hid) {
pane.visible = true
frameContent.visible = true
hid = false;
}
}
onPositionChanged: {
if (pressed) {
if (pane.visible) {
pane.visible = false;
frameContent.visible = false
hid = true;
}
var delta = Qt.vector2d(mouseX, mouseY).minus(pressOrigin);
frame.deltaSize(delta.x, delta.y)
}
}
HiFiGlyphs {
visible: sizeDrag.enabled
x: -11 // Move a little to visually align
y: -4 // ""
text: hifi.glyphs.resizeHandle
size: iconSize + 10
color: sizeDrag.containsMouse || sizeDrag.pressed ? hifi.colors.white : hifi.colors.white50
}
}
}

View file

@ -0,0 +1,81 @@
//
// ModalFrame.qml
//
// Created by Bradley Austin Davis on 15 Jan 2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import "."
import "../controls-uit"
import "../styles-uit"
Frame {
HifiConstants { id: hifi }
Rectangle {
id: modalFrame
readonly property bool hasTitle: window.title != ""
anchors {
fill: parent
topMargin: -hifi.dimensions.modalDialogMargin.y - (modalFrame.hasTitle ? hifi.dimensions.modalDialogTitleHeight + 10 : 0)
leftMargin: -hifi.dimensions.modalDialogMargin.x
rightMargin: -hifi.dimensions.modalDialogMargin.x
bottomMargin: -hifi.dimensions.modalDialogMargin.y
}
border {
width: hifi.dimensions.borderWidth
color: hifi.colors.lightGrayText80
}
radius: hifi.dimensions.borderRadius
color: hifi.colors.faintGray
Item {
visible: modalFrame.hasTitle
anchors.fill: parent
anchors {
topMargin: -parent.anchors.topMargin
leftMargin: -parent.anchors.leftMargin
rightMargin: -parent.anchors.rightMargin
}
Item {
width: title.width + (window.iconText !== "" ? icon.width + hifi.dimensions.contentSpacing.x : 0)
x: (parent.width - width) / 2
FontAwesome {
id: icon
text: window.iconText
size: 30
color: hifi.colors.lightGrayText
visible: text != ""
y: -hifi.dimensions.modalDialogTitleHeight - 5
anchors.left: parent.left
}
RalewayRegular {
id: title
text: window.title
elide: Text.ElideRight
color: hifi.colors.baseGrayHighlight
size: hifi.fontSizes.overlayTitle
y: -hifi.dimensions.modalDialogTitleHeight
anchors.right: parent.right
}
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: hifi.colors.lightGray
}
}
}
}

View file

@ -0,0 +1,22 @@
//
// ModalWindow.qml
//
// Created by Bradley Austin Davis on 22 Jan 2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import "."
Window {
id: window
anchors.centerIn: parent
modality: Qt.ApplicationModal
destroyOnCloseButton: true
destroyOnInvisible: true
frame: ModalFrame{}
}

View file

@ -0,0 +1,281 @@
//
// Window.qml
//
// Created by Bradley Austin Davis on 12 Jan 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
import "."
import "../styles-uit"
// FIXME how do I set the initial position of a window without
// overriding places where the a individual client of the window
// might be setting the position with a Settings{} element?
// FIXME how to I enable dragging without allowing the window to lay outside
// of the desktop? How do I ensure when the desktop resizes all the windows
// are still at least partially visible?
Fadable {
id: window
HifiConstants { id: hifi }
// The Window size is the size of the content, while the frame
// decorations can extend outside it.
implicitHeight: content ? content.height : 0
implicitWidth: content ? content.width : 0
x: -1; y: -1
enabled: visible
signal windowDestroyed();
property int modality: Qt.NonModal
readonly property bool topLevelWindow: true
property string title
// Should the window be closable control?
property bool closable: true
// Should the window try to remain on top of other windows?
property bool alwaysOnTop: false
// Should hitting the close button hide or destroy the window?
property bool destroyOnCloseButton: true
// Should hiding the window destroy it or just hide it?
property bool destroyOnInvisible: false
// FIXME support for pinned / unpinned pending full design
// property bool pinnable: false
// property bool pinned: false
property bool resizable: false
property vector2d minSize: Qt.vector2d(100, 100)
property vector2d maxSize: Qt.vector2d(1280, 720)
// The content to place inside the window, determined by the client
default property var content
function setDefaultFocus() {} // Default function; can be overridden by dialogs.
property var rectifier: Timer {
property bool executing: false;
interval: 100
repeat: false
running: false
onTriggered: {
executing = true;
x = Math.floor(x);
y = Math.floor(y);
executing = false;
}
function begin() {
if (!executing) {
restart();
}
}
}
onXChanged: rectifier.begin();
onYChanged: rectifier.begin();
// This mouse area serves to raise the window. To function, it must live
// in the window and have a higher Z-order than the content, but follow
// the position and size of frame decoration
property var activator: MouseArea {
width: frame.decoration.width
height: frame.decoration.height
x: frame.decoration.anchors.leftMargin
y: frame.decoration.anchors.topMargin
propagateComposedEvents: true
acceptedButtons: Qt.AllButtons
enabled: window.visible
onPressed: {
//console.log("Pressed on activator area");
window.raise();
mouse.accepted = false;
}
}
// This mouse area serves to swallow mouse events while the mouse is over the window
// to prevent things like mouse wheel events from reaching the application and changing
// the camera if the user is scrolling through a list and gets to the end.
property var swallower: MouseArea {
width: frame.decoration.width
height: frame.decoration.height
x: frame.decoration.anchors.leftMargin
y: frame.decoration.anchors.topMargin
hoverEnabled: true
acceptedButtons: Qt.AllButtons
enabled: window.visible
onClicked: {}
onDoubleClicked: {}
onPressAndHold: {}
onReleased: {}
onWheel: {}
}
// Default to a standard frame. Can be overriden to provide custom
// frame styles, like a full desktop frame to simulate a modal window
property var frame: DefaultFrame { }
// Scrollable window content.
property var pane: Item {
property bool isScrolling: scrollView.height < scrollView.contentItem.height
property int contentWidth: scrollView.width - (isScrolling ? 11 : 0)
anchors.fill: parent
anchors.rightMargin: isScrolling ? 11 : 0
Rectangle {
id: contentBackground
anchors.fill: parent
anchors.rightMargin: parent.isScrolling ? 11 : 0
color: hifi.colors.baseGray
visible: modality != Qt.ApplicationModal
}
LinearGradient {
// FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX.
// Check again when have a later version of QtQuick.
visible: modality != Qt.ApplicationModal && Qt.platform.os != "osx"
anchors.top: contentBackground.bottom
anchors.left: contentBackground.left
width: contentBackground.width - 1
height: 4
start: Qt.point(0, 0)
end: Qt.point(0, 4)
gradient: Gradient {
GradientStop { position: 0.0; color: hifi.colors.darkGray }
GradientStop { position: 1.0; color: hifi.colors.darkGray0 }
}
cached: true
}
ScrollView {
id: scrollView
contentItem: content
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
anchors.fill: parent
anchors.rightMargin: parent.isScrolling ? 1 : 0
style: ScrollViewStyle {
padding.right: -7 // Move to right away from content.
handle: Item {
implicitWidth: 8
Rectangle {
radius: 4
color: hifi.colors.white30
anchors {
fill: parent
leftMargin: 2 // Finesse size and position.
topMargin: 1
bottomMargin: 1
}
}
}
scrollBarBackground: Item {
implicitWidth: 10
Rectangle {
color: hifi.colors.darkGray30
radius: 4
anchors {
fill: parent
topMargin: -1 // Finesse size
bottomMargin: -2
}
}
}
incrementControl: Item {
visible: false
}
decrementControl: Item {
visible: false
}
}
}
}
children: [ swallower, frame, pane, activator ]
Component.onCompleted: { raise(); setDefaultFocus(); }
Component.onDestruction: windowDestroyed();
onParentChanged: raise();
onVisibleChanged: {
if (!visible && destroyOnInvisible) {
destroy();
return;
}
if (visible) {
raise();
}
enabled = visible
}
function raise() {
if (visible && parent) {
desktop.raise(window)
}
}
function pin() {
// pinned = ! pinned
}
// our close function performs the same way as the OffscreenUI class:
// don't do anything but manipulate the targetVisible flag and let the other
// mechanisms decide if the window should be destroyed after the close
// animation completes
// FIXME using this close function messes up the visibility signals received by the
// type and it's derived types
// function close() {
// console.log("Closing " + window)
// if (destroyOnCloseButton) {
// destroyOnInvisible = true
// }
// visible = false;
// }
function framedRect() {
if (!frame || !frame.decoration) {
return Qt.rect(0, 0, window.width, window.height)
}
return Qt.rect(frame.decoration.anchors.leftMargin, frame.decoration.anchors.topMargin,
window.width - frame.decoration.anchors.leftMargin - frame.decoration.anchors.rightMargin,
window.height - frame.decoration.anchors.topMargin - frame.decoration.anchors.bottomMargin)
}
Keys.onPressed: {
switch(event.key) {
case Qt.Key_Control:
case Qt.Key_Shift:
case Qt.Key_Meta:
case Qt.Key_Alt:
break;
case Qt.Key_W:
if (window.closable && (event.modifiers === Qt.ControlModifier)) {
visible = false
event.accepted = true
}
// fall through
default:
// Consume unmodified keyboard entries while the window is focused, to prevent them
// from propagating to the application
if (event.modifiers === Qt.NoModifier) {
event.accepted = true;
}
break;
}
}
}

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);
@ -1259,6 +1260,8 @@ void Application::initializeUi() {
rootContext->setContextProperty("Render", _renderEngine->getConfiguration().get());
rootContext->setContextProperty("Reticle", _compositor.getReticleInterface());
rootContext->setContextProperty("ApplicationCompositor", &_compositor);
_glWidget->installEventFilter(offscreenUi.data());
offscreenUi->setMouseTranslator([=](const QPointF& pt) {
QPointF result = pt;
@ -3772,8 +3775,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
// The pending changes collecting the changes here
render::PendingChanges pendingChanges;
// FIXME: Move this out of here!, Background / skybox should be driven by the enityt content just like the other entities
// Background rendering decision
if (BackgroundRenderData::_item == 0) {
if (!render::Item::isValidID(BackgroundRenderData::_item)) {
auto backgroundRenderData = make_shared<BackgroundRenderData>();
auto backgroundRenderPayload = make_shared<BackgroundRenderData::Payload>(backgroundRenderData);
BackgroundRenderData::_item = _main3DScene->allocateID();
@ -3798,8 +3802,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
}
}
// FIXME: Move this out of here!, WorldBox should be driven by the entity content just like the other entities
// Make sure the WorldBox is in the scene
if (WorldBoxRenderData::_item == 0) {
if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
auto worldBoxRenderData = make_shared<WorldBoxRenderData>();
auto worldBoxRenderPayload = make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
@ -3814,9 +3819,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
}
// Setup the current Zone Entity lighting and skybox
// Fixme: We need a better soution through an actual render item !!!
{
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
// FIXME: Use a zone setting to determine the ambient light mode
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(-1);
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity(), skyStage->getSunLight()->getAmbientIntensity());
@ -4307,7 +4312,7 @@ bool Application::askToSetAvatarUrl(const QString& url) {
case FSTReader::HEAD_AND_BODY_MODEL:
ok = QMessageBox::Ok == OffscreenUi::question("Set Avatar",
"Would you like to use '" + modelName + "' for your avatar?",
QMessageBox::Ok | QMessageBox::Cancel);
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
break;
default:
@ -4627,34 +4632,6 @@ float Application::getRenderResolutionScale() const {
}
}
int Application::getRenderAmbientLight() const {
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLightGlobal)) {
return -1;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight0)) {
return 0;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight1)) {
return 1;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight2)) {
return 2;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight3)) {
return 3;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight4)) {
return 4;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight5)) {
return 5;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight6)) {
return 6;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight7)) {
return 7;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight8)) {
return 8;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight9)) {
return 9;
} else {
return -1;
}
}
void Application::notifyPacketVersionMismatch() {
if (!_notifiedPacketVersionMismatchThisDomain) {
_notifiedPacketVersionMismatchThisDomain = true;
@ -5036,27 +5013,11 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de
// controller pose is in Avatar frame.
glm::vec3 position = pose.getTranslation();
glm::quat rotation = pose.getRotation();
glm::vec3 rawVelocity = pose.getVelocity();
glm::vec3 angularVelocity = pose.getAngularVelocity();
// Compute current velocity from position change
glm::vec3 rawVelocity;
if (deltaTime > 0.0f) {
rawVelocity = (position - palm.getRawPosition()) / deltaTime;
} else {
rawVelocity = glm::vec3(0.0f);
}
palm.setRawVelocity(rawVelocity); // meters/sec
// Angular Velocity of Palm
glm::quat deltaRotation = rotation * glm::inverse(palm.getRawRotation());
glm::vec3 angularVelocity(0.0f);
float rotationAngle = glm::angle(deltaRotation);
if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) {
angularVelocity = glm::normalize(glm::axis(deltaRotation));
angularVelocity *= (rotationAngle / deltaTime);
palm.setRawAngularVelocity(angularVelocity);
} else {
palm.setRawAngularVelocity(glm::vec3(0.0f));
}
palm.setRawVelocity(rawVelocity);
palm.setRawAngularVelocity(angularVelocity);
if (controller::InputDevice::getLowVelocityFilter()) {
// Use a velocity sensitive filter to damp small motions and preserve large ones with
@ -5128,3 +5089,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();
@ -351,7 +352,6 @@ private:
void checkSkeleton();
void initializeAcceptedFiles();
int getRenderAmbientLight() const;
void displaySide(RenderArgs* renderArgs, Camera& whichCamera, bool selfAvatarOnly = false);

View file

@ -312,12 +312,6 @@ Menu::Menu() {
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/AudioPreferencesDialog.qml"), "AudioPreferencesDialog");
});
// Settings > Graphics...
action = addActionToQMenuAndActionHash(settingsMenu, "Graphics...");
connect(action, &QAction::triggered, [] {
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"), "GraphicsPreferencesDialog");
});
// Settings > LOD...-- FIXME: needs implementation
action = addActionToQMenuAndActionHash(settingsMenu, "LOD...");
connect(action, &QAction::triggered, [] {
@ -345,27 +339,17 @@ Menu::Menu() {
// Developer menu ----------------------------------
MenuWrapper* developerMenu = addMenu("Developer", "Developer");
// Developer > Graphics...
action = addActionToQMenuAndActionHash(developerMenu, "Graphics...");
connect(action, &QAction::triggered, [] {
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"), "GraphicsPreferencesDialog");
});
// Developer > Render >>>
MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render");
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, 0, true);
// Developer > Render > Ambient Light
MenuWrapper* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight);
QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu);
ambientLightGroup->setExclusive(true);
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLightGlobal, 0, true));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight0, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight1, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight2, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight3, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight4, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight5, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight6, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight7, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false));
// Developer > Render > Throttle FPS If Not Focus
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ThrottleFPSIfNotFocus, 0, true);

View file

@ -266,18 +266,6 @@ namespace MenuOption {
const QString RenderResolutionHalf = "1/2";
const QString RenderResolutionThird = "1/3";
const QString RenderResolutionQuarter = "1/4";
const QString RenderAmbientLight = "Ambient Light";
const QString RenderAmbientLightGlobal = "Global";
const QString RenderAmbientLight0 = "OLD_TOWN_SQUARE";
const QString RenderAmbientLight1 = "GRACE_CATHEDRAL";
const QString RenderAmbientLight2 = "EUCALYPTUS_GROVE";
const QString RenderAmbientLight3 = "ST_PETERS_BASILICA";
const QString RenderAmbientLight4 = "UFFIZI_GALLERY";
const QString RenderAmbientLight5 = "GALILEOS_TOMB";
const QString RenderAmbientLight6 = "VINE_STREET_KITCHEN";
const QString RenderAmbientLight7 = "BREEZEWAY";
const QString RenderAmbientLight8 = "CAMPUS_SUNSET";
const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET";
const QString ResetAvatarSize = "Reset Avatar Size";
const QString ResetSensors = "Reset Sensors";
const QString RunningScripts = "Running Scripts...";

View file

@ -315,6 +315,7 @@ bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene>
void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_renderItemID);
render::Item::clearID(_renderItemID);
_skeletonModel.removeFromScene(scene, pendingChanges);
getHead()->getFaceModel().removeFromScene(scene, pendingChanges);
for (auto& attachmentModel : _attachmentModels) {
@ -323,7 +324,7 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::S
}
void Avatar::updateRenderItem(render::PendingChanges& pendingChanges) {
if (_renderItemID != render::Item::INVALID_ITEM_ID) {
if (render::Item::isValidID(_renderItemID)) {
pendingChanges.updateItem<render::Payload<AvatarData>>(_renderItemID, [](render::Payload<AvatarData>& p) {});
}
}
@ -930,35 +931,6 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
}
_attachmentModels[i]->setURL(attachmentData[i].modelURL);
}
// AJT: TODO REMOVE
/*
// make sure we have as many models as attachments
while (_attachmentModels.size() < attachmentData.size()) {
Model* model = nullptr;
if (_unusedAttachments.size() > 0) {
model = _unusedAttachments.takeFirst();
} else {
model = new Model(std::make_shared<Rig>(), this);
}
model->init();
_attachmentModels.append(model);
}
while (_attachmentModels.size() > attachmentData.size()) {
auto attachmentModel = _attachmentModels.back();
_attachmentModels.pop_back();
_attachmentsToRemove.push_back(attachmentModel);
}
*/
/*
// update the urls
for (int i = 0; i < attachmentData.size(); i++) {
_attachmentModels[i]->setURL(attachmentData.at(i).modelURL);
_attachmentModels[i]->setSnapModelToCenter(true);
_attachmentModels[i]->setScaleToFit(true, getUniformScale() * _attachmentData.at(i).scale);
}
*/
}

View file

@ -93,7 +93,8 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
activateBody(true);
}
std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position) {
std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position,
glm::vec3& linearVelocity, glm::vec3& angularVelocity) {
auto avatarManager = DependencyManager::get<AvatarManager>();
auto holdingAvatar = std::static_pointer_cast<Avatar>(avatarManager->getAvatarBySessionID(_holderID));
@ -103,19 +104,22 @@ std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::ve
withReadLock([&]{
bool isRightHand = (_hand == "right");
glm::vec3 palmPosition { Vectors::ZERO };
glm::quat palmRotation { Quaternions::IDENTITY };
glm::vec3 palmPosition;
glm::quat palmRotation;
glm::vec3 palmLinearVelocity;
glm::vec3 palmAngularVelocity;
PalmData palmData = holdingAvatar->getHand()->getCopyOfPalmData(isRightHand ? HandData::RightHand : HandData::LeftHand);
// TODO: adjust according to _relativePosition and _relativeRotation?
linearVelocity = palmData.getVelocity();
angularVelocity = palmData.getAngularVelocity();
if (_ignoreIK && holdingAvatar->isMyAvatar()) {
// We cannot ignore other avatars IK and this is not the point of this option
// This is meant to make the grabbing behavior more reactive.
if (isRightHand) {
palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition();
palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation();
} else {
palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition();
palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation();
}
palmPosition = palmData.getPosition();
palmRotation = palmData.getRotation();
} else if (holdingAvatar->isMyAvatar()) {
glm::vec3 avatarRigidBodyPosition;
glm::quat avatarRigidBodyRotation;
@ -153,14 +157,19 @@ std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::ve
rotation = palmRotation * _relativeRotation;
position = palmPosition + rotation * _relativePosition;
// update linearVelocity based on offset via _relativePosition;
linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition);
});
return holdingAvatar;
}
void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
glm::quat rotation { Quaternions::IDENTITY };
glm::vec3 position { Vectors::ZERO };
glm::quat rotation;
glm::vec3 position;
glm::vec3 linearVelocity;
glm::vec3 angularVelocity;
bool valid = false;
int holdCount = 0;
@ -173,7 +182,8 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
std::shared_ptr<AvatarActionHold> holdAction = std::static_pointer_cast<AvatarActionHold>(action);
glm::quat rotationForAction;
glm::vec3 positionForAction;
std::shared_ptr<Avatar> holdingAvatar = holdAction->getTarget(rotationForAction, positionForAction);
glm::vec3 linearVelocityForAction, angularVelocityForAction;
std::shared_ptr<Avatar> holdingAvatar = holdAction->getTarget(rotationForAction, positionForAction, linearVelocityForAction, angularVelocityForAction);
if (holdingAvatar) {
holdCount ++;
if (holdAction.get() == this) {
@ -183,15 +193,21 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
}
position += positionForAction;
linearVelocity += linearVelocityForAction;
angularVelocity += angularVelocityForAction;
}
}
if (valid && holdCount > 0) {
position /= holdCount;
linearVelocity /= holdCount;
angularVelocity /= holdCount;
withWriteLock([&]{
_positionalTarget = position;
_rotationalTarget = rotation;
_linearVelocityTarget = linearVelocity;
_angularVelocityTarget = angularVelocity;
_positionalTargetSet = true;
_rotationalTargetSet = true;
_active = true;
@ -225,15 +241,8 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
withWriteLock([&]{
if (_kinematicSetVelocity) {
if (_previousSet) {
// smooth velocity over 2 frames
glm::vec3 positionalDelta = _positionalTarget - _previousPositionalTarget;
glm::vec3 positionalVelocity =
(positionalDelta + _previousPositionalDelta) / (deltaTimeStep + _previousDeltaTimeStep);
rigidBody->setLinearVelocity(glmToBullet(positionalVelocity));
_previousPositionalDelta = positionalDelta;
_previousDeltaTimeStep = deltaTimeStep;
}
rigidBody->setLinearVelocity(glmToBullet(_linearVelocityTarget));
rigidBody->setAngularVelocity(glmToBullet(_angularVelocityTarget));
}
btTransform worldTrans = rigidBody->getWorldTransform();

View file

@ -36,7 +36,8 @@ public:
virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); }
bool getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
std::shared_ptr<Avatar> getTarget(glm::quat& rotation, glm::vec3& position);
std::shared_ptr<Avatar> getTarget(glm::quat& rotation, glm::vec3& position,
glm::vec3& linearVelocity, glm::vec3& angularVelocity);
virtual void prepareForPhysicsSimulation() override;
@ -50,6 +51,9 @@ private:
QString _hand { "right" };
QUuid _holderID;
glm::vec3 _linearVelocityTarget;
glm::vec3 _angularVelocityTarget;
bool _kinematic { false };
bool _kinematicSetVelocity { false };
bool _previousSet { false };
@ -57,7 +61,6 @@ private:
glm::vec3 _previousPositionalTarget;
glm::quat _previousRotationalTarget;
float _previousDeltaTimeStep = 0.0f;
glm::vec3 _previousPositionalDelta;
glm::vec3 _palmOffsetFromRigidBody;

View file

@ -123,8 +123,11 @@ MyAvatar::MyAvatar(RigPointer rig) :
}
// connect to AddressManager signal for location jumps
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
this, &MyAvatar::goToLocation);
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
[=](const glm::vec3& newPosition, bool hasOrientation, const glm::quat& newOrientation, bool shouldFaceLocation){
goToLocation(newPosition, hasOrientation, newOrientation, shouldFaceLocation);
});
_characterController.setEnabled(true);
_bodySensorMatrix = deriveBodyFromHMDSensor();
@ -1666,6 +1669,41 @@ void MyAvatar::resetSize() {
qCDebug(interfaceapp, "Reset scale to %f", (double)_targetScale);
}
void MyAvatar::goToLocation(const QVariant& propertiesVar) {
qCDebug(interfaceapp, "MyAvatar QML goToLocation");
auto properties = propertiesVar.toMap();
if (!properties.contains("position")) {
qCWarning(interfaceapp, "goToLocation called without a position variable");
return;
}
bool validPosition;
glm::vec3 v = vec3FromVariant(properties["position"], validPosition);
if (!validPosition) {
qCWarning(interfaceapp, "goToLocation called with invalid position variable");
return;
}
bool validOrientation = false;
glm::quat q;
if (properties.contains("orientation")) {
q = quatFromVariant(properties["orientation"], validOrientation);
if (!validOrientation) {
glm::vec3 eulerOrientation = vec3FromVariant(properties["orientation"], validOrientation);
q = glm::quat(eulerOrientation);
if (!validOrientation) {
qCWarning(interfaceapp, "goToLocation called with invalid orientation variable");
}
}
}
if (validOrientation) {
goToLocation(v, true, q);
} else {
goToLocation(v);
}
}
void MyAvatar::goToLocation(const glm::vec3& newPosition,
bool hasOrientation, const glm::quat& newOrientation,
bool shouldFaceLocation) {
@ -1873,7 +1911,7 @@ bool MyAvatar::FollowHelper::shouldActivate(const MyAvatar& myAvatar, const glm:
const float CYLINDER_RADIUS = 0.15f;
glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);
glm::vec3 radialOffset(offset.x, 0.0f, offset.y);
glm::vec3 radialOffset(offset.x, 0.0f, offset.z);
float radialDistance = glm::length(radialOffset);
return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM) || (radialDistance > CYLINDER_RADIUS);

View file

@ -253,6 +253,7 @@ public slots:
void goToLocation(const glm::vec3& newPosition,
bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(),
bool shouldFaceLocation = false);
void goToLocation(const QVariant& properties);
// Set/Get update the thrust that will move the avatar around
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };

View file

@ -283,16 +283,43 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
//Mouse Pointer
if (getReticleVisible()) {
glm::mat4 overlayXfm;
_modelTransform.getMatrix(overlayXfm);
if (getReticleDepth() != 1.0f) {
// calculate the "apparent location" based on the depth and the current ray
glm::vec3 origin, direction;
auto reticlePosition = getReticlePosition();
computeHmdPickRay(reticlePosition, origin, direction);
auto apparentPosition = origin + (direction * getReticleDepth());
auto reticlePosition = getReticlePosition();
glm::vec2 projection = overlayToSpherical(reticlePosition);
float cursorDepth = getReticleDepth();
mat4 pointerXfm = glm::scale(mat4(), vec3(cursorDepth)) * glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
mat4 reticleXfm = overlayXfm * pointerXfm;
reticleXfm = glm::scale(reticleXfm, reticleScale);
batch.setModelTransform(reticleXfm);
// same code as used to render for apparent location
auto myCamera = qApp->getCamera();
mat4 cameraMat = myCamera->getTransform();
auto UITransform = cameraMat * glm::inverse(headPose);
auto relativePosition4 = glm::inverse(UITransform) * vec4(apparentPosition, 1);
auto relativePosition = vec3(relativePosition4) / relativePosition4.w;
auto relativeDistance = glm::length(relativePosition);
// look at borrowed from overlays
float elevation = -asinf(relativePosition.y / glm::length(relativePosition));
float azimuth = atan2f(relativePosition.x, relativePosition.z);
glm::quat faceCamera = glm::quat(glm::vec3(elevation, azimuth, 0)) * quat(vec3(0, 0, -1)); // this extra *quat(vec3(0,0,-1)) was required to get the quad to flip this seems like we could optimize
Transform transform;
transform.setTranslation(relativePosition);
transform.setScale(reticleScale);
transform.postScale(relativeDistance); // scale not quite working, distant things too large
transform.setRotation(faceCamera);
batch.setModelTransform(transform);
} else {
glm::mat4 overlayXfm;
_modelTransform.getMatrix(overlayXfm);
auto reticlePosition = getReticlePosition();
glm::vec2 projection = overlayToSpherical(reticlePosition);
mat4 pointerXfm = glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
mat4 reticleXfm = overlayXfm * pointerXfm;
reticleXfm = glm::scale(reticleXfm, reticleScale);
batch.setModelTransform(reticleXfm);
}
geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad);
}
});
@ -300,7 +327,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
QPointF ApplicationCompositor::getMouseEventPosition(QMouseEvent* event) {
if (qApp->isHMDMode()) {
QMutexLocker locker(&_reticlePositionInHMDLock);
QMutexLocker locker(&_reticleLock);
return QPointF(_reticlePositionInHMD.x, _reticlePositionInHMD.y);
}
return event->localPos();
@ -354,7 +381,7 @@ bool ApplicationCompositor::handleRealMouseMoveEvent(bool sendFakeEvent) {
// If we're in HMD mode
if (shouldCaptureMouse()) {
QMutexLocker locker(&_reticlePositionInHMDLock);
QMutexLocker locker(&_reticleLock);
auto newPosition = QCursor::pos();
auto changeInRealMouse = newPosition - _lastKnownRealMouse;
auto newReticlePosition = _reticlePositionInHMD + toGlm(changeInRealMouse);
@ -368,9 +395,9 @@ bool ApplicationCompositor::handleRealMouseMoveEvent(bool sendFakeEvent) {
return false; // let the caller know to process the event
}
glm::vec2 ApplicationCompositor::getReticlePosition() {
glm::vec2 ApplicationCompositor::getReticlePosition() const {
if (qApp->isHMDMode()) {
QMutexLocker locker(&_reticlePositionInHMDLock);
QMutexLocker locker(&_reticleLock);
return _reticlePositionInHMD;
}
return toGlm(QCursor::pos());
@ -378,7 +405,7 @@ glm::vec2 ApplicationCompositor::getReticlePosition() {
void ApplicationCompositor::setReticlePosition(glm::vec2 position, bool sendFakeEvent) {
if (qApp->isHMDMode()) {
QMutexLocker locker(&_reticlePositionInHMDLock);
QMutexLocker locker(&_reticleLock);
const float MOUSE_EXTENTS_VERT_ANGULAR_SIZE = 170.0f; // 5deg from poles
const float MOUSE_EXTENTS_VERT_PIXELS = VIRTUAL_SCREEN_SIZE_Y * (MOUSE_EXTENTS_VERT_ANGULAR_SIZE / DEFAULT_HMD_UI_VERT_ANGULAR_SIZE);
const float MOUSE_EXTENTS_HORZ_ANGULAR_SIZE = 360.0f; // full sphere

View file

@ -29,6 +29,7 @@ class RenderArgs;
class ReticleInterface;
const float DEFAULT_RETICLE_DEPTH = 1.0f; // FIXME - probably should be based on UI radius
const float MAGNIFY_WIDTH = 220.0f;
const float MAGNIFY_HEIGHT = 100.0f;
@ -46,6 +47,7 @@ class ApplicationCompositor : public QObject {
Q_OBJECT
Q_PROPERTY(float alpha READ getAlpha WRITE setAlpha)
Q_PROPERTY(bool reticleOverDesktop READ getReticleOverDesktop WRITE setReticleOverDesktop)
public:
ApplicationCompositor();
~ApplicationCompositor();
@ -83,13 +85,14 @@ public:
float getAlpha() const { return _alpha; }
void setAlpha(float alpha) { _alpha = alpha; }
bool getReticleVisible() { return _reticleVisible; }
bool getReticleVisible() const { return _reticleVisible; }
void setReticleVisible(bool visible) { _reticleVisible = visible; }
float getReticleDepth() { return _reticleDepth; }
float getReticleDepth() const { return _reticleDepth; }
void setReticleDepth(float depth) { _reticleDepth = depth; }
void resetReticleDepth() { _reticleDepth = DEFAULT_RETICLE_DEPTH; }
glm::vec2 getReticlePosition();
glm::vec2 getReticlePosition() const;
void setReticlePosition(glm::vec2 position, bool sendFakeEvent = true);
glm::vec2 getReticleMaximumPosition() const;
@ -103,7 +106,12 @@ public:
bool shouldCaptureMouse() const;
/// if the reticle is pointing to a system overlay (a dialog box for example) then the function returns true otherwise false
bool getReticleOverDesktop() const { return _isOverDesktop; }
void setReticleOverDesktop(bool value) { _isOverDesktop = value; }
private:
bool _isOverDesktop { true };
void displayOverlayTextureStereo(RenderArgs* renderArgs, float aspectRatio, float fov);
void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
@ -147,11 +155,13 @@ private:
// application specific position, when it's in desktop mode, the reticle position will simply move
// the system mouse.
glm::vec2 _reticlePositionInHMD { 0.0f, 0.0f };
mutable QMutex _reticlePositionInHMDLock{ QMutex::Recursive };
mutable QMutex _reticleLock { QMutex::Recursive };
QPointF _lastKnownRealMouse;
bool _ignoreMouseMove { false };
bool _reticleOverQml { false };
ReticleInterface* _reticleInterface;
};
@ -163,11 +173,13 @@ class ReticleInterface : public QObject {
Q_PROPERTY(float depth READ getDepth WRITE setDepth)
Q_PROPERTY(glm::vec2 maximumPosition READ getMaximumPosition)
Q_PROPERTY(bool mouseCaptured READ isMouseCaptured)
Q_PROPERTY(bool pointingAtSystemOverlay READ isPointingAtSystemOverlay)
public:
ReticleInterface(ApplicationCompositor* outer) : QObject(outer), _compositor(outer) {}
Q_INVOKABLE bool isMouseCaptured() { return _compositor->shouldCaptureMouse(); }
Q_INVOKABLE bool isPointingAtSystemOverlay() { return !_compositor->getReticleOverDesktop(); }
Q_INVOKABLE bool getVisible() { return _compositor->getReticleVisible(); }
Q_INVOKABLE void setVisible(bool visible) { _compositor->setReticleVisible(visible); }
@ -179,6 +191,7 @@ public:
Q_INVOKABLE void setPosition(glm::vec2 position) { _compositor->setReticlePosition(position); }
Q_INVOKABLE glm::vec2 getMaximumPosition() { return _compositor->getReticleMaximumPosition(); }
private:
ApplicationCompositor* _compositor;
};

View file

@ -330,15 +330,6 @@ void setupPreferences() {
preferences->addPreference(preference);
}
auto antialiasingConfig = renderConfig->getConfig<Antialiasing>();
{
auto getter = [antialiasingConfig]()->QString { return antialiasingConfig->getPreset(); };
auto setter = [antialiasingConfig](QString preset) { antialiasingConfig->setPreset(preset); };
auto preference = new ComboBoxPreference(RENDER, "Antialiasing", getter, setter);
preference->setItems(antialiasingConfig->getPresetList());
preferences->addPreference(preference);
}
auto shadowConfig = renderConfig->getConfig<RenderShadowTask>();
{
auto getter = [shadowConfig]()->QString { return shadowConfig->getPreset(); };

View file

@ -342,22 +342,14 @@ void Stats::setRenderDetails(const RenderDetails& details) {
STAT_UPDATE(triangles, details._trianglesRendered);
STAT_UPDATE(materialSwitches, details._materialSwitches);
if (_expanded) {
STAT_UPDATE(opaqueConsidered, (int)details._opaque._considered);
STAT_UPDATE(opaqueOutOfView, details._opaque._outOfView);
STAT_UPDATE(opaqueTooSmall, details._opaque._tooSmall);
STAT_UPDATE(opaqueRendered, (int)details._opaque._rendered);
STAT_UPDATE(shadowConsidered, (int)details._shadow._considered);
STAT_UPDATE(itemConsidered, details._item._considered);
STAT_UPDATE(itemOutOfView, details._item._outOfView);
STAT_UPDATE(itemTooSmall, details._item._tooSmall);
STAT_UPDATE(itemRendered, details._item._rendered);
STAT_UPDATE(shadowConsidered, details._shadow._considered);
STAT_UPDATE(shadowOutOfView, details._shadow._outOfView);
STAT_UPDATE(shadowTooSmall, details._shadow._tooSmall);
STAT_UPDATE(shadowRendered, (int)details._shadow._rendered);
STAT_UPDATE(translucentConsidered, (int)details._translucent._considered);
STAT_UPDATE(translucentOutOfView, details._translucent._outOfView);
STAT_UPDATE(translucentTooSmall, details._translucent._tooSmall);
STAT_UPDATE(translucentRendered, (int)details._translucent._rendered);
STAT_UPDATE(otherConsidered, (int)details._other._considered);
STAT_UPDATE(otherOutOfView, details._other._outOfView);
STAT_UPDATE(otherTooSmall, details._other._tooSmall);
STAT_UPDATE(otherRendered, (int)details._other._rendered);
STAT_UPDATE(shadowRendered, details._shadow._rendered);
}
}

View file

@ -59,22 +59,14 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, triangles, 0)
STATS_PROPERTY(int, quads, 0)
STATS_PROPERTY(int, materialSwitches, 0)
STATS_PROPERTY(int, opaqueConsidered, 0)
STATS_PROPERTY(int, opaqueOutOfView, 0)
STATS_PROPERTY(int, opaqueTooSmall, 0)
STATS_PROPERTY(int, opaqueRendered, 0)
STATS_PROPERTY(int, itemConsidered, 0)
STATS_PROPERTY(int, itemOutOfView, 0)
STATS_PROPERTY(int, itemTooSmall, 0)
STATS_PROPERTY(int, itemRendered, 0)
STATS_PROPERTY(int, shadowConsidered, 0)
STATS_PROPERTY(int, shadowOutOfView, 0)
STATS_PROPERTY(int, shadowTooSmall, 0)
STATS_PROPERTY(int, shadowRendered, 0)
STATS_PROPERTY(int, translucentConsidered, 0)
STATS_PROPERTY(int, translucentOutOfView, 0)
STATS_PROPERTY(int, translucentTooSmall, 0)
STATS_PROPERTY(int, translucentRendered, 0)
STATS_PROPERTY(int, otherConsidered, 0)
STATS_PROPERTY(int, otherOutOfView, 0)
STATS_PROPERTY(int, otherTooSmall, 0)
STATS_PROPERTY(int, otherRendered, 0)
STATS_PROPERTY(QString, sendingMode, QString())
STATS_PROPERTY(QString, packetStats, QString())
STATS_PROPERTY(QString, lodStatus, QString())
@ -145,22 +137,14 @@ signals:
void trianglesChanged();
void quadsChanged();
void materialSwitchesChanged();
void opaqueConsideredChanged();
void opaqueOutOfViewChanged();
void opaqueTooSmallChanged();
void opaqueRenderedChanged();
void itemConsideredChanged();
void itemOutOfViewChanged();
void itemTooSmallChanged();
void itemRenderedChanged();
void shadowConsideredChanged();
void shadowOutOfViewChanged();
void shadowTooSmallChanged();
void shadowRenderedChanged();
void translucentConsideredChanged();
void translucentOutOfViewChanged();
void translucentTooSmallChanged();
void translucentRenderedChanged();
void otherConsideredChanged();
void otherOutOfViewChanged();
void otherTooSmallChanged();
void otherRenderedChanged();
void sendingModeChanged();
void packetStatsChanged();
void lodStatusChanged();

View file

@ -45,7 +45,7 @@ void ModelOverlay::update(float deltatime) {
_updateModel = false;
_model.setSnapModelToCenter(true);
_model.setScale(getScale());
_model.setScale(getDimensions());
_model.setRotation(getRotation());
_model.setTranslation(getPosition());
_model.setURL(_url);
@ -82,22 +82,6 @@ void ModelOverlay::render(RenderArgs* args) {
if (!_visible) {
return;
}
/*
if (_model.isActive()) {
if (_model.isRenderable()) {
float glowLevel = getGlowLevel();
Glower* glower = NULL;
if (glowLevel > 0.0f) {
glower = new Glower(glowLevel);
}
_model.render(args, getAlpha());
if (glower) {
delete glower;
}
}
}
*/
}
void ModelOverlay::setProperties(const QScriptValue &properties) {
@ -107,10 +91,19 @@ void ModelOverlay::setProperties(const QScriptValue &properties) {
Volume3DOverlay::setProperties(properties);
if (position != getPosition() || rotation != getRotation() || scale != getDimensions()) {
_model.setScaleToFit(true, getScale());
if (position != getPosition() || rotation != getRotation()) {
_updateModel = true;
}
if (scale != getDimensions()) {
auto newScale = getDimensions();
if (newScale.x <= 0 || newScale.y <= 0 || newScale.z <= 0) {
setDimensions(scale);
} else {
_model.setScaleToFit(true, getDimensions());
_updateModel = true;
}
}
QScriptValue urlValue = properties.property("url");
if (urlValue.isValid() && urlValue.isString()) {
@ -140,7 +133,7 @@ QScriptValue ModelOverlay::getProperty(const QString& property) {
if (property == "url") {
return _url.toString();
}
if (property == "dimensions") {
if (property == "dimensions" || property == "scale" || property == "size") {
return vec3toScriptValue(_scriptEngine, _model.getScaleToFitDimensions());
}
if (property == "textures") {

View file

@ -229,6 +229,6 @@ bool Overlay::addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene
void Overlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_renderItemID);
_renderItemID = render::Item::INVALID_ITEM_ID;
render::Item::clearID(_renderItemID);
}

View file

@ -94,7 +94,7 @@ void Overlays::cleanupOverlaysToDelete() {
Overlay::Pointer overlay = _overlaysToDelete.takeLast();
auto itemID = overlay->getRenderItemID();
if (itemID != render::Item::INVALID_ITEM_ID) {
if (render::Item::isValidID(itemID)) {
overlay->removeFromScene(overlay, scene, pendingChanges);
}
} while (!_overlaysToDelete.isEmpty());
@ -241,7 +241,7 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
render::ItemKey itemKey = render::payloadGetKey(thisOverlay);
if (itemKey != oldItemKey) {
auto itemID = thisOverlay->getRenderItemID();
if (itemID != render::Item::INVALID_ITEM_ID) {
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges;
pendingChanges.resortItem(itemID, oldItemKey, itemKey);

View file

@ -104,7 +104,9 @@ void AudioInjector::restart() {
// reset state to start sending from beginning again
_nextFrame = 0;
_frameTimer->invalidate();
if (_frameTimer) {
_frameTimer->invalidate();
}
_hasSentFirstFrame = false;
// check our state to decide if we need extra handling for the restart request
@ -122,7 +124,9 @@ void AudioInjector::restart() {
injectLocally();
} else {
// wake the AudioInjectorManager back up if it's stuck waiting
injectorManager->restartFinishedInjector(this);
if (!injectorManager->restartFinishedInjector(this)) {
_state = State::Finished; // we're not playing, so reset the state used by isPlaying.
}
}
}
}

View file

@ -129,6 +129,15 @@ void AudioInjectorManager::run() {
static const int MAX_INJECTORS_PER_THREAD = 40; // calculated based on AudioInjector time to send frame, with sufficient padding
bool AudioInjectorManager::wouldExceedLimits() { // Should be called inside of a lock.
if (_injectors.size() >= MAX_INJECTORS_PER_THREAD) {
qDebug() << "AudioInjectorManager::threadInjector could not thread AudioInjector - at max of"
<< MAX_INJECTORS_PER_THREAD << "current audio injectors.";
return true;
}
return false;
}
bool AudioInjectorManager::threadInjector(AudioInjector* injector) {
if (_shouldStop) {
qDebug() << "AudioInjectorManager::threadInjector asked to thread injector but is shutting down.";
@ -138,8 +147,9 @@ bool AudioInjectorManager::threadInjector(AudioInjector* injector) {
// guard the injectors vector with a mutex
Lock lock(_injectorsMutex);
// check if we'll be able to thread this injector (do we have < max concurrent injectors)
if (_injectors.size() < MAX_INJECTORS_PER_THREAD) {
if (wouldExceedLimits()) {
return false;
} else {
if (!_thread) {
createThread();
}
@ -156,23 +166,22 @@ bool AudioInjectorManager::threadInjector(AudioInjector* injector) {
_injectorReady.notify_one();
return true;
} else {
// unable to thread this injector, at the max
qDebug() << "AudioInjectorManager::threadInjector could not thread AudioInjector - at max of"
<< MAX_INJECTORS_PER_THREAD << "current audio injectors.";
return false;
}
}
void AudioInjectorManager::restartFinishedInjector(AudioInjector* injector) {
bool AudioInjectorManager::restartFinishedInjector(AudioInjector* injector) {
if (!_shouldStop) {
// guard the injectors vector with a mutex
Lock lock(_injectorsMutex);
if (wouldExceedLimits()) {
return false;
}
// add the injector to the queue with a send timestamp of now
_injectors.emplace(usecTimestampNow(), InjectorQPointer { injector });
// notify our wait condition so we can inject two frames for this injector immediately
_injectorReady.notify_one();
}
return true;
}

View file

@ -50,8 +50,9 @@ private:
using Lock = std::unique_lock<Mutex>;
bool threadInjector(AudioInjector* injector);
void restartFinishedInjector(AudioInjector* injector);
bool restartFinishedInjector(AudioInjector* injector);
void notifyInjectorReadyCondition() { _injectorReady.notify_one(); }
bool wouldExceedLimits();
AudioInjectorManager() {};
AudioInjectorManager(const AudioInjectorManager&) = delete;

View file

@ -93,6 +93,7 @@ public:
PalmData(HandData* owningHandData = nullptr, HandData::Hand hand = HandData::UnknownHand);
glm::vec3 getPosition() const { return _owningHandData->localToWorldPosition(_rawPosition); }
glm::vec3 getVelocity() const { return _owningHandData->localToWorldDirection(_rawVelocity); }
glm::vec3 getAngularVelocity() const { return _owningHandData->localToWorldDirection(_rawAngularVelocity); }
const glm::vec3& getRawPosition() const { return _rawPosition; }
bool isActive() const { return _isActive; }

View file

@ -66,10 +66,11 @@ public:
void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_myItem);
render::Item::clearID(_myItem);
}
void notifyChanged() {
if (_myItem == render::Item::INVALID_ITEM_ID) {
if (!render::Item::isValidID(_myItem)) {
return;
}

View file

@ -251,6 +251,7 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p
void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_myMetaItem);
render::Item::clearID(_myMetaItem);
if (_model) {
_model->removeFromScene(scene, pendingChanges);
}

View file

@ -179,6 +179,7 @@ void RenderableParticleEffectEntityItem::removeFromScene(EntityItemPointer self,
render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_renderItemId);
_scene = nullptr;
render::Item::clearID(_renderItemId);
};
void RenderableParticleEffectEntityItem::update(const quint64& now) {
@ -199,7 +200,8 @@ void RenderableParticleEffectEntityItem::update(const quint64& now) {
}
void RenderableParticleEffectEntityItem::updateRenderItem() {
if (!_scene) {
// this 2 tests are synonyms for this class, but we would like to get rid of the _scene pointer ultimately
if (!_scene || !render::Item::isValidID(_renderItemId)) {
return;
}
if (!getVisible()) {
@ -312,7 +314,7 @@ void RenderableParticleEffectEntityItem::createPipelines() {
}
void RenderableParticleEffectEntityItem::notifyBoundChanged() {
if (_renderItemId == render::Item::INVALID_ITEM_ID) {
if (!render::Item::isValidID(_renderItemId)) {
return;
}
render::PendingChanges pendingChanges;

View file

@ -572,6 +572,7 @@ void RenderablePolyVoxEntityItem::removeFromScene(EntityItemPointer self,
std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_myItem);
render::Item::clearID(_myItem);
}
namespace render {

View file

@ -230,6 +230,7 @@ bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_pt
void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_myMetaItem);
render::Item::clearID(_myMetaItem);
if (_model) {
_model->removeFromScene(scene, pendingChanges);
}
@ -237,7 +238,7 @@ void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, std::shar
void RenderableZoneEntityItem::notifyBoundChanged() {
if (_myMetaItem == render::Item::INVALID_ITEM_ID) {
if (!render::Item::isValidID(_myMetaItem)) {
return;
}
render::PendingChanges pendingChanges;

View file

@ -44,11 +44,12 @@ out vec4 varColor;
out vec2 varTexcoord;
const int NUM_VERTICES_PER_PARTICLE = 4;
// This ordering ensures that un-rotated particles render upright in the wiewer.
const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE](
vec4(-1.0, -1.0, 0.0, 0.0),
vec4(1.0, -1.0, 0.0, 0.0),
vec4(-1.0, 1.0, 0.0, 0.0),
vec4(1.0, 1.0, 0.0, 0.0)
vec4(-1.0, -1.0, 0.0, 0.0),
vec4(1.0, 1.0, 0.0, 0.0),
vec4(1.0, -1.0, 0.0, 0.0)
);
float bezierInterpolate(float y1, float y2, float y3, float u) {
@ -115,7 +116,8 @@ void main(void) {
float seed = inColor.y;
// Pass the texcoord and the z texcoord is representing the texture icon
varTexcoord = vec2((UNIT_QUAD[twoTriID].xy + 1.0) * 0.5);
// Offset for corrected vertex ordering.
varTexcoord = vec2((UNIT_QUAD[twoTriID].xy -1.0) * vec2(0.5, -0.5));
varColor = interpolate3Vec4(particle.color.start, particle.color.middle, particle.color.finish, age);
// anchor point in eye space

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

@ -21,6 +21,17 @@
class NLPacket : public udt::Packet {
Q_OBJECT
public:
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Packet Type | Packet Version |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Node UUID | Hash (only if verified) | Optional (only if sourced)
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// NLPacket Header Format
// this is used by the Octree classes - must be known at compile time
static const int MAX_PACKET_HEADER_SIZE =
sizeof(udt::Packet::SequenceNumberAndBitField) + sizeof(udt::Packet::MessageNumberAndBitField) +

View file

@ -26,10 +26,65 @@ namespace udt {
static const int UDP_SEND_BUFFER_SIZE_BYTES = 1048576;
static const int UDP_RECEIVE_BUFFER_SIZE_BYTES = 1048576;
static const int DEFAULT_SYN_INTERVAL_USECS = 10 * 1000;
static const int SEQUENCE_NUMBER_BITS = sizeof(SequenceNumber) * 8;
static const int MESSAGE_LINE_NUMBER_BITS = 32;
static const int MESSAGE_NUMBER_BITS = 30;
static const uint32_t CONTROL_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 1);
// Header constants
// Bit sizes (in order)
static const int CONTROL_BIT_SIZE = 1;
static const int RELIABILITY_BIT_SIZE = 1;
static const int MESSAGE_BIT_SIZE = 1;
static const int OBFUSCATION_LEVEL_SIZE = 2;
static const int SEQUENCE_NUMBER_SIZE= 27;
static const int PACKET_POSITION_SIZE = 2;
static const int MESSAGE_NUMBER_SIZE = 30;
static const int MESSAGE_PART_NUMBER_SIZE = 32;
// Offsets
static const int SEQUENCE_NUMBER_OFFSET = 0;
static const int OBFUSCATION_LEVEL_OFFSET = SEQUENCE_NUMBER_OFFSET + SEQUENCE_NUMBER_SIZE;
static const int MESSAGE_BIT_OFFSET = OBFUSCATION_LEVEL_OFFSET + OBFUSCATION_LEVEL_SIZE;
static const int RELIABILITY_BIT_OFFSET = MESSAGE_BIT_OFFSET + MESSAGE_BIT_SIZE;
static const int CONTROL_BIT_OFFSET = RELIABILITY_BIT_OFFSET + RELIABILITY_BIT_SIZE;
static const int MESSAGE_NUMBER_OFFSET = 0;
static const int PACKET_POSITION_OFFSET = MESSAGE_NUMBER_OFFSET + MESSAGE_NUMBER_SIZE;
static const int MESSAGE_PART_NUMBER_OFFSET = 0;
// Masks
static const uint32_t CONTROL_BIT_MASK = uint32_t(1) << CONTROL_BIT_OFFSET;
static const uint32_t RELIABILITY_BIT_MASK = uint32_t(1) << RELIABILITY_BIT_OFFSET;
static const uint32_t MESSAGE_BIT_MASK = uint32_t(1) << MESSAGE_BIT_OFFSET;
static const uint32_t OBFUSCATION_LEVEL_MASK = uint32_t(3) << OBFUSCATION_LEVEL_OFFSET;
static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK | OBFUSCATION_LEVEL_MASK;
static const uint32_t SEQUENCE_NUMBER_MASK = ~BIT_FIELD_MASK;
static const uint32_t PACKET_POSITION_MASK = uint32_t(3) << PACKET_POSITION_OFFSET;
static const uint32_t MESSAGE_NUMBER_MASK = ~PACKET_POSITION_MASK;
static const uint32_t MESSAGE_PART_NUMBER_MASK = ~uint32_t(0);
// Static checks
static_assert(CONTROL_BIT_SIZE + RELIABILITY_BIT_SIZE + MESSAGE_BIT_SIZE +
OBFUSCATION_LEVEL_SIZE + SEQUENCE_NUMBER_SIZE == 32, "Sequence number line size incorrect");
static_assert(PACKET_POSITION_SIZE + MESSAGE_NUMBER_SIZE == 32, "Message number line size incorrect");
static_assert(MESSAGE_PART_NUMBER_SIZE == 32, "Message part number line size incorrect");
static_assert(CONTROL_BIT_MASK == 0x80000000, "CONTROL_BIT_MASK incorrect");
static_assert(RELIABILITY_BIT_MASK == 0x40000000, "RELIABILITY_BIT_MASK incorrect");
static_assert(MESSAGE_BIT_MASK == 0x20000000, "MESSAGE_BIT_MASK incorrect");
static_assert(OBFUSCATION_LEVEL_MASK == 0x18000000, "OBFUSCATION_LEVEL_MASK incorrect");
static_assert(BIT_FIELD_MASK == 0xF8000000, "BIT_FIELD_MASK incorrect");
static_assert(SEQUENCE_NUMBER_MASK == 0x07FFFFFF, "SEQUENCE_NUMBER_MASK incorrect");
static_assert(PACKET_POSITION_MASK == 0xC0000000, "PACKET_POSITION_MASK incorrect");
static_assert(MESSAGE_NUMBER_MASK == 0x3FFFFFFF, "MESSAGE_NUMBER_MASK incorrect");
static_assert(MESSAGE_PART_NUMBER_MASK == 0xFFFFFFFF, "MESSAGE_PART_NUMBER_MASK incorrect");
}
#endif // hifi_udt_Constants_h

View file

@ -11,10 +11,35 @@
#include "Packet.h"
#include <array>
#include <LogHandler.h>
using namespace udt;
static int packetMetaTypeId = qRegisterMetaType<Packet*>("Packet*");
using Key = uint64_t;
static const std::array<Key, 4> KEYS {{
0x0,
0x6362726973736574,
0x7362697261726461,
0x72687566666d616e,
}};
void xorHelper(char* start, int size, Key key) {
const auto end = start + size;
auto p = start;
for (; p + sizeof(Key) < end; p += sizeof(Key)) {
*reinterpret_cast<Key*>(p) ^= key;
}
for (int i = 0; p < end; ++p || ++i) {
*p ^= *(reinterpret_cast<const char*>(&key) + i);
}
}
int Packet::localHeaderSize(bool isPartOfMessage) {
return sizeof(Packet::SequenceNumberAndBitField) +
(isPartOfMessage ? sizeof(Packet::MessageNumberAndBitField) + sizeof(MessagePartNumber) : 0);
@ -69,44 +94,48 @@ Packet::Packet(std::unique_ptr<char[]> data, qint64 size, const HifiSockAddr& se
readHeader();
adjustPayloadStartAndCapacity(Packet::localHeaderSize(_isPartOfMessage), _payloadSize > 0);
if (getObfuscationLevel() != Packet::NoObfuscation) {
#ifdef UDT_CONNECTION_DEBUG
QString debugString = "Unobfuscating packet %1 with level %2";
debugString = debugString.arg(QString::number((uint32_t)getSequenceNumber()),
QString::number(getObfuscationLevel()));
if (isPartOfMessage()) {
debugString += "\n";
debugString += " Message Number: %1, Part Number: %2.";
debugString = debugString.arg(QString::number(getMessageNumber()),
QString::number(getMessagePartNumber()));
}
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("^Unobfuscating packet .*");
qDebug() << qPrintable(debugString);
#endif
obfuscate(NoObfuscation); // Undo obfuscation
}
}
Packet::Packet(const Packet& other) :
BasePacket(other)
{
_isReliable = other._isReliable;
_isPartOfMessage = other._isPartOfMessage;
_sequenceNumber = other._sequenceNumber;
Packet::Packet(const Packet& other) : BasePacket(other) {
copyMembers(other);
}
Packet& Packet::operator=(const Packet& other) {
BasePacket::operator=(other);
_isReliable = other._isReliable;
_isPartOfMessage = other._isPartOfMessage;
_sequenceNumber = other._sequenceNumber;
copyMembers(other);
return *this;
}
Packet::Packet(Packet&& other) :
BasePacket(std::move(other))
{
_isReliable = other._isReliable;
_isPartOfMessage = other._isPartOfMessage;
_sequenceNumber = other._sequenceNumber;
_packetPosition = other._packetPosition;
_messageNumber = other._messageNumber;
Packet::Packet(Packet&& other) : BasePacket(std::move(other)) {
copyMembers(other);
}
Packet& Packet::operator=(Packet&& other) {
BasePacket::operator=(std::move(other));
_isReliable = other._isReliable;
_isPartOfMessage = other._isPartOfMessage;
_sequenceNumber = other._sequenceNumber;
_packetPosition = other._packetPosition;
_messageNumber = other._messageNumber;
copyMembers(other);
return *this;
}
@ -124,13 +153,27 @@ void Packet::writeSequenceNumber(SequenceNumber sequenceNumber) const {
writeHeader();
}
static const uint32_t RELIABILITY_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 2);
static const uint32_t MESSAGE_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 3);
static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK;
void Packet::obfuscate(ObfuscationLevel level) {
auto obfuscationKey = KEYS[getObfuscationLevel()] ^ KEYS[level]; // Undo old and apply new one.
if (obfuscationKey != 0) {
xorHelper(getData() + localHeaderSize(isPartOfMessage()),
getDataSize() - localHeaderSize(isPartOfMessage()), obfuscationKey);
static const uint8_t PACKET_POSITION_OFFSET = 30;
static const uint32_t PACKET_POSITION_MASK = uint32_t(0x03) << PACKET_POSITION_OFFSET;
static const uint32_t MESSAGE_NUMBER_MASK = ~PACKET_POSITION_MASK;
// Update members and header
_obfuscationLevel = level;
writeHeader();
}
}
void Packet::copyMembers(const Packet& other) {
_isReliable = other._isReliable;
_isPartOfMessage = other._isPartOfMessage;
_obfuscationLevel = other._obfuscationLevel;
_sequenceNumber = other._sequenceNumber;
_packetPosition = other._packetPosition;
_messageNumber = other._messageNumber;
_messagePartNumber = other._messagePartNumber;
}
void Packet::readHeader() const {
SequenceNumberAndBitField* seqNumBitField = reinterpret_cast<SequenceNumberAndBitField*>(_packet.get());
@ -139,10 +182,12 @@ void Packet::readHeader() const {
_isReliable = (bool) (*seqNumBitField & RELIABILITY_BIT_MASK); // Only keep reliability bit
_isPartOfMessage = (bool) (*seqNumBitField & MESSAGE_BIT_MASK); // Only keep message bit
_sequenceNumber = SequenceNumber{ *seqNumBitField & ~BIT_FIELD_MASK }; // Remove the bit field
_obfuscationLevel = (ObfuscationLevel)((*seqNumBitField & OBFUSCATION_LEVEL_MASK) >> OBFUSCATION_LEVEL_OFFSET);
_sequenceNumber = SequenceNumber{ *seqNumBitField & SEQUENCE_NUMBER_MASK }; // Remove the bit field
if (_isPartOfMessage) {
MessageNumberAndBitField* messageNumberAndBitField = seqNumBitField + 1;
_messageNumber = *messageNumberAndBitField & MESSAGE_NUMBER_MASK;
_packetPosition = static_cast<PacketPosition>(*messageNumberAndBitField >> PACKET_POSITION_OFFSET);
@ -163,6 +208,10 @@ void Packet::writeHeader() const {
if (_isReliable) {
*seqNumBitField |= RELIABILITY_BIT_MASK;
}
if (_obfuscationLevel != NoObfuscation) {
*seqNumBitField |= (_obfuscationLevel << OBFUSCATION_LEVEL_OFFSET);
}
if (_isPartOfMessage) {
*seqNumBitField |= MESSAGE_BIT_MASK;

View file

@ -25,6 +25,25 @@ namespace udt {
class Packet : public BasePacket {
Q_OBJECT
public:
// Packet Header Format
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |C|R|M| O | Sequence Number |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | P | Message Number | Optional (only if M = 1)
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Message Part Number | Optional (only if M = 1)
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// C: Control bit
// R: Reliable bit
// M: Message bit
// O: Obfuscation level
// P: Position bits
// NOTE: The SequenceNumber is only actually 29 bits to leave room for a bit field
using SequenceNumberAndBitField = uint32_t;
@ -35,12 +54,20 @@ public:
// Use same size as MessageNumberAndBitField so we can use the enum with bitwise operations
enum PacketPosition : MessageNumberAndBitField {
ONLY = 0x0,
FIRST = 0x2,
MIDDLE = 0x3,
LAST = 0x1
ONLY = 0x0, // 00
FIRST = 0x2, // 10
MIDDLE = 0x3, // 11
LAST = 0x1 // 01
};
// Use same size as SequenceNumberAndBitField so we can use the enum with bitwise operations
enum ObfuscationLevel : SequenceNumberAndBitField {
NoObfuscation = 0x0, // 00
ObfuscationL1 = 0x1, // 01
ObfuscationL2 = 0x2, // 10
ObfuscationL3 = 0x3, // 11
};
static std::unique_ptr<Packet> create(qint64 size = -1, bool isReliable = false, bool isPartOfMessage = false);
static std::unique_ptr<Packet> fromReceivedPacket(std::unique_ptr<char[]> data, qint64 size, const HifiSockAddr& senderSockAddr);
@ -56,7 +83,8 @@ public:
bool isPartOfMessage() const { return _isPartOfMessage; }
bool isReliable() const { return _isReliable; }
ObfuscationLevel getObfuscationLevel() const { return _obfuscationLevel; }
SequenceNumber getSequenceNumber() const { return _sequenceNumber; }
MessageNumber getMessageNumber() const { return _messageNumber; }
PacketPosition getPacketPosition() const { return _packetPosition; }
@ -64,6 +92,7 @@ public:
void writeMessageNumber(MessageNumber messageNumber, PacketPosition position, MessagePartNumber messagePartNumber);
void writeSequenceNumber(SequenceNumber sequenceNumber) const;
void obfuscate(ObfuscationLevel level);
protected:
Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false);
@ -76,6 +105,8 @@ protected:
Packet& operator=(Packet&& other);
private:
void copyMembers(const Packet& other);
// Header readers - these read data to member variables after pulling packet off wire
void readHeader() const;
void writeHeader() const;
@ -83,6 +114,7 @@ private:
// Simple holders to prevent multiple reading and bitwise ops
mutable bool _isReliable { false };
mutable bool _isPartOfMessage { false };
mutable ObfuscationLevel _obfuscationLevel { NoObfuscation };
mutable SequenceNumber _sequenceNumber { 0 };
mutable MessageNumber _messageNumber { 0 };
mutable PacketPosition _packetPosition { PacketPosition::ONLY };

View file

@ -16,7 +16,7 @@
using namespace udt;
MessageNumber PacketQueue::getNextMessageNumber() {
static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << MESSAGE_NUMBER_BITS;
static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << MESSAGE_NUMBER_SIZE;
_currentMessageNumber = (_currentMessageNumber + 1) % MAX_MESSAGE_NUMBER;
return _currentMessageNumber;
}

View file

@ -18,6 +18,7 @@
#include <QtCore/QDateTime>
#include <QtCore/QThread>
#include <LogHandler.h>
#include <SharedUtil.h>
#include "../NetworkLogging.h"
@ -225,7 +226,9 @@ void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr<Packet> newPacket,
{
// Insert the packet we have just sent in the sent list
QWriteLocker locker(&_sentLock);
_sentPackets[newPacket->getSequenceNumber()].swap(newPacket);
auto& entry = _sentPackets[newPacket->getSequenceNumber()];
entry.first = 0; // No resend
entry.second.swap(newPacket);
}
Q_ASSERT_X(!newPacket, "SendQueue::sendNewPacketAndAddToSentList()", "Overriden packet in sent list");
@ -354,14 +357,46 @@ bool SendQueue::maybeResendPacket() {
auto it = _sentPackets.find(resendNumber);
if (it != _sentPackets.end()) {
auto& entry = it->second;
// we found the packet - grab it
auto& resendPacket = *(it->second);
// send it off
sendPacket(resendPacket);
// unlock the sent packets
sentLocker.unlock();
auto& resendPacket = *(entry.second);
++entry.first; // Add 1 resend
Packet::ObfuscationLevel level = (Packet::ObfuscationLevel)(entry.first < 2 ? 0 : (entry.first - 2) % 4);
if (level != Packet::NoObfuscation) {
#ifdef UDT_CONNECTION_DEBUG
QString debugString = "Obfuscating packet %1 with level %2";
debugString = debugString.arg(QString::number((uint32_t)resendPacket.getSequenceNumber()),
QString::number(level));
if (resendPacket.isPartOfMessage()) {
debugString += "\n";
debugString += " Message Number: %1, Part Number: %2.";
debugString = debugString.arg(QString::number(resendPacket.getMessageNumber()),
QString::number(resendPacket.getMessagePartNumber()));
}
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("^Obfuscating packet .*");
qCritical() << qPrintable(debugString);
#endif
// Create copy of the packet
auto packet = Packet::createCopy(resendPacket);
// unlock the sent packets
sentLocker.unlock();
// Obfuscate packet
packet->obfuscate(level);
// send it off
sendPacket(*packet);
} else {
// send it off
sendPacket(resendPacket);
// unlock the sent packets
sentLocker.unlock();
}
emit packetRetransmitted();

View file

@ -126,7 +126,8 @@ private:
LossList _naks; // Sequence numbers of packets to resend
mutable QReadWriteLock _sentLock; // Protects the sent packet list
std::unordered_map<SequenceNumber, std::unique_ptr<Packet>> _sentPackets; // Packets waiting for ACK.
using PacketResendPair = std::pair<uint8_t, std::unique_ptr<Packet>>; // Number of resend + packet ptr
std::unordered_map<SequenceNumber, PacketResendPair> _sentPackets; // Packets waiting for ACK.
std::mutex _handshakeMutex; // Protects the handshake ACK condition_variable
std::atomic<bool> _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client

View file

@ -24,9 +24,9 @@ public:
using Type = int32_t;
using UType = uint32_t;
// Values are for 29 bit SequenceNumber
static const Type THRESHOLD = 0x0FFFFFFF; // threshold for comparing sequence numbers
static const Type MAX = 0x1FFFFFFF; // maximum sequence number used in UDT
// Values are for 27 bit SequenceNumber
static const Type THRESHOLD = 0x03FFFFFF; // threshold for comparing sequence numbers
static const Type MAX = 0x07FFFFFF; // maximum sequence number used in UDT
SequenceNumber() = default;
SequenceNumber(const SequenceNumber& other) : _value(other._value) {}

View file

@ -277,7 +277,7 @@ void Socket::readPendingDatagrams() {
if (packet->isReliable()) {
// if this was a reliable packet then signal the matching connection with the sequence number
auto& connection = findOrCreateConnection(senderSockAddr);
if (!connection.processReceivedSequenceNumber(packet->getSequenceNumber(),
packet->getDataSize(),
packet->getPayloadSize())) {

View file

@ -16,11 +16,11 @@
#include "render/DrawTask.h"
class AntiAliasingConfig : public render::Job::Config::Persistent {
class AntiAliasingConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled)
public:
AntiAliasingConfig() : render::Job::Config::Persistent("Antialiasing", false) {}
AntiAliasingConfig() : render::Job::Config(true) {}
};
class Antialiasing {

View file

@ -43,7 +43,7 @@ Model::Model(RigPointer rig, QObject* parent) :
_rotation(),
_scale(1.0f, 1.0f, 1.0f),
_scaleToFit(false),
_scaleToFitDimensions(0.0f),
_scaleToFitDimensions(1.0f),
_scaledToFit(false),
_snapModelToRegistrationPoint(false),
_snappedToRegistrationPoint(false),
@ -909,6 +909,14 @@ void Model::setScaleToFit(bool scaleToFit, float largestDimension, bool forceRes
}
}
glm::vec3 Model::getScaleToFitDimensions() const {
if (_scaleToFitDimensions.y == FAKE_DIMENSION_PLACEHOLDER &&
_scaleToFitDimensions.z == FAKE_DIMENSION_PLACEHOLDER) {
return glm::vec3(_scaleToFitDimensions.x);
}
return _scaleToFitDimensions;
}
void Model::scaleToFit() {
// If our _scaleToFitDimensions.y/z are FAKE_DIMENSION_PLACEHOLDER then it means our
// user asked to scale us in a fixed aspect ratio to a single largest dimension, but

View file

@ -197,7 +197,7 @@ public:
/// enables/disables scale to fit behavior, the model will be automatically scaled to the specified largest dimension
bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit
const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to
glm::vec3 getScaleToFitDimensions() const; /// the dimensions model is scaled to, including inferred y/z
void setCauterizeBones(bool flag) { _cauterizeBones = flag; }
bool getCauterizeBones() const { return _cauterizeBones; }

View file

@ -56,7 +56,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
// Fetch and cull the items from the scene
auto sceneFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
const auto sceneSelection = addJob<FetchSpatialTree>("FetchSceneSelection", sceneFilter);
const auto culledSceneSelection = addJob<CullSpatialSelection>("CullSceneSelection", sceneSelection, cullFunctor, RenderDetails::OPAQUE_ITEM, sceneFilter);
const auto culledSceneSelection = addJob<CullSpatialSelection>("CullSceneSelection", sceneSelection, cullFunctor, RenderDetails::ITEM, sceneFilter);
// Multi filter visible items into different buckets
const int NUM_FILTERS = 3;

View file

@ -108,7 +108,7 @@ RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) : Task(std::make_sha
const auto fetchedItems = addJob<FetchItems>("FetchShadowMap");
// CPU: Cull against KeyLight frustum (nearby viewing camera)
const auto culledItems = addJob<CullItems<RenderDetails::SHADOW_ITEM>>("CullShadowMap", fetchedItems, cullFunctor);
const auto culledItems = addJob<CullItems<RenderDetails::SHADOW>>("CullShadowMap", fetchedItems, cullFunctor);
// CPU: Sort by pipeline
const auto sortedShapes = addJob<PipelineSortShapes>("PipelineSortShadowSort", culledItems);

View file

@ -44,11 +44,11 @@ void main() {
// fetch raw RGB values for nearby locations
// sampling pattern is "five on a die" (each diagonal direction and the center)
// computing the coordinates for these texture reads could be moved to the vertex shader for speed if needed
vec3 rgbNW = texture2D(colorTexture, varTexcoord + (vec2(-1.0, -1.0) * texcoordOffset)).xyz;
vec3 rgbNE = texture2D(colorTexture, varTexcoord + (vec2(+1.0, -1.0) * texcoordOffset)).xyz;
vec3 rgbSW = texture2D(colorTexture, varTexcoord + (vec2(-1.0, +1.0) * texcoordOffset)).xyz;
vec3 rgbSE = texture2D(colorTexture, varTexcoord + (vec2(+1.0, +1.0) * texcoordOffset)).xyz;
vec3 rgbM = texture2D(colorTexture, varTexcoord).xyz;
vec3 rgbNW = texture(colorTexture, varTexcoord + (vec2(-1.0, -1.0) * texcoordOffset)).xyz;
vec3 rgbNE = texture(colorTexture, varTexcoord + (vec2(+1.0, -1.0) * texcoordOffset)).xyz;
vec3 rgbSW = texture(colorTexture, varTexcoord + (vec2(-1.0, +1.0) * texcoordOffset)).xyz;
vec3 rgbSE = texture(colorTexture, varTexcoord + (vec2(+1.0, +1.0) * texcoordOffset)).xyz;
vec3 rgbM = texture(colorTexture, varTexcoord).xyz;
// convert RGB values to luminance
vec3 luma = vec3(0.299, 0.587, 0.114);
@ -76,11 +76,11 @@ void main() {
// perform additional texture sampling perpendicular to gradient
vec3 rgbA = (1.0 / 2.0) * (
texture2D(colorTexture, varTexcoord + dir * (1.0 / 3.0 - 0.5)).xyz +
texture2D(colorTexture, varTexcoord + dir * (2.0 / 3.0 - 0.5)).xyz);
texture(colorTexture, varTexcoord + dir * (1.0 / 3.0 - 0.5)).xyz +
texture(colorTexture, varTexcoord + dir * (2.0 / 3.0 - 0.5)).xyz);
vec3 rgbB = rgbA * (1.0 / 2.0) + (1.0 / 4.0) * (
texture2D(colorTexture, varTexcoord + dir * (0.0 / 3.0 - 0.5)).xyz +
texture2D(colorTexture, varTexcoord + dir * (3.0 / 3.0 - 0.5)).xyz);
texture(colorTexture, varTexcoord + dir * (0.0 / 3.0 - 0.5)).xyz +
texture(colorTexture, varTexcoord + dir * (3.0 / 3.0 - 0.5)).xyz);
float lumaB = dot(rgbB, luma);
// compare luma of new samples to the luma range of the original neighborhood

View file

@ -28,7 +28,7 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc
RenderArgs* args = renderContext->args;
ViewFrustum* frustum = args->_viewFrustum;
details._considered += inItems.size();
details._considered += (int)inItems.size();
// Culling / LOD
for (auto item : inItems) {
@ -59,7 +59,7 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc
details._outOfView++;
}
}
details._rendered += outItems.size();
details._rendered += (int)outItems.size();
}
struct ItemBoundSort {
@ -202,7 +202,7 @@ void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const Re
auto& scene = sceneContext->_scene;
auto& details = args->_details.edit(_detailType);
details._considered += inSelection.numItems();
details._considered += (int)inSelection.numItems();
// Eventually use a frozen frustum
auto argFrustum = args->_viewFrustum;
@ -325,7 +325,7 @@ void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const Re
}
}
details._rendered += outItems.size();
details._rendered += (int)outItems.size();
// Restore frustum if using the frozen one:

View file

@ -138,7 +138,7 @@ namespace render {
_cullFunctor{ cullFunctor } {}
CullFunctor _cullFunctor;
RenderDetails::Type _detailType{ RenderDetails::OPAQUE_ITEM };
RenderDetails::Type _detailType{ RenderDetails::OTHER };
ItemFilter _filter{ ItemFilter::Builder::opaqueShape().withoutLayered() };
void configure(const Config& config);

View file

@ -217,6 +217,10 @@ public:
static const ID INVALID_ITEM_ID = 0;
static const ItemCell INVALID_CELL = -1;
// Convenient function to clear an ID or check it s valid
static void clearID(ID& id) { id = INVALID_ITEM_ID; }
static bool isValidID(const ID id) { return id != INVALID_ITEM_ID; }
// Bound is the AABBox fully containing this item
typedef AABox Bound;

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

@ -9,10 +9,13 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QColor>
#include <QUrl>
#include <QUuid>
#include <QRect>
#include <QtCore/QUrl>
#include <QtCore/QUuid>
#include <QtCore/QRect>
#include <QtCore/QVariant>
#include <QtGui/QColor>
#include <QtGui/QVector3D>
#include <QtGui/QQuaternion>
#include <glm/gtc/quaternion.hpp>
#include "RegisteredMetaTypes.h"
@ -91,6 +94,51 @@ QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::
return array;
}
glm::vec3 vec3FromVariant(const QVariant &object, bool& valid) {
glm::vec3 v;
valid = false;
if (!object.isValid() || object.isNull()) {
return v;
} else if (object.canConvert<float>()) {
v = glm::vec3(object.toFloat());
valid = true;
} else if (object.canConvert<QVector3D>()) {
auto qvec3 = qvariant_cast<QVector3D>(object);
v.x = qvec3.x();
v.y = qvec3.y();
v.z = qvec3.z();
valid = true;
} else {
auto map = object.toMap();
auto x = map["x"];
auto y = map["y"];
auto z = map["z"];
if (!x.isValid()) {
x = map["width"];
}
if (!y.isValid()) {
y = map["height"];
}
if (!y.isValid()) {
z = map["depth"];
}
if (x.canConvert<float>() && y.canConvert<float>() && z.canConvert<float>()) {
v.x = x.toFloat();
v.y = y.toFloat();
v.z = z.toFloat();
valid = true;
}
}
return v;
}
glm::vec3 vec3FromVariant(const QVariant &object) {
bool valid = false;
return vec3FromVariant(object, valid);
}
QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat &quat) {
QScriptValue obj = engine->newObject();
if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) {
@ -111,6 +159,42 @@ void quatFromScriptValue(const QScriptValue &object, glm::quat &quat) {
quat.w = object.property("w").toVariant().toFloat();
}
glm::quat quatFromVariant(const QVariant &object, bool& isValid) {
glm::quat q;
if (object.canConvert<QQuaternion>()) {
auto qvec3 = qvariant_cast<QQuaternion>(object);
q.x = qvec3.x();
q.y = qvec3.y();
q.z = qvec3.z();
q.w = qvec3.scalar();
isValid = true;
} else {
auto map = object.toMap();
q.x = map["x"].toFloat(&isValid);
if (!isValid) {
return glm::quat();
}
q.y = map["y"].toFloat(&isValid);
if (!isValid) {
return glm::quat();
}
q.z = map["z"].toFloat(&isValid);
if (!isValid) {
return glm::quat();
}
q.w = map["w"].toFloat(&isValid);
if (!isValid) {
return glm::quat();
}
}
return q;
}
glm::quat quatFromVariant(const QVariant &object) {
bool valid = false;
return quatFromVariant(object, valid);
}
QScriptValue qVectorQuatToScriptValue(QScriptEngine* engine, const QVector<glm::quat>& vector) {
QScriptValue array = engine->newArray();
for (int i = 0; i < vector.size(); i++) {

View file

@ -41,12 +41,18 @@ void vec4FromScriptValue(const QScriptValue& object, glm::vec4& vec4);
QScriptValue vec3toScriptValue(QScriptEngine* engine, const glm::vec3 &vec3);
void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3);
glm::vec3 vec3FromVariant(const QVariant &object, bool& valid);
glm::vec3 vec3FromVariant(const QVariant &object);
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2);
void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2);
QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat& quat);
void quatFromScriptValue(const QScriptValue &object, glm::quat& quat);
glm::quat quatFromVariant(const QVariant &object, bool& isValid);
glm::quat quatFromVariant(const QVariant &object);
QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect);
void qRectFromScriptValue(const QScriptValue& object, QRect& rect);

View file

@ -35,36 +35,31 @@ class ShapePipeline;
class RenderDetails {
public:
enum Type {
OPAQUE_ITEM,
SHADOW_ITEM,
TRANSLUCENT_ITEM,
OTHER_ITEM
ITEM,
SHADOW,
OTHER
};
struct Item {
size_t _considered = 0;
size_t _rendered = 0;
int _considered = 0;
int _outOfView = 0;
int _tooSmall = 0;
int _rendered = 0;
};
int _materialSwitches = 0;
int _trianglesRendered = 0;
Item _opaque;
Item _item;
Item _shadow;
Item _translucent;
Item _other;
Item& edit(Type type) {
switch (type) {
case OPAQUE_ITEM:
return _opaque;
case SHADOW_ITEM:
case SHADOW:
return _shadow;
case TRANSLUCENT_ITEM:
return _translucent;
case OTHER_ITEM:
case ITEM:
return _item;
default:
return _other;
}

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);
}
}
@ -251,15 +254,15 @@ QMessageBox::StandardButton OffscreenUi::critical(const QString& title, const QS
}
QMessageBox::StandardButton OffscreenUi::information(const QString& title, const QString& text,
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Information, title, text, buttons, defaultButton);
}
QMessageBox::StandardButton OffscreenUi::question(const QString& title, const QString& text,
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Question, title, text, buttons, defaultButton);
}
QMessageBox::StandardButton OffscreenUi::warning(const QString& title, const QString& text,
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Warning, title, text, buttons, defaultButton);
}
@ -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() {

Some files were not shown because too many files have changed in this diff Show more