mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 12:23:24 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
1297ae5d0d
20 changed files with 306 additions and 58 deletions
|
@ -196,6 +196,7 @@ function goActive() {
|
|||
}
|
||||
MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting.
|
||||
stopAwayAnimation();
|
||||
MyAvatar.reset(true);
|
||||
hideOverlay();
|
||||
|
||||
// restore overlays state to what it was when we went "away"
|
||||
|
|
|
@ -27,6 +27,7 @@ var directoryWindow = new OverlayWebWindow({
|
|||
|
||||
var toolHeight = 50;
|
||||
var toolWidth = 50;
|
||||
var TOOLBAR_MARGIN_Y = 25;
|
||||
|
||||
|
||||
function showDirectory() {
|
||||
|
@ -53,11 +54,14 @@ var toolBar = (function() {
|
|||
browseDirectoryButton;
|
||||
|
||||
function initialize() {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.directory.toolbar", function(windowDimensions, toolbar) {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.directory.toolbar", function(windowDimensions, toolbar) {
|
||||
return {
|
||||
x: windowDimensions.x - 8 - toolbar.width,
|
||||
y: 50
|
||||
x: windowDimensions.x / 2,
|
||||
y: windowDimensions.y
|
||||
};
|
||||
}, {
|
||||
x: -2 * toolWidth,
|
||||
y: -TOOLBAR_MARGIN_Y - toolHeight
|
||||
});
|
||||
browseDirectoryButton = toolBar.addTool({
|
||||
imageURL: toolIconUrl + "directory-01.svg",
|
||||
|
|
|
@ -53,6 +53,7 @@ selectionManager.addEventListener(function() {
|
|||
var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/";
|
||||
var toolHeight = 50;
|
||||
var toolWidth = 50;
|
||||
var TOOLBAR_MARGIN_Y = 25;
|
||||
|
||||
var DEGREES_TO_RADIANS = Math.PI / 180.0;
|
||||
var RADIANS_TO_DEGREES = 180.0 / Math.PI;
|
||||
|
@ -179,11 +180,14 @@ var toolBar = (function() {
|
|||
newParticleButton
|
||||
|
||||
function initialize() {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.edit.toolbar", function(windowDimensions, toolbar) {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.edit.toolbar", function(windowDimensions, toolbar) {
|
||||
return {
|
||||
x: windowDimensions.x - 8 - toolbar.width,
|
||||
y: (windowDimensions.y - toolbar.height) / 2
|
||||
x: windowDimensions.x / 2,
|
||||
y: windowDimensions.y
|
||||
};
|
||||
}, {
|
||||
x: toolWidth,
|
||||
y: -TOOLBAR_MARGIN_Y - toolHeight
|
||||
});
|
||||
|
||||
activeButton = toolBar.addTool({
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
HIFI_PUBLIC_BUCKET = 'http://s3.amazonaws.com/hifi-public/';
|
||||
|
||||
Script.include("../../libraries/toolBars.js");
|
||||
Script.include('../../libraries/toolBars.js');
|
||||
|
||||
const DEFAULT_NUM_LAYERS = 16;
|
||||
const DEFAULT_BASE_DIMENSION = { x: 7, y: 2, z: 7 };
|
||||
|
@ -30,6 +30,8 @@ const DEFAULT_RESTITUTION = 0.0;
|
|||
const DEFAULT_SPAWN_DISTANCE = 3;
|
||||
const DEFAULT_BLOCK_YAW_OFFSET = 45;
|
||||
|
||||
const PLANKY_LIFETIME = 3600; // 1 hour (3600 seconds)
|
||||
|
||||
var editMode = false;
|
||||
|
||||
const BUTTON_DIMENSIONS = {width: 49, height: 49};
|
||||
|
@ -51,13 +53,17 @@ SettingsWindow = function() {
|
|||
this.plankyStack = null;
|
||||
this.webWindow = null;
|
||||
this.init = function(plankyStack) {
|
||||
_this.webWindow = new OverlayWebWindow('Planky', Script.resolvePath('../../html/plankySettings.html'), 255, 500, true);
|
||||
_this.webWindow = new OverlayWebWindow({
|
||||
title: 'Planky',
|
||||
source: Script.resolvePath('../../html/plankySettings.html'),
|
||||
toolWindow: true
|
||||
});
|
||||
_this.webWindow.setVisible(false);
|
||||
_this.webWindow.eventBridge.webEventReceived.connect(_this.onWebEventReceived);
|
||||
_this.webWindow.webEventReceived.connect(_this.onWebEventReceived);
|
||||
_this.plankyStack = plankyStack;
|
||||
};
|
||||
this.sendData = function(data) {
|
||||
_this.webWindow.eventBridge.emitScriptEvent(JSON.stringify(data));
|
||||
_this.webWindow.emitScriptEvent(JSON.stringify(data));
|
||||
};
|
||||
this.onWebEventReceived = function(data) {
|
||||
data = JSON.parse(data);
|
||||
|
@ -188,7 +194,8 @@ PlankyStack = function() {
|
|||
dimensions: _this.options.baseDimension,
|
||||
position: Vec3.sum(_this.basePosition, {y: -(_this.options.baseDimension.y / 2)}),
|
||||
rotation: _this.baseRotation,
|
||||
shapeType: 'box'
|
||||
shapeType: 'box',
|
||||
lifetime: PLANKY_LIFETIME
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -254,7 +261,8 @@ PlankyStack = function() {
|
|||
density: _this.options.density,
|
||||
velocity: {x: 0, y: 0, z: 0},
|
||||
angularVelocity: Quat.fromPitchYawRollDegrees(0, 0, 0),
|
||||
collisionless: true
|
||||
collisionless: true,
|
||||
lifetime: PLANKY_LIFETIME
|
||||
};
|
||||
_this.planks.forEach(function(plank, index, object) {
|
||||
if (plank.layer === layer && plank.row === row) {
|
||||
|
@ -304,6 +312,7 @@ var settingsWindow = new SettingsWindow();
|
|||
var plankyStack = new PlankyStack();
|
||||
settingsWindow.init(plankyStack);
|
||||
|
||||
// This function is used to get the ideal y-location for a floor
|
||||
function grabLowestJointY() {
|
||||
var jointNames = MyAvatar.getJointNames();
|
||||
var floorY = MyAvatar.position.y;
|
||||
|
|
|
@ -27,6 +27,7 @@ var examplesWindow = new OverlayWebWindow({
|
|||
|
||||
var toolHeight = 50;
|
||||
var toolWidth = 50;
|
||||
var TOOLBAR_MARGIN_Y = 25;
|
||||
|
||||
|
||||
function showExamples(marketplaceID) {
|
||||
|
@ -58,11 +59,14 @@ var toolBar = (function() {
|
|||
browseExamplesButton;
|
||||
|
||||
function initialize() {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.examples.toolbar", function(windowDimensions, toolbar) {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.HORIXONTAL, "highfidelity.examples.toolbar", function(windowDimensions, toolbar) {
|
||||
return {
|
||||
x: windowDimensions.x - 8 - toolbar.width,
|
||||
y: 135
|
||||
x: windowDimensions.x / 2,
|
||||
y: windowDimensions.y
|
||||
};
|
||||
}, {
|
||||
x: -toolWidth / 2,
|
||||
y: -TOOLBAR_MARGIN_Y - toolHeight
|
||||
});
|
||||
browseExamplesButton = toolBar.addTool({
|
||||
imageURL: toolIconUrl + "examples-01.svg",
|
||||
|
|
|
@ -3,11 +3,15 @@
|
|||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<script type="text/javascript" src="jquery-2.1.4.min.js"></script>
|
||||
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
<script type="text/javascript" src="eventBridgeLoader.js"></script>
|
||||
<script type="text/javascript">
|
||||
var properties = [];
|
||||
function sendWebEvent(data) {
|
||||
EventBridge.emitWebEvent(JSON.stringify(data));
|
||||
|
||||
var sendWebEvent = function(data) {
|
||||
console.log('sendWebEvent not initialized.');
|
||||
}
|
||||
|
||||
PropertyInput = function(key, label, value, attributes) {
|
||||
this.key = key;
|
||||
this.label = label;
|
||||
|
@ -93,7 +97,7 @@ function addHeader(label) {
|
|||
$('#properties-list').append($('<div>').addClass('section-header').append($('<label>').text(label)));
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$(function() {
|
||||
addHeader('Stack Settings');
|
||||
properties['numLayers'] = new NumberInput('numLayers', 'Layers', 17, {'min': 0, 'max': 300, 'step': 1});
|
||||
properties['blocksPerLayer'] = new NumberInput('blocksPerLayer', 'Blocks per layer', 4, {'min': 1, 'max': 100, 'step': 1});
|
||||
|
@ -120,7 +124,8 @@ $(function() {
|
|||
.append($('<input>').val('factory reset').attr('type', 'button').on('click', function() { sendWebEvent({action: 'factory-reset'}); }))
|
||||
.append($('<input>').val('save as default').attr('type', 'button').on('click', function() { sendWebEvent({action: 'save-default'}); }))
|
||||
.append($('<input>').val('cleanup planky').attr('type', 'button').on('click', function() { sendWebEvent({action: 'cleanup'}); }));
|
||||
if (window.EventBridge !== undefined) {
|
||||
|
||||
openEventBridge(function() {
|
||||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
if (data.action == 'load') {
|
||||
|
@ -129,12 +134,15 @@ $(function() {
|
|||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
sendWebEvent({action: 'loaded'});
|
||||
sendWebEvent = function(data) {
|
||||
EventBridge.emitWebEvent(JSON.stringify(data));
|
||||
};
|
||||
sendWebEvent({action: 'loaded'});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body class="properties">
|
||||
<div id="properties-list"></div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -139,12 +139,13 @@ Tool.prototype = new Overlay2D;
|
|||
Tool.IMAGE_HEIGHT = 50;
|
||||
Tool.IMAGE_WIDTH = 50;
|
||||
|
||||
ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPositionFunction) {
|
||||
ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPositionFunction, optionalOffset) {
|
||||
this.tools = new Array();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.offset = optionalOffset ? optionalOffset : { x: 0, y: 0 };
|
||||
this.width = 0;
|
||||
this.height = 0
|
||||
this.height = 0;
|
||||
this.backAlpha = 1.0;
|
||||
this.back = Overlays.addOverlay("rectangle", {
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
|
@ -237,7 +238,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
}
|
||||
}
|
||||
|
||||
this.move = function(x, y) {
|
||||
this.move = function (x, y) {
|
||||
var dx = x - this.x;
|
||||
var dy = y - this.y;
|
||||
this.x = x;
|
||||
|
@ -370,14 +371,14 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
that.onResizeViewport = function (newSize) { // Can be overridden or extended by clients.
|
||||
var recommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var recommendedDimmensions = { x: recommendedRect.width, y: recommendedRect.height };
|
||||
var originRelativeX = (that.x - that.origin.x);
|
||||
var originRelativeY = (that.y - that.origin.y);
|
||||
var originRelativeX = (that.x - that.origin.x - that.offset.x);
|
||||
var originRelativeY = (that.y - that.origin.y - that.offset.y);
|
||||
var fractionX = clamp(originRelativeX / that.windowDimensions.x, 0, 1);
|
||||
var fractionY = clamp(originRelativeY / that.windowDimensions.y, 0, 1);
|
||||
that.windowDimensions = newSize || recommendedDimmensions;
|
||||
that.origin = { x: recommendedRect.x, y: recommendedRect.y };
|
||||
var newX = (fractionX * that.windowDimensions.x) + recommendedRect.x;
|
||||
var newY = (fractionY * that.windowDimensions.y) + recommendedRect.y;
|
||||
var newX = (fractionX * that.windowDimensions.x) + recommendedRect.x + that.offset.x;
|
||||
var newY = (fractionY * that.windowDimensions.y) + recommendedRect.y + that.offset.y;
|
||||
that.move(newX, newY);
|
||||
};
|
||||
if (optionalPersistenceKey) {
|
||||
|
@ -387,7 +388,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
var screenSize = { x: recommendedRect.width, y: recommendedRect.height };
|
||||
if (screenSize.x > 0 && screenSize.y > 0) {
|
||||
// Guard against invalid screen size that can occur at shut-down.
|
||||
var fraction = {x: that.x / screenSize.x, y: that.y / screenSize.y};
|
||||
var fraction = {x: (that.x - that.offset.x) / screenSize.x, y: (that.y - that.offset.y) / screenSize.y};
|
||||
Settings.setValue(this.fractionKey, JSON.stringify(fraction));
|
||||
}
|
||||
}
|
||||
|
@ -456,7 +457,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
var screenSize = { x: recommendedRect.width, y: recommendedRect.height };
|
||||
if (savedFraction) {
|
||||
// If we have saved data, keep the toolbar at the same proportion of the screen width/height.
|
||||
that.move(savedFraction.x * screenSize.x, savedFraction.y * screenSize.y);
|
||||
that.move(savedFraction.x * screenSize.x + that.offset.x, savedFraction.y * screenSize.y + that.offset.y);
|
||||
} else if (!optionalInitialPositionFunction) {
|
||||
print("No initPosition(screenSize, intializedToolbar) specified for ToolBar");
|
||||
} else {
|
||||
|
@ -464,7 +465,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
var that = this;
|
||||
Script.setTimeout(function () {
|
||||
var position = optionalInitialPositionFunction(screenSize, that);
|
||||
that.move(position.x, position.y);
|
||||
that.move(position.x + that.offset.x, position.y + that.offset.y);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ Window {
|
|||
title: "Asset Browser"
|
||||
resizable: true
|
||||
destroyOnInvisible: true
|
||||
x: 40; y: 40
|
||||
implicitWidth: 384; implicitHeight: 640
|
||||
minSize: Qt.vector2d(200, 300)
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ Hifi.AvatarInputs {
|
|||
readonly property int iconPadding: 5
|
||||
|
||||
readonly property bool shouldReposition: true
|
||||
|
||||
|
||||
Settings {
|
||||
category: "Overlay.AvatarInputs"
|
||||
property alias x: root.x
|
||||
|
|
|
@ -22,4 +22,19 @@ Windows.Window {
|
|||
url: infoView.url
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
centerWindow(root);
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
centerWindow(root);
|
||||
}
|
||||
}
|
||||
|
||||
function centerWindow() {
|
||||
desktop.centerOnVisible(root);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@ FocusScope {
|
|||
objectName: "desktop"
|
||||
anchors.fill: parent
|
||||
|
||||
property rect recommendedRect: rect(0,0,0,0);
|
||||
readonly property int invalid_position: -9999;
|
||||
property rect recommendedRect: Qt.rect(0,0,0,0);
|
||||
property var expectedChildren;
|
||||
|
||||
onHeightChanged: d.handleSizeChanged();
|
||||
|
||||
|
@ -55,13 +57,18 @@ FocusScope {
|
|||
|
||||
function handleSizeChanged() {
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var newRecommendedRectJS = Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
|
||||
newRecommendedRectJS.width,
|
||||
newRecommendedRectJS.height);
|
||||
|
||||
if (oldRecommendedRect != Qt.rect(0,0,0,0)
|
||||
&& oldRecommendedRect != newRecommendedRect) {
|
||||
var oldChildren = expectedChildren;
|
||||
var newChildren = d.getRepositionChildren();
|
||||
if (oldRecommendedRect != Qt.rect(0,0,0,0)
|
||||
&& (oldRecommendedRect != newRecommendedRect
|
||||
|| oldChildren != newChildren)
|
||||
) {
|
||||
expectedChildren = newChildren;
|
||||
d.repositionAll();
|
||||
}
|
||||
recommendedRect = newRecommendedRect;
|
||||
|
@ -279,13 +286,56 @@ FocusScope {
|
|||
targetWindow.focus = true;
|
||||
}
|
||||
|
||||
showDesktop();
|
||||
}
|
||||
|
||||
function centerOnVisible(item) {
|
||||
var targetWindow = d.getDesktopWindow(item);
|
||||
if (!targetWindow) {
|
||||
console.warn("Could not find top level window for " + item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof Controller === "undefined") {
|
||||
console.warn("Controller not yet available... can't center");
|
||||
return;
|
||||
}
|
||||
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
|
||||
newRecommendedRectJS.width,
|
||||
newRecommendedRectJS.height);
|
||||
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
|
||||
var newX = newRecommendedRect.x + ((newRecommendedRect.width - targetWindow.width) / 2);
|
||||
var newY = newRecommendedRect.y + ((newRecommendedRect.height - targetWindow.height) / 2);
|
||||
targetWindow.x = newX;
|
||||
targetWindow.y = newY;
|
||||
|
||||
// If we've noticed that our recommended desktop rect has changed, record that change here.
|
||||
if (recommendedRect != newRecommendedRect) {
|
||||
recommendedRect = newRecommendedRect;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function repositionOnVisible(item) {
|
||||
var targetWindow = d.getDesktopWindow(item);
|
||||
if (!targetWindow) {
|
||||
console.warn("Could not find top level window for " + item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof Controller === "undefined") {
|
||||
console.warn("Controller not yet available... can't reposition targetWindow:" + targetWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
|
||||
var newRecommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
|
||||
repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
|
||||
|
||||
showDesktop();
|
||||
}
|
||||
|
||||
function repositionWindow(targetWindow, forceReposition,
|
||||
|
@ -324,10 +374,8 @@ FocusScope {
|
|||
}
|
||||
var fractionX = Utils.clamp(originRelativeX / oldRecommendedDimmensions.x, 0, 1);
|
||||
var fractionY = Utils.clamp(originRelativeY / oldRecommendedDimmensions.y, 0, 1);
|
||||
|
||||
var newX = (fractionX * newRecommendedDimmensions.x) + newRecommendedRect.x;
|
||||
var newY = (fractionY * newRecommendedDimmensions.y) + newRecommendedRect.y;
|
||||
|
||||
newPosition = Qt.vector2d(newX, newY);
|
||||
}
|
||||
targetWindow.x = newPosition.x;
|
||||
|
|
|
@ -23,7 +23,6 @@ Window {
|
|||
title: "Running Scripts"
|
||||
resizable: true
|
||||
destroyOnInvisible: true
|
||||
x: 40; y: 40
|
||||
implicitWidth: 400
|
||||
implicitHeight: isHMD ? 695 : 728
|
||||
minSize: Qt.vector2d(200, 300)
|
||||
|
|
|
@ -31,7 +31,7 @@ Fadable {
|
|||
// decorations can extend outside it.
|
||||
implicitHeight: content ? content.height : 0
|
||||
implicitWidth: content ? content.width : 0
|
||||
x: -1; y: -1
|
||||
x: desktop.invalid_position; y: desktop.invalid_position;
|
||||
enabled: visible
|
||||
|
||||
signal windowDestroyed();
|
||||
|
@ -252,6 +252,7 @@ Fadable {
|
|||
window.parentChanged.connect(raise);
|
||||
raise();
|
||||
setDefaultFocus();
|
||||
centerOrReposition();
|
||||
}
|
||||
Component.onDestruction: {
|
||||
window.parentChanged.disconnect(raise); // Prevent warning on shutdown
|
||||
|
@ -267,6 +268,18 @@ Fadable {
|
|||
raise();
|
||||
}
|
||||
enabled = visible
|
||||
|
||||
if (visible && parent) {
|
||||
centerOrReposition();
|
||||
}
|
||||
}
|
||||
|
||||
function centerOrReposition() {
|
||||
if (x == desktop.invalid_position && y == desktop.invalid_position) {
|
||||
desktop.centerOnVisible(window);
|
||||
} else {
|
||||
desktop.repositionOnVisible(window);
|
||||
}
|
||||
}
|
||||
|
||||
function raise() {
|
||||
|
|
|
@ -19,7 +19,7 @@ Fadable {
|
|||
// decorations can extend outside it.
|
||||
implicitHeight: content ? content.height : 0
|
||||
implicitWidth: content ? content.width : 0
|
||||
x: -1; y: -1
|
||||
x: desktop.invalid_position; y: desktop.invalid_position;
|
||||
enabled: visible
|
||||
|
||||
signal windowDestroyed();
|
||||
|
@ -117,12 +117,21 @@ Fadable {
|
|||
Component.onCompleted: {
|
||||
window.parentChanged.connect(raise);
|
||||
raise();
|
||||
centerOrReposition();
|
||||
}
|
||||
Component.onDestruction: {
|
||||
window.parentChanged.disconnect(raise); // Prevent warning on shutdown
|
||||
windowDestroyed();
|
||||
}
|
||||
|
||||
function centerOrReposition() {
|
||||
if (x == desktop.invalid_position && y == desktop.invalid_position) {
|
||||
desktop.centerOnVisible(window);
|
||||
} else {
|
||||
desktop.repositionOnVisible(window);
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible && destroyOnInvisible) {
|
||||
destroy();
|
||||
|
@ -132,6 +141,10 @@ Fadable {
|
|||
raise();
|
||||
}
|
||||
enabled = visible
|
||||
|
||||
if (visible && parent) {
|
||||
centerOrReposition();
|
||||
}
|
||||
}
|
||||
|
||||
function raise() {
|
||||
|
|
|
@ -4315,6 +4315,7 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket) {
|
||||
// Attempt to identify the sender from its address.
|
||||
if (sendingNode) {
|
||||
|
|
|
@ -235,7 +235,12 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) {
|
|||
return AvatarData::toByteArray(cullSmallChanges, sendAll);
|
||||
}
|
||||
|
||||
void MyAvatar::reset(bool andReload) {
|
||||
void MyAvatar::reset(bool andRecenter) {
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "reset", Q_ARG(bool, andRecenter));
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset dynamic state.
|
||||
_wasPushing = _isPushing = _isBraking = false;
|
||||
|
@ -245,7 +250,7 @@ void MyAvatar::reset(bool andReload) {
|
|||
_targetVelocity = glm::vec3(0.0f);
|
||||
setThrust(glm::vec3(0.0f));
|
||||
|
||||
if (andReload) {
|
||||
if (andRecenter) {
|
||||
// derive the desired body orientation from the *old* hmd orientation, before the sensor reset.
|
||||
auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation..
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ public:
|
|||
AudioListenerMode getAudioListenerModeCamera() const { return FROM_CAMERA; }
|
||||
AudioListenerMode getAudioListenerModeCustom() const { return CUSTOM; }
|
||||
|
||||
void reset(bool andReload = false);
|
||||
Q_INVOKABLE void reset(bool andRecenter = false);
|
||||
void update(float deltaTime);
|
||||
void preRender(RenderArgs* renderArgs);
|
||||
|
||||
|
|
|
@ -110,7 +110,14 @@ void Text3DOverlay::render(RenderArgs* args) {
|
|||
|
||||
glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR,
|
||||
_color.blue / MAX_COLOR, getTextAlpha() };
|
||||
|
||||
// FIXME: Factor out textRenderer so that Text3DOverlay overlay parts can be grouped by pipeline
|
||||
// for a gpu performance increase. Currently,
|
||||
// Text renderer sets its own pipeline,
|
||||
_textRenderer->draw(batch, 0, 0, _text, textColor, glm::vec2(-1.0f), getDrawInFront());
|
||||
// so before we continue, we must reset the pipeline
|
||||
batch.setPipeline(args->_pipeline->pipeline);
|
||||
args->_pipeline->prepare(batch);
|
||||
}
|
||||
|
||||
const render::ShapeKey Text3DOverlay::getShapeKey() {
|
||||
|
|
|
@ -413,9 +413,15 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag
|
|||
|
||||
class CubeLayout {
|
||||
public:
|
||||
|
||||
enum SourceProjection {
|
||||
FLAT = 0,
|
||||
EQUIRECTANGULAR,
|
||||
};
|
||||
int _type = FLAT;
|
||||
int _widthRatio = 1;
|
||||
int _heightRatio = 1;
|
||||
|
||||
|
||||
class Face {
|
||||
public:
|
||||
int _x = 0;
|
||||
|
@ -435,6 +441,7 @@ public:
|
|||
Face _faceZNeg;
|
||||
|
||||
CubeLayout(int wr, int hr, Face fXP, Face fXN, Face fYP, Face fYN, Face fZP, Face fZN) :
|
||||
_type(FLAT),
|
||||
_widthRatio(wr),
|
||||
_heightRatio(hr),
|
||||
_faceXPos(fXP),
|
||||
|
@ -444,6 +451,11 @@ public:
|
|||
_faceZPos(fZP),
|
||||
_faceZNeg(fZN) {}
|
||||
|
||||
CubeLayout(int wr, int hr) :
|
||||
_type(EQUIRECTANGULAR),
|
||||
_widthRatio(wr),
|
||||
_heightRatio(hr) {}
|
||||
|
||||
|
||||
static const CubeLayout CUBEMAP_LAYOUTS[];
|
||||
static const int NUM_CUBEMAP_LAYOUTS;
|
||||
|
@ -459,9 +471,102 @@ public:
|
|||
}
|
||||
return foundLayout;
|
||||
}
|
||||
|
||||
static QImage extractEquirectangularFace(const QImage& source, gpu::Texture::CubeFace face, int faceWidth) {
|
||||
QImage image(faceWidth, faceWidth, source.format());
|
||||
|
||||
glm::vec2 dstInvSize(1.0f / (float)image.width(), 1.0f / (float)image.height());
|
||||
|
||||
struct CubeToXYZ {
|
||||
gpu::Texture::CubeFace _face;
|
||||
CubeToXYZ(gpu::Texture::CubeFace face) : _face(face) {}
|
||||
|
||||
glm::vec3 xyzFrom(const glm::vec2& uv) {
|
||||
auto faceDir = glm::normalize(glm::vec3(-1.0f + 2.0f * uv.x, -1.0f + 2.0f * uv.y, 1.0f));
|
||||
|
||||
switch (_face) {
|
||||
case gpu::Texture::CubeFace::CUBE_FACE_BACK_POS_Z:
|
||||
return glm::vec3(-faceDir.x, faceDir.y, faceDir.z);
|
||||
case gpu::Texture::CubeFace::CUBE_FACE_FRONT_NEG_Z:
|
||||
return glm::vec3(faceDir.x, faceDir.y, -faceDir.z);
|
||||
case gpu::Texture::CubeFace::CUBE_FACE_LEFT_NEG_X:
|
||||
return glm::vec3(faceDir.z, faceDir.y, faceDir.x);
|
||||
case gpu::Texture::CubeFace::CUBE_FACE_RIGHT_POS_X:
|
||||
return glm::vec3(-faceDir.z, faceDir.y, -faceDir.x);
|
||||
case gpu::Texture::CubeFace::CUBE_FACE_BOTTOM_NEG_Y:
|
||||
return glm::vec3(-faceDir.x, -faceDir.z, faceDir.y);
|
||||
case gpu::Texture::CubeFace::CUBE_FACE_TOP_POS_Y:
|
||||
default:
|
||||
return glm::vec3(-faceDir.x, faceDir.z, -faceDir.y);
|
||||
}
|
||||
}
|
||||
};
|
||||
CubeToXYZ cubeToXYZ(face);
|
||||
|
||||
struct RectToXYZ {
|
||||
RectToXYZ() {}
|
||||
|
||||
glm::vec2 uvFrom(const glm::vec3& xyz) {
|
||||
auto flatDir = glm::normalize(glm::vec2(xyz.x, xyz.z));
|
||||
auto uvRad = glm::vec2(atan2(flatDir.x, flatDir.y), asin(xyz.y));
|
||||
|
||||
const float LON_TO_RECT_U = 1.0f / (glm::pi<float>());
|
||||
const float LAT_TO_RECT_V = 2.0f / glm::pi<float>();
|
||||
return glm::vec2(0.5f * uvRad.x * LON_TO_RECT_U + 0.5f, 0.5f * uvRad.y * LAT_TO_RECT_V + 0.5f);
|
||||
}
|
||||
};
|
||||
RectToXYZ rectToXYZ;
|
||||
|
||||
int srcFaceHeight = source.height();
|
||||
int srcFaceWidth = source.width();
|
||||
|
||||
glm::vec2 dstCoord;
|
||||
glm::ivec2 srcPixel;
|
||||
for (int y = 0; y < faceWidth; ++y) {
|
||||
dstCoord.y = 1.0f - (y + 0.5f) * dstInvSize.y; // Fill cube face images from top to bottom
|
||||
for (int x = 0; x < faceWidth; ++x) {
|
||||
dstCoord.x = (x + 0.5f) * dstInvSize.x;
|
||||
|
||||
auto xyzDir = cubeToXYZ.xyzFrom(dstCoord);
|
||||
auto srcCoord = rectToXYZ.uvFrom(xyzDir);
|
||||
|
||||
srcPixel.x = floor(srcCoord.x * srcFaceWidth);
|
||||
// Flip the vertical axis to QImage going top to bottom
|
||||
srcPixel.y = floor((1.0f - srcCoord.y) * srcFaceHeight);
|
||||
|
||||
if (((uint32) srcPixel.x < (uint32) source.width()) && ((uint32) srcPixel.y < (uint32) source.height())) {
|
||||
image.setPixel(x, y, source.pixel(QPoint(srcPixel.x, srcPixel.y)));
|
||||
|
||||
// Keep for debug, this is showing the dir as a color
|
||||
// glm::u8vec4 rgba((xyzDir.x + 1.0)*0.5 * 256, (xyzDir.y + 1.0)*0.5 * 256, (xyzDir.z + 1.0)*0.5 * 256, 256);
|
||||
// unsigned int val = 0xff000000 | (rgba.r) | (rgba.g << 8) | (rgba.b << 16);
|
||||
// image.setPixel(x, y, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
};
|
||||
|
||||
const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = {
|
||||
|
||||
// Here is the expected layout for the faces in an image with the 2/1 aspect ratio:
|
||||
// THis is detected as an Equirectangular projection
|
||||
// WIDTH
|
||||
// <--------------------------->
|
||||
// ^ +------+------+------+------+
|
||||
// H | | | | |
|
||||
// E | | | | |
|
||||
// I | | | | |
|
||||
// G +------+------+------+------+
|
||||
// H | | | | |
|
||||
// T | | | | |
|
||||
// | | | | | |
|
||||
// v +------+------+------+------+
|
||||
//
|
||||
// FaceWidth = width = height / 6
|
||||
{ 2, 1 },
|
||||
|
||||
// Here is the expected layout for the faces in an image with the 1/6 aspect ratio:
|
||||
//
|
||||
// WIDTH
|
||||
|
@ -582,14 +687,25 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
|
|||
// If found, go extract the faces as separate images
|
||||
if (foundLayout >= 0) {
|
||||
auto& layout = CubeLayout::CUBEMAP_LAYOUTS[foundLayout];
|
||||
int faceWidth = image.width() / layout._widthRatio;
|
||||
if (layout._type == CubeLayout::FLAT) {
|
||||
int faceWidth = image.width() / layout._widthRatio;
|
||||
|
||||
faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror));
|
||||
} else if (layout._type == CubeLayout::EQUIRECTANGULAR) {
|
||||
// THe face width is estimated from the input image
|
||||
const int EQUIRECT_FACE_RATIO_TO_WIDTH = 4;
|
||||
const int EQUIRECT_MAX_FACE_WIDTH = 2048;
|
||||
int faceWidth = std::min(image.width() / EQUIRECT_FACE_RATIO_TO_WIDTH, EQUIRECT_MAX_FACE_WIDTH);
|
||||
for (int face = gpu::Texture::CUBE_FACE_RIGHT_POS_X; face < gpu::Texture::NUM_CUBE_FACES; face++) {
|
||||
QImage faceImage = CubeLayout::extractEquirectangularFace(image, (gpu::Texture::CubeFace) face, faceWidth);
|
||||
faces.push_back(faceImage);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCDebug(modelLog) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str());
|
||||
return nullptr;
|
||||
|
|
|
@ -107,7 +107,8 @@ public:
|
|||
|
||||
// The recommended bounds for primary overlay placement
|
||||
virtual QRect getRecommendedOverlayRect() const {
|
||||
auto recommendedSize = getRecommendedUiSize();
|
||||
const int DESKTOP_SCREEN_PADDING = 50;
|
||||
auto recommendedSize = getRecommendedUiSize() - glm::uvec2(DESKTOP_SCREEN_PADDING);
|
||||
return QRect(0, 0, recommendedSize.x, recommendedSize.y);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue