mirror of
https://github.com/overte-org/overte.git
synced 2025-07-25 13:09:21 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into red
This commit is contained in:
commit
5baaad9b6e
77 changed files with 3232 additions and 1050 deletions
68
examples/cows/cowEntityScript.js
Normal file
68
examples/cows/cowEntityScript.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
|
||||
// cowEntityScript.js
|
||||
// examples/cows
|
||||
//
|
||||
// Created by Eric Levin on 3/25/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// This entity script handles the logic for untipping a cow after it collides with something
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
|
||||
(function() {
|
||||
Script.include("../libraries/utils.js");
|
||||
|
||||
var _this = this;
|
||||
_this.COLLISION_COOLDOWN_TIME = 5000;
|
||||
|
||||
|
||||
this.preload = function(entityID) {
|
||||
print("EBL Preload!!");
|
||||
_this.entityID = entityID;
|
||||
_this.mooSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/eric/Sounds/moo.wav")
|
||||
_this.mooSoundOptions = {volume: 0.7, loop: false};
|
||||
_this.timeSinceLastCollision = 0;
|
||||
_this.shouldUntipCow = true;
|
||||
}
|
||||
|
||||
this.collisionWithEntity = function(myID, otherID, collisionInfo) {
|
||||
if(_this.shouldUntipCow) {
|
||||
Script.setTimeout(function() {
|
||||
_this.untipCow();
|
||||
_this.shouldUntipCow = true;
|
||||
}, _this.COLLISION_COOLDOWN_TIME);
|
||||
}
|
||||
|
||||
_this.shouldUntipCow = false;
|
||||
|
||||
}
|
||||
|
||||
this.untipCow = function() {
|
||||
// keep yaw but reset pitch and roll
|
||||
var cowProps = Entities.getEntityProperties(_this.entityID, ["rotation", "position"]);
|
||||
var eulerRotation = Quat.safeEulerAngles(cowProps.rotation);
|
||||
eulerRotation.x = 0;
|
||||
eulerRotation.z = 0;
|
||||
var newRotation = Quat.fromVec3Degrees(eulerRotation);
|
||||
Entities.editEntity(_this.entityID, {
|
||||
rotation: newRotation,
|
||||
velocity: {x: 0, y: 0, z: 0},
|
||||
angularVelocity: {x: 0, y: 0, z:0}
|
||||
});
|
||||
|
||||
|
||||
_this.mooSoundOptions.position = cowProps.position;
|
||||
if (!_this.soundInjector) {
|
||||
_this.soundInjector = Audio.playSound(_this.mooSound, _this.mooSoundOptions);
|
||||
} else {
|
||||
_this.soundInjector.setOptions(_this.mooSoundOptions);
|
||||
_this.soundInjector.restart();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
53
examples/cows/cowSpawner.js
Normal file
53
examples/cows/cowSpawner.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
|
||||
// cowSpawner.js
|
||||
// examples/cows
|
||||
//
|
||||
// Created by Eric Levin on 3/25/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// This spawns a cow which will untip itself
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var orientation = MyAvatar.orientation;
|
||||
orientation = Quat.safeEulerAngles(orientation);
|
||||
orientation.x = 0;
|
||||
orientation = Quat.fromVec3Degrees(orientation);
|
||||
var center = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(2, Quat.getFront(orientation)));
|
||||
|
||||
|
||||
var SCRIPT_URL = Script.resolvePath("cowEntityScript.js?");
|
||||
var cow = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: "http://hifi-content.s3.amazonaws.com/DomainContent/production/cow/newMooCow.fbx",
|
||||
name: "playa_model_throwinCow",
|
||||
position: center,
|
||||
animation: {
|
||||
currentFrame: 278,
|
||||
running: true,
|
||||
url: "http://hifi-content.s3.amazonaws.com/DomainContent/Junkyard/Playa/newMooCow.fbx"
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.739,
|
||||
y: 1.613,
|
||||
z: 2.529
|
||||
},
|
||||
dynamic: true,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -5,
|
||||
z: 0
|
||||
},
|
||||
shapeType: "box",
|
||||
script: SCRIPT_URL,
|
||||
userData: "{\"grabbableKey\":{\"grabbable\":true}}"
|
||||
});
|
||||
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(cow);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
|
@ -112,7 +112,7 @@ function autoHideReticle() {
|
|||
function checkReticleDepth() {
|
||||
var now = Date.now();
|
||||
var timeSinceLastDepthCheck = now - lastDepthCheckTime;
|
||||
if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) {
|
||||
if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS && Reticle.visible) {
|
||||
var newDesiredDepth = desiredDepth;
|
||||
lastDepthCheckTime = now;
|
||||
var reticlePosition = Reticle.position;
|
||||
|
@ -160,7 +160,6 @@ function moveToDesiredDepth() {
|
|||
} else {
|
||||
newDepth = Reticle.depth + distanceToAdjustThisCycle;
|
||||
}
|
||||
|
||||
Reticle.setDepth(newDepth);
|
||||
}
|
||||
}
|
||||
|
|
883
examples/html/edit-style.css
Normal file
883
examples/html/edit-style.css
Normal file
|
@ -0,0 +1,883 @@
|
|||
/*
|
||||
// edit-style.css
|
||||
//
|
||||
// Created by Ryan Huffman on 13 Nov 2014
|
||||
// Copyright 2014 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
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: Raleway-Regular;
|
||||
src: url(../../resources/fonts/Raleway-Regular.ttf), /* Production */
|
||||
url(../../interface/resources/fonts/Raleway-Regular.ttf); /* Development */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Raleway-Light;
|
||||
src: url(../../resources/fonts/Raleway-Light.ttf),
|
||||
url(../../interface/resources/fonts/Raleway-Light.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Raleway-Bold;
|
||||
src: url(../../resources/fonts/Raleway-Bold.ttf),
|
||||
url(../../interface/resources/fonts/Raleway-Bold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Raleway-SemiBold;
|
||||
src: url(../../resources/fonts/Raleway-SemiBold.ttf),
|
||||
url(../../interface/resources/fonts/Raleway-SemiBold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: FiraSans-SemiBold;
|
||||
src: url(../../resources/fonts/FiraSans-SemiBold.ttf),
|
||||
url(../../interface/resources/fonts/FiraSans-SemiBold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: AnonymousPro-Regular;
|
||||
src: url(../../resources/fonts/AnonymousPro-Regular.ttf),
|
||||
url(../../interface/resources/fonts/AnonymousPro-Regular.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: HiFi-Glyphs;
|
||||
src: url(../../resources/fonts/hifi-glyphs.ttf),
|
||||
url(../../interface/resources/fonts/hifi-glyphs.ttf);
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 24px 12px 24px 12px;
|
||||
|
||||
color: #afafaf;
|
||||
background-color: #404040;
|
||||
font-family: Raleway-Regular;
|
||||
font-size: 15px;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
||||
table {
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 15px;
|
||||
color: #afafaf;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
border: 2px solid #575757;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
thead {
|
||||
font-family: Raleway-Regular;
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
background-color: #1c1c1c;
|
||||
padding: 1px 0px;
|
||||
border-bottom: 1px solid #575757;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
tbody {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
tfoot {
|
||||
font-family: Raleway-Light;
|
||||
font-size: 13px;
|
||||
background-color: #1c1c1c;
|
||||
border-top: 1px solid #575757;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
tfoot tr {
|
||||
background-color: #1c1cff;
|
||||
}
|
||||
|
||||
thead tr {
|
||||
height: 26px; /* 28px with thead padding */
|
||||
}
|
||||
|
||||
thead th {
|
||||
height: 26px;
|
||||
background-color: #1c1c1c;
|
||||
border-right: 1px solid #575757;
|
||||
}
|
||||
|
||||
thead th:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
tbody td {
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
tfoot td {
|
||||
height: 18px;
|
||||
width: 100%;
|
||||
background-color: #1c1c1c;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
tr {
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
tr:nth-child(odd) {
|
||||
background-color: #2e2e2e;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: #1c1c1c;
|
||||
}
|
||||
|
||||
tr:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
tr.selected {
|
||||
color: #000000;
|
||||
background-color: #00b4ef;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: center;
|
||||
word-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
td {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
word-wrap: nowrap;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
td.url {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
input[type="text"], input[type="number"], textarea {
|
||||
margin: 0;
|
||||
padding: 0 12px;
|
||||
color: #afafaf;
|
||||
background-color: #252525;
|
||||
border: none;
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
font-family: AnonymousPro-Regular;
|
||||
font-size: 16px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
min-height: 64px;
|
||||
width: 100%;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
input::-webkit-input-placeholder {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
input:focus, textarea:focus {
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
outline: 1px solid #00b4ef;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
input::selection, textarea::selection {
|
||||
color: #000000;
|
||||
background-color: #00b4ef;
|
||||
}
|
||||
|
||||
input.search {
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
input:disabled, textarea:disabled {
|
||||
background-color: #383838;
|
||||
color: #afafaf;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
height: 28px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
position: relative;
|
||||
height: 28px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
input[type=number] {
|
||||
padding-right: 6px;
|
||||
}
|
||||
input[type=number]::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
opacity: 1.0;
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 10px;
|
||||
overflow: hidden;
|
||||
font-family: hifi-glyphs;
|
||||
font-size: 50px;
|
||||
color: #afafaf;
|
||||
cursor: pointer;
|
||||
/*background-color: #000000;*/
|
||||
}
|
||||
input[type=number]::-webkit-inner-spin-button:before,
|
||||
input[type=number]::-webkit-inner-spin-button:after {
|
||||
position:absolute;
|
||||
left: -21px;
|
||||
line-height: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
input[type=number]::-webkit-inner-spin-button:before {
|
||||
content: "6";
|
||||
top: 5px;
|
||||
}
|
||||
input[type=number]::-webkit-inner-spin-button:after {
|
||||
content: "5";
|
||||
bottom: 6px;
|
||||
}
|
||||
input[type="number"]::-webkit-inner-spin-button:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
input.no-spin::-webkit-outer-spin-button,
|
||||
input.no-spin::-webkit-inner-spin-button {
|
||||
display: none;
|
||||
-webkit-appearance: none;
|
||||
margin: 0; /* <-- Apparently some margin are still there even though it's hidden */
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
input[type=button] {
|
||||
font-family: Raleway-Bold;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
vertical-align: top;
|
||||
height: 28px;
|
||||
min-width: 120px;
|
||||
padding: 0px 12px;
|
||||
margin-right: 8px;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
background: linear-gradient(#343434 20%, #000 100%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type=button].glyph {
|
||||
font-family: HiFi-Glyphs;
|
||||
font-size: 20px;
|
||||
text-transform: none;
|
||||
min-width: 32px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input[type=button].red {
|
||||
color: #fff;
|
||||
background-color: #94132e;
|
||||
background: linear-gradient(#d42043 20%, #94132e 100%);
|
||||
}
|
||||
input[type=button].blue {
|
||||
color: #fff;
|
||||
background-color: #94132e;
|
||||
background: linear-gradient(#00b4ef 20%, #1080b8 100%);
|
||||
}
|
||||
|
||||
input[type=button]:enabled:hover {
|
||||
background: linear-gradient(#000, #000);
|
||||
border: none;
|
||||
}
|
||||
input[type=button].red:enabled:hover {
|
||||
background: linear-gradient(#d42043, #d42043);
|
||||
border: none;
|
||||
}
|
||||
input[type=button].blue:enabled:hover {
|
||||
background: linear-gradient(#00b4ef, #00b4ef);
|
||||
border: none;
|
||||
}
|
||||
|
||||
input[type=button]:active {
|
||||
background: linear-gradient(#343434, #343434);
|
||||
}
|
||||
input[type=button].red:active {
|
||||
background: linear-gradient(#94132e, #94132e);
|
||||
}
|
||||
input[type=button].blue:active {
|
||||
background: linear-gradient(#1080b8, #1080b8);
|
||||
}
|
||||
|
||||
input[type=button]:disabled {
|
||||
color: #252525;
|
||||
background: linear-gradient(#575757 20%, #252525 100%);
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
display: none;
|
||||
}
|
||||
input[type=checkbox] + label {
|
||||
padding-left: 24px;
|
||||
background-position-y: 6px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACpSURBVDhPY2xoaGD68+dPMSMjY9L////VgTQjAw4AlH8PxLOPHj1azWxjY1MBVNsBFBfBpwkEgNKcQGwtJyfHyATkF0KEiQdAzYlMQEIUyicFyDD9+/ePgRxMvsb///4zkIOZ/v0HmkAGHginYjGNGAzS+BpdkAj8mun/3//92DyPD//993cG88nTJ4+Zm5p/BSZeJYb/DEJADEzNOPF7hn8Mk69cvVIPAHN5pyfo70F5AAAAAElFTkSuQmCC);
|
||||
}
|
||||
input[type=checkbox]:enabled + label:hover {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAClSURBVDhPY2hoaGD6//9/6b9//64D8T8gGycASr/7+/dv5/79+1kYgIxKqDjRAKiniRFIv2JgYBAFYlLAE0aQ66AckgDjjx8/yNP44cMH8jS+fPmSPI0PHz4kT+PNmzfJ03jp0iXyNJ46dYo8jYcPHyYnAbxm+vnzZz8wLhlIwd+/f5/BrKSkdExCQuLrnz9/lIBpUAiIQekXF34PTGmTT548WQ8AokXg+rhVtPYAAAAASUVORK5CYII=);
|
||||
}
|
||||
input[type=checkbox]:checked + label {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFLSURBVDhPjZK9SgNBFIXvbCaQRDQq7mIhQRPBRisJKcwLWOobaCsExEaxcEEQe0trGysfwg0EwWoDsbFIJUaIBJOwus547saNP3FlPzgzzJxzL5edFbZtG77v7wkhtrXWS9gFRQC/DZ07jnOYKJfL+8ie4n7mvyIGdhpay+VyQuK8y5dPZoHuVtbpZcLi4wjJ1x4t316R9dDgBlsSi8mGu7pJjyJFzVaH+r7iqyHSELSQzVADjS0UgjlDKUUsLzVO98+9kSLGV5qaHXhjU0GWNSxk3hCIwnsfeMNCjTArLmHeUBodoLiE+R+jxuHPUZP4elGE3teonx2S/Q7lJzOUlkYQ+A4/xzyegzNhXmJpwTMXry9IFjcoa84O0r+QXpcK1cugCLREZadyoA19Ergxwf96nKjd1KqlYqmLQ540TUNwItUmRWdu3T36AODjwgpY9xqqAAAAAElFTkSuQmCC);
|
||||
}
|
||||
input[type=checkbox]:checked + label:hover {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEySURBVDhPnZLPSsNAEMa/XVPBCE0RhNy0OarP4Av4AD6JB0GwVBA8efBBxHsgh4CQswcRoUIpiIpVAm3zZ5M4szFSbQPBH3xkJvNNZskOer2eLIriKM/ze1JOcS1UHmdZduF5ngEKjr/fN4Z6+oKerwA2gxC4HAFPEWVLsAzgZAvYt3Q6Enw6jg7uBAaTFMNwhpnKdbXCkAJdy8ROu4XrXW2HTJIErHcFDD6nC02Mom8PwymeE2gvS0ZRBBaTlsOXEmdlrfLLOI7Bakrl/zWxCT8T/904f9QW/b06qtrCUdtFCqdjYs2Q2jAPX8c2XQd7Kr/wfV8vwIPs4Ga1ixe5Xrr/YFLTYfKIvWzM6ZtwXZdX7lxXG0L+sxXHcW5t254opRzawQ0S72+dPmjTroIgOP0CQSMt5LDn1T8AAAAASUVORK5CYII=);
|
||||
}
|
||||
|
||||
.selectable {
|
||||
-webkit-touch-callout: text;
|
||||
-webkit-user-select: text;
|
||||
-khtml-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.color-box {
|
||||
display: inline-block;
|
||||
width: 15pt;
|
||||
height: 15pt;
|
||||
border: 0.75pt solid black;
|
||||
margin: 1.5pt;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.color-box.highlight {
|
||||
width: 13.5pt;
|
||||
height: 13.5pt;
|
||||
border: 1.5pt solid black;
|
||||
}
|
||||
|
||||
|
||||
.section-header, .sub-section-header {
|
||||
display: table;
|
||||
width: 100%;
|
||||
margin: 22px -12px 0 -12px;
|
||||
padding: 14px 12px 0 12px;
|
||||
font-family: Raleway-Regular;
|
||||
font-size: 12px;
|
||||
color: #afafaf;
|
||||
height: 28px;
|
||||
text-transform: uppercase;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
position: relative;
|
||||
background: #404040 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAqCAIAAAAbNW1vAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAmSURBVChTY1BFAgzhSIDBAQmMcoYHRwIJMCgjAQZ9JMBgBQdWVgBh5XmBV5A2FQAAAABJRU5ErkJggg==) repeat-x top left;
|
||||
}
|
||||
|
||||
.sub-section-header, .no-collapse {
|
||||
background: #404040 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAjSURBVBhXY1RVVf3PgARYjIyMoEwIYHRwcEBRwQSloYCBAQCwjgPMiI7W2QAAAABJRU5ErkJggg==) repeat-x top left;
|
||||
}
|
||||
|
||||
.section-header:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
background: none;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.sub-section-header {
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
|
||||
.section-header span {
|
||||
font-family: HiFi-Glyphs;
|
||||
font-size: 30px;
|
||||
float: right;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
.section-header[collapsed="true"] {
|
||||
margin-bottom: -22px;
|
||||
}
|
||||
|
||||
.text-group[collapsed="true"] ~ .text-group,
|
||||
.zone-group[collapsed="true"] ~ .zone-group,
|
||||
.web-group[collapsed="true"] ~ .web-group,
|
||||
.hyperlink-group[collapsed="true"] ~ .hyperlink-group,
|
||||
.spatial-group[collapsed="true"] ~ .spatial-group,
|
||||
.physical-group[collapsed="true"] ~ .physical-group,
|
||||
.behavior-group[collapsed="true"] ~ .behavior-group,
|
||||
.model-group[collapsed="true"] ~ .model-group,
|
||||
.light-group[collapsed="true"] ~ .light-group {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
.property {
|
||||
display: table;
|
||||
width: 100%;
|
||||
margin-top: 22px;
|
||||
min-height: 29px;
|
||||
}
|
||||
|
||||
.property label {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
font-family: Raleway-SemiBold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.value {
|
||||
display: block;
|
||||
min-height: 18px;
|
||||
}
|
||||
.value label {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 48px;
|
||||
}
|
||||
.value span {
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.checkbox + .checkbox {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.checkbox-sub-props {
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.property .number {
|
||||
float: left;
|
||||
}
|
||||
.property .number + .number {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.text label, .url label, .number label, .textarea label, .rgb label, .xyz label, .pyr label, .dropdown label, .gen label {
|
||||
float: left;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.number > input {
|
||||
clear: both;
|
||||
float: left;
|
||||
}
|
||||
.number > span {
|
||||
clear: both;
|
||||
float: left;
|
||||
}
|
||||
.xyz > div, .pyr > div, .gen > div {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.unit {
|
||||
padding-left: 4px;
|
||||
vertical-align: top;
|
||||
position: relative;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
margin-bottom: -17px;
|
||||
}
|
||||
|
||||
.dropdown select {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dropdown dl {
|
||||
clear: both;
|
||||
}
|
||||
.dropdown dl {
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 15px;
|
||||
width: 172px;
|
||||
height: 28px;
|
||||
padding: 0 28px 0 12px;
|
||||
|
||||
color: #afafaf;
|
||||
background: linear-gradient(#7d7d7d 20%, #686a68 100%);
|
||||
|
||||
position: relative;
|
||||
}
|
||||
.dropdown dl[dropped="true"] {
|
||||
color: #404040;
|
||||
background: linear-gradient(#afafaf, #afafaf);
|
||||
}
|
||||
|
||||
.dropdown dt {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
border-right: 1px solid #121212;
|
||||
width: 100%;
|
||||
}
|
||||
.dropdown dt:hover {
|
||||
color: #404040;
|
||||
}
|
||||
.dropdown dt:focus {
|
||||
outline: none;
|
||||
}
|
||||
.dropdown dt span:first-child {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: 5px;
|
||||
}
|
||||
.dropdown dt span:last-child {
|
||||
font-family: HiFi-Glyphs;
|
||||
font-size: 42px;
|
||||
float: right;
|
||||
margin-right: -48px;
|
||||
position: relative;
|
||||
left: -12px;
|
||||
top: -11px;
|
||||
}
|
||||
|
||||
.dropdown dd {
|
||||
position: absolute;
|
||||
top: 28px;
|
||||
left: 3px;
|
||||
display: none;
|
||||
}
|
||||
.dropdown dl[dropped="true"] dd {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdown li {
|
||||
list-style-type: none;
|
||||
padding: 3px 0 1px 12px;
|
||||
width: 200px;
|
||||
height: auto;
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 15px;
|
||||
color: #404040;
|
||||
background-color: #afafaf
|
||||
}
|
||||
.dropdown li:hover {
|
||||
background-color: #00b4ef;
|
||||
}
|
||||
|
||||
|
||||
div.refresh {
|
||||
box-sizing: border-box;
|
||||
padding-right: 44px;
|
||||
}
|
||||
div.refresh input[type="button"] {
|
||||
float: right;
|
||||
margin-right: -44px;
|
||||
}
|
||||
|
||||
.color-picker {
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
margin-bottom: 12px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 4px solid #afafaf;
|
||||
border-radius: 4px;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABTSURBVChTjcxBDoAwCETRwTs33sFjwB6uaCE1Ggvav5qQF7CSqu40dllHjYiOT3gh3yV8Ii+Fb+RNMEP9hm3sKENmBhG5P1aImWMH/EMerSAAOAFgTC/R8ZXSXAAAAABJRU5ErkJggg==);
|
||||
background-position: bottom right;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.color-picker:focus {
|
||||
outline: none;
|
||||
}
|
||||
.color-picker[active="true"] {
|
||||
border-color: #000;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABDSURBVChTjcoLCkAhCETRNq0tf97Y5xGZ1gVJ45TH6njThIO+xk2UwhWFcEdH6JCqOuiQiMDi/hcii3crRRb/7ggAPvIMVihQwvSXAAAAAElFTkSuQmCC);
|
||||
}
|
||||
|
||||
.rgb label {
|
||||
float: left;
|
||||
margin-top: 10px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
.rgb label + * {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.tuple {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.tuple div {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
min-width: 120px;
|
||||
min-height: 1px;
|
||||
}
|
||||
.tuple div:nth-child(1) {
|
||||
float: left;
|
||||
}
|
||||
.tuple div:nth-child(2) {
|
||||
}
|
||||
.tuple div:nth-child(3) {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.rgb .tuple input {
|
||||
padding-left: 65px;
|
||||
}
|
||||
.xyz .tuple input {
|
||||
padding-left: 25px;
|
||||
}
|
||||
.pyr .tuple input {
|
||||
padding-left: 45px;
|
||||
}
|
||||
|
||||
.tuple div > label:first-child {
|
||||
float: left;
|
||||
}
|
||||
.tuple div > label + input {
|
||||
clear: both;
|
||||
float: left;
|
||||
}
|
||||
.tuple div input + label {
|
||||
display: inline !important;
|
||||
float: none !important;
|
||||
position: absolute;
|
||||
margin-top: 8px;
|
||||
margin-left: 6px;
|
||||
left: 0;
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 12px;
|
||||
}
|
||||
.tuple .red + label, .tuple .x + label, .tuple .pitch + label {
|
||||
color: #e2334d;
|
||||
}
|
||||
.tuple .green + label, .tuple .y + label, .tuple .yaw + label {
|
||||
color: #1ac567;
|
||||
}
|
||||
.tuple .blue + label, .tuple .z + label, .tuple .roll + label {
|
||||
color: #1080b8;
|
||||
}
|
||||
|
||||
.tuple .red:focus, .tuple .x:focus, .tuple .pitch:focus {
|
||||
outline-color: #e2334d;
|
||||
}
|
||||
.tuple .green:focus, .tuple .y:focus, .tuple .yaw:focus {
|
||||
outline-color: #1ac567;
|
||||
}
|
||||
tuple, .blue:focus, .tuple .z:focus, .tuple .roll:focus {
|
||||
outline-color: #1080b8;
|
||||
}
|
||||
|
||||
.xyz .buttons input {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.xyz .buttons span {
|
||||
word-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.row input {
|
||||
float: left;
|
||||
}
|
||||
.row input[type=button] {
|
||||
margin-left: 8px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: #2e2e2e;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #696969;
|
||||
border: 2px solid #2e2e2e;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* FIXME: Revisit textarea resizer/corner when move to Qt 5.6 or later: see if can get resizer/corner to always be visible and
|
||||
have correct background color with and without scrollbars. */
|
||||
textarea:enabled::-webkit-resizer {
|
||||
background-size: 10px 10px;
|
||||
background: #252525 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAXSURBVChTY1RVVWXADZigNA4wMqUZGACS3gCD5UUtKAAAAABJRU5ErkJggg==) no-repeat bottom right;
|
||||
}
|
||||
textarea:focus::-webkit-resizer {
|
||||
background-size: 10px 10px;
|
||||
background: #000000 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACOSURBVChThdC5DQQhDAXQvyRI5LQxFdABARWQElAPogYkiqEWQhLYGe8xxzJaS5a/8AuQHwDG2n+Lvee0hBDQWlO+hRvy3mNZFjDG5vCDOOeIMaL3/guPKISAWiu9n+AVSSlhraXdF86Qcw6tNdoTvEOlFOScd6iUOv3JGEMopYQx9jNvaawnoHnNr8Z4AuRLPOq2gPgnAAAAAElFTkSuQmCC) no-repeat bottom right;
|
||||
}
|
||||
textarea:enabled[scrolling="true"]::-webkit-resizer {
|
||||
background-size: 10px 10px;
|
||||
background: #2e2e2e url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACKSURBVChTjdAxDsMgDAXQT4UYuQIzCwsSKxsSJ4YDoByDY7AwUOG2aZMQqX+xhd9gzIwxA3/k8a7LCCFgraX+Fk4UY4RSCoyxNfwgzjlyzhhjXOEvSimhtUbvB3hGUkp472m2wxUKIaD3TnOCd6jWim3bvlBrfdjJOUeolEJoZj/4PMH83bl/BXgCWSs2Z09IjgoAAAAASUVORK5CYII=) no-repeat bottom right;
|
||||
}
|
||||
|
||||
|
||||
#entity-list-header {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
#delete {
|
||||
float: right;
|
||||
margin-right: 0;
|
||||
background-color: #ff0000;
|
||||
}
|
||||
|
||||
#entity-list {
|
||||
position: relative; /* New positioning context. */
|
||||
}
|
||||
|
||||
#search-area {
|
||||
padding-right: 148px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
#filter {
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
#radius-and-unit {
|
||||
float: right;
|
||||
margin-right: -148px;
|
||||
}
|
||||
|
||||
|
||||
#entity-table-scroll {
|
||||
/* Height is set by JavaScript. */
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-top: 28px; /* Space for header and footer outside of scroll region. */
|
||||
margin-top: 28px;
|
||||
border-left: 2px solid #575757;
|
||||
border-right: 2px solid #575757;
|
||||
}
|
||||
|
||||
#entity-table-scroll, #entity-table {
|
||||
background-color: #1c1c1c;
|
||||
}
|
||||
|
||||
#entity-table {
|
||||
margin-top: -28px;
|
||||
margin-bottom: -18px;
|
||||
table-layout: fixed;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#entity-table thead {
|
||||
border: 2px solid #575757;
|
||||
border-top-left-radius: 7px;
|
||||
border-top-right-radius: 7px;
|
||||
border-bottom: 1px solid #575757;
|
||||
}
|
||||
|
||||
#entity-table tfoot {
|
||||
border: 2px solid #575757;
|
||||
border-bottom-left-radius: 7px;
|
||||
border-bottom-right-radius: 7px;
|
||||
border-top: 1px solid #575757;
|
||||
}
|
||||
|
||||
#entity-table thead tr, #entity-table thead tr th,
|
||||
#entity-table tfoot tr, #entity-table tfoot tr td {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#entity-table th:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#col-type {
|
||||
width: 16%;
|
||||
}
|
||||
#col-name {
|
||||
width: 42%;
|
||||
}
|
||||
#col-url {
|
||||
width: 42%;
|
||||
}
|
||||
|
||||
#entity-table thead {
|
||||
position: absolute;
|
||||
top: 49px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#entity-table thead th {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#entity-table tfoot {
|
||||
position: absolute;
|
||||
bottom: -21px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#no-entities {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
padding: 12px;
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 15px;
|
||||
font-style: italic;
|
||||
color: #afafaf;
|
||||
}
|
||||
|
||||
|
||||
#properties-list .property:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#property-id::selection {
|
||||
color: #000000;
|
||||
background-color: #00b4ef;
|
||||
}
|
||||
|
||||
|
||||
input#dimension-rescale-button {
|
||||
min-width: 50px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
|
||||
.color-set label, .color-set span {
|
||||
display: block;
|
||||
}
|
||||
.color-set span {
|
||||
padding-top: 2px;
|
||||
}
|
|
@ -1,6 +1,16 @@
|
|||
<!--
|
||||
// entityList.html
|
||||
//
|
||||
// Created by Ryan Huffman on 19 Nov 2014
|
||||
// Copyright 2014 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
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<link rel="stylesheet" type="text/css" href="edit-style.css">
|
||||
<script src="list.min.js"></script>
|
||||
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
<script type="text/javascript" src="eventBridgeLoader.js"></script>
|
||||
|
@ -26,8 +36,10 @@
|
|||
elDelete = document.getElementById("delete");
|
||||
elTeleport = document.getElementById("teleport");
|
||||
elRadius = document.getElementById("radius");
|
||||
elFooter = document.getElementById("footer-text");
|
||||
elNoEntitiesMessage = document.getElementById("no-entities");
|
||||
elNoEntitiesRadius = document.getElementById("no-entities-radius");
|
||||
elEntityTableScroll = document.getElementById("entity-table-scroll");
|
||||
|
||||
document.getElementById("entity-name").onclick = function() {
|
||||
setSortColumn('name');
|
||||
|
@ -168,6 +180,17 @@
|
|||
notFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedEntities.length > 1) {
|
||||
elFooter.firstChild.nodeValue = selectedEntities.length + " entities selected";
|
||||
} else if (selectedEntities.length === 1) {
|
||||
elFooter.firstChild.nodeValue = "1 entity selected";
|
||||
} else if (entityList.visibleItems.length === 1) {
|
||||
elFooter.firstChild.nodeValue = "1 entity found";
|
||||
} else {
|
||||
elFooter.firstChild.nodeValue = entityList.visibleItems.length + " entities found";
|
||||
}
|
||||
|
||||
return notFound;
|
||||
}
|
||||
|
||||
|
@ -214,57 +237,90 @@
|
|||
} else if (data.type == "update") {
|
||||
var newEntities = data.entities;
|
||||
if (newEntities.length == 0) {
|
||||
elEntityTable.style.display = "none";
|
||||
elNoEntitiesMessage.style.display = "block";
|
||||
} else {
|
||||
elEntityTable.style.display = "table";
|
||||
elNoEntitiesMessage.style.display = "none";
|
||||
for (var i = 0; i < newEntities.length; i++) {
|
||||
var id = newEntities[i].id;
|
||||
addEntity(id, newEntities[i].name, newEntities[i].type, newEntities[i].url);
|
||||
}
|
||||
updateSelectedEntities(data.selectedIDs);
|
||||
resize();
|
||||
}
|
||||
}
|
||||
});
|
||||
setTimeout(refreshEntities, 1000);
|
||||
}
|
||||
|
||||
function resize() {
|
||||
// Take up available window space
|
||||
elEntityTableScroll.style.height = window.innerHeight - 232;
|
||||
|
||||
// Update the widths of the header cells to match the body
|
||||
var tds = document.querySelectorAll("#entity-table-body tr:first-child td");
|
||||
var ths = document.querySelectorAll("#entity-table thead th");
|
||||
if (tds.length >= ths.length) {
|
||||
for (var i = 0; i < ths.length; i++) {
|
||||
ths[i].style.width = tds[i].offsetWidth;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.onresize = resize;
|
||||
resize();
|
||||
});
|
||||
}
|
||||
|
||||
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
|
||||
document.addEventListener("contextmenu", function (event) {
|
||||
event.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload='loaded();'>
|
||||
<div id="entity-list-header">
|
||||
<input type="button" id="refresh" value="Refresh" />
|
||||
<input type="button" id="teleport" value="Teleport" />
|
||||
<input type="button" id="delete" style="background-color: rgb(244, 64, 64); float: right" value="Delete" />
|
||||
<input type="button" class="glyph" id="refresh" value="F" />
|
||||
<input type="button" id="teleport" value="Jump To Selection" />
|
||||
<input type="button" class="red" id="delete" value="Delete" />
|
||||
</div>
|
||||
|
||||
<div id="entity-list">
|
||||
<div id="search-area">
|
||||
<input type="text" class="search" id="filter" placeholder="Filter" />
|
||||
<span id="radius-and-unit"><input type="number" id="radius" value="100" /> m</span>
|
||||
<span id="radius-and-unit"><input type="number" id="radius" value="100" /><span class="unit">m</span></span>
|
||||
</div>
|
||||
<div id="entity-table-scroll">
|
||||
<table id="entity-table">
|
||||
<colgroup>
|
||||
<col span="1" id="col-type" />
|
||||
<col span="1" id="col-name" />
|
||||
<col span="1" id="col-url" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="entity-type" data-sort="type">Type <span class="sort-order" style="display: inline"> ▾</span></th>
|
||||
<th id="entity-name" data-sort="type">Name <span class="sort-order" style="display: none"> ▾</span></th>
|
||||
<th id="entity-url" data-sort="url">File <span class="sort-order" style="display: none"> ▾</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list" id="entity-table-body">
|
||||
<tr>
|
||||
<td class="type">Type</td>
|
||||
<td class="name">Name</td>
|
||||
<td class="url"><div class='outer'><div class='inner'>URL</div></div></td>
|
||||
<td class="id" style="display: none">Type</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td id="footer-text" colspan="3">Footer text</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<div id="no-entities">
|
||||
No entities found within a <span id="no-entities-radius">100</span> meter radius. Try moving to a different location and refreshing.
|
||||
</div>
|
||||
</div>
|
||||
<table id="entity-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="entity-type" data-sort="type">Type <span class="sort-order" style="display: inline"> ▾</span></th>
|
||||
<th id="entity-name" data-sort="type">Name <span class="sort-order" style="display: inline"> ▾</span></th>
|
||||
<th id="entity-url" data-sort="url">URL <span class="sort-order" style="display: none"> ▾</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list" id="entity-table-body">
|
||||
<tr>
|
||||
<td class="id" style="display: none">Type</td>
|
||||
<td class="type">Type</td>
|
||||
<td class="name">Name</td>
|
||||
<td class="url"><div class='outer'><div class='inner'>URL</div></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="no-entities">
|
||||
No entities found within a <span id="no-entities-radius">100</span> meter radius. Try moving to a different location and refreshing.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,16 @@
|
|||
<!--
|
||||
// gridControls.html
|
||||
//
|
||||
// Created by Ryan Huffman on 6 Nov 2014
|
||||
// Copyright 2014 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
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<link rel="stylesheet" type="text/css" href="edit-style.css">
|
||||
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
<script type="text/javascript" src="eventBridgeLoader.js"></script>
|
||||
<script>
|
||||
|
@ -109,61 +119,63 @@
|
|||
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
|
||||
});
|
||||
|
||||
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
|
||||
document.addEventListener("contextmenu", function (event) {
|
||||
event.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload='loaded();'>
|
||||
<div class="grid-section">
|
||||
<div id="grid-section">
|
||||
|
||||
<div class="property-section">
|
||||
<label>Visible</label>
|
||||
<div class="section-header">
|
||||
<label>Editing Grid</label>
|
||||
</div>
|
||||
|
||||
<div class="property checkbox">
|
||||
<input type='checkbox' id="horiz-grid-visible">
|
||||
<label for="horiz-grid-visible">Visible</label>
|
||||
</div>
|
||||
|
||||
<div class="property checkbox">
|
||||
<input type="checkbox" id="snap-to-grid">
|
||||
<label for="snap-to-grid">Snap entities to grid</label>
|
||||
</div>
|
||||
|
||||
<div class="property">
|
||||
<div class="number">
|
||||
<label>Major grid size</label>
|
||||
<span>
|
||||
<input type="number" id="major-spacing" min="1" step="1" /><span class="unit">m</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="number">
|
||||
<label>Minor grid size</label>
|
||||
<span>
|
||||
<input type="number" id="minor-spacing" min="0.2" step="0.2" /><span class="unit">m</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="property number">
|
||||
<label>Position (Y axis)</label>
|
||||
<span>
|
||||
<input type='checkbox' id="horiz-grid-visible">
|
||||
<input type="number" id="horiz-y" step="0.1" /><span class="unit">m</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="property-section">
|
||||
<label>Snap to grid</label>
|
||||
<span>
|
||||
<input type='checkbox' id="snap-to-grid">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="horizontal-position" class="property-section">
|
||||
<label>Position (Y Axis)</label>
|
||||
<span>
|
||||
<input type='number' id="horiz-y" class="number" step="0.1"></input>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="property-section">
|
||||
<label>Minor Grid Size</label>
|
||||
<span>
|
||||
<input type='number' id="minor-spacing" min="0.2" step="0.2"></input>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="property-section">
|
||||
<label>Major Grid Every</label>
|
||||
<span>
|
||||
<input type='number' id="major-spacing" min="1" step="1", ></input>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="property-section">
|
||||
<label>Grid Color</label>
|
||||
<div class="property color-set">
|
||||
<label>Grid line color</label>
|
||||
<span id="grid-colors"></span>
|
||||
</div>
|
||||
|
||||
<div class="property-section">
|
||||
<div class="property">
|
||||
<span>
|
||||
<input type="button" id="move-to-selection" value="Move to Selection">
|
||||
</span>
|
||||
</div>
|
||||
<div class="property-section">
|
||||
<span>
|
||||
<input type="button" id="move-to-avatar" value="Move to Avatar">
|
||||
</span>
|
||||
<input type="button" id="move-to-selection" value="Align To Selection">
|
||||
<input type="button" id="move-to-avatar" value="Align To Avatar">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -5,7 +5,7 @@ EntityListTool = function(opts) {
|
|||
|
||||
var url = ENTITY_LIST_HTML_URL;
|
||||
var webView = new OverlayWebWindow({
|
||||
title: 'Entities', source: url, toolWindow: true
|
||||
title: 'Entity List', source: url, toolWindow: true
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
<script type="text/javascript" src="../html/eventBridgeLoader.js"></script>
|
||||
<script type="text/javascript" src="particleExplorer.js?v42"></script>
|
||||
<script>
|
||||
function loaded() {
|
||||
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
|
||||
document.addEventListener("contextmenu", function (event) {
|
||||
event.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
|
||||
|
@ -60,7 +66,7 @@ body{
|
|||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<body onload="loaded();">
|
||||
<div class="importer">
|
||||
<input type='text' id="importer-input" placeholder="Import: Paste JSON here." onkeypress="handleInputKeyPress(event)">
|
||||
<div class = "exported-props-section">
|
||||
|
|
|
@ -120,27 +120,95 @@ function menuItemEvent(menuItem) {
|
|||
if (menuItem.endsWith(" for Output")) {
|
||||
var selectedDevice = menuItem.trimStartsWith("Use ").trimEndsWith(" for Output");
|
||||
print("output audio selection..." + selectedDevice);
|
||||
Menu.menuItemEvent.disconnect(menuItemEvent);
|
||||
Menu.menuItemEvent.disconnect(menuItemEvent);
|
||||
Menu.setIsOptionChecked(selectedOutputMenu, false);
|
||||
selectedOutputMenu = menuItem;
|
||||
Menu.setIsOptionChecked(selectedOutputMenu, true);
|
||||
if (AudioDevice.setOutputDevice(selectedDevice)) {
|
||||
Settings.setValue(OUTPUT_DEVICE_SETTING, selectedDevice);
|
||||
}
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
} else if (menuItem.endsWith(" for Input")) {
|
||||
var selectedDevice = menuItem.trimStartsWith("Use ").trimEndsWith(" for Input");
|
||||
print("input audio selection..." + selectedDevice);
|
||||
Menu.menuItemEvent.disconnect(menuItemEvent);
|
||||
Menu.menuItemEvent.disconnect(menuItemEvent);
|
||||
Menu.setIsOptionChecked(selectedInputMenu, false);
|
||||
selectedInputMenu = menuItem;
|
||||
Menu.setIsOptionChecked(selectedInputMenu, true);
|
||||
if (AudioDevice.setInputDevice(selectedDevice)) {
|
||||
Settings.setValue(INPUT_DEVICE_SETTING, selectedDevice);
|
||||
}
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
|
||||
// Some HMDs (like Oculus CV1) have a built in audio device. If they
|
||||
// do, then this function will handle switching to that device automatically
|
||||
// when you goActive with the HMD active.
|
||||
var wasHmdMounted = false; // assume it's un-mounted to start
|
||||
var switchedAudioInputToHMD = false;
|
||||
var switchedAudioOutputToHMD = false;
|
||||
var previousSelectedInputAudioDevice = "";
|
||||
var previousSelectedOutputAudioDevice = "";
|
||||
|
||||
function restoreAudio() {
|
||||
if (switchedAudioInputToHMD) {
|
||||
print("switching back from HMD preferred audio input to:" + previousSelectedInputAudioDevice);
|
||||
menuItemEvent("Use " + previousSelectedInputAudioDevice + " for Input");
|
||||
}
|
||||
if (switchedAudioOutputToHMD) {
|
||||
print("switching back from HMD preferred audio output to:" + previousSelectedOutputAudioDevice);
|
||||
menuItemEvent("Use " + previousSelectedOutputAudioDevice + " for Output");
|
||||
}
|
||||
}
|
||||
|
||||
function checkHMDAudio() {
|
||||
// Mounted state is changing... handle switching
|
||||
if (HMD.mounted != wasHmdMounted) {
|
||||
print("HMD mounted changed...");
|
||||
|
||||
// We're putting the HMD on... switch to those devices
|
||||
if (HMD.mounted) {
|
||||
print("NOW mounted...");
|
||||
var hmdPreferredAudioInput = HMD.preferredAudioInput();
|
||||
var hmdPreferredAudioOutput = HMD.preferredAudioOutput();
|
||||
print("hmdPreferredAudioInput:" + hmdPreferredAudioInput);
|
||||
print("hmdPreferredAudioOutput:" + hmdPreferredAudioOutput);
|
||||
|
||||
|
||||
var hmdHasPreferredAudio = (hmdPreferredAudioInput !== "") || (hmdPreferredAudioOutput !== "");
|
||||
if (hmdHasPreferredAudio) {
|
||||
print("HMD has preferred audio!");
|
||||
previousSelectedInputAudioDevice = Settings.getValue(INPUT_DEVICE_SETTING);
|
||||
previousSelectedOutputAudioDevice = Settings.getValue(OUTPUT_DEVICE_SETTING);
|
||||
print("previousSelectedInputAudioDevice:" + previousSelectedInputAudioDevice);
|
||||
print("previousSelectedOutputAudioDevice:" + previousSelectedOutputAudioDevice);
|
||||
if (hmdPreferredAudioInput != previousSelectedInputAudioDevice && hmdPreferredAudioInput !== "") {
|
||||
print("switching to HMD preferred audio input to:" + hmdPreferredAudioInput);
|
||||
switchedAudioInputToHMD = true;
|
||||
menuItemEvent("Use " + hmdPreferredAudioInput + " for Input");
|
||||
}
|
||||
if (hmdPreferredAudioOutput != previousSelectedOutputAudioDevice && hmdPreferredAudioOutput !== "") {
|
||||
print("switching to HMD preferred audio output to:" + hmdPreferredAudioOutput);
|
||||
switchedAudioOutputToHMD = true;
|
||||
menuItemEvent("Use " + hmdPreferredAudioOutput + " for Output");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print("HMD NOW un-mounted...");
|
||||
restoreAudio();
|
||||
}
|
||||
}
|
||||
wasHmdMounted = HMD.mounted;
|
||||
}
|
||||
|
||||
Script.update.connect(checkHMDAudio);
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
restoreAudio();
|
||||
Menu.menuItemEvent.disconnect(menuItemEvent);
|
||||
Script.update.disconnect(checkHMDAudio);
|
||||
});
|
||||
|
|
BIN
examples/tests/cube_texture.png
Normal file
BIN
examples/tests/cube_texture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 MiB |
41
examples/tests/textureStress.fs
Normal file
41
examples/tests/textureStress.fs
Normal file
|
@ -0,0 +1,41 @@
|
|||
float aspect(vec2 v) {
|
||||
return v.x / v.y;
|
||||
}
|
||||
|
||||
vec3 aspectCorrectedTexture() {
|
||||
vec2 uv = _position.xy;
|
||||
uv += 0.5;
|
||||
uv.y = 1.0 - uv.y;
|
||||
|
||||
float targetAspect = iWorldScale.x / iWorldScale.y;
|
||||
float sourceAspect = aspect(iChannelResolution[0].xy);
|
||||
float aspectCorrection = sourceAspect / targetAspect;
|
||||
if (aspectCorrection > 1.0) {
|
||||
float offset = aspectCorrection - 1.0;
|
||||
float halfOffset = offset / 2.0;
|
||||
uv.y -= halfOffset;
|
||||
uv.y *= aspectCorrection;
|
||||
} else {
|
||||
float offset = 1.0 - aspectCorrection;
|
||||
float halfOffset = offset / 2.0;
|
||||
uv.x -= halfOffset;
|
||||
uv.x /= aspectCorrection;
|
||||
}
|
||||
|
||||
if (any(lessThan(uv, vec2(0.0)))) {
|
||||
return vec3(0.0);
|
||||
}
|
||||
|
||||
if (any(greaterThan(uv, vec2(1.0)))) {
|
||||
return vec3(0.0);
|
||||
}
|
||||
|
||||
vec4 color = texture(iChannel0, uv);
|
||||
return color.rgb * max(0.5, sourceAspect) * max(0.9, fract(iWorldPosition.x));
|
||||
}
|
||||
|
||||
float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) {
|
||||
specular = aspectCorrectedTexture();
|
||||
return 1.0;
|
||||
}
|
||||
|
67
examples/tests/textureStress.js
Normal file
67
examples/tests/textureStress.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
Script.include("https://s3.amazonaws.com/DreamingContent/scripts/Austin.js");
|
||||
|
||||
var ENTITY_SPAWN_LIMIT = 500;
|
||||
var ENTITY_LIFETIME = 600;
|
||||
var RADIUS = 1.0; // Spawn within this radius (square)
|
||||
var TEST_ENTITY_NAME = "EntitySpawnTest";
|
||||
|
||||
var entities = [];
|
||||
var textureIndex = 0;
|
||||
var texture = Script.resolvePath('cube_texture.png');
|
||||
var shader = Script.resolvePath('textureStress.fs');
|
||||
var qml = Script.resolvePath('textureStress.qml');
|
||||
qmlWindow = new OverlayWindow({
|
||||
title: 'Test Qml',
|
||||
source: qml,
|
||||
height: 240,
|
||||
width: 320,
|
||||
toolWindow: false,
|
||||
visible: true
|
||||
});
|
||||
|
||||
function deleteItems(count) {
|
||||
if (!count) {
|
||||
var ids = Entities.findEntities(MyAvatar.position, 50);
|
||||
ids.forEach(function(id) {
|
||||
var properties = Entities.getEntityProperties(id, ["name"]);
|
||||
if (properties.name === TEST_ENTITY_NAME) {
|
||||
Entities.deleteEntity(id);
|
||||
}
|
||||
}, this);
|
||||
entities = [];
|
||||
return;
|
||||
} else {
|
||||
// FIXME... implement
|
||||
}
|
||||
}
|
||||
|
||||
function createItems(count) {
|
||||
for (var i = 0; i < count; ++i) {
|
||||
var newEntity = Entities.addEntity({
|
||||
type: "Box",
|
||||
name: TEST_ENTITY_NAME,
|
||||
position: AUSTIN.avatarRelativePosition(AUSTIN.randomPositionXZ({ x: 0, y: 0, z: -2 }, RADIUS)),
|
||||
color: { r: 255, g: 255, b: 255 },
|
||||
dimensions: AUSTIN.randomDimensions(),
|
||||
lifetime: ENTITY_LIFETIME,
|
||||
userData: JSON.stringify({
|
||||
ProceduralEntity: {
|
||||
version: 2,
|
||||
shaderUrl: shader,
|
||||
channels: [ texture + "?" + textureIndex++ ]
|
||||
}
|
||||
})
|
||||
});
|
||||
entities.push(newEntity);
|
||||
}
|
||||
}
|
||||
|
||||
qmlWindow.fromQml.connect(function(message){
|
||||
print(message);
|
||||
if (message[0] === "create") {
|
||||
var count = message[1] || 1;
|
||||
createItems(message[1] || 1);
|
||||
} else if (message[0] === "delete") {
|
||||
deleteItems(message[1]);
|
||||
}
|
||||
});
|
69
examples/tests/textureStress.qml
Normal file
69
examples/tests/textureStress.qml
Normal file
|
@ -0,0 +1,69 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
width: parent ? parent.width : 100
|
||||
height: parent ? parent.height : 100
|
||||
|
||||
signal sendToScript(var message);
|
||||
|
||||
Text {
|
||||
id: label
|
||||
text: "GPU Texture Usage: "
|
||||
}
|
||||
Text {
|
||||
id: usage
|
||||
anchors.left: label.right
|
||||
anchors.leftMargin: 8
|
||||
text: "N/A"
|
||||
Timer {
|
||||
repeat: true
|
||||
running: true
|
||||
interval: 500
|
||||
onTriggered: {
|
||||
usage.text = Render.getConfig("Stats")["textureGPUMemoryUsage"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
|
||||
|
||||
anchors { left: parent.left; right: parent.right; top: label.bottom; topMargin: 8; bottom: parent.bottom }
|
||||
spacing: 8
|
||||
|
||||
Button {
|
||||
text: "Add 1"
|
||||
onClicked: root.sendToScript(["create", 1]);
|
||||
}
|
||||
Button {
|
||||
text: "Add 10"
|
||||
onClicked: root.sendToScript(["create", 10]);
|
||||
}
|
||||
Button {
|
||||
text: "Add 100"
|
||||
onClicked: root.sendToScript(["create", 100]);
|
||||
}
|
||||
/*
|
||||
Button {
|
||||
text: "Delete 1"
|
||||
onClicked: root.sendToScript(["delete", 1]);
|
||||
}
|
||||
Button {
|
||||
text: "Delete 10"
|
||||
onClicked: root.sendToScript(["delete", 10]);
|
||||
}
|
||||
Button {
|
||||
text: "Delete 100"
|
||||
onClicked: root.sendToScript(["delete", 100]);
|
||||
}
|
||||
*/
|
||||
Button {
|
||||
text: "Delete All"
|
||||
onClicked: root.sendToScript(["delete", 0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +106,13 @@ elseif(WIN32)
|
|||
|
||||
# add an executable that also has the icon itself and the configured rc file as resources
|
||||
add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT})
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
COMMAND "mt.exe" -manifest "${CMAKE_CURRENT_SOURCE_DIR}/interface.exe.manifest" -inputresource:"$<TARGET_FILE:${TARGET_NAME}>"\;\#1 -outputresource:"$<TARGET_FILE:${TARGET_NAME}>"\;\#1
|
||||
COMMENT "Adding OS version support manifest to exe"
|
||||
)
|
||||
else()
|
||||
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
||||
endif()
|
||||
|
|
15
interface/interface.exe.manifest
Normal file
15
interface/interface.exe.manifest
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!--This Id value indicates the application supports Windows 7 functionality-->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<!--This Id value indicates the application supports Windows 8 functionality-->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<!--This Id value indicates the application supports Windows 8.1 functionality-->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!--This Id value indicates the application supports Windows 10 functionality-->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
Binary file not shown.
|
@ -416,7 +416,6 @@ Window {
|
|||
anchors.top: assetDirectory.bottom
|
||||
anchors.bottom: uploadSection.top
|
||||
anchors.margins: 12
|
||||
anchors.bottomMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
|
@ -445,7 +444,7 @@ Window {
|
|||
name: "Upload A File"
|
||||
spacing: hifi.dimensions.contentSpacing.y
|
||||
anchors.bottom: parent.bottom
|
||||
height: 130
|
||||
height: 92
|
||||
|
||||
Item {
|
||||
height: parent.height
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
//
|
||||
// ToolWindow.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 QtWebEngine 1.1
|
||||
import QtWebChannel 1.0
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "windows" as Windows
|
||||
import "controls" as Controls
|
||||
import "windows-uit"
|
||||
import "controls-uit"
|
||||
import "styles-uit"
|
||||
|
||||
Windows.Window {
|
||||
Window {
|
||||
id: toolWindow
|
||||
resizable: true
|
||||
objectName: "ToolWindow"
|
||||
|
@ -15,9 +27,13 @@ Windows.Window {
|
|||
destroyOnInvisible: false
|
||||
closable: true
|
||||
visible: false
|
||||
width: 384; height: 640;
|
||||
title: "Tools"
|
||||
title: "Edit"
|
||||
property alias tabView: tabView
|
||||
implicitWidth: 520; implicitHeight: 695
|
||||
minSize: Qt.vector2d(400, 500)
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
onParentChanged: {
|
||||
if (parent) {
|
||||
x = 120;
|
||||
|
@ -32,8 +48,11 @@ Windows.Window {
|
|||
}
|
||||
|
||||
TabView {
|
||||
anchors.fill: parent
|
||||
id: tabView;
|
||||
width: pane.contentWidth
|
||||
height: pane.scrollHeight // Pane height so that don't use Window's scrollbars otherwise tabs may be scrolled out of view.
|
||||
property int tabCount: 0
|
||||
|
||||
Repeater {
|
||||
model: 4
|
||||
Tab {
|
||||
|
@ -43,7 +62,7 @@ Windows.Window {
|
|||
enabled: false
|
||||
property string originalUrl: "";
|
||||
|
||||
Controls.WebView {
|
||||
WebView {
|
||||
id: webView;
|
||||
anchors.fill: parent
|
||||
enabled: false
|
||||
|
@ -60,6 +79,61 @@ Windows.Window {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
style: TabViewStyle {
|
||||
|
||||
frame: Rectangle { // Background shown before content loads.
|
||||
anchors.fill: parent
|
||||
color: hifi.colors.baseGray
|
||||
}
|
||||
|
||||
frameOverlap: 0
|
||||
|
||||
tab: Rectangle {
|
||||
implicitWidth: text.width
|
||||
implicitHeight: 3 * text.height
|
||||
color: styleData.selected ? hifi.colors.black : hifi.colors.tabBackgroundDark
|
||||
|
||||
RalewayRegular {
|
||||
id: text
|
||||
text: styleData.title
|
||||
font.capitalization: Font.AllUppercase
|
||||
size: hifi.fontSizes.tabName
|
||||
width: tabView.tabCount > 1 ? styleData.availableWidth / tabView.tabCount : implicitWidth + 2 * hifi.dimensions.contentSpacing.x
|
||||
elide: Text.ElideRight
|
||||
color: styleData.selected ? hifi.colors.primaryHighlight : hifi.colors.lightGrayText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Rectangle { // Separator.
|
||||
width: 1
|
||||
height: parent.height
|
||||
color: hifi.colors.black
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
visible: styleData.index > 0
|
||||
|
||||
Rectangle {
|
||||
width: 1
|
||||
height: 1
|
||||
color: hifi.colors.baseGray
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { // Active underline.
|
||||
width: parent.width - (styleData.index > 0 ? 1 : 0)
|
||||
height: 1
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
color: styleData.selected ? hifi.colors.primaryHighlight : hifi.colors.baseGray
|
||||
}
|
||||
}
|
||||
|
||||
tabOverlap: 0
|
||||
}
|
||||
}
|
||||
|
||||
function updateVisiblity() {
|
||||
|
@ -129,6 +203,7 @@ Windows.Window {
|
|||
tab.originalUrl = "";
|
||||
tab.item.url = "about:blank";
|
||||
tab.item.enabled = false;
|
||||
tabView.tabCount--;
|
||||
}
|
||||
|
||||
function addWebTab(properties) {
|
||||
|
@ -150,6 +225,7 @@ Windows.Window {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (properties.width) {
|
||||
tabView.width = Math.min(Math.max(tabView.width, properties.width), toolWindow.maxSize.x);
|
||||
}
|
||||
|
@ -169,6 +245,7 @@ Windows.Window {
|
|||
|
||||
var result = tab.item;
|
||||
result.enabled = true;
|
||||
tabView.tabCount++;
|
||||
console.log("Setting event bridge: " + eventBridge);
|
||||
result.eventBridgeWrapper.eventBridge = eventBridge;
|
||||
result.url = properties.source;
|
||||
|
|
|
@ -46,7 +46,7 @@ Column {
|
|||
Item {
|
||||
id: leadingSpace
|
||||
width: 1
|
||||
height: isFirst ? hifi.dimensions.contentSpacing.y : hifi.dimensions.controlInterlineHeight
|
||||
height: isFirst ? hifi.dimensions.contentSpacing.y : 0
|
||||
anchors.top: parent.top
|
||||
}
|
||||
|
||||
|
@ -97,11 +97,11 @@ Column {
|
|||
|
||||
HiFiGlyphs {
|
||||
anchors {
|
||||
verticalCenter: title.verticalCenter
|
||||
top: title.top
|
||||
topMargin: -9
|
||||
right: parent.right
|
||||
rightMargin: -4
|
||||
}
|
||||
y: -2
|
||||
size: hifi.fontSizes.disclosureButton
|
||||
text: isCollapsed ? hifi.glyphs.disclosureButtonExpand : hifi.glyphs.disclosureButtonCollapse
|
||||
color: hifi.colors.lightGrayText
|
||||
|
|
74
interface/resources/qml/controls-uit/WebView.qml
Normal file
74
interface/resources/qml/controls-uit/WebView.qml
Normal file
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// WebView.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 QtWebEngine 1.1
|
||||
|
||||
WebEngineView {
|
||||
id: root
|
||||
property var newUrl;
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging")
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
}
|
||||
|
||||
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
|
||||
Timer {
|
||||
id: urlReplacementTimer
|
||||
running: false
|
||||
repeat: false
|
||||
interval: 50
|
||||
onTriggered: url = newUrl;
|
||||
}
|
||||
|
||||
onUrlChanged: {
|
||||
console.log("Url changed to " + url);
|
||||
var originalUrl = url.toString();
|
||||
newUrl = urlHandler.fixupUrl(originalUrl).toString();
|
||||
if (newUrl !== originalUrl) {
|
||||
root.stop();
|
||||
if (urlReplacementTimer.running) {
|
||||
console.warn("Replacement timer already running");
|
||||
return;
|
||||
}
|
||||
urlReplacementTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
onFeaturePermissionRequested: {
|
||||
grantFeaturePermission(securityOrigin, feature, true);
|
||||
}
|
||||
|
||||
onLoadingChanged: {
|
||||
// Required to support clicking on "hifi://" links
|
||||
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
|
||||
var url = loadRequest.url.toString();
|
||||
if (urlHandler.canHandleUrl(url)) {
|
||||
if (urlHandler.handleUrl(url)) {
|
||||
root.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onNewViewRequested:{
|
||||
var component = Qt.createComponent("../Browser.qml");
|
||||
var newWindow = component.createObject(desktop);
|
||||
request.openIn(newWindow.webView)
|
||||
}
|
||||
|
||||
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6
|
||||
// See https://bugreports.qt.io/browse/QTBUG-49521
|
||||
//profile: desktop.browserProfile
|
||||
}
|
|
@ -44,7 +44,7 @@ Preference {
|
|||
|
||||
children: [ contentContainer ]
|
||||
|
||||
height: contentContainer.height + (root.isLast ? 2 * hifi.dimensions.contentSpacing.y : 0)
|
||||
height: contentContainer.height + (contentContainer.isCollapsed ? 0 : hifi.dimensions.controlInterlineHeight)
|
||||
|
||||
Component.onCompleted: d.buildPreferences();
|
||||
|
||||
|
@ -111,7 +111,6 @@ Preference {
|
|||
|
||||
case Preference.Checkbox:
|
||||
checkBoxCount++;
|
||||
console.log("####### checkBoxCount = " + checkBoxCount);
|
||||
builder = checkboxBuilder;
|
||||
break;
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ Window {
|
|||
}
|
||||
|
||||
HifiControls.VerticalSpacer {
|
||||
height: 2 // Table view draws a little taller than it's height.
|
||||
height: hifi.dimensions.controlInterlineHeight + 2 // Table view draws a little taller than it's height.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ Item {
|
|||
readonly property color lightGrayText: "#afafaf"
|
||||
readonly property color faintGray: "#e3e3e3"
|
||||
readonly property color primaryHighlight: "#00b4ef"
|
||||
readonly property color blueHighlight: "#00b4ef"
|
||||
readonly property color blueAccent: "#1080b8"
|
||||
readonly property color redHighlight: "#e2334d"
|
||||
readonly property color redAccent: "#b70a37"
|
||||
|
@ -75,12 +76,12 @@ Item {
|
|||
readonly property color lightGrayText80: "#ccafafaf"
|
||||
readonly property color faintGray80: "#cce3e3e3"
|
||||
readonly property color faintGray50: "#80e3e3e3"
|
||||
readonly property color locked: "#252525"
|
||||
|
||||
// Other colors
|
||||
readonly property color white: "#ffffff"
|
||||
readonly property color gray: "#808080"
|
||||
readonly property color black: "#000000"
|
||||
readonly property color locked: "#252525"
|
||||
// Semitransparent
|
||||
readonly property color white50: "#80ffffff"
|
||||
readonly property color white30: "#4dffffff"
|
||||
|
@ -115,6 +116,8 @@ Item {
|
|||
readonly property color dropDownDarkStart: "#7d7d7d"
|
||||
readonly property color dropDownDarkFinish: "#6b6a6b"
|
||||
readonly property color textFieldLightBackground: "#d4d4d4"
|
||||
readonly property color tabBackgroundDark: "#252525"
|
||||
readonly property color tabBackgroundLight: "#d4d4d4"
|
||||
}
|
||||
|
||||
Item {
|
||||
|
@ -152,6 +155,7 @@ Item {
|
|||
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 textFieldInputLabel: dimensions.largeScreen ? 13 : 9
|
||||
readonly property real tableText: dimensions.largeScreen ? 15 : 12
|
||||
readonly property real buttonLabel: dimensions.largeScreen ? 13 : 9
|
||||
readonly property real iconButton: dimensions.largeScreen ? 13 : 9
|
||||
|
@ -164,7 +168,7 @@ Item {
|
|||
readonly property real menuItem: dimensions.largeScreen ? 15 : 11
|
||||
readonly property real shortcutText: dimensions.largeScreen ? 13 : 9
|
||||
readonly property real carat: dimensions.largeScreen ? 38 : 30
|
||||
readonly property real disclosureButton: dimensions.largeScreen ? 20 : 15
|
||||
readonly property real disclosureButton: dimensions.largeScreen ? 30 : 22
|
||||
}
|
||||
|
||||
Item {
|
||||
|
|
|
@ -53,7 +53,7 @@ Fadable {
|
|||
property bool resizable: false
|
||||
|
||||
property vector2d minSize: Qt.vector2d(100, 100)
|
||||
property vector2d maxSize: Qt.vector2d(1280, 720)
|
||||
property vector2d maxSize: Qt.vector2d(1280, 800)
|
||||
|
||||
// The content to place inside the window, determined by the client
|
||||
default property var content
|
||||
|
|
|
@ -3215,6 +3215,25 @@ void Application::update(float deltaTime) {
|
|||
|
||||
updateLOD();
|
||||
|
||||
if (!_physicsEnabled && _processOctreeStatsCounter > 0) {
|
||||
|
||||
// process octree stats packets are sent in between full sends of a scene.
|
||||
// We keep physics disabled until we've recieved a full scene and everything near the avatar in that
|
||||
// scene is ready to compute its collision shape.
|
||||
|
||||
if (nearbyEntitiesAreReadyForPhysics()) {
|
||||
_physicsEnabled = true;
|
||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||
} else {
|
||||
auto characterController = getMyAvatar()->getCharacterController();
|
||||
if (characterController) {
|
||||
// if we have a character controller, disable it here so the avatar doesn't get stuck due to
|
||||
// a non-loading collision hull.
|
||||
characterController->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("devices");
|
||||
DeviceTracker::updateAll();
|
||||
|
@ -4260,22 +4279,7 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer
|
|||
});
|
||||
});
|
||||
|
||||
if (!_physicsEnabled) {
|
||||
if (nearbyEntitiesAreReadyForPhysics()) {
|
||||
// These stats packets are sent in between full sends of a scene.
|
||||
// We keep physics disabled until we've recieved a full scene and everything near the avatar in that
|
||||
// scene is ready to compute its collision shape.
|
||||
_physicsEnabled = true;
|
||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||
} else {
|
||||
auto characterController = getMyAvatar()->getCharacterController();
|
||||
if (characterController) {
|
||||
// if we have a character controller, disable it here so the avatar doesn't get stuck due to
|
||||
// a non-loading collision hull.
|
||||
characterController->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
_processOctreeStatsCounter++;
|
||||
|
||||
return statsMessageLength;
|
||||
}
|
||||
|
|
|
@ -515,6 +515,8 @@ private:
|
|||
|
||||
std::map<void*, std::function<void()>> _preRenderLambdas;
|
||||
std::mutex _preRenderLambdasLock;
|
||||
|
||||
std::atomic<uint32_t> _processOctreeStatsCounter { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -105,13 +105,18 @@ bool ModelPackager::loadModel() {
|
|||
qWarning() << QString("ModelPackager::loadModel(): Could not open FBX file %1").arg(_fbxInfo.filePath());
|
||||
return false;
|
||||
}
|
||||
qCDebug(interfaceapp) << "Reading FBX file : " << _fbxInfo.filePath();
|
||||
QByteArray fbxContents = fbx.readAll();
|
||||
try {
|
||||
qCDebug(interfaceapp) << "Reading FBX file : " << _fbxInfo.filePath();
|
||||
QByteArray fbxContents = fbx.readAll();
|
||||
|
||||
_geometry.reset(readFBX(fbxContents, QVariantHash(), _fbxInfo.filePath()));
|
||||
_geometry.reset(readFBX(fbxContents, QVariantHash(), _fbxInfo.filePath()));
|
||||
|
||||
// make sure we have some basic mappings
|
||||
populateBasicMapping(_mapping, _fbxInfo.filePath(), *_geometry);
|
||||
// make sure we have some basic mappings
|
||||
populateBasicMapping(_mapping, _fbxInfo.filePath(), *_geometry);
|
||||
} catch (const QString& error) {
|
||||
qCDebug(interfaceapp) << "Error reading " << _fbxInfo.filePath() << ": " << error;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <BugSplat.h>
|
||||
#endif
|
||||
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
disableQtBearerPoll(); // Fixes wifi ping spikes
|
||||
|
||||
|
@ -180,6 +181,8 @@ int main(int argc, const char* argv[]) {
|
|||
mpSender.sendAdditionalFile(qPrintable(logPath));
|
||||
#endif
|
||||
|
||||
printSystemInformation();
|
||||
|
||||
QTranslator translator;
|
||||
translator.load("i18n/interface_en");
|
||||
app.installTranslator(&translator);
|
||||
|
|
|
@ -97,3 +97,11 @@ bool HMDScriptingInterface::isMounted() const{
|
|||
auto displayPlugin = qApp->getActiveDisplayPlugin();
|
||||
return (displayPlugin->isHmd() && displayPlugin->isDisplayVisible());
|
||||
}
|
||||
|
||||
QString HMDScriptingInterface::preferredAudioInput() const {
|
||||
return qApp->getActiveDisplayPlugin()->getPreferredAudioInDevice();
|
||||
}
|
||||
|
||||
QString HMDScriptingInterface::preferredAudioOutput() const {
|
||||
return qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice();
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ public:
|
|||
|
||||
Q_INVOKABLE glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const;
|
||||
Q_INVOKABLE glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const;
|
||||
Q_INVOKABLE QString preferredAudioInput() const;
|
||||
Q_INVOKABLE QString preferredAudioOutput() const;
|
||||
|
||||
public:
|
||||
HMDScriptingInterface();
|
||||
|
|
|
@ -36,7 +36,7 @@ AnimationPointer AnimationCache::getAnimation(const QUrl& url) {
|
|||
|
||||
QSharedPointer<Resource> AnimationCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
bool delayLoad, const void* extra) {
|
||||
return QSharedPointer<Resource>(new Animation(url), &Resource::allReferencesCleared);
|
||||
return QSharedPointer<Resource>(new Animation(url), &Resource::deleter);
|
||||
}
|
||||
|
||||
Animation::Animation(const QUrl& url) : Resource(url) {}
|
||||
|
|
|
@ -175,6 +175,50 @@ int numDestinationSamplesRequired(const QAudioFormat& sourceFormat, const QAudio
|
|||
return (numSourceSamples * ratio) + 0.5f;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QString friendlyNameForAudioDevice(IMMDevice* pEndpoint) {
|
||||
QString deviceName;
|
||||
IPropertyStore* pPropertyStore;
|
||||
pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore);
|
||||
pEndpoint->Release();
|
||||
pEndpoint = NULL;
|
||||
PROPVARIANT pv;
|
||||
PropVariantInit(&pv);
|
||||
HRESULT hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
|
||||
pPropertyStore->Release();
|
||||
pPropertyStore = NULL;
|
||||
deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal);
|
||||
if (!IsWindows8OrGreater()) {
|
||||
// Windows 7 provides only the 31 first characters of the device name.
|
||||
const DWORD QT_WIN7_MAX_AUDIO_DEVICENAME_LEN = 31;
|
||||
deviceName = deviceName.left(QT_WIN7_MAX_AUDIO_DEVICENAME_LEN);
|
||||
}
|
||||
PropVariantClear(&pv);
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
QString AudioClient::friendlyNameForAudioDevice(wchar_t* guid) {
|
||||
QString deviceName;
|
||||
HRESULT hr = S_OK;
|
||||
CoInitialize(NULL);
|
||||
IMMDeviceEnumerator* pMMDeviceEnumerator = NULL;
|
||||
CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator);
|
||||
IMMDevice* pEndpoint;
|
||||
hr = pMMDeviceEnumerator->GetDevice(guid, &pEndpoint);
|
||||
if (hr == E_NOTFOUND) {
|
||||
printf("Audio Error: device not found\n");
|
||||
deviceName = QString("NONE");
|
||||
} else {
|
||||
deviceName = ::friendlyNameForAudioDevice(pEndpoint);
|
||||
}
|
||||
pMMDeviceEnumerator->Release();
|
||||
pMMDeviceEnumerator = NULL;
|
||||
CoUninitialize();
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
||||
#ifdef __APPLE__
|
||||
if (QAudioDeviceInfo::availableDevices(mode).size() > 1) {
|
||||
|
@ -248,23 +292,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
|||
printf("Audio Error: device not found\n");
|
||||
deviceName = QString("NONE");
|
||||
} else {
|
||||
IPropertyStore* pPropertyStore;
|
||||
pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore);
|
||||
pEndpoint->Release();
|
||||
pEndpoint = NULL;
|
||||
PROPVARIANT pv;
|
||||
PropVariantInit(&pv);
|
||||
hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
|
||||
pPropertyStore->Release();
|
||||
pPropertyStore = NULL;
|
||||
deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal);
|
||||
if (!IsWindows8OrGreater()) {
|
||||
// Windows 7 provides only the 31 first characters of the device name.
|
||||
const DWORD QT_WIN7_MAX_AUDIO_DEVICENAME_LEN = 31;
|
||||
deviceName = deviceName.left(QT_WIN7_MAX_AUDIO_DEVICENAME_LEN);
|
||||
}
|
||||
qCDebug(audioclient) << (mode == QAudio::AudioOutput ? "output" : "input") << " device:" << deviceName;
|
||||
PropVariantClear(&pv);
|
||||
deviceName = friendlyNameForAudioDevice(pEndpoint);
|
||||
}
|
||||
pMMDeviceEnumerator->Release();
|
||||
pMMDeviceEnumerator = NULL;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <QtCore/qsystemdetection.h>
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QObject>
|
||||
|
@ -126,6 +127,10 @@ public:
|
|||
|
||||
static const float CALLBACK_ACCELERATOR_RATIO;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static QString friendlyNameForAudioDevice(wchar_t* guid);
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
void stop();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <QtCore/QDebug>
|
||||
|
||||
#include <udt/PacketHeaders.h>
|
||||
#include <LogHandler.h>
|
||||
|
||||
#include "AudioLogging.h"
|
||||
|
||||
|
@ -129,7 +130,10 @@ int AudioRingBuffer::writeData(const char* data, int maxSize) {
|
|||
int samplesToDelete = samplesToCopy - samplesRoomFor;
|
||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
||||
_overflowCount++;
|
||||
qCDebug(audio) << "Overflowed ring buffer! Overwriting old data";
|
||||
|
||||
const QString RING_BUFFER_OVERFLOW_DEBUG { "AudioRingBuffer::writeData has overflown the buffer. Overwriting old data." };
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
}
|
||||
|
||||
if (_endOfLastWrite + samplesToCopy <= _buffer + _bufferLength) {
|
||||
|
|
|
@ -36,5 +36,5 @@ SharedSoundPointer SoundCache::getSound(const QUrl& url) {
|
|||
QSharedPointer<Resource> SoundCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
bool delayLoad, const void* extra) {
|
||||
qCDebug(audio) << "Requesting sound at" << url.toString();
|
||||
return QSharedPointer<Resource>(new Sound(url), &Resource::allReferencesCleared);
|
||||
return QSharedPointer<Resource>(new Sound(url), &Resource::deleter);
|
||||
}
|
||||
|
|
|
@ -116,11 +116,18 @@ QVariantMap RenderableModelEntityItem::parseTexturesToMap(QString textures) {
|
|||
|
||||
QJsonParseError error;
|
||||
QJsonDocument texturesJson = QJsonDocument::fromJson(textures.toUtf8(), &error);
|
||||
// If textures are invalid, revert to original textures
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << textures;
|
||||
return _originalTextures;
|
||||
}
|
||||
|
||||
QVariantMap texturesMap = texturesJson.toVariant().toMap();
|
||||
// If textures are unset, revert to original textures
|
||||
if (texturesMap.isEmpty()) {
|
||||
return _originalTextures;
|
||||
}
|
||||
|
||||
return texturesJson.toVariant().toMap();
|
||||
}
|
||||
|
||||
|
@ -133,10 +140,8 @@ void RenderableModelEntityItem::remapTextures() {
|
|||
return; // nothing to do if the model has not yet loaded
|
||||
}
|
||||
|
||||
auto& geometry = _model->getGeometry()->getGeometry();
|
||||
|
||||
if (!_originalTexturesRead) {
|
||||
_originalTextures = geometry->getTextures();
|
||||
_originalTextures = _model->getTextures();
|
||||
_originalTexturesRead = true;
|
||||
|
||||
// Default to _originalTextures to avoid remapping immediately and lagging on load
|
||||
|
@ -152,7 +157,7 @@ void RenderableModelEntityItem::remapTextures() {
|
|||
auto newTextures = parseTexturesToMap(textures);
|
||||
|
||||
if (newTextures != _currentTextures) {
|
||||
geometry->setTextures(newTextures);
|
||||
_model->setTextures(newTextures);
|
||||
_currentTextures = newTextures;
|
||||
}
|
||||
}
|
||||
|
@ -366,41 +371,16 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
assert(getType() == EntityTypes::Model);
|
||||
|
||||
if (hasModel()) {
|
||||
if (_model) {
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
|
||||
// check to see if when we added our models to the scene they were ready, if they were not ready, then
|
||||
// fix them up in the scene
|
||||
bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0;
|
||||
if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) {
|
||||
_showCollisionHull = shouldShowCollisionHull;
|
||||
render::PendingChanges pendingChanges;
|
||||
|
||||
_model->removeFromScene(scene, pendingChanges);
|
||||
|
||||
render::Item::Status::Getters statusGetters;
|
||||
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
|
||||
_model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull);
|
||||
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
|
||||
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
||||
// the renderable item. As it stands now the model checks it's visible/invisible state
|
||||
// so most of the time we don't do anything in this function.
|
||||
_model->setVisibleInScene(getVisible(), scene);
|
||||
}
|
||||
|
||||
|
||||
remapTextures();
|
||||
// Prepare the current frame
|
||||
{
|
||||
// float alpha = getLocalRenderAlpha();
|
||||
|
||||
if (!_model || _needsModelReload) {
|
||||
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
||||
PerformanceTimer perfTimer("getModel");
|
||||
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
|
||||
getModel(renderer);
|
||||
|
||||
// Remap textures immediately after loading to avoid flicker
|
||||
remapTextures();
|
||||
}
|
||||
|
||||
if (_model) {
|
||||
|
@ -431,15 +411,40 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
}
|
||||
});
|
||||
updateModelBounds();
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the URL has changed
|
||||
// Do this last as the getModel is queued for the next frame,
|
||||
// and we need to keep state directing the model to reinitialize
|
||||
auto& currentURL = getParsedModelURL();
|
||||
if (currentURL != _model->getURL()) {
|
||||
// Defer setting the url to the render thread
|
||||
getModel(_myRenderer);
|
||||
}
|
||||
// Enqueue updates for the next frame
|
||||
if (_model) {
|
||||
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
|
||||
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
||||
// the renderable item. As it stands now the model checks it's visible/invisible state
|
||||
// so most of the time we don't do anything in this function.
|
||||
_model->setVisibleInScene(getVisible(), scene);
|
||||
|
||||
// Remap textures for the next frame to avoid flicker
|
||||
remapTextures();
|
||||
|
||||
// check to see if when we added our models to the scene they were ready, if they were not ready, then
|
||||
// fix them up in the scene
|
||||
bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0;
|
||||
if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) {
|
||||
_showCollisionHull = shouldShowCollisionHull;
|
||||
render::PendingChanges pendingChanges;
|
||||
|
||||
render::Item::Status::Getters statusGetters;
|
||||
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
|
||||
_model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull);
|
||||
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
|
||||
auto& currentURL = getParsedModelURL();
|
||||
if (currentURL != _model->getURL()) {
|
||||
// Defer setting the url to the render thread
|
||||
getModel(_myRenderer);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -47,6 +47,9 @@ template<class T> QVariant readBinaryArray(QDataStream& in, int& position) {
|
|||
in.readRawData(compressed.data() + sizeof(quint32), compressedLength);
|
||||
position += compressedLength;
|
||||
QByteArray uncompressed = qUncompress(compressed);
|
||||
if (uncompressed.isEmpty()) { // answers empty byte array if corrupt
|
||||
throw QString("corrupt fbx file");
|
||||
}
|
||||
QDataStream uncompressedIn(uncompressed);
|
||||
uncompressedIn.setByteOrder(QDataStream::LittleEndian);
|
||||
uncompressedIn.setVersion(QDataStream::Qt_4_5); // for single/double precision switch
|
||||
|
|
|
@ -457,6 +457,14 @@ uint32 Texture::getStoredMipSize(uint16 level) const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
gpu::Resource::Size Texture::getStoredSize() const {
|
||||
auto size = 0;
|
||||
for (int level = 0; level < evalNumMips(); ++level) {
|
||||
size += getStoredMipSize(level);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
uint16 Texture::evalNumSamplesUsed(uint16 numSamplesTried) {
|
||||
uint16 sample = numSamplesTried;
|
||||
if (numSamplesTried <= 1)
|
||||
|
|
|
@ -288,9 +288,12 @@ public:
|
|||
Stamp getStamp() const { return _stamp; }
|
||||
Stamp getDataStamp() const { return _storage->getStamp(); }
|
||||
|
||||
// The size in bytes of data stored in the texture
|
||||
// The theoretical size in bytes of data stored in the texture
|
||||
Size getSize() const { return _size; }
|
||||
|
||||
// The actual size in bytes of data stored in the texture
|
||||
Size getStoredSize() const;
|
||||
|
||||
// Resize, unless auto mips mode would destroy all the sub mips
|
||||
Size resize1D(uint16 width, uint16 numSamples);
|
||||
Size resize2D(uint16 width, uint16 height, uint16 numSamples);
|
||||
|
|
|
@ -29,6 +29,10 @@ public:
|
|||
const QUrl& textureBaseUrl;
|
||||
};
|
||||
|
||||
QUrl resolveTextureBaseUrl(const QUrl& url, const QUrl& textureBaseUrl) {
|
||||
return textureBaseUrl.isValid() ? textureBaseUrl : url;
|
||||
}
|
||||
|
||||
class GeometryMappingResource : public GeometryResource {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -52,30 +56,28 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
|
|||
finishedLoading(false);
|
||||
} else {
|
||||
QUrl url = _url.resolved(filename);
|
||||
QUrl textureBaseUrl;
|
||||
|
||||
QString texdir = mapping.value("texdir").toString();
|
||||
if (!texdir.isNull()) {
|
||||
if (!texdir.endsWith('/')) {
|
||||
texdir += '/';
|
||||
}
|
||||
textureBaseUrl = _url.resolved(texdir);
|
||||
_textureBaseUrl = resolveTextureBaseUrl(url, _url.resolved(texdir));
|
||||
}
|
||||
|
||||
auto modelCache = DependencyManager::get<ModelCache>();
|
||||
GeometryExtra extra{ mapping, textureBaseUrl };
|
||||
GeometryExtra extra{ mapping, _textureBaseUrl };
|
||||
|
||||
// Get the raw GeometryResource, not the wrapped NetworkGeometry
|
||||
_geometryResource = modelCache->getResource(url, QUrl(), true, &extra).staticCast<GeometryResource>();
|
||||
_geometryResource = modelCache->getResource(url, QUrl(), false, &extra).staticCast<GeometryResource>();
|
||||
// Avoid caching nested resources - their references will be held by the parent
|
||||
_geometryResource->_isCacheable = false;
|
||||
|
||||
if (_geometryResource->isLoaded()) {
|
||||
onGeometryMappingLoaded(!_geometryResource->getURL().isEmpty());
|
||||
} else {
|
||||
connect(_geometryResource.data(), &Resource::finished, this, &GeometryMappingResource::onGeometryMappingLoaded);
|
||||
}
|
||||
|
||||
// Avoid caching nested resources - their references will be held by the parent
|
||||
_geometryResource->_isCacheable = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,6 +88,10 @@ void GeometryMappingResource::onGeometryMappingLoaded(bool success) {
|
|||
_meshes = _geometryResource->_meshes;
|
||||
_materials = _geometryResource->_materials;
|
||||
}
|
||||
|
||||
// Avoid holding onto extra references
|
||||
_geometryResource.reset();
|
||||
|
||||
finishedLoading(success);
|
||||
}
|
||||
|
||||
|
@ -157,7 +163,7 @@ class GeometryDefinitionResource : public GeometryResource {
|
|||
Q_OBJECT
|
||||
public:
|
||||
GeometryDefinitionResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
|
||||
GeometryResource(url), _mapping(mapping), _textureBaseUrl(textureBaseUrl.isValid() ? textureBaseUrl : url) {}
|
||||
GeometryResource(url, resolveTextureBaseUrl(url, textureBaseUrl)), _mapping(mapping) {}
|
||||
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
|
@ -166,7 +172,6 @@ protected:
|
|||
|
||||
private:
|
||||
QVariantHash _mapping;
|
||||
QUrl _textureBaseUrl;
|
||||
};
|
||||
|
||||
void GeometryDefinitionResource::downloadFinished(const QByteArray& data) {
|
||||
|
@ -220,13 +225,20 @@ QSharedPointer<Resource> ModelCache::createResource(const QUrl& url, const QShar
|
|||
resource = new GeometryDefinitionResource(url, geometryExtra->mapping, geometryExtra->textureBaseUrl);
|
||||
}
|
||||
|
||||
return QSharedPointer<Resource>(resource, &Resource::allReferencesCleared);
|
||||
return QSharedPointer<Resource>(resource, &Resource::deleter);
|
||||
}
|
||||
|
||||
std::shared_ptr<NetworkGeometry> ModelCache::getGeometry(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) {
|
||||
GeometryExtra geometryExtra = { mapping, textureBaseUrl };
|
||||
GeometryResource::Pointer resource = getResource(url, QUrl(), true, &geometryExtra).staticCast<GeometryResource>();
|
||||
return std::make_shared<NetworkGeometry>(resource);
|
||||
if (resource) {
|
||||
if (resource->isLoaded() && !resource->hasTextures()) {
|
||||
resource->setTextures();
|
||||
}
|
||||
return std::make_shared<NetworkGeometry>(resource);
|
||||
} else {
|
||||
return NetworkGeometry::Pointer();
|
||||
}
|
||||
}
|
||||
|
||||
const QVariantMap Geometry::getTextures() const {
|
||||
|
@ -270,6 +282,9 @@ void Geometry::setTextures(const QVariantMap& textureMap) {
|
|||
|
||||
material->setTextures(textureMap);
|
||||
_areTexturesLoaded = false;
|
||||
|
||||
// If we only use cached textures, they should all be loaded
|
||||
areTexturesLoaded();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -279,8 +294,6 @@ void Geometry::setTextures(const QVariantMap& textureMap) {
|
|||
|
||||
bool Geometry::areTexturesLoaded() const {
|
||||
if (!_areTexturesLoaded) {
|
||||
_hasTransparentTextures = false;
|
||||
|
||||
for (auto& material : _materials) {
|
||||
// Check if material textures are loaded
|
||||
if (std::any_of(material->_textures.cbegin(), material->_textures.cend(),
|
||||
|
@ -293,8 +306,6 @@ bool Geometry::areTexturesLoaded() const {
|
|||
const auto albedoTexture = material->_textures[NetworkMaterial::MapChannel::ALBEDO_MAP];
|
||||
if (albedoTexture.texture && albedoTexture.texture->getGPUTexture()) {
|
||||
material->resetOpacityMap();
|
||||
|
||||
_hasTransparentTextures |= material->getKey().isTranslucent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,6 +324,21 @@ const std::shared_ptr<const NetworkMaterial> Geometry::getShapeMaterial(int shap
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void GeometryResource::deleter() {
|
||||
resetTextures();
|
||||
Resource::deleter();
|
||||
}
|
||||
|
||||
void GeometryResource::setTextures() {
|
||||
for (const FBXMaterial& material : _geometry->materials) {
|
||||
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryResource::resetTextures() {
|
||||
_materials.clear();
|
||||
}
|
||||
|
||||
NetworkGeometry::NetworkGeometry(const GeometryResource::Pointer& networkGeometry) : _resource(networkGeometry) {
|
||||
connect(_resource.data(), &Resource::finished, this, &NetworkGeometry::resourceFinished);
|
||||
connect(_resource.data(), &Resource::onRefresh, this, &NetworkGeometry::resourceRefreshed);
|
||||
|
|
|
@ -74,9 +74,6 @@ public:
|
|||
void setTextures(const QVariantMap& textureMap);
|
||||
|
||||
virtual bool areTexturesLoaded() const;
|
||||
// Returns true if any albedo texture has a non-masking alpha channel.
|
||||
// This can only be known after areTexturesLoaded().
|
||||
bool hasTransparentTextures() const { return _hasTransparentTextures; }
|
||||
|
||||
protected:
|
||||
friend class GeometryMappingResource;
|
||||
|
@ -91,7 +88,6 @@ protected:
|
|||
|
||||
private:
|
||||
mutable bool _areTexturesLoaded { false };
|
||||
mutable bool _hasTransparentTextures { false };
|
||||
};
|
||||
|
||||
/// A geometry loaded from the network.
|
||||
|
@ -99,15 +95,25 @@ class GeometryResource : public Resource, public Geometry {
|
|||
public:
|
||||
using Pointer = QSharedPointer<GeometryResource>;
|
||||
|
||||
GeometryResource(const QUrl& url) : Resource(url) {}
|
||||
GeometryResource(const QUrl& url, const QUrl& textureBaseUrl = QUrl()) :
|
||||
Resource(url), _textureBaseUrl(textureBaseUrl) {}
|
||||
|
||||
virtual bool areTexturesLoaded() const { return isLoaded() && Geometry::areTexturesLoaded(); }
|
||||
|
||||
virtual void deleter() override;
|
||||
|
||||
protected:
|
||||
friend class ModelCache;
|
||||
friend class GeometryMappingResource;
|
||||
|
||||
virtual bool isCacheable() const override { return _loaded && _isCacheable; }
|
||||
// Geometries may not hold onto textures while cached - that is for the texture cache
|
||||
bool hasTextures() const { return !_materials.empty(); }
|
||||
void setTextures();
|
||||
void resetTextures();
|
||||
|
||||
QUrl _textureBaseUrl;
|
||||
|
||||
virtual bool isCacheable() const override { return _loaded && _isCacheable; }
|
||||
bool _isCacheable { true };
|
||||
};
|
||||
|
||||
|
|
|
@ -28,6 +28,6 @@ NetworkShaderPointer ShaderCache::getShader(const QUrl& url) {
|
|||
}
|
||||
|
||||
QSharedPointer<Resource> ShaderCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
||||
return QSharedPointer<Resource>(new NetworkShader(url, delayLoad), &Resource::allReferencesCleared);
|
||||
return QSharedPointer<Resource>(new NetworkShader(url, delayLoad), &Resource::deleter);
|
||||
}
|
||||
|
||||
|
|
|
@ -166,12 +166,11 @@ gpu::TexturePointer TextureCache::getImageTexture(const QString& path) {
|
|||
return texture;
|
||||
}
|
||||
|
||||
|
||||
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
|
||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
||||
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);
|
||||
return QSharedPointer<Resource>(new NetworkTexture(url, textureExtra->type, textureExtra->content),
|
||||
&Resource::allReferencesCleared);
|
||||
&Resource::deleter);
|
||||
}
|
||||
|
||||
NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content) :
|
||||
|
@ -339,10 +338,13 @@ void NetworkTexture::setImage(void* voidTexture, int originalWidth,
|
|||
if (gpuTexture) {
|
||||
_width = gpuTexture->getWidth();
|
||||
_height = gpuTexture->getHeight();
|
||||
setBytes(gpuTexture->getStoredSize());
|
||||
} else {
|
||||
// FIXME: If !gpuTexture, we failed to load!
|
||||
_width = _height = 0;
|
||||
qWarning() << "Texture did not load";
|
||||
}
|
||||
|
||||
|
||||
finishedLoading(true);
|
||||
|
||||
emit networkTextureCreated(qWeakPointerCast<NetworkTexture, Resource> (_self));
|
||||
|
|
|
@ -200,7 +200,7 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data) {
|
|||
return upload;
|
||||
}
|
||||
|
||||
bool AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end,
|
||||
MessageID AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end,
|
||||
ReceivedAssetCallback callback, ProgressCallback progressCallback) {
|
||||
if (hash.length() != SHA256_HASH_HEX_LENGTH) {
|
||||
qCWarning(asset_client) << "Invalid hash size";
|
||||
|
@ -230,17 +230,16 @@ bool AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end
|
|||
|
||||
_pendingRequests[assetServer][messageID] = { QSharedPointer<ReceivedMessage>(), callback, progressCallback };
|
||||
|
||||
|
||||
return true;
|
||||
return messageID;
|
||||
} else {
|
||||
callback(false, AssetServerError::NoError, QByteArray());
|
||||
return false;
|
||||
return INVALID_MESSAGE_ID;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) {
|
||||
MessageID AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
|
@ -257,10 +256,10 @@ bool AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) {
|
|||
|
||||
_pendingInfoRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
return messageID;
|
||||
} else {
|
||||
callback(false, AssetServerError::NoError, { "", 0 });
|
||||
return false;
|
||||
return INVALID_MESSAGE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,7 +351,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer<ReceivedMessage> message, S
|
|||
}
|
||||
}
|
||||
|
||||
bool AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallback callback) {
|
||||
MessageID AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
|
@ -370,14 +369,14 @@ bool AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallbac
|
|||
|
||||
_pendingMappingRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
return messageID;
|
||||
} else {
|
||||
callback(false, AssetServerError::NoError, QSharedPointer<ReceivedMessage>());
|
||||
return false;
|
||||
return INVALID_MESSAGE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) {
|
||||
MessageID AssetClient::getAllAssetMappings(MappingOperationCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
|
@ -393,14 +392,14 @@ bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) {
|
|||
|
||||
_pendingMappingRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
return messageID;
|
||||
} else {
|
||||
callback(false, AssetServerError::NoError, QSharedPointer<ReceivedMessage>());
|
||||
return false;
|
||||
return INVALID_MESSAGE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback) {
|
||||
MessageID AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
|
@ -422,14 +421,14 @@ bool AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperati
|
|||
|
||||
_pendingMappingRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
return messageID;
|
||||
} else {
|
||||
callback(false, AssetServerError::NoError, QSharedPointer<ReceivedMessage>());
|
||||
return false;
|
||||
return INVALID_MESSAGE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback) {
|
||||
MessageID AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
|
@ -448,14 +447,14 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma
|
|||
|
||||
_pendingMappingRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
return messageID;
|
||||
} else {
|
||||
callback(false, AssetServerError::NoError, QSharedPointer<ReceivedMessage>());
|
||||
return false;
|
||||
return INVALID_MESSAGE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetClient::renameAssetMapping(const AssetPath& oldPath, const AssetPath& newPath, MappingOperationCallback callback) {
|
||||
MessageID AssetClient::renameAssetMapping(const AssetPath& oldPath, const AssetPath& newPath, MappingOperationCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
|
@ -474,15 +473,53 @@ bool AssetClient::renameAssetMapping(const AssetPath& oldPath, const AssetPath&
|
|||
|
||||
_pendingMappingRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
return messageID;
|
||||
|
||||
} else {
|
||||
callback(false, AssetServerError::NoError, QSharedPointer<ReceivedMessage>());
|
||||
return false;
|
||||
return INVALID_MESSAGE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callback) {
|
||||
bool AssetClient::cancelMappingRequest(MessageID id) {
|
||||
for (auto& kv : _pendingMappingRequests) {
|
||||
if (kv.second.erase(id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssetClient::cancelGetAssetInfoRequest(MessageID id) {
|
||||
for (auto& kv : _pendingInfoRequests) {
|
||||
if (kv.second.erase(id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssetClient::cancelGetAssetRequest(MessageID id) {
|
||||
// Search through each pending mapping request for id `id`
|
||||
for (auto& kv : _pendingRequests) {
|
||||
if (kv.second.erase(id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssetClient::cancelUploadAssetRequest(MessageID id) {
|
||||
// Search through each pending mapping request for id `id`
|
||||
for (auto& kv : _pendingUploads) {
|
||||
if (kv.second.erase(id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MessageID AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
|
@ -500,10 +537,10 @@ bool AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callb
|
|||
|
||||
_pendingUploads[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
return messageID;
|
||||
} else {
|
||||
callback(false, AssetServerError::NoError, QString());
|
||||
return false;
|
||||
return INVALID_MESSAGE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,8 @@ public:
|
|||
Q_INVOKABLE AssetUpload* createUpload(const QString& filename);
|
||||
Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data);
|
||||
|
||||
static const MessageID INVALID_MESSAGE_ID = 0;
|
||||
|
||||
public slots:
|
||||
void init();
|
||||
|
||||
|
@ -75,16 +77,21 @@ private slots:
|
|||
void handleNodeKilled(SharedNodePointer node);
|
||||
|
||||
private:
|
||||
bool getAssetMapping(const AssetHash& hash, MappingOperationCallback callback);
|
||||
bool getAllAssetMappings(MappingOperationCallback callback);
|
||||
bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback);
|
||||
bool deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback);
|
||||
bool renameAssetMapping(const AssetPath& oldPath, const AssetPath& newPath, MappingOperationCallback callback);
|
||||
MessageID getAssetMapping(const AssetHash& hash, MappingOperationCallback callback);
|
||||
MessageID getAllAssetMappings(MappingOperationCallback callback);
|
||||
MessageID setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback);
|
||||
MessageID deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback);
|
||||
MessageID renameAssetMapping(const AssetPath& oldPath, const AssetPath& newPath, MappingOperationCallback callback);
|
||||
|
||||
bool getAssetInfo(const QString& hash, GetInfoCallback callback);
|
||||
bool getAsset(const QString& hash, DataOffset start, DataOffset end,
|
||||
MessageID getAssetInfo(const QString& hash, GetInfoCallback callback);
|
||||
MessageID getAsset(const QString& hash, DataOffset start, DataOffset end,
|
||||
ReceivedAssetCallback callback, ProgressCallback progressCallback);
|
||||
bool uploadAsset(const QByteArray& data, UploadResultCallback callback);
|
||||
MessageID uploadAsset(const QByteArray& data, UploadResultCallback callback);
|
||||
|
||||
bool cancelMappingRequest(MessageID id);
|
||||
bool cancelGetAssetInfoRequest(MessageID id);
|
||||
bool cancelGetAssetRequest(MessageID id);
|
||||
bool cancelUploadAssetRequest(MessageID id);
|
||||
|
||||
struct GetAssetRequestData {
|
||||
QSharedPointer<ReceivedMessage> message;
|
||||
|
@ -100,6 +107,7 @@ private:
|
|||
|
||||
friend class AssetRequest;
|
||||
friend class AssetUpload;
|
||||
friend class MappingRequest;
|
||||
friend class GetMappingRequest;
|
||||
friend class GetAllMappingsRequest;
|
||||
friend class SetMappingRequest;
|
||||
|
|
|
@ -25,6 +25,16 @@ AssetRequest::AssetRequest(const QString& hash) :
|
|||
{
|
||||
}
|
||||
|
||||
AssetRequest::~AssetRequest() {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
if (_assetRequestID) {
|
||||
assetClient->cancelGetAssetRequest(_assetRequestID);
|
||||
}
|
||||
if (_assetInfoRequestID) {
|
||||
assetClient->cancelGetAssetInfoRequest(_assetInfoRequestID);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetRequest::start() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "start", Qt::AutoConnection);
|
||||
|
@ -60,7 +70,11 @@ void AssetRequest::start() {
|
|||
_state = WaitingForInfo;
|
||||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
assetClient->getAssetInfo(_hash, [this](bool responseReceived, AssetServerError serverError, AssetInfo info) {
|
||||
_assetInfoRequestID = assetClient->getAssetInfo(_hash,
|
||||
[this](bool responseReceived, AssetServerError serverError, AssetInfo info) {
|
||||
|
||||
_assetInfoRequestID = AssetClient::INVALID_MESSAGE_ID;
|
||||
|
||||
_info = info;
|
||||
|
||||
if (!responseReceived) {
|
||||
|
@ -92,8 +106,11 @@ void AssetRequest::start() {
|
|||
int start = 0, end = _info.size;
|
||||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
assetClient->getAsset(_hash, start, end, [this, start, end](bool responseReceived, AssetServerError serverError,
|
||||
const QByteArray& data) {
|
||||
_assetRequestID = assetClient->getAsset(_hash, start, end,
|
||||
[this, start, end](bool responseReceived, AssetServerError serverError, const QByteArray& data) {
|
||||
|
||||
_assetRequestID = AssetClient::INVALID_MESSAGE_ID;
|
||||
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else if (serverError != AssetServerError::NoError) {
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
};
|
||||
|
||||
AssetRequest(const QString& hash);
|
||||
virtual ~AssetRequest() override;
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
|
@ -61,6 +62,8 @@ private:
|
|||
QString _hash;
|
||||
QByteArray _data;
|
||||
int _numPendingRequests { 0 };
|
||||
MessageID _assetRequestID { AssetClient::INVALID_MESSAGE_ID };
|
||||
MessageID _assetInfoRequestID { AssetClient::INVALID_MESSAGE_ID };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,7 +21,7 @@ class AssetResourceRequest : public ResourceRequest {
|
|||
Q_OBJECT
|
||||
public:
|
||||
AssetResourceRequest(const QUrl& url) : ResourceRequest(url) { }
|
||||
~AssetResourceRequest();
|
||||
virtual ~AssetResourceRequest() override;
|
||||
|
||||
protected:
|
||||
virtual void doSend() override;
|
||||
|
|
|
@ -15,7 +15,12 @@
|
|||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "AssetClient.h"
|
||||
MappingRequest::~MappingRequest() {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
if (_mappingRequestID) {
|
||||
assetClient->cancelMappingRequest(_mappingRequestID);
|
||||
}
|
||||
}
|
||||
|
||||
void MappingRequest::start() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
|
@ -60,7 +65,10 @@ void GetMappingRequest::doStart() {
|
|||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
|
||||
assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
_mappingRequestID = assetClient->getAssetMapping(_path,
|
||||
[this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
|
||||
_mappingRequestID = AssetClient::INVALID_MESSAGE_ID;
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
|
@ -89,7 +97,11 @@ GetAllMappingsRequest::GetAllMappingsRequest() {
|
|||
|
||||
void GetAllMappingsRequest::doStart() {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
_mappingRequestID = assetClient->getAllAssetMappings(
|
||||
[this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
|
||||
_mappingRequestID = AssetClient::INVALID_MESSAGE_ID;
|
||||
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
|
@ -137,7 +149,10 @@ void SetMappingRequest::doStart() {
|
|||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
|
||||
assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
_mappingRequestID = assetClient->setAssetMapping(_path, _hash,
|
||||
[this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
|
||||
_mappingRequestID = AssetClient::INVALID_MESSAGE_ID;
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
|
@ -177,7 +192,10 @@ void DeleteMappingsRequest::doStart() {
|
|||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
|
||||
assetClient->deleteAssetMappings(_paths, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
_mappingRequestID = assetClient->deleteAssetMappings(_paths,
|
||||
[this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
|
||||
_mappingRequestID = AssetClient::INVALID_MESSAGE_ID;
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
|
@ -216,9 +234,10 @@ void RenameMappingRequest::doStart() {
|
|||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
|
||||
assetClient->renameAssetMapping(_oldPath, _newPath, [this, assetClient](bool responseReceived,
|
||||
AssetServerError error,
|
||||
QSharedPointer<ReceivedMessage> message) {
|
||||
_mappingRequestID = assetClient->renameAssetMapping(_oldPath, _newPath,
|
||||
[this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
|
||||
_mappingRequestID = AssetClient::INVALID_MESSAGE_ID;
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <QtCore/QObject>
|
||||
|
||||
#include "AssetUtils.h"
|
||||
#include "AssetClient.h"
|
||||
|
||||
class MappingRequest : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -31,12 +32,15 @@ public:
|
|||
UnknownError
|
||||
};
|
||||
|
||||
virtual ~MappingRequest();
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
Error getError() const { return _error; }
|
||||
Q_INVOKABLE QString getErrorString() const;
|
||||
|
||||
protected:
|
||||
Error _error { NoError };
|
||||
MessageID _mappingRequestID { AssetClient::INVALID_MESSAGE_ID };
|
||||
|
||||
private:
|
||||
virtual void doStart() = 0;
|
||||
|
|
|
@ -117,22 +117,22 @@ void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) {
|
|||
}
|
||||
|
||||
void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource) {
|
||||
if (resource->getBytesTotal() > _unusedResourcesMaxSize) {
|
||||
// If it doesn't fit anyway, let's leave whatever is already in the cache.
|
||||
// If it doesn't fit or its size is unknown, leave the cache alone.
|
||||
if (resource->getBytes() == 0 || resource->getBytes() > _unusedResourcesMaxSize) {
|
||||
resource->setCache(nullptr);
|
||||
return;
|
||||
}
|
||||
reserveUnusedResource(resource->getBytesTotal());
|
||||
reserveUnusedResource(resource->getBytes());
|
||||
|
||||
resource->setLRUKey(++_lastLRUKey);
|
||||
_unusedResources.insert(resource->getLRUKey(), resource);
|
||||
_unusedResourcesSize += resource->getBytesTotal();
|
||||
_unusedResourcesSize += resource->getBytes();
|
||||
}
|
||||
|
||||
void ResourceCache::removeUnusedResource(const QSharedPointer<Resource>& resource) {
|
||||
if (_unusedResources.contains(resource->getLRUKey())) {
|
||||
_unusedResources.remove(resource->getLRUKey());
|
||||
_unusedResourcesSize -= resource->getBytesTotal();
|
||||
_unusedResourcesSize -= resource->getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
|
|||
// unload the oldest resource
|
||||
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
|
||||
|
||||
_unusedResourcesSize -= it.value()->getBytesTotal();
|
||||
_unusedResourcesSize -= it.value()->getBytes();
|
||||
it.value()->setCache(nullptr);
|
||||
_unusedResources.erase(it);
|
||||
}
|
||||
|
@ -399,7 +399,7 @@ void Resource::makeRequest() {
|
|||
connect(_request, &ResourceRequest::progress, this, &Resource::handleDownloadProgress);
|
||||
connect(_request, &ResourceRequest::finished, this, &Resource::handleReplyFinished);
|
||||
|
||||
_bytesReceived = _bytesTotal = 0;
|
||||
_bytesReceived = _bytesTotal = _bytes = 0;
|
||||
|
||||
_request->send();
|
||||
}
|
||||
|
@ -412,6 +412,8 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota
|
|||
void Resource::handleReplyFinished() {
|
||||
Q_ASSERT_X(_request, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished");
|
||||
|
||||
_bytes = _bytesTotal;
|
||||
|
||||
if (!_request || _request != sender()) {
|
||||
// This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted.
|
||||
qWarning(networking) << "Received signal Resource::handleReplyFinished from ResourceRequest that is not the current"
|
||||
|
|
|
@ -181,6 +181,9 @@ public:
|
|||
/// For loading resources, returns the number of total bytes (<= zero if unknown).
|
||||
qint64 getBytesTotal() const { return _bytesTotal; }
|
||||
|
||||
/// For loaded resources, returns the number of actual bytes (defaults to total bytes if not explicitly set).
|
||||
qint64 getBytes() const { return _bytes; }
|
||||
|
||||
/// For loading resources, returns the load progress.
|
||||
float getProgress() const { return (_bytesTotal <= 0) ? 0.0f : (float)_bytesReceived / _bytesTotal; }
|
||||
|
||||
|
@ -191,7 +194,7 @@ public:
|
|||
|
||||
void setCache(ResourceCache* cache) { _cache = cache; }
|
||||
|
||||
Q_INVOKABLE void allReferencesCleared();
|
||||
virtual void deleter() { allReferencesCleared(); }
|
||||
|
||||
const QUrl& getURL() const { return _url; }
|
||||
|
||||
|
@ -222,10 +225,15 @@ protected:
|
|||
/// This should be overridden by subclasses that need to process the data once it is downloaded.
|
||||
virtual void downloadFinished(const QByteArray& data) { finishedLoading(true); }
|
||||
|
||||
/// Called when the download is finished and processed, sets the number of actual bytes.
|
||||
void setBytes(qint64 bytes) { _bytes = bytes; }
|
||||
|
||||
/// Called when the download is finished and processed.
|
||||
/// This should be called by subclasses that override downloadFinished to mark the end of processing.
|
||||
Q_INVOKABLE void finishedLoading(bool success);
|
||||
|
||||
Q_INVOKABLE void allReferencesCleared();
|
||||
|
||||
QUrl _url;
|
||||
QUrl _activeUrl;
|
||||
bool _startedLoading = false;
|
||||
|
@ -253,6 +261,7 @@ private:
|
|||
QTimer* _replyTimer = nullptr;
|
||||
qint64 _bytesReceived = 0;
|
||||
qint64 _bytesTotal = 0;
|
||||
qint64 _bytes = 0;
|
||||
int _attempts = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ class ResourceRequest : public QObject {
|
|||
Q_OBJECT
|
||||
public:
|
||||
ResourceRequest(const QUrl& url);
|
||||
virtual ~ResourceRequest() = default;
|
||||
|
||||
enum State {
|
||||
NotStarted = 0,
|
||||
|
|
|
@ -10,10 +10,13 @@
|
|||
//
|
||||
|
||||
#include "SequenceNumberStats.h"
|
||||
#include "NetworkLogging.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <LogHandler.h>
|
||||
|
||||
#include "NetworkLogging.h"
|
||||
|
||||
float PacketStreamStats::getLostRate() const {
|
||||
return (_expectedReceived == 0) ? 0.0f : (float)_lost / (float)_expectedReceived;
|
||||
}
|
||||
|
@ -63,6 +66,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
|
|||
arrivalInfo._status = OnTime;
|
||||
_lastReceivedSequence = incoming;
|
||||
_stats._expectedReceived++;
|
||||
|
||||
} else { // out of order
|
||||
|
||||
if (wantExtraDebugging) {
|
||||
|
@ -85,6 +89,9 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
|
|||
} else if (absGap > MAX_REASONABLE_SEQUENCE_GAP) {
|
||||
arrivalInfo._status = Unreasonable;
|
||||
|
||||
static const QString UNREASONABLE_SEQUENCE_REGEX { "unreasonable sequence number: \\d+ previous: \\d+" };
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(UNREASONABLE_SEQUENCE_REGEX);
|
||||
|
||||
qCDebug(networking) << "unreasonable sequence number:" << incoming << "previous:" << _lastReceivedSequence;
|
||||
|
||||
_stats._unreasonable++;
|
||||
|
@ -147,6 +154,9 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
|
|||
|
||||
arrivalInfo._status = Unreasonable;
|
||||
|
||||
static const QString UNREASONABLE_SEQUENCE_REGEX { "unreasonable sequence number: \\d+ \\(possible duplicate\\)" };
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(UNREASONABLE_SEQUENCE_REGEX);
|
||||
|
||||
qCDebug(networking) << "unreasonable sequence number:" << incoming << "(possible duplicate)";
|
||||
|
||||
_stats._unreasonable++;
|
||||
|
|
|
@ -74,6 +74,9 @@ public:
|
|||
/// whether the HMD is being worn
|
||||
virtual bool isDisplayVisible() const { return false; }
|
||||
|
||||
virtual QString getPreferredAudioInDevice() const { return QString(); }
|
||||
virtual QString getPreferredAudioOutDevice() const { return QString(); }
|
||||
|
||||
// Rendering support
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,6 +36,6 @@ NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) {
|
|||
}
|
||||
|
||||
QSharedPointer<Resource> ClipCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
||||
return QSharedPointer<Resource>(new NetworkClipLoader(url, delayLoad), &Resource::allReferencesCleared);
|
||||
return QSharedPointer<Resource>(new NetworkClipLoader(url, delayLoad), &Resource::deleter);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,14 +76,9 @@ AbstractViewStateInterface* Model::_viewState = NULL;
|
|||
|
||||
bool Model::needsFixupInScene() const {
|
||||
if (readyToAddToScene()) {
|
||||
// Once textures are loaded, fixup if they are now transparent
|
||||
if (_needsUpdateTransparentTextures && _geometry->getGeometry()->areTexturesLoaded()) {
|
||||
_needsUpdateTransparentTextures = false;
|
||||
bool hasTransparentTextures = _geometry->getGeometry()->hasTransparentTextures();
|
||||
if (_hasTransparentTextures != hasTransparentTextures) {
|
||||
_hasTransparentTextures = hasTransparentTextures;
|
||||
return true;
|
||||
}
|
||||
if (_needsUpdateTextures && _geometry->getGeometry()->areTexturesLoaded()) {
|
||||
_needsUpdateTextures = false;
|
||||
return true;
|
||||
}
|
||||
if (!_readyWhenAdded) {
|
||||
return true;
|
||||
|
@ -546,43 +541,6 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scen
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges, bool showCollisionHull) {
|
||||
|
||||
if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) {
|
||||
_showCollisionHull = showCollisionHull;
|
||||
segregateMeshGroups();
|
||||
}
|
||||
|
||||
bool somethingAdded = false;
|
||||
|
||||
foreach (auto renderItem, _modelMeshRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<ModelMeshPartPayload>(item, [](ModelMeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
_modelMeshRenderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
}
|
||||
|
||||
foreach (auto renderItem, _collisionRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<MeshPartPayload>(item, [](MeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
_collisionRenderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
}
|
||||
|
||||
_readyWhenAdded = readyToAddToScene();
|
||||
|
||||
return somethingAdded;
|
||||
}
|
||||
|
||||
bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges,
|
||||
render::Item::Status::Getters& statusGetters,
|
||||
|
@ -594,28 +552,48 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
|||
|
||||
bool somethingAdded = false;
|
||||
|
||||
foreach (auto renderItem, _modelMeshRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<ModelMeshPartPayload>(item, [](ModelMeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
_modelMeshRenderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
if (_modelMeshRenderItems.size()) {
|
||||
for (auto item : _modelMeshRenderItems.keys()) {
|
||||
pendingChanges.updateItem<ModelMeshPartPayload>(item, [](ModelMeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (auto renderItem : _modelMeshRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
if (statusGetters.size()) {
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
}
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<ModelMeshPartPayload>(item, [](ModelMeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
_modelMeshRenderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (auto renderItem, _collisionRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<MeshPartPayload>(item, [](MeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
_collisionRenderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
if (_collisionRenderItems.size()) {
|
||||
for (auto item : _collisionRenderItems.keys()) {
|
||||
pendingChanges.updateItem<MeshPartPayload>(item, [](MeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (auto renderItem : _collisionRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||
if (statusGetters.size()) {
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
}
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<MeshPartPayload>(item, [](MeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
_collisionRenderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
_readyWhenAdded = readyToAddToScene();
|
||||
|
@ -791,6 +769,13 @@ int Model::getLastFreeJointIndex(int jointIndex) const {
|
|||
return (isActive() && jointIndex != -1) ? getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1;
|
||||
}
|
||||
|
||||
void Model::setTextures(const QVariantMap& textures) {
|
||||
if (isLoaded()) {
|
||||
_needsUpdateTextures = true;
|
||||
_geometry->getGeometry()->setTextures(textures);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::setURL(const QUrl& url) {
|
||||
// don't recreate the geometry if it's the same URL
|
||||
if (_url == url && _geometry && _geometry->getURL() == url) {
|
||||
|
@ -807,8 +792,7 @@ void Model::setURL(const QUrl& url) {
|
|||
}
|
||||
|
||||
_needsReload = true;
|
||||
_needsUpdateTransparentTextures = true;
|
||||
_hasTransparentTextures = false;
|
||||
_needsUpdateTextures = true;
|
||||
_meshGroupsKnown = false;
|
||||
invalidCalculatedMeshBoxes();
|
||||
deleteGeometry();
|
||||
|
|
|
@ -87,7 +87,10 @@ public:
|
|||
bool initWhenReady(render::ScenePointer scene);
|
||||
bool addToScene(std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges,
|
||||
bool showCollisionHull = false);
|
||||
bool showCollisionHull = false) {
|
||||
auto getters = render::Item::Status::Getters(0);
|
||||
return addToScene(scene, pendingChanges, getters, showCollisionHull);
|
||||
}
|
||||
bool addToScene(std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges,
|
||||
render::Item::Status::Getters& statusGetters,
|
||||
|
@ -129,6 +132,9 @@ public:
|
|||
/// Returns a reference to the shared collision geometry.
|
||||
const NetworkGeometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
|
||||
|
||||
const QVariantMap getTextures() const { assert(isLoaded()); return _geometry->getGeometry()->getTextures(); }
|
||||
void setTextures(const QVariantMap& textures);
|
||||
|
||||
/// Provided as a convenience, will crash if !isLoaded()
|
||||
// And so that getGeometry() isn't chained everywhere
|
||||
const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return getGeometry()->getGeometry()->getGeometry(); }
|
||||
|
@ -385,9 +391,8 @@ protected:
|
|||
bool _readyWhenAdded { false };
|
||||
bool _needsReload { true };
|
||||
bool _needsUpdateClusterMatrices { true };
|
||||
mutable bool _needsUpdateTransparentTextures { true };
|
||||
mutable bool _hasTransparentTextures { false };
|
||||
bool _showCollisionHull { false };
|
||||
mutable bool _needsUpdateTextures { true };
|
||||
|
||||
friend class ModelMeshPartPayload;
|
||||
RigPointer _rig;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <NetworkAccessManager.h>
|
||||
#include <SharedUtil.h>
|
||||
#include "ResourceManager.h"
|
||||
#include "ScriptEngines.h"
|
||||
|
||||
BatchLoader::BatchLoader(const QList<QUrl>& urls)
|
||||
: QObject(),
|
||||
|
@ -34,8 +35,9 @@ void BatchLoader::start() {
|
|||
}
|
||||
|
||||
_started = true;
|
||||
|
||||
for (const auto& url : _urls) {
|
||||
|
||||
for (const auto& rawURL : _urls) {
|
||||
QUrl url = expandScriptUrl(normalizeScriptURL(rawURL));
|
||||
auto request = ResourceManager::createResourceRequest(this, url);
|
||||
if (!request) {
|
||||
_data.insert(url, QString());
|
||||
|
|
|
@ -220,11 +220,10 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
|
|||
return;
|
||||
}
|
||||
|
||||
_fileNameString = scriptURL.toString();
|
||||
QUrl url = expandScriptUrl(scriptURL);
|
||||
_fileNameString = url.toString();
|
||||
_isReloading = reload;
|
||||
|
||||
QUrl url(scriptURL);
|
||||
|
||||
bool isPending;
|
||||
auto scriptCache = DependencyManager::get<ScriptCache>();
|
||||
scriptCache->getScript(url, this, isPending, reload);
|
||||
|
@ -848,7 +847,7 @@ QUrl ScriptEngine::resolvePath(const QString& include) const {
|
|||
QUrl url(include);
|
||||
// first lets check to see if it's already a full URL
|
||||
if (!url.scheme().isEmpty()) {
|
||||
return url;
|
||||
return expandScriptUrl(url);
|
||||
}
|
||||
|
||||
// we apparently weren't a fully qualified url, so, let's assume we're relative
|
||||
|
@ -865,7 +864,7 @@ QUrl ScriptEngine::resolvePath(const QString& include) const {
|
|||
}
|
||||
|
||||
// at this point we should have a legitimate fully qualified URL for our parent
|
||||
url = parentURL.resolved(url);
|
||||
url = expandScriptUrl(parentURL.resolved(url));
|
||||
return url;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,13 +47,6 @@ QUrl normalizeScriptURL(const QUrl& rawScriptURL) {
|
|||
QUrl fullNormal = rawScriptURL;
|
||||
QUrl defaultScriptLoc = defaultScriptsLocation();
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#else
|
||||
// Force lowercase on file scripts because of drive letter weirdness.
|
||||
if (rawScriptURL.isLocalFile()) {
|
||||
fullNormal.setPath(fullNormal.path().toLower());
|
||||
}
|
||||
#endif
|
||||
// if this url is something "beneath" the default script url, replace the local path with ~
|
||||
if (fullNormal.scheme() == defaultScriptLoc.scheme() &&
|
||||
fullNormal.host() == defaultScriptLoc.host() &&
|
||||
|
@ -69,7 +62,8 @@ QUrl normalizeScriptURL(const QUrl& rawScriptURL) {
|
|||
}
|
||||
}
|
||||
|
||||
QUrl expandScriptUrl(const QUrl& normalizedScriptURL) {
|
||||
QUrl expandScriptUrl(const QUrl& rawScriptURL) {
|
||||
QUrl normalizedScriptURL = normalizeScriptURL(rawScriptURL);
|
||||
if (normalizedScriptURL.scheme() == "http" ||
|
||||
normalizedScriptURL.scheme() == "https" ||
|
||||
normalizedScriptURL.scheme() == "atp") {
|
||||
|
@ -230,7 +224,7 @@ QVariantList ScriptEngines::getRunning() {
|
|||
}
|
||||
QVariantMap resultNode;
|
||||
resultNode.insert("name", runningScriptURL.fileName());
|
||||
QUrl displayURL = expandScriptUrl(QUrl(runningScriptURL));
|
||||
QUrl displayURL = expandScriptUrl(runningScriptURL);
|
||||
QString displayURLString;
|
||||
if (displayURL.isLocalFile()) {
|
||||
displayURLString = displayURL.toLocalFile();
|
||||
|
@ -251,7 +245,7 @@ static const QString SETTINGS_KEY = "Settings";
|
|||
|
||||
void ScriptEngines::loadDefaultScripts() {
|
||||
QUrl defaultScriptsLoc = defaultScriptsLocation();
|
||||
defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "/scripts/defaultScripts.js");
|
||||
defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "/defaultScripts.js");
|
||||
loadScript(defaultScriptsLoc.toString());
|
||||
}
|
||||
|
||||
|
@ -268,7 +262,7 @@ void ScriptEngines::loadScripts() {
|
|||
loadDefaultScripts();
|
||||
_firstRun.set(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// loads all saved scripts
|
||||
Settings settings;
|
||||
|
@ -310,7 +304,12 @@ void ScriptEngines::saveScripts() {
|
|||
|
||||
QStringList ScriptEngines::getRunningScripts() {
|
||||
QReadLocker lock(&_scriptEnginesHashLock);
|
||||
return _scriptEnginesHash.keys();
|
||||
QList<QUrl> urls = _scriptEnginesHash.keys();
|
||||
QStringList result;
|
||||
for (auto url : urls) {
|
||||
result.append(url.toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ScriptEngines::stopAllScripts(bool restart) {
|
||||
|
@ -318,7 +317,7 @@ void ScriptEngines::stopAllScripts(bool restart) {
|
|||
if (restart) {
|
||||
// Delete all running scripts from cache so that they are re-downloaded when they are restarted
|
||||
auto scriptCache = DependencyManager::get<ScriptCache>();
|
||||
for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
|
||||
for (QHash<QUrl, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
|
||||
it != _scriptEnginesHash.constEnd(); it++) {
|
||||
if (!it.value()->isFinished()) {
|
||||
scriptCache->deleteScript(it.key());
|
||||
|
@ -327,7 +326,7 @@ void ScriptEngines::stopAllScripts(bool restart) {
|
|||
}
|
||||
|
||||
// Stop and possibly restart all currently running scripts
|
||||
for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
|
||||
for (QHash<QUrl, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
|
||||
it != _scriptEnginesHash.constEnd(); it++) {
|
||||
if (it.value()->isFinished()) {
|
||||
continue;
|
||||
|
@ -350,21 +349,20 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) {
|
|||
if (!scriptURL.isValid()) {
|
||||
scriptURL = normalizeScriptURL(QUrl::fromLocalFile(rawScriptURL));
|
||||
}
|
||||
const QString scriptURLString = scriptURL.toString();
|
||||
|
||||
QReadLocker lock(&_scriptEnginesHashLock);
|
||||
if (_scriptEnginesHash.contains(scriptURLString)) {
|
||||
ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURLString];
|
||||
if (_scriptEnginesHash.contains(scriptURL)) {
|
||||
ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURL];
|
||||
if (restart) {
|
||||
auto scriptCache = DependencyManager::get<ScriptCache>();
|
||||
scriptCache->deleteScript(QUrl(scriptURLString));
|
||||
scriptCache->deleteScript(scriptURL);
|
||||
connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) {
|
||||
reloadScript(scriptName);
|
||||
});
|
||||
}
|
||||
scriptEngine->stop();
|
||||
stoppedScript = true;
|
||||
qCDebug(scriptengine) << "stopping script..." << scriptURLString;
|
||||
qCDebug(scriptengine) << "stopping script..." << scriptURL;
|
||||
}
|
||||
}
|
||||
return stoppedScript;
|
||||
|
@ -379,7 +377,7 @@ void ScriptEngines::setScriptsLocation(const QString& scriptsLocation) {
|
|||
_scriptsModel.updateScriptsLocation(scriptsLocation);
|
||||
}
|
||||
|
||||
void ScriptEngines::reloadAllScripts() {
|
||||
void ScriptEngines::reloadAllScripts() {
|
||||
DependencyManager::get<ScriptCache>()->clearCache();
|
||||
emit scriptsReloading();
|
||||
stopAllScripts(true);
|
||||
|
@ -409,7 +407,7 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL
|
|||
scriptUrl = normalizeScriptURL(scriptFilename);
|
||||
}
|
||||
|
||||
auto scriptEngine = getScriptEngine(scriptUrl.toString());
|
||||
auto scriptEngine = getScriptEngine(scriptUrl);
|
||||
if (scriptEngine) {
|
||||
return scriptEngine;
|
||||
}
|
||||
|
@ -429,18 +427,18 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL
|
|||
connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError);
|
||||
|
||||
// get the script engine object to load the script at the designated script URL
|
||||
scriptEngine->loadURL(QUrl(expandScriptUrl(scriptUrl.toString())), reload);
|
||||
scriptEngine->loadURL(scriptUrl, reload);
|
||||
}
|
||||
|
||||
return scriptEngine;
|
||||
}
|
||||
|
||||
ScriptEngine* ScriptEngines::getScriptEngine(const QString& rawScriptURL) {
|
||||
ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) {
|
||||
ScriptEngine* result = nullptr;
|
||||
{
|
||||
QReadLocker lock(&_scriptEnginesHashLock);
|
||||
const QString scriptURLString = normalizeScriptURL(QUrl(rawScriptURL)).toString();
|
||||
auto it = _scriptEnginesHash.find(scriptURLString);
|
||||
const QUrl scriptURL = normalizeScriptURL(rawScriptURL);
|
||||
auto it = _scriptEnginesHash.find(scriptURL);
|
||||
if (it != _scriptEnginesHash.end()) {
|
||||
result = it.value();
|
||||
}
|
||||
|
@ -459,8 +457,7 @@ void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) {
|
|||
QWriteLocker lock(&_scriptEnginesHashLock);
|
||||
QUrl url = QUrl(rawScriptURL);
|
||||
QUrl normalized = normalizeScriptURL(url);
|
||||
const QString scriptURLString = normalized.toString();
|
||||
_scriptEnginesHash.insertMulti(scriptURLString, scriptEngine);
|
||||
_scriptEnginesHash.insertMulti(normalized, scriptEngine);
|
||||
}
|
||||
emit scriptCountChanged();
|
||||
}
|
||||
|
@ -486,8 +483,8 @@ void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine*
|
|||
bool removed = false;
|
||||
{
|
||||
QWriteLocker lock(&_scriptEnginesHashLock);
|
||||
const QString scriptURLString = normalizeScriptURL(QUrl(rawScriptURL)).toString();
|
||||
for (auto it = _scriptEnginesHash.find(scriptURLString); it != _scriptEnginesHash.end(); ++it) {
|
||||
const QUrl scriptURL = normalizeScriptURL(QUrl(rawScriptURL));
|
||||
for (auto it = _scriptEnginesHash.find(scriptURL); it != _scriptEnginesHash.end(); ++it) {
|
||||
if (it.value() == engine) {
|
||||
_scriptEnginesHash.erase(it);
|
||||
removed = true;
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
void loadDefaultScripts();
|
||||
void setScriptsLocation(const QString& scriptsLocation);
|
||||
QStringList getRunningScripts();
|
||||
ScriptEngine* getScriptEngine(const QString& scriptHash);
|
||||
ScriptEngine* getScriptEngine(const QUrl& scriptHash);
|
||||
|
||||
ScriptsModel* scriptsModel() { return &_scriptsModel; };
|
||||
ScriptsModelFilter* scriptsModelFilter() { return &_scriptsModelFilter; };
|
||||
|
@ -65,12 +65,12 @@ public:
|
|||
// Called at shutdown time
|
||||
void shutdownScripting();
|
||||
|
||||
signals:
|
||||
signals:
|
||||
void scriptCountChanged();
|
||||
void scriptsReloading();
|
||||
void scriptLoadError(const QString& filename, const QString& error);
|
||||
|
||||
protected slots:
|
||||
protected slots:
|
||||
void onScriptFinished(const QString& fileNameString, ScriptEngine* engine);
|
||||
|
||||
protected:
|
||||
|
@ -86,7 +86,7 @@ protected:
|
|||
|
||||
Setting::Handle<bool> _firstRun { "firstRun", true };
|
||||
QReadWriteLock _scriptEnginesHashLock;
|
||||
QHash<QString, ScriptEngine*> _scriptEnginesHash;
|
||||
QHash<QUrl, ScriptEngine*> _scriptEnginesHash;
|
||||
QSet<ScriptEngine*> _allKnownScriptEngines;
|
||||
QMutex _allScriptsMutex;
|
||||
std::atomic<bool> _stoppingAllScripts { false };
|
||||
|
@ -97,6 +97,6 @@ protected:
|
|||
};
|
||||
|
||||
QUrl normalizeScriptURL(const QUrl& rawScriptURL);
|
||||
QUrl expandScriptUrl(const QUrl& normalizedScriptURL);
|
||||
QUrl expandScriptUrl(const QUrl& rawScriptURL);
|
||||
|
||||
#endif // hifi_ScriptEngine_h
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#define __STR1__(x) __STR2__(x)
|
||||
#define __LOC__ __FILE__ "(" __STR1__(__LINE__) ") : Warning Msg: "
|
||||
|
||||
static const QString MODELS_LOCATION = "scripts/";
|
||||
static const QString PREFIX_PARAMETER_NAME = "prefix";
|
||||
static const QString MARKER_PARAMETER_NAME = "marker";
|
||||
static const QString IS_TRUNCATED_NAME = "IsTruncated";
|
||||
|
@ -41,7 +40,7 @@ TreeNodeBase::TreeNodeBase(TreeNodeFolder* parent, const QString& name, TreeNode
|
|||
TreeNodeScript::TreeNodeScript(const QString& localPath, const QString& fullPath, ScriptOrigin origin) :
|
||||
TreeNodeBase(NULL, localPath.split("/").last(), TREE_NODE_TYPE_SCRIPT),
|
||||
_localPath(localPath),
|
||||
_fullPath(fullPath),
|
||||
_fullPath(expandScriptUrl(QUrl(fullPath)).toString()),
|
||||
_origin(origin) {
|
||||
};
|
||||
|
||||
|
@ -159,9 +158,11 @@ void ScriptsModel::requestDefaultFiles(QString marker) {
|
|||
|
||||
if (url.isLocalFile()) {
|
||||
// if the url indicates a local directory, use QDirIterator
|
||||
// QString localDir = url.toLocalFile() + "/scripts";
|
||||
QString localDir = expandScriptUrl(url).toLocalFile() + "/scripts";
|
||||
QString localDir = expandScriptUrl(url).toLocalFile();
|
||||
int localDirPartCount = localDir.split("/").size();
|
||||
if (localDir.endsWith("/")) {
|
||||
localDirPartCount--;
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
localDirPartCount++; // one for the drive letter
|
||||
#endif
|
||||
|
@ -176,7 +177,7 @@ void ScriptsModel::requestDefaultFiles(QString marker) {
|
|||
} else {
|
||||
// the url indicates http(s), use QNetworkRequest
|
||||
QUrlQuery query;
|
||||
query.addQueryItem(PREFIX_PARAMETER_NAME, MODELS_LOCATION);
|
||||
query.addQueryItem(PREFIX_PARAMETER_NAME, ".");
|
||||
if (!marker.isEmpty()) {
|
||||
query.addQueryItem(MARKER_PARAMETER_NAME, marker);
|
||||
}
|
||||
|
@ -240,7 +241,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) {
|
|||
if (jsRegex.exactMatch(xml.text().toString())) {
|
||||
QString localPath = lastKey.split("/").mid(1).join("/");
|
||||
QUrl fullPath = defaultScriptsLocation();
|
||||
fullPath.setPath(fullPath.path() + "/" + lastKey);
|
||||
fullPath.setPath(fullPath.path() + lastKey);
|
||||
const QString fullPathStr = normalizeScriptURL(fullPath).toString();
|
||||
_treeNodes.append(new TreeNodeScript(localPath, fullPathStr, SCRIPT_ORIGIN_DEFAULT));
|
||||
}
|
||||
|
@ -309,6 +310,9 @@ void ScriptsModel::rebuildTree() {
|
|||
QString hash;
|
||||
QStringList pathList = script->getLocalPath().split(tr("/"));
|
||||
pathList.removeLast();
|
||||
if (pathList.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
QStringList::const_iterator pathIterator;
|
||||
for (pathIterator = pathList.constBegin(); pathIterator != pathList.constEnd(); ++pathIterator) {
|
||||
hash.append(*pathIterator + "/");
|
||||
|
|
75
libraries/shared/src/CPUID.cpp
Normal file
75
libraries/shared/src/CPUID.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// CPUID.cpp
|
||||
//
|
||||
// Created by Ryan Huffman on 3/25/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "CPUID.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
const CPUID::CPUID_Internal CPUID::CPU_Rep;
|
||||
|
||||
std::vector<CPUID::Feature> CPUID::getAllFeatures() {
|
||||
std::vector<CPUID::Feature> features;
|
||||
|
||||
features.push_back({ "3DNOW", CPUID::_3DNOW() });
|
||||
features.push_back({ "3DNOWEXT", CPUID::_3DNOWEXT() });
|
||||
features.push_back({ "ABM", CPUID::ABM() });
|
||||
features.push_back({ "ADX", CPUID::ADX() });
|
||||
features.push_back({ "AES", CPUID::AES() });
|
||||
features.push_back({ "AVX", CPUID::AVX() });
|
||||
features.push_back({ "AVX2", CPUID::AVX2() });
|
||||
features.push_back({ "AVX512CD", CPUID::AVX512CD() });
|
||||
features.push_back({ "AVX512ER", CPUID::AVX512ER() });
|
||||
features.push_back({ "AVX512F", CPUID::AVX512F() });
|
||||
features.push_back({ "AVX512PF", CPUID::AVX512PF() });
|
||||
features.push_back({ "BMI1", CPUID::BMI1() });
|
||||
features.push_back({ "BMI2", CPUID::BMI2() });
|
||||
features.push_back({ "CLFSH", CPUID::CLFSH() });
|
||||
features.push_back({ "CMPXCHG16B", CPUID::CMPXCHG16B() });
|
||||
features.push_back({ "CX8", CPUID::CX8() });
|
||||
features.push_back({ "ERMS", CPUID::ERMS() });
|
||||
features.push_back({ "F16C", CPUID::F16C() });
|
||||
features.push_back({ "FMA", CPUID::FMA() });
|
||||
features.push_back({ "FSGSBASE", CPUID::FSGSBASE() });
|
||||
features.push_back({ "FXSR", CPUID::FXSR() });
|
||||
features.push_back({ "HLE", CPUID::HLE() });
|
||||
features.push_back({ "INVPCID", CPUID::INVPCID() });
|
||||
features.push_back({ "LAHF", CPUID::LAHF() });
|
||||
features.push_back({ "LZCNT", CPUID::LZCNT() });
|
||||
features.push_back({ "MMX", CPUID::MMX() });
|
||||
features.push_back({ "MMXEXT", CPUID::MMXEXT() });
|
||||
features.push_back({ "MONITOR", CPUID::MONITOR() });
|
||||
features.push_back({ "MOVBE", CPUID::MOVBE() });
|
||||
features.push_back({ "MSR", CPUID::MSR() });
|
||||
features.push_back({ "OSXSAVE", CPUID::OSXSAVE() });
|
||||
features.push_back({ "PCLMULQDQ", CPUID::PCLMULQDQ() });
|
||||
features.push_back({ "POPCNT", CPUID::POPCNT() });
|
||||
features.push_back({ "PREFETCHWT1", CPUID::PREFETCHWT1() });
|
||||
features.push_back({ "RDRAND", CPUID::RDRAND() });
|
||||
features.push_back({ "RDSEED", CPUID::RDSEED() });
|
||||
features.push_back({ "RDTSCP", CPUID::RDTSCP() });
|
||||
features.push_back({ "RTM", CPUID::RTM() });
|
||||
features.push_back({ "SEP", CPUID::SEP() });
|
||||
features.push_back({ "SHA", CPUID::SHA() });
|
||||
features.push_back({ "SSE", CPUID::SSE() });
|
||||
features.push_back({ "SSE2", CPUID::SSE2() });
|
||||
features.push_back({ "SSE3", CPUID::SSE3() });
|
||||
features.push_back({ "SSE4.1", CPUID::SSE41() });
|
||||
features.push_back({ "SSE4.2", CPUID::SSE42() });
|
||||
features.push_back({ "SSE4a", CPUID::SSE4a() });
|
||||
features.push_back({ "SSSE3", CPUID::SSSE3() });
|
||||
features.push_back({ "SYSCALL", CPUID::SYSCALL() });
|
||||
features.push_back({ "TBM", CPUID::TBM() });
|
||||
features.push_back({ "XOP", CPUID::XOP() });
|
||||
features.push_back({ "XSAVE", CPUID::XSAVE() });
|
||||
|
||||
return features;
|
||||
};
|
||||
|
||||
#endif
|
212
libraries/shared/src/CPUID.h
Normal file
212
libraries/shared/src/CPUID.h
Normal file
|
@ -0,0 +1,212 @@
|
|||
//
|
||||
// CPUID.h
|
||||
//
|
||||
// Adapted from Microsoft's example for using the cpuid intrinsic,
|
||||
// found at https://msdn.microsoft.com/en-us/library/hskdteyh.aspx
|
||||
//
|
||||
// Provides acccess to information provided by the CPUID opcode
|
||||
//
|
||||
// TODO: Generalize to work outside of Windows.
|
||||
//
|
||||
// Created by Ryan Huffman on 3/25/16.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_CPUID_h
|
||||
#define hifi_CPUID_h
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
class CPUID
|
||||
{
|
||||
// forward declarations
|
||||
class CPUID_Internal;
|
||||
|
||||
public:
|
||||
struct Feature {
|
||||
std::string name;
|
||||
bool supported;
|
||||
};
|
||||
|
||||
static std::vector<Feature> getAllFeatures();
|
||||
|
||||
static std::string Vendor(void) { return CPU_Rep.vendor_; }
|
||||
static std::string Brand(void) { return CPU_Rep.brand_; }
|
||||
|
||||
static bool SSE3(void) { return CPU_Rep.f_1_ECX_[0]; }
|
||||
static bool PCLMULQDQ(void) { return CPU_Rep.f_1_ECX_[1]; }
|
||||
static bool MONITOR(void) { return CPU_Rep.f_1_ECX_[3]; }
|
||||
static bool SSSE3(void) { return CPU_Rep.f_1_ECX_[9]; }
|
||||
static bool FMA(void) { return CPU_Rep.f_1_ECX_[12]; }
|
||||
static bool CMPXCHG16B(void) { return CPU_Rep.f_1_ECX_[13]; }
|
||||
static bool SSE41(void) { return CPU_Rep.f_1_ECX_[19]; }
|
||||
static bool SSE42(void) { return CPU_Rep.f_1_ECX_[20]; }
|
||||
static bool MOVBE(void) { return CPU_Rep.f_1_ECX_[22]; }
|
||||
static bool POPCNT(void) { return CPU_Rep.f_1_ECX_[23]; }
|
||||
static bool AES(void) { return CPU_Rep.f_1_ECX_[25]; }
|
||||
static bool XSAVE(void) { return CPU_Rep.f_1_ECX_[26]; }
|
||||
static bool OSXSAVE(void) { return CPU_Rep.f_1_ECX_[27]; }
|
||||
static bool AVX(void) { return CPU_Rep.f_1_ECX_[28]; }
|
||||
static bool F16C(void) { return CPU_Rep.f_1_ECX_[29]; }
|
||||
static bool RDRAND(void) { return CPU_Rep.f_1_ECX_[30]; }
|
||||
|
||||
static bool MSR(void) { return CPU_Rep.f_1_EDX_[5]; }
|
||||
static bool CX8(void) { return CPU_Rep.f_1_EDX_[8]; }
|
||||
static bool SEP(void) { return CPU_Rep.f_1_EDX_[11]; }
|
||||
static bool CMOV(void) { return CPU_Rep.f_1_EDX_[15]; }
|
||||
static bool CLFSH(void) { return CPU_Rep.f_1_EDX_[19]; }
|
||||
static bool MMX(void) { return CPU_Rep.f_1_EDX_[23]; }
|
||||
static bool FXSR(void) { return CPU_Rep.f_1_EDX_[24]; }
|
||||
static bool SSE(void) { return CPU_Rep.f_1_EDX_[25]; }
|
||||
static bool SSE2(void) { return CPU_Rep.f_1_EDX_[26]; }
|
||||
|
||||
static bool FSGSBASE(void) { return CPU_Rep.f_7_EBX_[0]; }
|
||||
static bool BMI1(void) { return CPU_Rep.f_7_EBX_[3]; }
|
||||
static bool HLE(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[4]; }
|
||||
static bool AVX2(void) { return CPU_Rep.f_7_EBX_[5]; }
|
||||
static bool BMI2(void) { return CPU_Rep.f_7_EBX_[8]; }
|
||||
static bool ERMS(void) { return CPU_Rep.f_7_EBX_[9]; }
|
||||
static bool INVPCID(void) { return CPU_Rep.f_7_EBX_[10]; }
|
||||
static bool RTM(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[11]; }
|
||||
static bool AVX512F(void) { return CPU_Rep.f_7_EBX_[16]; }
|
||||
static bool RDSEED(void) { return CPU_Rep.f_7_EBX_[18]; }
|
||||
static bool ADX(void) { return CPU_Rep.f_7_EBX_[19]; }
|
||||
static bool AVX512PF(void) { return CPU_Rep.f_7_EBX_[26]; }
|
||||
static bool AVX512ER(void) { return CPU_Rep.f_7_EBX_[27]; }
|
||||
static bool AVX512CD(void) { return CPU_Rep.f_7_EBX_[28]; }
|
||||
static bool SHA(void) { return CPU_Rep.f_7_EBX_[29]; }
|
||||
|
||||
static bool PREFETCHWT1(void) { return CPU_Rep.f_7_ECX_[0]; }
|
||||
|
||||
static bool LAHF(void) { return CPU_Rep.f_81_ECX_[0]; }
|
||||
static bool LZCNT(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_ECX_[5]; }
|
||||
static bool ABM(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[5]; }
|
||||
static bool SSE4a(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[6]; }
|
||||
static bool XOP(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[11]; }
|
||||
static bool TBM(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[21]; }
|
||||
|
||||
static bool SYSCALL(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[11]; }
|
||||
static bool MMXEXT(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[22]; }
|
||||
static bool RDTSCP(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[27]; }
|
||||
static bool _3DNOWEXT(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[30]; }
|
||||
static bool _3DNOW(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[31]; }
|
||||
|
||||
private:
|
||||
static const CPUID_Internal CPU_Rep;
|
||||
|
||||
class CPUID_Internal
|
||||
{
|
||||
public:
|
||||
CPUID_Internal()
|
||||
: nIds_ { 0 },
|
||||
nExIds_ { 0 },
|
||||
isIntel_ { false },
|
||||
isAMD_ { false },
|
||||
f_1_ECX_ { 0 },
|
||||
f_1_EDX_ { 0 },
|
||||
f_7_EBX_ { 0 },
|
||||
f_7_ECX_ { 0 },
|
||||
f_81_ECX_ { 0 },
|
||||
f_81_EDX_ { 0 },
|
||||
data_ {},
|
||||
extdata_ {}
|
||||
{
|
||||
//int cpuInfo[4] = {-1};
|
||||
std::array<int, 4> cpui;
|
||||
|
||||
// Calling __cpuid with 0x0 as the function_id argument
|
||||
// gets the number of the highest valid function ID.
|
||||
__cpuid(cpui.data(), 0);
|
||||
nIds_ = cpui[0];
|
||||
|
||||
for (int i = 0; i <= nIds_; ++i) {
|
||||
__cpuidex(cpui.data(), i, 0);
|
||||
data_.push_back(cpui);
|
||||
}
|
||||
|
||||
// Capture vendor string
|
||||
char vendor[0x20];
|
||||
memset(vendor, 0, sizeof(vendor));
|
||||
*reinterpret_cast<int*>(vendor) = data_[0][1];
|
||||
*reinterpret_cast<int*>(vendor + 4) = data_[0][3];
|
||||
*reinterpret_cast<int*>(vendor + 8) = data_[0][2];
|
||||
vendor_ = vendor;
|
||||
if (vendor_ == "GenuineIntel") {
|
||||
isIntel_ = true;
|
||||
} else if (vendor_ == "AuthenticAMD") {
|
||||
isAMD_ = true;
|
||||
}
|
||||
|
||||
// load bitset with flags for function 0x00000001
|
||||
if (nIds_ >= 1) {
|
||||
f_1_ECX_ = data_[1][2];
|
||||
f_1_EDX_ = data_[1][3];
|
||||
}
|
||||
|
||||
// load bitset with flags for function 0x00000007
|
||||
if (nIds_ >= 7) {
|
||||
f_7_EBX_ = data_[7][1];
|
||||
f_7_ECX_ = data_[7][2];
|
||||
}
|
||||
|
||||
// Calling __cpuid with 0x80000000 as the function_id argument
|
||||
// gets the number of the highest valid extended ID.
|
||||
__cpuid(cpui.data(), 0x80000000);
|
||||
nExIds_ = cpui[0];
|
||||
|
||||
char brand[0x40];
|
||||
memset(brand, 0, sizeof(brand));
|
||||
|
||||
for (int i = 0x80000000; i <= nExIds_; ++i) {
|
||||
__cpuidex(cpui.data(), i, 0);
|
||||
extdata_.push_back(cpui);
|
||||
}
|
||||
|
||||
// load bitset with flags for function 0x80000001
|
||||
if (nExIds_ >= 0x80000001) {
|
||||
f_81_ECX_ = extdata_[1][2];
|
||||
f_81_EDX_ = extdata_[1][3];
|
||||
}
|
||||
|
||||
// Interpret CPU brand string if reported
|
||||
if (nExIds_ >= 0x80000004) {
|
||||
memcpy(brand, extdata_[2].data(), sizeof(cpui));
|
||||
memcpy(brand + 16, extdata_[3].data(), sizeof(cpui));
|
||||
memcpy(brand + 32, extdata_[4].data(), sizeof(cpui));
|
||||
brand_ = brand;
|
||||
}
|
||||
};
|
||||
|
||||
int nIds_;
|
||||
int nExIds_;
|
||||
std::string vendor_;
|
||||
std::string brand_;
|
||||
bool isIntel_;
|
||||
bool isAMD_;
|
||||
std::bitset<32> f_1_ECX_;
|
||||
std::bitset<32> f_1_EDX_;
|
||||
std::bitset<32> f_7_EBX_;
|
||||
std::bitset<32> f_7_ECX_;
|
||||
std::bitset<32> f_81_ECX_;
|
||||
std::bitset<32> f_81_EDX_;
|
||||
std::vector<std::array<int, 4>> data_;
|
||||
std::vector<std::array<int, 4>> extdata_;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // hifi_CPUID_h
|
|
@ -57,11 +57,11 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector<QSt
|
|||
|
||||
QUrl defaultScriptsLocation() {
|
||||
#ifdef Q_OS_WIN
|
||||
return QUrl(("file:///" + QCoreApplication::applicationDirPath()).toLower());
|
||||
return QUrl(("file:///" + QCoreApplication::applicationDirPath()).toLower() + "/scripts");
|
||||
#elif defined(Q_OS_OSX)
|
||||
return QUrl(("file://" + QCoreApplication::applicationDirPath() + "/../Resources").toLower());
|
||||
return QUrl(("file://" + QCoreApplication::applicationDirPath() + "/../Resources/scripts").toLower());
|
||||
#else
|
||||
// return "http://s3.amazonaws.com/hifi-public";
|
||||
return QUrl("file://" + QCoreApplication::applicationDirPath());
|
||||
return QUrl("file://" + QCoreApplication::applicationDirPath() + "/scripts");
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -23,6 +23,11 @@
|
|||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "CPUID.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
@ -30,6 +35,8 @@
|
|||
#include <QtCore/QDebug>
|
||||
#include <QDateTime>
|
||||
#include <QElapsedTimer>
|
||||
#include <QProcess>
|
||||
#include <QSysInfo>
|
||||
#include <QThread>
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
|
@ -692,3 +699,82 @@ void disableQtBearerPoll() {
|
|||
qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
|
||||
}
|
||||
|
||||
void printSystemInformation() {
|
||||
// Write system information to log
|
||||
qDebug() << "Build Information";
|
||||
qDebug().noquote() << "\tBuild ABI: " << QSysInfo::buildAbi();
|
||||
qDebug().noquote() << "\tBuild CPU Architecture: " << QSysInfo::buildCpuArchitecture();
|
||||
|
||||
qDebug().noquote() << "System Information";
|
||||
qDebug().noquote() << "\tProduct Name: " << QSysInfo::prettyProductName();
|
||||
qDebug().noquote() << "\tCPU Architecture: " << QSysInfo::currentCpuArchitecture();
|
||||
qDebug().noquote() << "\tKernel Type: " << QSysInfo::kernelType();
|
||||
qDebug().noquote() << "\tKernel Version: " << QSysInfo::kernelVersion();
|
||||
|
||||
auto macVersion = QSysInfo::macVersion();
|
||||
if (macVersion != QSysInfo::MV_None) {
|
||||
qDebug() << "\tMac Version: " << macVersion;
|
||||
}
|
||||
|
||||
auto windowsVersion = QSysInfo::windowsVersion();
|
||||
if (windowsVersion != QSysInfo::WV_None) {
|
||||
qDebug() << "\tWindows Version: " << windowsVersion;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
SYSTEM_INFO si;
|
||||
GetNativeSystemInfo(&si);
|
||||
|
||||
qDebug() << "SYSTEM_INFO";
|
||||
qDebug().noquote() << "\tOEM ID: " << si.dwOemId;
|
||||
qDebug().noquote() << "\tProcessor Architecture: " << si.wProcessorArchitecture;
|
||||
qDebug().noquote() << "\tProcessor Type: " << si.dwProcessorType;
|
||||
qDebug().noquote() << "\tProcessor Level: " << si.wProcessorLevel;
|
||||
qDebug().noquote() << "\tProcessor Revision: "
|
||||
<< QString("0x%1").arg(si.wProcessorRevision, 4, 16, QChar('0'));
|
||||
qDebug().noquote() << "\tNumber of Processors: " << si.dwNumberOfProcessors;
|
||||
qDebug().noquote() << "\tPage size: " << si.dwPageSize << " Bytes";
|
||||
qDebug().noquote() << "\tMin Application Address: "
|
||||
<< QString("0x%1").arg(qulonglong(si.lpMinimumApplicationAddress), 16, 16, QChar('0'));
|
||||
qDebug().noquote() << "\tMax Application Address: "
|
||||
<< QString("0x%1").arg(qulonglong(si.lpMaximumApplicationAddress), 16, 16, QChar('0'));
|
||||
|
||||
const double BYTES_TO_MEGABYTE = 1.0 / (1024 * 1024);
|
||||
|
||||
qDebug() << "MEMORYSTATUSEX";
|
||||
MEMORYSTATUSEX ms;
|
||||
ms.dwLength = sizeof(ms);
|
||||
if (GlobalMemoryStatusEx(&ms)) {
|
||||
qDebug().noquote() << QString("\tCurrent System Memory Usage: %1%").arg(ms.dwMemoryLoad);
|
||||
qDebug().noquote() << QString("\tAvail Physical Memory: %1 MB").arg(ms.ullAvailPhys * BYTES_TO_MEGABYTE, 20, 'f', 2);
|
||||
qDebug().noquote() << QString("\tTotal Physical Memory: %1 MB").arg(ms.ullTotalPhys * BYTES_TO_MEGABYTE, 20, 'f', 2);
|
||||
qDebug().noquote() << QString("\tAvail in Page File: %1 MB").arg(ms.ullAvailPageFile * BYTES_TO_MEGABYTE, 20, 'f', 2);
|
||||
qDebug().noquote() << QString("\tTotal in Page File: %1 MB").arg(ms.ullTotalPageFile * BYTES_TO_MEGABYTE, 20, 'f', 2);
|
||||
qDebug().noquote() << QString("\tAvail Virtual Memory: %1 MB").arg(ms.ullAvailVirtual * BYTES_TO_MEGABYTE, 20, 'f', 2);
|
||||
qDebug().noquote() << QString("\tTotal Virtual Memory: %1 MB").arg(ms.ullTotalVirtual * BYTES_TO_MEGABYTE, 20, 'f', 2);
|
||||
} else {
|
||||
qDebug() << "\tFailed to retrieve memory status: " << GetLastError();
|
||||
}
|
||||
|
||||
qDebug() << "CPUID";
|
||||
|
||||
qDebug() << "\tCPU Vendor: " << CPUID::Vendor().c_str();
|
||||
qDebug() << "\tCPU Brand: " << CPUID::Brand().c_str();
|
||||
|
||||
for (auto& feature : CPUID::getAllFeatures()) {
|
||||
qDebug().nospace().noquote() << "\t[" << (feature.supported ? "x" : " ") << "] " << feature.name.c_str();
|
||||
}
|
||||
#endif
|
||||
|
||||
qDebug() << "Environment Variables";
|
||||
// List of env variables to include in the log. For privacy reasons we don't send all env variables.
|
||||
const QStringList envWhitelist = {
|
||||
"QTWEBENGINE_REMOTE_DEBUGGING"
|
||||
};
|
||||
auto envVariables = QProcessEnvironment::systemEnvironment();
|
||||
for (auto& env : envWhitelist)
|
||||
{
|
||||
qDebug().noquote().nospace() << "\t" <<
|
||||
(envVariables.contains(env) ? " = " + envVariables.value(env) : " NOT FOUND");
|
||||
}
|
||||
}
|
|
@ -198,4 +198,6 @@ uint qHash(const std::shared_ptr<T>& ptr, uint seed = 0)
|
|||
|
||||
void disableQtBearerPoll();
|
||||
|
||||
void printSystemInformation();
|
||||
|
||||
#endif // hifi_SharedUtil_h
|
||||
|
|
|
@ -122,13 +122,23 @@ void QmlWindowClass::initQml(QVariantMap properties) {
|
|||
object->setProperty(SOURCE_PROPERTY, _source);
|
||||
|
||||
// Forward messages received from QML on to the script
|
||||
connect(_qmlWindow, SIGNAL(sendToScript(QVariant)), this, SIGNAL(fromQml(const QVariant&)), Qt::QueuedConnection);
|
||||
connect(_qmlWindow, SIGNAL(sendToScript(QVariant)), this, SLOT(qmlToScript(const QVariant&)), Qt::QueuedConnection);
|
||||
});
|
||||
}
|
||||
Q_ASSERT(_qmlWindow);
|
||||
Q_ASSERT(dynamic_cast<const QQuickItem*>(_qmlWindow.data()));
|
||||
}
|
||||
|
||||
void QmlWindowClass::qmlToScript(const QVariant& message) {
|
||||
if (message.canConvert<QJSValue>()) {
|
||||
emit fromQml(qvariant_cast<QJSValue>(message).toVariant());
|
||||
} else if (message.canConvert<QString>()) {
|
||||
emit fromQml(message.toString());
|
||||
} else {
|
||||
qWarning() << "Unsupported message type " << message;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlWindowClass::sendToQml(const QVariant& message) {
|
||||
// Forward messages received from the script on to QML
|
||||
QMetaObject::invokeMethod(asQuickItem(), "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
|
|
|
@ -63,6 +63,7 @@ signals:
|
|||
|
||||
protected slots:
|
||||
void hasClosed();
|
||||
void qmlToScript(const QVariant& message);
|
||||
|
||||
protected:
|
||||
static QVariantMap parseArguments(QScriptContext* context);
|
||||
|
|
|
@ -12,8 +12,8 @@ if (WIN32)
|
|||
add_definitions(-DGLEW_STATIC)
|
||||
|
||||
set(TARGET_NAME oculus)
|
||||
setup_hifi_plugin()
|
||||
link_hifi_libraries(shared gl gpu controllers ui plugins display-plugins input-plugins)
|
||||
setup_hifi_plugin(Multimedia)
|
||||
link_hifi_libraries(shared gl gpu controllers ui plugins display-plugins input-plugins audio-client networking)
|
||||
|
||||
include_hifi_library_headers(octree)
|
||||
|
||||
|
@ -21,5 +21,6 @@ if (WIN32)
|
|||
find_package(LibOVR REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
|
||||
target_link_libraries(${TARGET_NAME} Winmm.lib)
|
||||
|
||||
endif()
|
|
@ -21,6 +21,7 @@ public:
|
|||
// Stereo specific methods
|
||||
virtual void resetSensors() override final;
|
||||
virtual void beginFrameRender(uint32_t frameIndex) override;
|
||||
float getTargetFrameRate() override { return _hmdDesc.DisplayRefreshRate; }
|
||||
|
||||
|
||||
protected:
|
||||
|
|
|
@ -6,7 +6,14 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "OculusDisplayPlugin.h"
|
||||
|
||||
// Odd ordering of header is required to avoid 'macro redinition warnings'
|
||||
#include <AudioClient.h>
|
||||
|
||||
#include <OVR_CAPI_Audio.h>
|
||||
|
||||
#include <shared/NsightHelpers.h>
|
||||
|
||||
#include "OculusHelpers.h"
|
||||
|
||||
const QString OculusDisplayPlugin::NAME("Oculus Rift");
|
||||
|
@ -86,3 +93,26 @@ void OculusDisplayPlugin::hmdPresent() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OculusDisplayPlugin::isHmdMounted() const {
|
||||
ovrSessionStatus status;
|
||||
return (OVR_SUCCESS(ovr_GetSessionStatus(_session, &status)) &&
|
||||
(ovrFalse != status.HmdMounted));
|
||||
}
|
||||
|
||||
QString OculusDisplayPlugin::getPreferredAudioInDevice() const {
|
||||
WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE];
|
||||
if (!OVR_SUCCESS(ovr_GetAudioDeviceInGuidStr(buffer))) {
|
||||
return QString();
|
||||
}
|
||||
return AudioClient::friendlyNameForAudioDevice(buffer);
|
||||
}
|
||||
|
||||
QString OculusDisplayPlugin::getPreferredAudioOutDevice() const {
|
||||
WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE];
|
||||
if (!OVR_SUCCESS(ovr_GetAudioDeviceOutGuidStr(buffer))) {
|
||||
return QString();
|
||||
}
|
||||
return AudioClient::friendlyNameForAudioDevice(buffer);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,20 +12,18 @@
|
|||
struct SwapFramebufferWrapper;
|
||||
using SwapFboPtr = QSharedPointer<SwapFramebufferWrapper>;
|
||||
|
||||
const float TARGET_RATE_Oculus = 75.0f;
|
||||
|
||||
class OculusDisplayPlugin : public OculusBaseDisplayPlugin {
|
||||
using Parent = OculusBaseDisplayPlugin;
|
||||
public:
|
||||
const QString& getName() const override { return NAME; }
|
||||
|
||||
float getTargetFrameRate() override { return TARGET_RATE_Oculus; }
|
||||
QString getPreferredAudioInDevice() const override;
|
||||
QString getPreferredAudioOutDevice() const override;
|
||||
|
||||
protected:
|
||||
bool internalActivate() override;
|
||||
void hmdPresent() override;
|
||||
// FIXME update with Oculus API call once it's available in the SDK
|
||||
bool isHmdMounted() const override { return true; }
|
||||
bool isHmdMounted() const override;
|
||||
void customizeContext() override;
|
||||
void uncustomizeContext() override;
|
||||
void cycleDebugOutput() override;
|
||||
|
|
|
@ -220,6 +220,24 @@ ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Add Tab 2"
|
||||
onClicked: {
|
||||
console.log(desktop.toolWindow);
|
||||
desktop.toolWindow.addWebTab({ source: "Foo 2" });
|
||||
desktop.toolWindow.showTabForUrl("Foo 2", true);
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Add Tab 3"
|
||||
onClicked: {
|
||||
console.log(desktop.toolWindow);
|
||||
desktop.toolWindow.addWebTab({ source: "Foo 3" });
|
||||
desktop.toolWindow.showTabForUrl("Foo 3", true);
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Destroy Tab"
|
||||
onClicked: {
|
||||
|
|
|
@ -34,20 +34,24 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) {
|
|||
return false;
|
||||
}
|
||||
std::cout << "Reading FBX.....\n";
|
||||
try {
|
||||
QByteArray fbxContents = fbx.readAll();
|
||||
FBXGeometry* geom;
|
||||
if (filename.toLower().endsWith(".obj")) {
|
||||
geom = OBJReader().readOBJ(fbxContents, QVariantHash());
|
||||
} else if (filename.toLower().endsWith(".fbx")) {
|
||||
geom = readFBX(fbxContents, QVariantHash(), filename);
|
||||
} else {
|
||||
qDebug() << "unknown file extension";
|
||||
return false;
|
||||
}
|
||||
result = *geom;
|
||||
|
||||
QByteArray fbxContents = fbx.readAll();
|
||||
FBXGeometry* geom;
|
||||
if (filename.toLower().endsWith(".obj")) {
|
||||
geom = OBJReader().readOBJ(fbxContents, QVariantHash());
|
||||
} else if (filename.toLower().endsWith(".fbx")) {
|
||||
geom = readFBX(fbxContents, QVariantHash(), filename);
|
||||
} else {
|
||||
qDebug() << "unknown file extension";
|
||||
reSortFBXGeometryMeshes(result);
|
||||
} catch (const QString& error) {
|
||||
qDebug() << "Error reading " << filename << ": " << error;
|
||||
return false;
|
||||
}
|
||||
result = *geom;
|
||||
|
||||
reSortFBXGeometryMeshes(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue