mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 12:14:00 +02:00
rearranged entity props and added check in setNormals to avoid uninitialized binormal values
This commit is contained in:
commit
0f7c21ddd7
70 changed files with 1625 additions and 1034 deletions
|
@ -1,7 +1,7 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
|
||||
|
||||
###Homebrew
|
||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all hifi dependencies very simple.
|
||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all High Fidelity dependencies very simple.
|
||||
|
||||
brew tap highfidelity/homebrew-formulas
|
||||
brew install cmake openssl
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QtCore/QDataStream>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// Created by Zander Otavka on 7/15/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Shows a few common controls in a FloatingUIPanel on right click.
|
||||
// Shows a few common controls in a OverlayPanel on right click.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -22,14 +22,13 @@ var MIC_IMAGE_URL = HIFI_PUBLIC_BUCKET + "images/tools/mic-toggle.svg";
|
|||
var FACE_IMAGE_URL = HIFI_PUBLIC_BUCKET + "images/tools/face-toggle.svg";
|
||||
var ADDRESS_BAR_IMAGE_URL = HIFI_PUBLIC_BUCKET + "images/tools/address-bar-toggle.svg";
|
||||
|
||||
var panel = new FloatingUIPanel({
|
||||
anchorPosition: {
|
||||
bind: "myAvatar"
|
||||
},
|
||||
offsetPosition: { x: 0, y: 0.4, z: 1 }
|
||||
var panel = new OverlayPanel({
|
||||
anchorPositionBinding: { avatar: "MyAvatar" },
|
||||
offsetPosition: { x: 0, y: 0.4, z: -1 },
|
||||
visible: false
|
||||
});
|
||||
|
||||
var background = new BillboardOverlay({
|
||||
var background = new Image3DOverlay({
|
||||
url: BG_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.5,
|
||||
|
@ -37,11 +36,12 @@ var background = new BillboardOverlay({
|
|||
},
|
||||
isFacingAvatar: false,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false
|
||||
ignoreRayIntersection: false,
|
||||
visible: false
|
||||
});
|
||||
panel.addChild(background);
|
||||
|
||||
var closeButton = new BillboardOverlay({
|
||||
var closeButton = new Image3DOverlay({
|
||||
url: CLOSE_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.15,
|
||||
|
@ -51,17 +51,18 @@ var closeButton = new BillboardOverlay({
|
|||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
offsetPosition: {
|
||||
x: -0.1,
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
z: -0.001
|
||||
}
|
||||
z: 0.001
|
||||
},
|
||||
visible: false
|
||||
});
|
||||
closeButton.onClick = function(event) {
|
||||
panel.visible = false;
|
||||
};
|
||||
panel.addChild(closeButton);
|
||||
|
||||
var micMuteButton = new BillboardOverlay({
|
||||
var micMuteButton = new Image3DOverlay({
|
||||
url: MIC_IMAGE_URL,
|
||||
subImage: {
|
||||
x: 0,
|
||||
|
@ -77,17 +78,18 @@ var micMuteButton = new BillboardOverlay({
|
|||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
offsetPosition: {
|
||||
x: 0.1,
|
||||
x: -0.1,
|
||||
y: 0.1,
|
||||
z: -0.001
|
||||
}
|
||||
z: 0.001
|
||||
},
|
||||
visible: false
|
||||
});
|
||||
micMuteButton.onClick = function(event) {
|
||||
AudioDevice.toggleMute();
|
||||
};
|
||||
panel.addChild(micMuteButton);
|
||||
|
||||
var faceMuteButton = new BillboardOverlay({
|
||||
var faceMuteButton = new Image3DOverlay({
|
||||
url: FACE_IMAGE_URL,
|
||||
subImage: {
|
||||
x: 0,
|
||||
|
@ -102,43 +104,47 @@ var faceMuteButton = new BillboardOverlay({
|
|||
isFacingAvatar: false,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
offsetPosition: {
|
||||
x: 0.1,
|
||||
y: -0.1,
|
||||
z: -0.001
|
||||
}
|
||||
});
|
||||
faceMuteButton.onClick = function(event) {
|
||||
FaceTracker.toggleMute();
|
||||
};
|
||||
panel.addChild(faceMuteButton);
|
||||
|
||||
var addressBarButton = new BillboardOverlay({
|
||||
url: ADDRESS_BAR_IMAGE_URL,
|
||||
subImage: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 45,
|
||||
height: 45
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.15,
|
||||
y: 0.15,
|
||||
},
|
||||
isFacingAvatar: false,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
offsetPosition: {
|
||||
x: -0.1,
|
||||
y: -0.1,
|
||||
z: -0.001
|
||||
}
|
||||
z: 0.001
|
||||
},
|
||||
visible: false
|
||||
});
|
||||
faceMuteButton.onClick = function(event) {
|
||||
FaceTracker.toggleMute();
|
||||
};
|
||||
panel.addChild(faceMuteButton);
|
||||
|
||||
var addressBarButton = new Image3DOverlay({
|
||||
url: ADDRESS_BAR_IMAGE_URL,
|
||||
subImage: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 45,
|
||||
height: 45
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.15,
|
||||
y: 0.15,
|
||||
},
|
||||
isFacingAvatar: false,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
offsetPosition: {
|
||||
x: 0.1,
|
||||
y: -0.1,
|
||||
z: 0.001
|
||||
},
|
||||
visible: false
|
||||
});
|
||||
addressBarButton.onClick = function(event) {
|
||||
DialogsManager.toggleAddressBar();
|
||||
};
|
||||
panel.addChild(addressBarButton);
|
||||
|
||||
panel.setChildrenVisible();
|
||||
|
||||
|
||||
function onMicMuteToggled() {
|
||||
var offset;
|
||||
|
@ -181,6 +187,16 @@ function onMouseDown(event) {
|
|||
if (event.isRightButton) {
|
||||
mouseDown.pos = { x: event.x, y: event.y };
|
||||
}
|
||||
mouseDown.maxDistance = 0;
|
||||
}
|
||||
|
||||
function onMouseMove(event) {
|
||||
if (mouseDown.maxDistance !== undefined) {
|
||||
var dist = Vec3.distance(mouseDown.pos, { x: event.x, y: event.y });
|
||||
if (dist > mouseDown.maxDistance) {
|
||||
mouseDown.maxDistance = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseUp(event) {
|
||||
|
@ -190,13 +206,10 @@ function onMouseUp(event) {
|
|||
overlay.onClick(event);
|
||||
}
|
||||
}
|
||||
if (event.isRightButton && Vec3.distance(mouseDown.pos, { x: event.x, y: event.y }) < 5) {
|
||||
if (event.isRightButton && mouseDown.maxDistance < 10) {
|
||||
panel.setProperties({
|
||||
visible: !panel.visible,
|
||||
offsetRotation: {
|
||||
bind: "quat",
|
||||
value: Quat.multiply(MyAvatar.orientation, { x: 0, y: 1, z: 0, w: 0 })
|
||||
}
|
||||
anchorRotation: MyAvatar.orientation
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -208,6 +221,7 @@ function onScriptEnd(event) {
|
|||
}
|
||||
|
||||
Controller.mousePressEvent.connect(onMouseDown);
|
||||
Controller.mouseMoveEvent.connect(onMouseMove);
|
||||
Controller.mouseReleaseEvent.connect(onMouseUp);
|
||||
AudioDevice.muteToggled.connect(onMicMuteToggled);
|
||||
FaceTracker.muteToggled.connect(onFaceMuteToggled);
|
||||
|
|
|
@ -178,7 +178,7 @@
|
|||
modelProperties.sittingPoints[seatIndex].rotation);
|
||||
this.scale = MyAvatar.scale / 3;
|
||||
|
||||
this.sphere = Overlays.addOverlay("billboard", {
|
||||
this.sphere = Overlays.addOverlay("image3d", {
|
||||
subImage: { x: 0, y: buttonHeight, width: buttonWidth, height: buttonHeight},
|
||||
url: buttonImageUrl,
|
||||
position: this.position,
|
||||
|
|
|
@ -252,7 +252,7 @@ function SpriteBillboard(sprite_properties, overlay) {
|
|||
}
|
||||
|
||||
var christmastree_loader = null;
|
||||
christmastree_loader = new OverlayPreloader("billboard",
|
||||
christmastree_loader = new OverlayPreloader("image3d",
|
||||
{url: CHRISTMAS_TREE_SPRITES_URL, alpha: 0}, function() {
|
||||
for (var i = 0; i < NUM_OF_TREES; i++) {
|
||||
var clonedOverlay = Overlays.cloneOverlay(christmastree_loader.overlay);
|
||||
|
@ -269,7 +269,7 @@ christmastree_loader = new OverlayPreloader("billboard",
|
|||
);
|
||||
|
||||
var santa_loader = null;
|
||||
santa_loader = new OverlayPreloader("billboard",
|
||||
santa_loader = new OverlayPreloader("image3d",
|
||||
{url: SANTA_SPRITES_URL, alpha: 0}, function() {
|
||||
for (var i = 0; i < NUM_OF_SANTAS; i++) {
|
||||
var clonedOverlay = Overlays.cloneOverlay(santa_loader.overlay);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// floatingUI.js
|
||||
// overlayPanelExample.js
|
||||
// examples/example/ui
|
||||
//
|
||||
// Created by Alexander Otavka
|
||||
|
@ -18,19 +18,18 @@ var BG_IMAGE_URL = HIFI_PUBLIC_BUCKET + "images/card-bg.svg";
|
|||
var RED_DOT_IMAGE_URL = HIFI_PUBLIC_BUCKET + "images/red-dot.svg";
|
||||
var BLUE_SQUARE_IMAGE_URL = HIFI_PUBLIC_BUCKET + "images/blue-square.svg";
|
||||
|
||||
var mainPanel = new FloatingUIPanel({
|
||||
offsetRotation: {
|
||||
bind: "quat",
|
||||
value: { w: 1, x: 0, y: 0, z: 0 }
|
||||
},
|
||||
offsetPosition: { x: 0, y: 0.4, z: 1 }
|
||||
var mainPanel = new OverlayPanel({
|
||||
anchorPositionBinding: { avatar: "MyAvatar" },
|
||||
offsetPosition: { x: 0, y: 0.4, z: -1 },
|
||||
isFacingAvatar: false
|
||||
});
|
||||
|
||||
var bluePanel = mainPanel.addChild(new FloatingUIPanel ({
|
||||
offsetPosition: { x: 0.1, y: 0.1, z: -0.2 }
|
||||
var bluePanel = mainPanel.addChild(new OverlayPanel ({
|
||||
offsetPosition: { x: 0.1, y: 0.1, z: 0.2 },
|
||||
offsetScale: 0.5
|
||||
}));
|
||||
|
||||
var mainPanelBackground = new BillboardOverlay({
|
||||
var mainPanelBackground = new Image3DOverlay({
|
||||
url: BG_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.5,
|
||||
|
@ -42,20 +41,44 @@ var mainPanelBackground = new BillboardOverlay({
|
|||
offsetPosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0.001
|
||||
z: -0.001
|
||||
}
|
||||
});
|
||||
|
||||
var bluePanelBackground = mainPanelBackground.clone();
|
||||
bluePanelBackground.dimensions = {
|
||||
x: 0.3,
|
||||
y: 0.3
|
||||
};
|
||||
|
||||
mainPanel.addChild(mainPanelBackground);
|
||||
bluePanel.addChild(bluePanelBackground);
|
||||
|
||||
var redDot = mainPanel.addChild(new BillboardOverlay({
|
||||
var textWidth = .25;
|
||||
var textHeight = .1;
|
||||
var numberOfLines = 1;
|
||||
var textMargin = 0.00625;
|
||||
var lineHeight = (textHeight - (2 * textMargin)) / numberOfLines;
|
||||
|
||||
var text = mainPanel.addChild(new Text3DOverlay({
|
||||
text: "TEXT",
|
||||
isFacingAvatar: false,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
offsetPosition: {
|
||||
x: 0.1,
|
||||
y: -0.15,
|
||||
z: 0.001
|
||||
},
|
||||
dimensions: { x: textWidth, y: textHeight },
|
||||
backgroundColor: { red: 0, green: 0, blue: 0 },
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
topMargin: textMargin,
|
||||
leftMargin: textMargin,
|
||||
bottomMargin: textMargin,
|
||||
rightMargin: textMargin,
|
||||
lineHeight: lineHeight,
|
||||
alpha: 0.9,
|
||||
backgroundAlpha: 0.9
|
||||
}));
|
||||
|
||||
var redDot = mainPanel.addChild(new Image3DOverlay({
|
||||
url: RED_DOT_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
|
@ -71,7 +94,7 @@ var redDot = mainPanel.addChild(new BillboardOverlay({
|
|||
}
|
||||
}));
|
||||
|
||||
var redDot2 = mainPanel.addChild(new BillboardOverlay({
|
||||
var redDot2 = mainPanel.addChild(new Image3DOverlay({
|
||||
url: RED_DOT_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
|
@ -87,46 +110,45 @@ var redDot2 = mainPanel.addChild(new BillboardOverlay({
|
|||
}
|
||||
}));
|
||||
|
||||
var blueSquare = bluePanel.addChild(new BillboardOverlay({
|
||||
var blueSquare = bluePanel.addChild(new Image3DOverlay({
|
||||
url: BLUE_SQUARE_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
x: 0.15,
|
||||
y: 0.15,
|
||||
},
|
||||
isFacingAvatar: false,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
offsetPosition: {
|
||||
x: 0.055,
|
||||
y: -0.055,
|
||||
x: 0.09,
|
||||
y: -0.09,
|
||||
z: 0
|
||||
}
|
||||
}));
|
||||
|
||||
var blueSquare2 = bluePanel.addChild(new BillboardOverlay({
|
||||
var blueSquare2 = bluePanel.addChild(new Image3DOverlay({
|
||||
url: BLUE_SQUARE_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
x: 0.15,
|
||||
y: 0.15,
|
||||
},
|
||||
isFacingAvatar: false,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
offsetPosition: {
|
||||
x: 0.055,
|
||||
y: 0.055,
|
||||
x: 0.09,
|
||||
y: 0.09,
|
||||
z: 0
|
||||
}
|
||||
}));
|
||||
|
||||
var blueSquare3 = blueSquare2.clone();
|
||||
blueSquare3.offsetPosition = {
|
||||
x: -0.055,
|
||||
y: 0.055,
|
||||
x: -0.09,
|
||||
y: 0.09,
|
||||
z: 0
|
||||
};
|
||||
|
||||
|
||||
var mouseDown = {};
|
||||
|
||||
function onMouseDown(event) {
|
||||
|
@ -136,26 +158,30 @@ function onMouseDown(event) {
|
|||
if (event.isRightButton) {
|
||||
mouseDown.pos = { x: event.x, y: event.y };
|
||||
}
|
||||
mouseDown.maxDistance = 0;
|
||||
}
|
||||
|
||||
function onMouseMove(event) {
|
||||
if (mouseDown.maxDistance !== undefined) {
|
||||
var dist = Vec3.distance(mouseDown.pos, { x: event.x, y: event.y });
|
||||
if (dist > mouseDown.maxDistance) {
|
||||
mouseDown.maxDistance = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseUp(event) {
|
||||
if (event.isLeftButton) {
|
||||
var overlay = OverlayManager.findAtPoint({ x: event.x, y: event.y });
|
||||
if (overlay === mouseDown.overlay) {
|
||||
if (overlay.attachedPanel === bluePanel) {
|
||||
if (overlay && overlay === mouseDown.overlay) {
|
||||
if (overlay.parentPanel === bluePanel) {
|
||||
overlay.destroy();
|
||||
} else if (overlay) {
|
||||
var oldPos = overlay.offsetPosition;
|
||||
var newPos = {
|
||||
x: Number(oldPos.x),
|
||||
y: Number(oldPos.y),
|
||||
z: Number(oldPos.z) + 0.1
|
||||
};
|
||||
overlay.offsetPosition = newPos;
|
||||
} else {
|
||||
overlay.offsetPosition = Vec3.sum(overlay.offsetPosition, { x: 0, y: 0, z: -0.1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.isRightButton && Vec3.distance(mouseDown.pos, { x: event.x, y: event.y }) < 5) {
|
||||
if (event.isRightButton && mouseDown.maxDistance < 10) {
|
||||
mainPanel.visible = !mainPanel.visible;
|
||||
}
|
||||
}
|
||||
|
@ -165,5 +191,6 @@ function onScriptEnd() {
|
|||
}
|
||||
|
||||
Controller.mousePressEvent.connect(onMouseDown);
|
||||
Controller.mouseMoveEvent.connect(onMouseMove);
|
||||
Controller.mouseReleaseEvent.connect(onMouseUp);
|
||||
Script.scriptEnding.connect(onScriptEnd);
|
||||
Script.scriptEnding.connect(onScriptEnd);
|
|
@ -362,6 +362,9 @@
|
|||
var elVoxelVolumeSizeY = document.getElementById("property-voxel-volume-size-y");
|
||||
var elVoxelVolumeSizeZ = document.getElementById("property-voxel-volume-size-z");
|
||||
var elVoxelSurfaceStyle = document.getElementById("property-voxel-surface-style");
|
||||
var elXTextureURL = document.getElementById("property-x-texture-url");
|
||||
var elYTextureURL = document.getElementById("property-y-texture-url");
|
||||
var elZTextureURL = document.getElementById("property-z-texture-url");
|
||||
|
||||
var elHyperlinkHref = document.getElementById("property-hyperlink-href");
|
||||
var elHyperlinkDescription = document.getElementById("property-hyperlink-description");
|
||||
|
@ -614,6 +617,9 @@
|
|||
elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2);
|
||||
elVoxelVolumeSizeZ.value = properties.voxelVolumeSize.z.toFixed(2);
|
||||
elVoxelSurfaceStyle.value = properties.voxelSurfaceStyle;
|
||||
elXTextureURL.value = properties.xTextureURL;
|
||||
elYTextureURL.value = properties.yTextureURL;
|
||||
elZTextureURL.value = properties.zTextureURL;
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
|
@ -867,6 +873,9 @@
|
|||
elVoxelVolumeSizeY.addEventListener('change', voxelVolumeSizeChangeFunction);
|
||||
elVoxelVolumeSizeZ.addEventListener('change', voxelVolumeSizeChangeFunction);
|
||||
elVoxelSurfaceStyle.addEventListener('change', createEmitTextPropertyUpdateFunction('voxelSurfaceStyle'));
|
||||
elXTextureURL.addEventListener('change', createEmitTextPropertyUpdateFunction('xTextureURL'));
|
||||
elYTextureURL.addEventListener('change', createEmitTextPropertyUpdateFunction('yTextureURL'));
|
||||
elZTextureURL.addEventListener('change', createEmitTextPropertyUpdateFunction('zTextureURL'));
|
||||
|
||||
elMoveSelectionToGrid.addEventListener("click", function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
|
@ -1063,7 +1072,22 @@
|
|||
<option value='0'>marching cubes</option>
|
||||
<option value='1'>cubic</option>
|
||||
<option value='2'>edged cubic</option>
|
||||
</select>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="label">X-axis Texture URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-x-texture-url" class="url"></input>
|
||||
</div>
|
||||
|
||||
<div class="label">Y-axis Texture URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-y-texture-url" class="url"></input>
|
||||
</div>
|
||||
|
||||
<div class="label">Z-axis Texture URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-z-texture-url" class="url"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -98,8 +98,8 @@ EntityPropertyDialogBox = (function () {
|
|||
index++;
|
||||
}
|
||||
|
||||
if (properties.type == "PolyVox") {
|
||||
array.push({ label: "Voxel Space Size:", type: "header" });
|
||||
if (properties.type == "PolyVox") {
|
||||
array.push({ label: "Voxel Space Size:", type: "header" });
|
||||
index++;
|
||||
|
||||
array.push({ label: "X:", value: properties.voxelVolumeSize.x.toFixed(decimals) });
|
||||
|
@ -109,9 +109,16 @@ EntityPropertyDialogBox = (function () {
|
|||
array.push({ label: "Z:", value: properties.voxelVolumeSize.z.toFixed(decimals) });
|
||||
index++;
|
||||
|
||||
array.push({ label: "Surface Extractor", value: properties.voxelSurfaceStyle });
|
||||
index++;
|
||||
}
|
||||
array.push({ label: "Surface Extractor", value: properties.voxelSurfaceStyle });
|
||||
index++;
|
||||
|
||||
array.push({ label: "X-axis Texture URL:", value: properties.xTextureURL });
|
||||
index++;
|
||||
array.push({ label: "Y-axis Texture URL:", value: properties.yTextureURL });
|
||||
index++;
|
||||
array.push({ label: "Z-axis Texture URL:", value: properties.zTextureURL });
|
||||
index++;
|
||||
}
|
||||
|
||||
array.push({ label: "Position:", type: "header" });
|
||||
index++;
|
||||
|
@ -348,14 +355,17 @@ EntityPropertyDialogBox = (function () {
|
|||
properties.backgroundColor.blue = array[index++].value;
|
||||
}
|
||||
|
||||
if (properties.type == "PolyVox") {
|
||||
if (properties.type == "PolyVox") {
|
||||
properties.shapeType = array[index++].value;
|
||||
|
||||
index++; // skip header
|
||||
properties.voxelVolumeSize.x = array[index++].value;
|
||||
properties.voxelVolumeSize.y = array[index++].value;
|
||||
properties.voxelVolumeSize.z = array[index++].value;
|
||||
properties.voxelSurfaceStyle = array[index++].value;
|
||||
index++; // skip header
|
||||
properties.voxelVolumeSize.x = array[index++].value;
|
||||
properties.voxelVolumeSize.y = array[index++].value;
|
||||
properties.voxelVolumeSize.z = array[index++].value;
|
||||
properties.voxelSurfaceStyle = array[index++].value;
|
||||
properties.xTextureURL = array[index++].value;
|
||||
properties.yTextureURL = array[index++].value;
|
||||
properties.zTextureURL = array[index++].value;
|
||||
}
|
||||
|
||||
index++; // skip header
|
||||
|
|
|
@ -340,7 +340,7 @@ SelectionDisplay = (function () {
|
|||
leftMargin: 0,
|
||||
});
|
||||
|
||||
var grabberMoveUp = Overlays.addOverlay("billboard", {
|
||||
var grabberMoveUp = Overlays.addOverlay("image3d", {
|
||||
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.svg",
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: handleColor,
|
||||
|
@ -609,7 +609,7 @@ SelectionDisplay = (function () {
|
|||
minorTickMarksColor: { red: 0, green: 0, blue: 0 },
|
||||
});
|
||||
|
||||
var yawHandle = Overlays.addOverlay("billboard", {
|
||||
var yawHandle = Overlays.addOverlay("image3d", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: handleColor,
|
||||
|
@ -622,7 +622,7 @@ SelectionDisplay = (function () {
|
|||
});
|
||||
|
||||
|
||||
var pitchHandle = Overlays.addOverlay("billboard", {
|
||||
var pitchHandle = Overlays.addOverlay("image3d", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: handleColor,
|
||||
|
@ -635,7 +635,7 @@ SelectionDisplay = (function () {
|
|||
});
|
||||
|
||||
|
||||
var rollHandle = Overlays.addOverlay("billboard", {
|
||||
var rollHandle = Overlays.addOverlay("image3d", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: handleColor,
|
||||
|
|
|
@ -61,7 +61,7 @@ LightOverlayManager = function() {
|
|||
// Allocate or get an unused overlay
|
||||
function getOverlay() {
|
||||
if (unusedOverlays.length == 0) {
|
||||
var overlay = Overlays.addOverlay("billboard", {
|
||||
var overlay = Overlays.addOverlay("image3d", {
|
||||
});
|
||||
allOverlays.push(overlay);
|
||||
} else {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// Manage overlays with object oriented goodness, instead of ugly `Overlays.h` methods.
|
||||
// Instead of:
|
||||
//
|
||||
// var billboard = Overlays.addOverlay("billboard", { visible: false });
|
||||
// var billboard = Overlays.addOverlay("image3d", { visible: false });
|
||||
// ...
|
||||
// Overlays.editOverlay(billboard, { visible: true });
|
||||
// ...
|
||||
|
@ -16,7 +16,7 @@
|
|||
//
|
||||
// You can now do:
|
||||
//
|
||||
// var billboard = new BillboardOverlay({ visible: false });
|
||||
// var billboard = new Image3DOverlay({ visible: false });
|
||||
// ...
|
||||
// billboard.visible = true;
|
||||
// ...
|
||||
|
@ -42,7 +42,18 @@
|
|||
var panels = {};
|
||||
|
||||
var overlayTypes;
|
||||
var Overlay, Overlay2D, Base3DOverlay, Planar3DOverlay, Volume3DOverlay;
|
||||
|
||||
// Abstract overlay types
|
||||
var Overlay,
|
||||
Overlay2D,
|
||||
Base3DOverlay,
|
||||
Planar3DOverlay,
|
||||
Billboard3DOverlay,
|
||||
Volume3DOverlay;
|
||||
|
||||
// Multiple inheritance mixins
|
||||
var PanelAttachable,
|
||||
Billboardable;
|
||||
|
||||
|
||||
//
|
||||
|
@ -55,10 +66,6 @@
|
|||
}
|
||||
var overlay = new overlayTypes[type]();
|
||||
overlay._id = id;
|
||||
var panelID = Overlays.getAttachedPanel(id)
|
||||
if (panelID && panelID in panels) {
|
||||
panels[panelID].addChild(overlay);
|
||||
}
|
||||
overlays[id] = overlay;
|
||||
return overlay;
|
||||
}
|
||||
|
@ -74,7 +81,7 @@
|
|||
//
|
||||
function findOverlay(id, knownOverlaysOnly, searchList) {
|
||||
if (id > 0) {
|
||||
knownOverlaysOnly = Boolean(knownOverlaysOnly) || Boolean(searchList);
|
||||
knownOverlaysOnly = Boolean(knownOverlaysOnly);
|
||||
searchList = searchList || overlays;
|
||||
var foundOverlay = searchList[id];
|
||||
if (foundOverlay) {
|
||||
|
@ -87,6 +94,48 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a new JavaScript object for a panel of given ID.
|
||||
//
|
||||
function makePanelFromId(id) {
|
||||
if (!Overlays.isAddedPanel(id)) {
|
||||
return null;
|
||||
}
|
||||
var panel = new OverlayPanel();
|
||||
panel._id = id;
|
||||
overlays[id] = overlay;
|
||||
return overlay;
|
||||
}
|
||||
|
||||
//
|
||||
// Get or create a panel object from the id.
|
||||
//
|
||||
// @param knownOverlaysOnly (Optional: Boolean)
|
||||
// If true, a new object will not be created.
|
||||
// @param searchList (Optional: Object)
|
||||
// Map of overlay id's and overlay objects. Can be generated with
|
||||
// `OverlayManager.makeSearchList`.
|
||||
//
|
||||
function findPanel(id, knownPanelsOnly, searchList) {
|
||||
if (id > 0) {
|
||||
knownPanelsOnly = Boolean(knownPanelsOnly);
|
||||
searchList = searchList || panels;
|
||||
var foundPanel = searchList[id];
|
||||
if (foundPanel) {
|
||||
return foundPanel;
|
||||
}
|
||||
if (!knownPanelsOnly) {
|
||||
return makePanelFromId(id);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findOverlayOrPanel(id, knownObjectsOnly, searchList) {
|
||||
return findOverlay(id, knownObjectsOnly, searchList) ||
|
||||
findPanel(id, knownObjectsOnly, searchList);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Perform global scoped operations on overlays, such as finding by ray intersection.
|
||||
|
@ -94,7 +143,6 @@
|
|||
OverlayManager = {
|
||||
findOnRay: function(pickRay, knownOverlaysOnly, searchList) {
|
||||
var rayPickResult = Overlays.findRayIntersection(pickRay);
|
||||
print("raypick " + rayPickResult.overlayID);
|
||||
if (rayPickResult.intersects) {
|
||||
return findOverlay(rayPickResult.overlayID, knownOverlaysOnly, searchList);
|
||||
}
|
||||
|
@ -102,7 +150,6 @@
|
|||
},
|
||||
findAtPoint: function(point, knownOverlaysOnly, searchList) {
|
||||
var foundID = Overlays.getOverlayAtPoint(point);
|
||||
print("at point " + foundID);
|
||||
if (foundID) {
|
||||
return findOverlay(foundID, knownOverlaysOnly, searchList);
|
||||
} else {
|
||||
|
@ -110,10 +157,10 @@
|
|||
return OverlayManager.findOnRay(pickRay, knownOverlaysOnly, searchList);
|
||||
}
|
||||
},
|
||||
makeSearchList: function(overlayArray) {
|
||||
makeSearchList: function(array) {
|
||||
var searchList = {};
|
||||
overlayArray.forEach(function(overlay){
|
||||
searchList[overlay._id] = overlay;
|
||||
array.forEach(function(object) {
|
||||
searchList[object._id] = object;
|
||||
});
|
||||
return searchList;
|
||||
}
|
||||
|
@ -125,7 +172,7 @@
|
|||
//
|
||||
// Usage:
|
||||
// // Create an overlay
|
||||
// var billboard = new BillboardOverlay({
|
||||
// var billboard = new Image3DOverlay({
|
||||
// visible: true,
|
||||
// isFacingAvatar: true,
|
||||
// ignoreRayIntersections: false
|
||||
|
@ -191,10 +238,6 @@
|
|||
return that;
|
||||
}
|
||||
|
||||
// Supports multiple inheritance of properties. Just `concat` them onto the end of the
|
||||
// properties list.
|
||||
var PANEL_ATTACHABLE_FIELDS = ["offsetPosition", "facingRotation"];
|
||||
|
||||
Overlay = (function() {
|
||||
var that = function(type, params) {
|
||||
if (type && params) {
|
||||
|
@ -203,7 +246,6 @@
|
|||
} else {
|
||||
this._id = 0;
|
||||
}
|
||||
this._attachedPanelPointer = null;
|
||||
};
|
||||
|
||||
that.prototype.constructor = that;
|
||||
|
@ -214,9 +256,9 @@
|
|||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(that.prototype, "attachedPanel", {
|
||||
Object.defineProperty(that.prototype, "parentPanel", {
|
||||
get: function() {
|
||||
return this._attachedPanelPointer;
|
||||
return findPanel(Overlays.getParentPanel(this._id));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -236,12 +278,21 @@
|
|||
Overlays.deleteOverlay(this._id);
|
||||
};
|
||||
|
||||
that.prototype.isPanelAttachable = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
return generateOverlayClass(that, ABSTRACT, [
|
||||
"alpha", "glowLevel", "pulseMax", "pulseMin", "pulsePeriod", "glowLevelPulse",
|
||||
"alphaPulse", "colorPulse", "visible", "anchor"
|
||||
]);
|
||||
})();
|
||||
|
||||
// Supports multiple inheritance of properties. Just `concat` them onto the end of the
|
||||
// properties list.
|
||||
PanelAttachable = ["offsetPosition", "offsetRotation", "offsetScale"];
|
||||
Billboardable = ["isFacingAvatar"];
|
||||
|
||||
Overlay2D = generateOverlayClass(Overlay, ABSTRACT, [
|
||||
"bounds", "x", "y", "width", "height"
|
||||
]);
|
||||
|
@ -255,6 +306,10 @@
|
|||
"dimensions"
|
||||
]);
|
||||
|
||||
Billboard3DOverlay = generateOverlayClass(Planar3DOverlay, ABSTRACT, [
|
||||
].concat(PanelAttachable).concat(Billboardable));
|
||||
Billboard3DOverlay.prototype.isPanelAttachable = function() { return true; };
|
||||
|
||||
Volume3DOverlay = generateOverlayClass(Base3DOverlay, ABSTRACT, [
|
||||
"dimensions"
|
||||
]);
|
||||
|
@ -263,13 +318,17 @@
|
|||
"subImage", "imageURL"
|
||||
]);
|
||||
|
||||
generateOverlayClass(Billboard3DOverlay, "image3d", [
|
||||
"url", "subImage"
|
||||
]);
|
||||
|
||||
generateOverlayClass(Overlay2D, "text", [
|
||||
"font", "text", "backgroundColor", "backgroundAlpha", "leftMargin", "topMargin"
|
||||
]);
|
||||
|
||||
generateOverlayClass(Planar3DOverlay, "text3d", [
|
||||
generateOverlayClass(Billboard3DOverlay, "text3d", [
|
||||
"text", "backgroundColor", "backgroundAlpha", "lineHeight", "leftMargin", "topMargin",
|
||||
"rightMargin", "bottomMargin", "isFacingAvatar"
|
||||
"rightMargin", "bottomMargin"
|
||||
]);
|
||||
|
||||
generateOverlayClass(Volume3DOverlay, "cube", [
|
||||
|
@ -302,13 +361,10 @@
|
|||
generateOverlayClass(Volume3DOverlay, "model", [
|
||||
"url", "dimensions", "textures"
|
||||
]);
|
||||
|
||||
generateOverlayClass(Planar3DOverlay, "billboard", [
|
||||
"url", "subImage", "isFacingAvatar"
|
||||
].concat(PANEL_ATTACHABLE_FIELDS));
|
||||
})();
|
||||
|
||||
ImageOverlay = overlayTypes["image"];
|
||||
Image3DOverlay = overlayTypes["image3d"];
|
||||
TextOverlay = overlayTypes["text"];
|
||||
Text3DOverlay = overlayTypes["text3d"];
|
||||
Cube3DOverlay = overlayTypes["cube"];
|
||||
|
@ -319,25 +375,24 @@
|
|||
Grid3DOverlay = overlayTypes["grid"];
|
||||
LocalModelsOverlay = overlayTypes["localmodels"];
|
||||
ModelOverlay = overlayTypes["model"];
|
||||
BillboardOverlay = overlayTypes["billboard"];
|
||||
|
||||
|
||||
//
|
||||
// Object oriented abstraction layer for panels.
|
||||
//
|
||||
FloatingUIPanel = (function() {
|
||||
OverlayPanel = (function() {
|
||||
var that = function(params) {
|
||||
this._id = Overlays.addPanel(params);
|
||||
this._children = [];
|
||||
this._visible = Boolean(params.visible);
|
||||
panels[this._id] = this;
|
||||
this._attachedPanelPointer = null;
|
||||
};
|
||||
|
||||
that.prototype.constructor = that;
|
||||
|
||||
var FIELDS = ["offsetPosition", "offsetRotation", "facingRotation"];
|
||||
FIELDS.forEach(function(prop) {
|
||||
var props = [
|
||||
"anchorPosition", "anchorPositionBinding", "anchorRotation", "anchorRotationBinding", "anchorScale", "visible"
|
||||
].concat(PanelAttachable).concat(Billboardable)
|
||||
|
||||
props.forEach(function(prop) {
|
||||
Object.defineProperty(that.prototype, prop, {
|
||||
get: function() {
|
||||
return Overlays.getPanelProperty(this._id, prop);
|
||||
|
@ -351,78 +406,47 @@
|
|||
});
|
||||
});
|
||||
|
||||
var PSEUDO_FIELDS = [];
|
||||
|
||||
PSEUDO_FIELDS.push("children");
|
||||
Object.defineProperty(that.prototype, "children", {
|
||||
Object.defineProperty(that.prototype, "parentPanel", {
|
||||
get: function() {
|
||||
return this._children.slice();
|
||||
return findPanel(Overlays.getParentPanel(this._id));
|
||||
}
|
||||
});
|
||||
|
||||
PSEUDO_FIELDS.push("visible");
|
||||
Object.defineProperty(that.prototype, "visible", {
|
||||
Object.defineProperty(that.prototype, "children", {
|
||||
get: function() {
|
||||
return this._visible;
|
||||
},
|
||||
set: function(visible) {
|
||||
this._visible = visible;
|
||||
this._children.forEach(function(child) {
|
||||
child.visible = visible;
|
||||
});
|
||||
var idArray = Overlays.getPanelProperty(this._id, "children");
|
||||
var objArray = [];
|
||||
for (var i = 0; i < idArray.length; i++) {
|
||||
objArray[i] = findOverlayOrPanel(idArray[i]);
|
||||
}
|
||||
return objArray;
|
||||
}
|
||||
});
|
||||
|
||||
that.prototype.addChild = function(child) {
|
||||
if (child instanceof Overlay) {
|
||||
Overlays.setAttachedPanel(child._id, this._id);
|
||||
} else if (child instanceof FloatingUIPanel) {
|
||||
child.setProperties({
|
||||
anchorPosition: {
|
||||
bind: "panel",
|
||||
value: this._id
|
||||
},
|
||||
offsetRotation: {
|
||||
bind: "panel",
|
||||
value: this._id
|
||||
}
|
||||
});
|
||||
}
|
||||
child._attachedPanelPointer = this;
|
||||
child.visible = this.visible;
|
||||
this._children.push(child);
|
||||
Overlays.setParentPanel(child._id, this._id);
|
||||
return child;
|
||||
};
|
||||
|
||||
that.prototype.removeChild = function(child) {
|
||||
var i = this._children.indexOf(child);
|
||||
if (i >= 0) {
|
||||
if (child instanceof Overlay) {
|
||||
Overlays.setAttachedPanel(child._id, 0);
|
||||
} else if (child instanceof FloatingUIPanel) {
|
||||
child.setProperties({
|
||||
anchorPosition: {
|
||||
bind: "myAvatar"
|
||||
},
|
||||
offsetRotation: {
|
||||
bind: "myAvatar"
|
||||
}
|
||||
});
|
||||
}
|
||||
child._attachedPanelPointer = null;
|
||||
this._children.splice(i, 1);
|
||||
if (child.parentPanel === this) {
|
||||
Overlays.setParentPanel(child._id, 0);
|
||||
}
|
||||
};
|
||||
|
||||
that.prototype.setProperties = function(properties) {
|
||||
for (var i in PSEUDO_FIELDS) {
|
||||
if (properties[PSEUDO_FIELDS[i]] !== undefined) {
|
||||
this[PSEUDO_FIELDS[i]] = properties[PSEUDO_FIELDS[i]];
|
||||
}
|
||||
}
|
||||
Overlays.editPanel(this._id, properties);
|
||||
};
|
||||
|
||||
that.prototype.setChildrenVisible = function() {
|
||||
this.children.forEach(function(child) {
|
||||
child.visible = true;
|
||||
if (child.setChildrenVisible !== undefined) {
|
||||
child.setChildrenVisible();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
that.prototype.destroy = function() {
|
||||
Overlays.deletePanel(this._id);
|
||||
};
|
||||
|
@ -433,8 +457,8 @@
|
|||
|
||||
function onOverlayDeleted(id) {
|
||||
if (id in overlays) {
|
||||
if (overlays[id]._attachedPanelPointer) {
|
||||
overlays[id]._attachedPanelPointer.removeChild(overlays[id]);
|
||||
if (overlays[id].parentPanel) {
|
||||
overlays[id].parentPanel.removeChild(overlays[id]);
|
||||
}
|
||||
delete overlays[id];
|
||||
}
|
||||
|
@ -442,10 +466,9 @@
|
|||
|
||||
function onPanelDeleted(id) {
|
||||
if (id in panels) {
|
||||
panels[id]._children.forEach(function(child) {
|
||||
print(JSON.stringify(child.destroy));
|
||||
child.destroy();
|
||||
});
|
||||
if (panels[id].parentPanel) {
|
||||
panels[id].parentPanel.removeChild(panels[id]);
|
||||
}
|
||||
delete panels[id];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ KeyboardKey = (function(keyboard, keyProperties) {
|
|||
};
|
||||
for (var i = 0; i < this.bounds.length; i++) {
|
||||
if (THREE_D_MODE) {
|
||||
this.overlays.push(Overlays.addOverlay("billboard", {
|
||||
this.overlays.push(Overlays.addOverlay("image3d", {
|
||||
scale: 1,
|
||||
rotation: MyAvatar.rotation,
|
||||
isFacingAvatar: false,
|
||||
|
@ -202,7 +202,7 @@ Keyboard = (function(params) {
|
|||
return windowDimensions.y - this.height();
|
||||
};
|
||||
if (THREE_D_MODE) {
|
||||
this.background = Overlays.addOverlay("billboard", {
|
||||
this.background = Overlays.addOverlay("image3d", {
|
||||
scale: 1,
|
||||
position: MyAvatar.position,
|
||||
rotation: MyAvatar.rotation,
|
||||
|
|
|
@ -260,7 +260,7 @@ function notify(notice, button, height) {
|
|||
positions = calculate3DOverlayPositions(noticeWidth, noticeHeight, notice.y);
|
||||
|
||||
notifications.push((Overlays.addOverlay("text3d", notice)));
|
||||
buttons.push((Overlays.addOverlay("billboard", button)));
|
||||
buttons.push((Overlays.addOverlay("image3d", button)));
|
||||
overlay3DDetails.push({
|
||||
notificationOrientation: positions.notificationOrientation,
|
||||
notificationPosition: positions.notificationPosition,
|
||||
|
|
|
@ -117,7 +117,7 @@
|
|||
visible: false,
|
||||
ignoreRayIntersection: true
|
||||
});
|
||||
bar3D.overlay = Overlays.addOverlay("billboard", {
|
||||
bar3D.overlay = Overlays.addOverlay("image3d", {
|
||||
url: BAR_URL,
|
||||
subImage: { x: BAR_WIDTH, y: 0, width: BAR_WIDTH, height: BAR_HEIGHT },
|
||||
scale: SCALE_3D * BAR_WIDTH,
|
||||
|
|
|
@ -175,7 +175,7 @@ function SeatIndicator(modelProperties, seatIndex) {
|
|||
modelProperties.sittingPoints[seatIndex].rotation);
|
||||
this.scale = MyAvatar.scale / 12;
|
||||
|
||||
this.sphere = Overlays.addOverlay("billboard", {
|
||||
this.sphere = Overlays.addOverlay("image3d", {
|
||||
subImage: { x: 0, y: buttonHeight, width: buttonWidth, height: buttonHeight},
|
||||
url: buttonImageUrl,
|
||||
position: this.position,
|
||||
|
|
|
@ -44,7 +44,7 @@ function mousePressEvent(event) {
|
|||
}
|
||||
}
|
||||
|
||||
// if the PolyVox entity is empty, we can't pick against its voxel. try picking against its
|
||||
// if the PolyVox entity is empty, we can't pick against its "on" voxels. try picking against its
|
||||
// bounding box, instead.
|
||||
intersection = Entities.findRayIntersection(pickRay, false); // bounding box picking
|
||||
if (intersection.intersects) {
|
||||
|
|
|
@ -3335,16 +3335,6 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom
|
|||
}
|
||||
}
|
||||
|
||||
bool Application::getShadowsEnabled() {
|
||||
Menu* menubar = Menu::getInstance();
|
||||
return menubar->isOptionChecked(MenuOption::SimpleShadows) ||
|
||||
menubar->isOptionChecked(MenuOption::CascadedShadows);
|
||||
}
|
||||
|
||||
bool Application::getCascadeShadowsEnabled() {
|
||||
return Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows);
|
||||
}
|
||||
|
||||
glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
|
||||
float horizontalScale = _glWidget->getDeviceWidth() / 2.0f;
|
||||
float verticalScale = _glWidget->getDeviceHeight() / 2.0f;
|
||||
|
|
|
@ -268,8 +268,6 @@ public:
|
|||
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const;
|
||||
|
||||
virtual ViewFrustum* getCurrentViewFrustum() { return getDisplayViewFrustum(); }
|
||||
virtual bool getShadowsEnabled();
|
||||
virtual bool getCascadeShadowsEnabled();
|
||||
virtual QThread* getMainThread() { return thread(); }
|
||||
virtual float getSizeScale() const;
|
||||
virtual int getBoundaryLevelAdjust() const;
|
||||
|
|
|
@ -346,12 +346,6 @@ Menu::Menu() {
|
|||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false));
|
||||
|
||||
MenuWrapper* shadowMenu = renderOptionsMenu->addMenu("Shadows");
|
||||
QActionGroup* shadowGroup = new QActionGroup(shadowMenu);
|
||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true));
|
||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false));
|
||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false));
|
||||
|
||||
{
|
||||
MenuWrapper* framerateMenu = renderOptionsMenu->addMenu(MenuOption::RenderTargetFramerate);
|
||||
QActionGroup* framerateGroup = new QActionGroup(framerateMenu);
|
||||
|
|
|
@ -154,7 +154,6 @@ namespace MenuOption {
|
|||
const QString BlueSpeechSphere = "Blue Sphere While Speaking";
|
||||
const QString BookmarkLocation = "Bookmark Location";
|
||||
const QString Bookmarks = "Bookmarks";
|
||||
const QString CascadedShadows = "Cascaded";
|
||||
const QString CachesSize = "RAM Caches Size";
|
||||
const QString CalibrateCamera = "Calibrate Camera";
|
||||
const QString CenterPlayerInView = "Center Player In View";
|
||||
|
@ -271,7 +270,6 @@ namespace MenuOption {
|
|||
const QString ShowIKConstraints = "Show IK Constraints";
|
||||
const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats";
|
||||
const QString ShowWhosLookingAtMe = "Show Who's Looking at Me";
|
||||
const QString SimpleShadows = "Simple";
|
||||
const QString SixenseEnabled = "Enable Hydra Support";
|
||||
const QString SixenseMouseInput = "Enable Sixense Mouse Input";
|
||||
const QString Stars = "Stars";
|
||||
|
|
|
@ -717,6 +717,29 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, floa
|
|||
|
||||
// Compute correct scale to apply
|
||||
float scale = DESIRED_HIGHT_ON_SCREEN / (fontSize * pixelHeight) * devicePixelRatio;
|
||||
#ifdef DEBUG
|
||||
// TODO: Temporary logging to track cause of invalid scale vale; remove once cause has been fixed.
|
||||
if (scale == 0.0f || glm::isnan(scale) || glm::isinf(scale)) {
|
||||
if (scale == 0.0f) {
|
||||
qDebug() << "ASSERT because scale == 0.0f";
|
||||
}
|
||||
if (glm::isnan(scale)) {
|
||||
qDebug() << "ASSERT because isnan(scale)";
|
||||
}
|
||||
if (glm::isinf(scale)) {
|
||||
qDebug() << "ASSERT because isinf(scale)";
|
||||
}
|
||||
qDebug() << "windowSizeY =" << windowSizeY;
|
||||
qDebug() << "p1.y =" << p1.y;
|
||||
qDebug() << "p1.w =" << p1.w;
|
||||
qDebug() << "p0.y =" << p0.y;
|
||||
qDebug() << "p0.w =" << p0.w;
|
||||
qDebug() << "qApp->getDevicePixelRatio() =" << qApp->getDevicePixelRatio();
|
||||
qDebug() << "fontSize =" << fontSize;
|
||||
qDebug() << "pixelHeight =" << pixelHeight;
|
||||
qDebug() << "devicePixelRatio =" << devicePixelRatio;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Compute pixel alignment offset
|
||||
float clipToPix = 0.5f * windowSizeY / p1.w; // Got from clip to pixel coordinates
|
||||
|
|
|
@ -56,12 +56,12 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
}
|
||||
}
|
||||
|
||||
void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index) {
|
||||
void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const JointState& state, int index) {
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
glm::mat3 axes = glm::mat3_cast(glm::quat());
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() *
|
||||
glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||
state.getPreTransform() * glm::mat4_cast(state.getPreRotation())));
|
||||
glm::vec3 pitchYawRoll = safeEulerAngles(_owningHead->getFinalOrientationInLocalFrame());
|
||||
glm::vec3 lean = glm::radians(glm::vec3(_owningHead->getFinalLeanForward(),
|
||||
_owningHead->getTorsoTwist(),
|
||||
|
@ -71,15 +71,15 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
|
|||
glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2]))
|
||||
* glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1]))
|
||||
* glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0]))
|
||||
* joint.rotation, DEFAULT_PRIORITY);
|
||||
* state.getDefaultRotation(), DEFAULT_PRIORITY);
|
||||
}
|
||||
|
||||
void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, int index) {
|
||||
void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const JointState& state, int index) {
|
||||
// likewise with the eye joints
|
||||
// NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual.
|
||||
glm::mat4 inverse = glm::inverse(glm::mat4_cast(model->getRotation()) * parentState.getTransform() *
|
||||
glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation));
|
||||
state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getDefaultRotation()));
|
||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientationInWorldFrame() * IDENTITY_FRONT, 0.0f));
|
||||
glm::vec3 lookAtDelta = _owningHead->getCorrectedLookAtPosition() - model->getTranslation();
|
||||
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * _owningHead->getSaccade(), 1.0f));
|
||||
|
@ -87,22 +87,22 @@ void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentSta
|
|||
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE;
|
||||
_rig->setJointRotationInConstrainedFrame(index, glm::angleAxis(glm::clamp(glm::angle(between),
|
||||
-MAX_ANGLE, MAX_ANGLE), glm::axis(between)) *
|
||||
joint.rotation, DEFAULT_PRIORITY);
|
||||
state.getDefaultRotation(), DEFAULT_PRIORITY);
|
||||
}
|
||||
|
||||
void FaceModel::maybeUpdateNeckAndEyeRotation(int index) {
|
||||
const JointState& state = _rig->getJointState(index);
|
||||
const FBXJoint& joint = state.getFBXJoint();
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const int parentIndex = state.getParentIndex();
|
||||
|
||||
// guard against out-of-bounds access to _jointStates
|
||||
if (joint.parentIndex != -1 && joint.parentIndex >= 0 && joint.parentIndex < _rig->getJointStateCount()) {
|
||||
const JointState& parentState = _rig->getJointState(joint.parentIndex);
|
||||
if (parentIndex != -1 && parentIndex >= 0 && parentIndex < _rig->getJointStateCount()) {
|
||||
const JointState& parentState = _rig->getJointState(parentIndex);
|
||||
if (index == geometry.neckJointIndex) {
|
||||
maybeUpdateNeckRotation(parentState, joint, index);
|
||||
maybeUpdateNeckRotation(parentState, state, index);
|
||||
|
||||
} else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) {
|
||||
maybeUpdateEyeRotation(this, parentState, joint, index);
|
||||
maybeUpdateEyeRotation(this, parentState, state, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ public:
|
|||
|
||||
virtual void simulate(float deltaTime, bool fullUpdate = true);
|
||||
|
||||
void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index);
|
||||
void maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, int index);
|
||||
void maybeUpdateNeckRotation(const JointState& parentState, const JointState& state, int index);
|
||||
void maybeUpdateEyeRotation(Model* model, const JointState& parentState, const JointState& state, int index);
|
||||
void maybeUpdateNeckAndEyeRotation(int index);
|
||||
|
||||
/// Retrieve the positions of up to two eye meshes.
|
||||
|
|
|
@ -402,7 +402,7 @@ bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckP
|
|||
glm::quat worldFrameRotation;
|
||||
bool success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation);
|
||||
if (success) {
|
||||
neckParentRotation = worldFrameRotation * _rig->getJointState(parentIndex).getFBXJoint().inverseDefaultRotation;
|
||||
neckParentRotation = worldFrameRotation * _rig->getJointState(parentIndex).getInverseDefaultRotation();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
@ -478,18 +478,17 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
|
|||
for (int i = 0; i < numStates; i++) {
|
||||
// compute the default transform of this joint
|
||||
const JointState& state = _rig->getJointState(i);
|
||||
const FBXJoint& joint = state.getFBXJoint();
|
||||
int parentIndex = joint.parentIndex;
|
||||
int parentIndex = state.getParentIndex();
|
||||
if (parentIndex == -1) {
|
||||
transforms[i] = _rig->getJointTransform(i);
|
||||
} else {
|
||||
glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation;
|
||||
transforms[i] = transforms[parentIndex] * glm::translate(joint.translation)
|
||||
* joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform;
|
||||
glm::quat modifiedRotation = state.getPreRotation() * state.getDefaultRotation() * state.getPostRotation();
|
||||
transforms[i] = transforms[parentIndex] * glm::translate(state.getTranslation())
|
||||
* state.getPreTransform() * glm::mat4_cast(modifiedRotation) * state.getPostTransform();
|
||||
}
|
||||
|
||||
// Each joint contributes a sphere at its position
|
||||
glm::vec3 axis(joint.boneRadius);
|
||||
glm::vec3 axis(state.getBoneRadius());
|
||||
glm::vec3 jointPosition = extractTranslation(transforms[i]);
|
||||
totalExtents.addPoint(jointPosition + axis);
|
||||
totalExtents.addPoint(jointPosition - axis);
|
||||
|
|
|
@ -115,6 +115,8 @@ void LodToolsDialog::reject() {
|
|||
void LodToolsDialog::closeEvent(QCloseEvent* event) {
|
||||
this->QDialog::closeEvent(event);
|
||||
emit closed();
|
||||
|
||||
#if RESET_TO_AUTOMATIC_WHEN_YOU_CLOSE_THE_DIALOG_BOX
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
|
||||
// always revert back to automatic LOD adjustment when closed
|
||||
|
@ -124,6 +126,7 @@ void LodToolsDialog::closeEvent(QCloseEvent* event) {
|
|||
if (lodManager->getOctreeSizeScale() > DEFAULT_OCTREE_SIZE_SCALE) {
|
||||
lodManager->setOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
46
interface/src/ui/overlays/Billboard3DOverlay.cpp
Normal file
46
interface/src/ui/overlays/Billboard3DOverlay.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// Billboard3DOverlay.cpp
|
||||
// hifi/interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 8/4/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "Billboard3DOverlay.h"
|
||||
#include "Application.h"
|
||||
|
||||
Billboard3DOverlay::Billboard3DOverlay(const Billboard3DOverlay* billboard3DOverlay) :
|
||||
Planar3DOverlay(billboard3DOverlay),
|
||||
PanelAttachable(*billboard3DOverlay),
|
||||
Billboardable(*billboard3DOverlay)
|
||||
{
|
||||
}
|
||||
|
||||
void Billboard3DOverlay::setProperties(const QScriptValue &properties) {
|
||||
Planar3DOverlay::setProperties(properties);
|
||||
PanelAttachable::setProperties(properties);
|
||||
Billboardable::setProperties(properties);
|
||||
}
|
||||
|
||||
QScriptValue Billboard3DOverlay::getProperty(const QString &property) {
|
||||
QScriptValue value;
|
||||
value = Billboardable::getProperty(_scriptEngine, property);
|
||||
if (value.isValid()) {
|
||||
return value;
|
||||
}
|
||||
value = PanelAttachable::getProperty(_scriptEngine, property);
|
||||
if (value.isValid()) {
|
||||
return value;
|
||||
}
|
||||
return Planar3DOverlay::getProperty(property);
|
||||
}
|
||||
|
||||
void Billboard3DOverlay::applyTransformTo(Transform& transform, bool force) {
|
||||
if (force || usecTimestampNow() > _transformExpiry) {
|
||||
PanelAttachable::applyTransformTo(transform, true);
|
||||
pointTransformAtCamera(transform, getOffsetRotation());
|
||||
}
|
||||
}
|
33
interface/src/ui/overlays/Billboard3DOverlay.h
Normal file
33
interface/src/ui/overlays/Billboard3DOverlay.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Billboard3DOverlay.h
|
||||
// hifi/interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 8/4/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_Billboard3DOverlay_h
|
||||
#define hifi_Billboard3DOverlay_h
|
||||
|
||||
#include "Planar3DOverlay.h"
|
||||
#include "PanelAttachable.h"
|
||||
#include "Billboardable.h"
|
||||
|
||||
class Billboard3DOverlay : public Planar3DOverlay, public PanelAttachable, public Billboardable {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Billboard3DOverlay() {}
|
||||
Billboard3DOverlay(const Billboard3DOverlay* billboard3DOverlay);
|
||||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
|
||||
protected:
|
||||
virtual void applyTransformTo(Transform& transform, bool force = false);
|
||||
};
|
||||
|
||||
#endif // hifi_Billboard3DOverlay_h
|
41
interface/src/ui/overlays/Billboardable.cpp
Normal file
41
interface/src/ui/overlays/Billboardable.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Billboardable.cpp
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 8/7/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "Billboardable.h"
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
void Billboardable::setProperties(const QScriptValue &properties) {
|
||||
QScriptValue isFacingAvatar = properties.property("isFacingAvatar");
|
||||
if (isFacingAvatar.isValid()) {
|
||||
setIsFacingAvatar(isFacingAvatar.toVariant().toBool());
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue Billboardable::getProperty(QScriptEngine* scriptEngine, const QString &property) {
|
||||
if (property == "isFacingAvatar") {
|
||||
return isFacingAvatar();
|
||||
}
|
||||
return QScriptValue();
|
||||
}
|
||||
|
||||
void Billboardable::pointTransformAtCamera(Transform& transform, glm::quat offsetRotation) {
|
||||
if (isFacingAvatar()) {
|
||||
glm::vec3 billboardPos = transform.getTranslation();
|
||||
glm::vec3 cameraPos = Application::getInstance()->getCamera()->getPosition();
|
||||
glm::vec3 look = cameraPos - billboardPos;
|
||||
float elevation = -asinf(look.y / glm::length(look));
|
||||
float azimuth = atan2f(look.x, look.z);
|
||||
glm::quat rotation(glm::vec3(elevation, azimuth, 0));
|
||||
transform.setRotation(rotation);
|
||||
transform.postRotate(offsetRotation);
|
||||
}
|
||||
}
|
35
interface/src/ui/overlays/Billboardable.h
Normal file
35
interface/src/ui/overlays/Billboardable.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// Billboardable.h
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 8/7/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_Billboardable_h
|
||||
#define hifi_Billboardable_h
|
||||
|
||||
#include <QScriptValue>
|
||||
#include <QScriptEngine>
|
||||
|
||||
#include <Transform.h>
|
||||
|
||||
class Billboardable {
|
||||
public:
|
||||
bool isFacingAvatar() const { return _isFacingAvatar; }
|
||||
void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; }
|
||||
|
||||
protected:
|
||||
void setProperties(const QScriptValue& properties);
|
||||
QScriptValue getProperty(QScriptEngine* scriptEngine, const QString& property);
|
||||
|
||||
void pointTransformAtCamera(Transform& transform, glm::quat offsetRotation = {1, 0, 0, 0});
|
||||
|
||||
private:
|
||||
bool _isFacingAvatar = false;
|
||||
};
|
||||
|
||||
#endif // hifi_Billboardable_h
|
|
@ -1,197 +0,0 @@
|
|||
//
|
||||
// FloatingUIPanel.cpp
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 7/2/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "FloatingUIPanel.h"
|
||||
|
||||
#include <QVariant>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "avatar/MyAvatar.h"
|
||||
#include "Application.h"
|
||||
#include "Base3DOverlay.h"
|
||||
|
||||
std::function<glm::vec3()> const FloatingUIPanel::AVATAR_POSITION = []() -> glm::vec3 {
|
||||
return DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition();
|
||||
};
|
||||
|
||||
std::function<glm::quat()> const FloatingUIPanel::AVATAR_ORIENTATION = []() -> glm::quat {
|
||||
return DependencyManager::get<AvatarManager>()->getMyAvatar()->getOrientation() *
|
||||
glm::angleAxis(glm::pi<float>(), IDENTITY_UP);
|
||||
};
|
||||
|
||||
glm::vec3 FloatingUIPanel::getPosition() const {
|
||||
return getOffsetRotation() * getOffsetPosition() + getAnchorPosition();
|
||||
}
|
||||
|
||||
glm::quat FloatingUIPanel::getRotation() const {
|
||||
return getOffsetRotation() * getFacingRotation();
|
||||
}
|
||||
|
||||
void FloatingUIPanel::setAnchorPosition(const glm::vec3& position) {
|
||||
setAnchorPosition([position]() -> glm::vec3 {
|
||||
return position;
|
||||
});
|
||||
}
|
||||
|
||||
void FloatingUIPanel::setOffsetRotation(const glm::quat& rotation) {
|
||||
setOffsetRotation([rotation]() -> glm::quat {
|
||||
return rotation;
|
||||
});
|
||||
}
|
||||
|
||||
void FloatingUIPanel::addChild(unsigned int childId) {
|
||||
if (!_children.contains(childId)) {
|
||||
_children.append(childId);
|
||||
}
|
||||
}
|
||||
|
||||
void FloatingUIPanel::removeChild(unsigned int childId) {
|
||||
if (_children.contains(childId)) {
|
||||
_children.removeOne(childId);
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue FloatingUIPanel::getProperty(const QString &property) {
|
||||
if (property == "anchorPosition") {
|
||||
return vec3toScriptValue(_scriptEngine, getAnchorPosition());
|
||||
}
|
||||
if (property == "offsetRotation") {
|
||||
return quatToScriptValue(_scriptEngine, getOffsetRotation());
|
||||
}
|
||||
if (property == "offsetPosition") {
|
||||
return vec3toScriptValue(_scriptEngine, getOffsetPosition());
|
||||
}
|
||||
if (property == "facingRotation") {
|
||||
return quatToScriptValue(_scriptEngine, getFacingRotation());
|
||||
}
|
||||
|
||||
return QScriptValue();
|
||||
}
|
||||
|
||||
void FloatingUIPanel::setProperties(const QScriptValue &properties) {
|
||||
QScriptValue anchor = properties.property("anchorPosition");
|
||||
if (anchor.isValid()) {
|
||||
QScriptValue bindType = anchor.property("bind");
|
||||
QScriptValue value = anchor.property("value");
|
||||
|
||||
if (bindType.isValid()) {
|
||||
QString bindTypeString = bindType.toVariant().toString();
|
||||
if (bindTypeString == "myAvatar") {
|
||||
setAnchorPosition(AVATAR_POSITION);
|
||||
} else if (value.isValid()) {
|
||||
if (bindTypeString == "overlay") {
|
||||
Overlay::Pointer overlay = Application::getInstance()->getOverlays()
|
||||
.getOverlay(value.toVariant().toUInt());
|
||||
if (overlay->is3D()) {
|
||||
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
|
||||
setAnchorPosition([&overlay3D]() -> glm::vec3 {
|
||||
return overlay3D->getPosition();
|
||||
});
|
||||
}
|
||||
} else if (bindTypeString == "panel") {
|
||||
FloatingUIPanel::Pointer panel = Application::getInstance()->getOverlays()
|
||||
.getPanel(value.toVariant().toUInt());
|
||||
setAnchorPosition([panel]() -> glm::vec3 {
|
||||
return panel->getPosition();
|
||||
});
|
||||
} else if (bindTypeString == "vec3") {
|
||||
QScriptValue x = value.property("x");
|
||||
QScriptValue y = value.property("y");
|
||||
QScriptValue z = value.property("z");
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {
|
||||
glm::vec3 newPosition;
|
||||
newPosition.x = x.toVariant().toFloat();
|
||||
newPosition.y = y.toVariant().toFloat();
|
||||
newPosition.z = z.toVariant().toFloat();
|
||||
setAnchorPosition(newPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue offsetRotation = properties.property("offsetRotation");
|
||||
if (offsetRotation.isValid()) {
|
||||
QScriptValue bindType = offsetRotation.property("bind");
|
||||
QScriptValue value = offsetRotation.property("value");
|
||||
|
||||
if (bindType.isValid()) {
|
||||
QString bindTypeString = bindType.toVariant().toString();
|
||||
if (bindTypeString == "myAvatar") {
|
||||
setOffsetRotation(AVATAR_ORIENTATION);
|
||||
} else if (value.isValid()) {
|
||||
if (bindTypeString == "overlay") {
|
||||
Overlay::Pointer overlay = Application::getInstance()->getOverlays()
|
||||
.getOverlay(value.toVariant().toUInt());
|
||||
if (overlay->is3D()) {
|
||||
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
|
||||
setOffsetRotation([&overlay3D]() -> glm::quat {
|
||||
return overlay3D->getRotation();
|
||||
});
|
||||
}
|
||||
} else if (bindTypeString == "panel") {
|
||||
FloatingUIPanel::Pointer panel = Application::getInstance()->getOverlays()
|
||||
.getPanel(value.toVariant().toUInt());
|
||||
setOffsetRotation([panel]() -> glm::quat {
|
||||
return panel->getRotation();
|
||||
});
|
||||
} else if (bindTypeString == "quat") {
|
||||
QScriptValue x = value.property("x");
|
||||
QScriptValue y = value.property("y");
|
||||
QScriptValue z = value.property("z");
|
||||
QScriptValue w = value.property("w");
|
||||
|
||||
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
|
||||
glm::quat newRotation;
|
||||
newRotation.x = x.toVariant().toFloat();
|
||||
newRotation.y = y.toVariant().toFloat();
|
||||
newRotation.z = z.toVariant().toFloat();
|
||||
newRotation.w = w.toVariant().toFloat();
|
||||
setOffsetRotation(newRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue offsetPosition = properties.property("offsetPosition");
|
||||
if (offsetPosition.isValid()) {
|
||||
QScriptValue x = offsetPosition.property("x");
|
||||
QScriptValue y = offsetPosition.property("y");
|
||||
QScriptValue z = offsetPosition.property("z");
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {
|
||||
glm::vec3 newPosition;
|
||||
newPosition.x = x.toVariant().toFloat();
|
||||
newPosition.y = y.toVariant().toFloat();
|
||||
newPosition.z = z.toVariant().toFloat();
|
||||
setOffsetPosition(newPosition);
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue facingRotation = properties.property("facingRotation");
|
||||
if (facingRotation.isValid()) {
|
||||
QScriptValue x = facingRotation.property("x");
|
||||
QScriptValue y = facingRotation.property("y");
|
||||
QScriptValue z = facingRotation.property("z");
|
||||
QScriptValue w = facingRotation.property("w");
|
||||
|
||||
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
|
||||
glm::quat newRotation;
|
||||
newRotation.x = x.toVariant().toFloat();
|
||||
newRotation.y = y.toVariant().toFloat();
|
||||
newRotation.z = z.toVariant().toFloat();
|
||||
newRotation.w = w.toVariant().toFloat();
|
||||
setFacingRotation(newRotation);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
//
|
||||
// FloatingUIPanel.h
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 7/2/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_FloatingUIPanel_h
|
||||
#define hifi_FloatingUIPanel_h
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <QScriptValue>
|
||||
|
||||
class FloatingUIPanel : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef std::shared_ptr<FloatingUIPanel> Pointer;
|
||||
|
||||
void init(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; }
|
||||
|
||||
glm::vec3 getAnchorPosition() const { return _anchorPosition(); }
|
||||
glm::quat getOffsetRotation() const { return _offsetRotation(); }
|
||||
glm::vec3 getOffsetPosition() const { return _offsetPosition; }
|
||||
glm::quat getFacingRotation() const { return _facingRotation; }
|
||||
glm::vec3 getPosition() const;
|
||||
glm::quat getRotation() const;
|
||||
|
||||
void setAnchorPosition(const std::function<glm::vec3()>& func) { _anchorPosition = func; }
|
||||
void setAnchorPosition(const glm::vec3& position);
|
||||
void setOffsetRotation(const std::function<glm::quat()>& func) { _offsetRotation = func; }
|
||||
void setOffsetRotation(const glm::quat& rotation);
|
||||
void setOffsetPosition(const glm::vec3& position) { _offsetPosition = position; }
|
||||
void setFacingRotation(const glm::quat& rotation) { _facingRotation = rotation; }
|
||||
|
||||
const QList<unsigned int>& getChildren() { return _children; }
|
||||
void addChild(unsigned int childId);
|
||||
void removeChild(unsigned int childId);
|
||||
unsigned int popLastChild() { return _children.takeLast(); }
|
||||
|
||||
QScriptValue getProperty(const QString& property);
|
||||
void setProperties(const QScriptValue& properties);
|
||||
|
||||
private:
|
||||
static std::function<glm::vec3()> const AVATAR_POSITION;
|
||||
static std::function<glm::quat()> const AVATAR_ORIENTATION;
|
||||
|
||||
std::function<glm::vec3()> _anchorPosition{AVATAR_POSITION};
|
||||
std::function<glm::quat()> _offsetRotation{AVATAR_ORIENTATION};
|
||||
glm::vec3 _offsetPosition{0, 0, 0};
|
||||
glm::quat _facingRotation{1, 0, 0, 0};
|
||||
QScriptEngine* _scriptEngine;
|
||||
QList<unsigned int> _children;
|
||||
};
|
||||
|
||||
#endif // hifi_FloatingUIPanel_h
|
|
@ -1,15 +1,16 @@
|
|||
//
|
||||
// BillboardOverlay.cpp
|
||||
// Image3DOverlay.cpp
|
||||
//
|
||||
//
|
||||
// Created by Clement on 7/1/14.
|
||||
// Modified and renamed by Zander Otavka on 8/4/15
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "BillboardOverlay.h"
|
||||
#include "Image3DOverlay.h"
|
||||
|
||||
#include <QScriptValue>
|
||||
|
||||
|
@ -17,53 +18,41 @@
|
|||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "GeometryUtil.h"
|
||||
|
||||
|
||||
QString const BillboardOverlay::TYPE = "billboard";
|
||||
QString const Image3DOverlay::TYPE = "image3d";
|
||||
|
||||
BillboardOverlay::BillboardOverlay() {
|
||||
Image3DOverlay::Image3DOverlay() {
|
||||
_isLoaded = false;
|
||||
}
|
||||
|
||||
BillboardOverlay::BillboardOverlay(const BillboardOverlay* billboardOverlay) :
|
||||
Planar3DOverlay(billboardOverlay),
|
||||
PanelAttachable(billboardOverlay),
|
||||
_url(billboardOverlay->_url),
|
||||
_texture(billboardOverlay->_texture),
|
||||
_fromImage(billboardOverlay->_fromImage),
|
||||
_isFacingAvatar(billboardOverlay->_isFacingAvatar)
|
||||
Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) :
|
||||
Billboard3DOverlay(image3DOverlay),
|
||||
_url(image3DOverlay->_url),
|
||||
_texture(image3DOverlay->_texture),
|
||||
_fromImage(image3DOverlay->_fromImage)
|
||||
{
|
||||
}
|
||||
|
||||
void BillboardOverlay::setTransforms(Transform& transform) {
|
||||
PanelAttachable::setTransforms(transform);
|
||||
if (_isFacingAvatar) {
|
||||
glm::quat rotation = Application::getInstance()->getCamera()->getOrientation();
|
||||
rotation *= glm::angleAxis(glm::pi<float>(), IDENTITY_UP);
|
||||
setRotation(rotation);
|
||||
}
|
||||
void Image3DOverlay::update(float deltatime) {
|
||||
applyTransformTo(_transform);
|
||||
}
|
||||
|
||||
void BillboardOverlay::update(float deltatime) {
|
||||
setTransforms(_transform);
|
||||
}
|
||||
|
||||
void BillboardOverlay::render(RenderArgs* args) {
|
||||
void Image3DOverlay::render(RenderArgs* args) {
|
||||
if (!_texture) {
|
||||
_isLoaded = true;
|
||||
_texture = DependencyManager::get<TextureCache>()->getTexture(_url);
|
||||
}
|
||||
|
||||
if (!_visible || !_texture || !_texture->isLoaded()) {
|
||||
if (!_visible || !getParentVisible() || !_texture || !_texture->isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
auto batch = args->_batch;
|
||||
gpu::Batch* batch = args->_batch;
|
||||
|
||||
float imageWidth = _texture->getWidth();
|
||||
float imageHeight = _texture->getHeight();
|
||||
|
@ -98,9 +87,10 @@ void BillboardOverlay::render(RenderArgs* args) {
|
|||
xColor color = getColor();
|
||||
float alpha = getAlpha();
|
||||
|
||||
setTransforms(_transform);
|
||||
applyTransformTo(_transform, true);
|
||||
Transform transform = _transform;
|
||||
transform.postScale(glm::vec3(getDimensions(), 1.0f));
|
||||
transform.postRotate(glm::angleAxis(glm::pi<float>(), IDENTITY_UP));
|
||||
|
||||
batch->setModelTransform(transform);
|
||||
batch->setResourceTexture(0, _texture->getGPUTexture());
|
||||
|
@ -114,15 +104,14 @@ void BillboardOverlay::render(RenderArgs* args) {
|
|||
batch->setResourceTexture(0, args->_whiteTexture); // restore default white color after me
|
||||
}
|
||||
|
||||
void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
||||
Planar3DOverlay::setProperties(properties);
|
||||
PanelAttachable::setProperties(properties);
|
||||
void Image3DOverlay::setProperties(const QScriptValue &properties) {
|
||||
Billboard3DOverlay::setProperties(properties);
|
||||
|
||||
QScriptValue urlValue = properties.property("url");
|
||||
if (urlValue.isValid()) {
|
||||
QString newURL = urlValue.toVariant().toString();
|
||||
if (newURL != _url) {
|
||||
setBillboardURL(newURL);
|
||||
setURL(newURL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,50 +145,34 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
|||
setClipFromSource(subImageRect);
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue isFacingAvatarValue = properties.property("isFacingAvatar");
|
||||
if (isFacingAvatarValue.isValid()) {
|
||||
_isFacingAvatar = isFacingAvatarValue.toVariant().toBool();
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue BillboardOverlay::getProperty(const QString& property) {
|
||||
QScriptValue Image3DOverlay::getProperty(const QString& property) {
|
||||
if (property == "url") {
|
||||
return _url;
|
||||
}
|
||||
if (property == "subImage") {
|
||||
return qRectToScriptValue(_scriptEngine, _fromImage);
|
||||
}
|
||||
if (property == "isFacingAvatar") {
|
||||
return _isFacingAvatar;
|
||||
}
|
||||
if (property == "offsetPosition") {
|
||||
return vec3toScriptValue(_scriptEngine, getOffsetPosition());
|
||||
}
|
||||
|
||||
QScriptValue value = PanelAttachable::getProperty(_scriptEngine, property);
|
||||
if (value.isValid()) {
|
||||
return value;
|
||||
}
|
||||
return Planar3DOverlay::getProperty(property);
|
||||
return Billboard3DOverlay::getProperty(property);
|
||||
}
|
||||
|
||||
void BillboardOverlay::setURL(const QString& url) {
|
||||
setBillboardURL(url);
|
||||
}
|
||||
|
||||
void BillboardOverlay::setBillboardURL(const QString& url) {
|
||||
void Image3DOverlay::setURL(const QString& url) {
|
||||
_url = url;
|
||||
_isLoaded = false;
|
||||
}
|
||||
|
||||
bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face) {
|
||||
bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face) {
|
||||
if (_texture && _texture->isLoaded()) {
|
||||
// Make sure position and rotation is updated.
|
||||
setTransforms(_transform);
|
||||
applyTransformTo(_transform, true);
|
||||
|
||||
// Produce the dimensions of the billboard based on the image's aspect ratio and the overlay's scale.
|
||||
// Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale.
|
||||
bool isNull = _fromImage.isNull();
|
||||
float width = isNull ? _texture->getWidth() : _fromImage.width();
|
||||
float height = isNull ? _texture->getHeight() : _fromImage.height();
|
||||
|
@ -212,6 +185,6 @@ bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::v
|
|||
return false;
|
||||
}
|
||||
|
||||
BillboardOverlay* BillboardOverlay::createClone() const {
|
||||
return new BillboardOverlay(this);
|
||||
Image3DOverlay* Image3DOverlay::createClone() const {
|
||||
return new Image3DOverlay(this);
|
||||
}
|
|
@ -1,30 +1,31 @@
|
|||
//
|
||||
// BillboardOverlay.h
|
||||
// Image3DOverlay.h
|
||||
//
|
||||
//
|
||||
// Created by Clement on 7/1/14.
|
||||
// Modified and renamed by Zander Otavka on 8/4/15
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_BillboardOverlay_h
|
||||
#define hifi_BillboardOverlay_h
|
||||
#ifndef hifi_Image3DOverlay_h
|
||||
#define hifi_Image3DOverlay_h
|
||||
|
||||
#include <TextureCache.h>
|
||||
|
||||
#include "Planar3DOverlay.h"
|
||||
#include "PanelAttachable.h"
|
||||
#include "Billboard3DOverlay.h"
|
||||
|
||||
class BillboardOverlay : public Planar3DOverlay, public PanelAttachable {
|
||||
class Image3DOverlay : public Billboard3DOverlay {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
|
||||
BillboardOverlay();
|
||||
BillboardOverlay(const BillboardOverlay* billboardOverlay);
|
||||
Image3DOverlay();
|
||||
Image3DOverlay(const Image3DOverlay* image3DOverlay);
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
|
@ -32,28 +33,20 @@ public:
|
|||
|
||||
// setters
|
||||
void setURL(const QString& url);
|
||||
void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; }
|
||||
void setClipFromSource(const QRect& bounds) { _fromImage = bounds; }
|
||||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
void setClipFromSource(const QRect& bounds) { _fromImage = bounds; }
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face);
|
||||
|
||||
virtual BillboardOverlay* createClone() const;
|
||||
|
||||
protected:
|
||||
virtual void setTransforms(Transform& transform);
|
||||
virtual Image3DOverlay* createClone() const;
|
||||
|
||||
private:
|
||||
void setBillboardURL(const QString& url);
|
||||
|
||||
QString _url;
|
||||
NetworkTexturePointer _texture;
|
||||
|
||||
QRect _fromImage; // where from in the image to sample
|
||||
|
||||
bool _isFacingAvatar = true;
|
||||
QRect _fromImage; // where from in the image to sample
|
||||
};
|
||||
|
||||
#endif // hifi_BillboardOverlay_h
|
||||
#endif // hifi_Image3DOverlay_h
|
200
interface/src/ui/overlays/OverlayPanel.cpp
Normal file
200
interface/src/ui/overlays/OverlayPanel.cpp
Normal file
|
@ -0,0 +1,200 @@
|
|||
//
|
||||
// OverlayPanel.cpp
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 7/2/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "OverlayPanel.h"
|
||||
|
||||
#include <QVariant>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <EntityScriptingInterface.h>
|
||||
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "avatar/MyAvatar.h"
|
||||
#include "Application.h"
|
||||
#include "Base3DOverlay.h"
|
||||
|
||||
PropertyBinding::PropertyBinding(QString avatar, QUuid entity) :
|
||||
avatar(avatar),
|
||||
entity(entity)
|
||||
{
|
||||
}
|
||||
|
||||
QScriptValue propertyBindingToScriptValue(QScriptEngine* engine, const PropertyBinding& value) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
|
||||
if (value.avatar == "MyAvatar") {
|
||||
obj.setProperty("avatar", "MyAvatar");
|
||||
} else if (!value.entity.isNull()) {
|
||||
obj.setProperty("entity", engine->newVariant(value.entity));
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void propertyBindingFromScriptValue(const QScriptValue& object, PropertyBinding& value) {
|
||||
QScriptValue avatar = object.property("avatar");
|
||||
QScriptValue entity = object.property("entity");
|
||||
|
||||
if (avatar.isValid() && !avatar.isNull()) {
|
||||
value.avatar = avatar.toVariant().toString();
|
||||
} else if (entity.isValid() && !entity.isNull()) {
|
||||
value.entity = entity.toVariant().toUuid();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OverlayPanel::addChild(unsigned int childId) {
|
||||
if (!_children.contains(childId)) {
|
||||
_children.append(childId);
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayPanel::removeChild(unsigned int childId) {
|
||||
if (_children.contains(childId)) {
|
||||
_children.removeOne(childId);
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue OverlayPanel::getProperty(const QString &property) {
|
||||
if (property == "anchorPosition") {
|
||||
return vec3toScriptValue(_scriptEngine, getAnchorPosition());
|
||||
}
|
||||
if (property == "anchorPositionBinding") {
|
||||
return propertyBindingToScriptValue(_scriptEngine,
|
||||
PropertyBinding(_anchorPositionBindMyAvatar ?
|
||||
"MyAvatar" : "",
|
||||
_anchorPositionBindEntity));
|
||||
}
|
||||
if (property == "anchorRotation") {
|
||||
return quatToScriptValue(_scriptEngine, getAnchorRotation());
|
||||
}
|
||||
if (property == "anchorRotationBinding") {
|
||||
return propertyBindingToScriptValue(_scriptEngine,
|
||||
PropertyBinding(_anchorRotationBindMyAvatar ?
|
||||
"MyAvatar" : "",
|
||||
_anchorRotationBindEntity));
|
||||
}
|
||||
if (property == "anchorScale") {
|
||||
return vec3toScriptValue(_scriptEngine, getAnchorScale());
|
||||
}
|
||||
if (property == "visible") {
|
||||
return getVisible();
|
||||
}
|
||||
if (property == "children") {
|
||||
QScriptValue array = _scriptEngine->newArray(_children.length());
|
||||
for (int i = 0; i < _children.length(); i++) {
|
||||
array.setProperty(i, _children[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
QScriptValue value = Billboardable::getProperty(_scriptEngine, property);
|
||||
if (value.isValid()) {
|
||||
return value;
|
||||
}
|
||||
return PanelAttachable::getProperty(_scriptEngine, property);
|
||||
}
|
||||
|
||||
void OverlayPanel::setProperties(const QScriptValue &properties) {
|
||||
PanelAttachable::setProperties(properties);
|
||||
Billboardable::setProperties(properties);
|
||||
|
||||
QScriptValue anchorPosition = properties.property("anchorPosition");
|
||||
if (anchorPosition.isValid() &&
|
||||
anchorPosition.property("x").isValid() &&
|
||||
anchorPosition.property("y").isValid() &&
|
||||
anchorPosition.property("z").isValid()) {
|
||||
glm::vec3 newPosition;
|
||||
vec3FromScriptValue(anchorPosition, newPosition);
|
||||
setAnchorPosition(newPosition);
|
||||
}
|
||||
|
||||
QScriptValue anchorPositionBinding = properties.property("anchorPositionBinding");
|
||||
if (anchorPositionBinding.isValid()) {
|
||||
PropertyBinding binding = {};
|
||||
propertyBindingFromScriptValue(anchorPositionBinding, binding);
|
||||
_anchorPositionBindMyAvatar = binding.avatar == "MyAvatar";
|
||||
_anchorPositionBindEntity = binding.entity;
|
||||
}
|
||||
|
||||
QScriptValue anchorRotation = properties.property("anchorRotation");
|
||||
if (anchorRotation.isValid() &&
|
||||
anchorRotation.property("x").isValid() &&
|
||||
anchorRotation.property("y").isValid() &&
|
||||
anchorRotation.property("z").isValid() &&
|
||||
anchorRotation.property("w").isValid()) {
|
||||
glm::quat newRotation;
|
||||
quatFromScriptValue(anchorRotation, newRotation);
|
||||
setAnchorRotation(newRotation);
|
||||
}
|
||||
|
||||
QScriptValue anchorRotationBinding = properties.property("anchorRotationBinding");
|
||||
if (anchorRotationBinding.isValid()) {
|
||||
PropertyBinding binding = {};
|
||||
propertyBindingFromScriptValue(anchorPositionBinding, binding);
|
||||
_anchorRotationBindMyAvatar = binding.avatar == "MyAvatar";
|
||||
_anchorRotationBindEntity = binding.entity;
|
||||
}
|
||||
|
||||
QScriptValue anchorScale = properties.property("anchorScale");
|
||||
if (anchorScale.isValid()) {
|
||||
if (anchorScale.property("x").isValid() &&
|
||||
anchorScale.property("y").isValid() &&
|
||||
anchorScale.property("z").isValid()) {
|
||||
glm::vec3 newScale;
|
||||
vec3FromScriptValue(anchorScale, newScale);
|
||||
setAnchorScale(newScale);
|
||||
} else {
|
||||
setAnchorScale(anchorScale.toVariant().toFloat());
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue visible = properties.property("visible");
|
||||
if (visible.isValid()) {
|
||||
setVisible(visible.toVariant().toBool());
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayPanel::applyTransformTo(Transform& transform, bool force) {
|
||||
if (force || usecTimestampNow() > _transformExpiry) {
|
||||
PanelAttachable::applyTransformTo(transform, true);
|
||||
if (!getParentPanel()) {
|
||||
if (_anchorPositionBindMyAvatar) {
|
||||
transform.setTranslation(DependencyManager::get<AvatarManager>()->getMyAvatar()
|
||||
->getPosition());
|
||||
} else if (!_anchorPositionBindEntity.isNull()) {
|
||||
transform.setTranslation(DependencyManager::get<EntityScriptingInterface>()
|
||||
->getEntityTree()->findEntityByID(_anchorPositionBindEntity)
|
||||
->getPosition());
|
||||
} else {
|
||||
transform.setTranslation(getAnchorPosition());
|
||||
}
|
||||
|
||||
if (_anchorRotationBindMyAvatar) {
|
||||
transform.setRotation(DependencyManager::get<AvatarManager>()->getMyAvatar()
|
||||
->getOrientation());
|
||||
} else if (!_anchorRotationBindEntity.isNull()) {
|
||||
transform.setRotation(DependencyManager::get<EntityScriptingInterface>()
|
||||
->getEntityTree()->findEntityByID(_anchorRotationBindEntity)
|
||||
->getRotation());
|
||||
} else {
|
||||
transform.setRotation(getAnchorRotation());
|
||||
}
|
||||
|
||||
transform.setScale(getAnchorScale());
|
||||
|
||||
transform.postTranslate(getOffsetPosition());
|
||||
transform.postRotate(getOffsetRotation());
|
||||
transform.postScale(getOffsetScale());
|
||||
}
|
||||
pointTransformAtCamera(transform, getOffsetRotation());
|
||||
}
|
||||
}
|
83
interface/src/ui/overlays/OverlayPanel.h
Normal file
83
interface/src/ui/overlays/OverlayPanel.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// OverlayPanel.h
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 7/2/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_OverlayPanel_h
|
||||
#define hifi_OverlayPanel_h
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <QScriptValue>
|
||||
#include <QUuid>
|
||||
|
||||
#include "PanelAttachable.h"
|
||||
#include "Billboardable.h"
|
||||
|
||||
class PropertyBinding {
|
||||
public:
|
||||
PropertyBinding() {}
|
||||
PropertyBinding(QString avatar, QUuid entity);
|
||||
QString avatar;
|
||||
QUuid entity;
|
||||
};
|
||||
|
||||
QScriptValue propertyBindingToScriptValue(QScriptEngine* engine, const PropertyBinding& value);
|
||||
void propertyBindingFromScriptValue(const QScriptValue& object, PropertyBinding& value);
|
||||
|
||||
|
||||
class OverlayPanel : public QObject, public PanelAttachable, public Billboardable {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef std::shared_ptr<OverlayPanel> Pointer;
|
||||
|
||||
void init(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; }
|
||||
|
||||
// getters
|
||||
glm::vec3 getAnchorPosition() const { return _anchorTransform.getTranslation(); }
|
||||
glm::quat getAnchorRotation() const { return _anchorTransform.getRotation(); }
|
||||
glm::vec3 getAnchorScale() const { return _anchorTransform.getScale(); }
|
||||
bool getVisible() const { return _visible; }
|
||||
|
||||
// setters
|
||||
void setAnchorPosition(const glm::vec3& position) { _anchorTransform.setTranslation(position); }
|
||||
void setAnchorRotation(const glm::quat& rotation) { _anchorTransform.setRotation(rotation); }
|
||||
void setAnchorScale(float scale) { _anchorTransform.setScale(scale); }
|
||||
void setAnchorScale(const glm::vec3& scale) { _anchorTransform.setScale(scale); }
|
||||
void setVisible(bool visible) { _visible = visible; }
|
||||
|
||||
const QList<unsigned int>& getChildren() { return _children; }
|
||||
void addChild(unsigned int childId);
|
||||
void removeChild(unsigned int childId);
|
||||
unsigned int popLastChild() { return _children.takeLast(); }
|
||||
|
||||
QScriptValue getProperty(const QString& property);
|
||||
void setProperties(const QScriptValue& properties);
|
||||
|
||||
virtual void applyTransformTo(Transform& transform, bool force = false);
|
||||
|
||||
private:
|
||||
Transform _anchorTransform;
|
||||
|
||||
bool _anchorPositionBindMyAvatar = false;
|
||||
QUuid _anchorPositionBindEntity;
|
||||
|
||||
bool _anchorRotationBindMyAvatar = false;
|
||||
QUuid _anchorRotationBindEntity;
|
||||
|
||||
bool _visible = true;
|
||||
QList<unsigned int> _children;
|
||||
|
||||
QScriptEngine* _scriptEngine;
|
||||
};
|
||||
|
||||
#endif // hifi_OverlayPanel_h
|
|
@ -18,7 +18,7 @@
|
|||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "BillboardOverlay.h"
|
||||
#include "Image3DOverlay.h"
|
||||
#include "Circle3DOverlay.h"
|
||||
#include "Cube3DOverlay.h"
|
||||
#include "ImageOverlay.h"
|
||||
|
@ -138,6 +138,8 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
|
|||
|
||||
if (type == ImageOverlay::TYPE) {
|
||||
thisOverlay = std::make_shared<ImageOverlay>();
|
||||
} else if (type == Image3DOverlay::TYPE || type == "billboard") { // "billboard" for backwards compatibility
|
||||
thisOverlay = std::make_shared<Image3DOverlay>();
|
||||
} else if (type == TextOverlay::TYPE) {
|
||||
thisOverlay = std::make_shared<TextOverlay>();
|
||||
} else if (type == Text3DOverlay::TYPE) {
|
||||
|
@ -158,8 +160,6 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
|
|||
thisOverlay = std::make_shared<LocalModelsOverlay>(Application::getInstance()->getEntityClipboardRenderer());
|
||||
} else if (type == ModelOverlay::TYPE) {
|
||||
thisOverlay = std::make_shared<ModelOverlay>();
|
||||
} else if (type == BillboardOverlay::TYPE) {
|
||||
thisOverlay = std::make_shared<BillboardOverlay>();
|
||||
}
|
||||
|
||||
if (thisOverlay) {
|
||||
|
@ -200,7 +200,12 @@ unsigned int Overlays::cloneOverlay(unsigned int id) {
|
|||
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||
|
||||
if (thisOverlay) {
|
||||
return addOverlay(Overlay::Pointer(thisOverlay->createClone()));
|
||||
unsigned int cloneId = addOverlay(Overlay::Pointer(thisOverlay->createClone()));
|
||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(thisOverlay);
|
||||
if (attachable && attachable->getParentPanel()) {
|
||||
attachable->getParentPanel()->addChild(cloneId);
|
||||
}
|
||||
return cloneId;
|
||||
}
|
||||
|
||||
return 0; // Not found
|
||||
|
@ -251,9 +256,9 @@ void Overlays::deleteOverlay(unsigned int id) {
|
|||
}
|
||||
|
||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlayToDelete);
|
||||
if (attachable && attachable->getAttachedPanel()) {
|
||||
attachable->getAttachedPanel()->removeChild(id);
|
||||
attachable->setAttachedPanel(nullptr);
|
||||
if (attachable && attachable->getParentPanel()) {
|
||||
attachable->getParentPanel()->removeChild(id);
|
||||
attachable->setParentPanel(nullptr);
|
||||
}
|
||||
|
||||
QWriteLocker lock(&_deleteLock);
|
||||
|
@ -270,28 +275,42 @@ QString Overlays::getOverlayType(unsigned int overlayId) const {
|
|||
return "";
|
||||
}
|
||||
|
||||
unsigned int Overlays::getAttachedPanel(unsigned int childId) const {
|
||||
unsigned int Overlays::getParentPanel(unsigned int childId) const {
|
||||
Overlay::Pointer overlay = getOverlay(childId);
|
||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlay);
|
||||
if (attachable) {
|
||||
return _panels.key(attachable->getAttachedPanel());
|
||||
return _panels.key(attachable->getParentPanel());
|
||||
} else if (_panels.contains(childId)) {
|
||||
return _panels.key(getPanel(childId)->getParentPanel());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Overlays::setAttachedPanel(unsigned int childId, unsigned int panelId) {
|
||||
Overlay::Pointer overlay = getOverlay(childId);
|
||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlay);
|
||||
void Overlays::setParentPanel(unsigned int childId, unsigned int panelId) {
|
||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(getOverlay(childId));
|
||||
if (attachable) {
|
||||
if (_panels.contains(panelId)) {
|
||||
auto panel = _panels[panelId];
|
||||
auto panel = getPanel(panelId);
|
||||
panel->addChild(childId);
|
||||
attachable->setAttachedPanel(panel);
|
||||
attachable->setParentPanel(panel);
|
||||
} else {
|
||||
auto panel = attachable->getAttachedPanel();
|
||||
auto panel = attachable->getParentPanel();
|
||||
if (panel) {
|
||||
panel->removeChild(childId);
|
||||
attachable->setAttachedPanel(nullptr);
|
||||
attachable->setParentPanel(nullptr);
|
||||
}
|
||||
}
|
||||
} else if (_panels.contains(childId)) {
|
||||
OverlayPanel::Pointer child = getPanel(childId);
|
||||
if (_panels.contains(panelId)) {
|
||||
auto panel = getPanel(panelId);
|
||||
panel->addChild(childId);
|
||||
child->setParentPanel(panel);
|
||||
} else {
|
||||
auto panel = child->getParentPanel();
|
||||
if (panel) {
|
||||
panel->removeChild(childId);
|
||||
child->setParentPanel(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -510,7 +529,7 @@ QSizeF Overlays::textSize(unsigned int id, const QString& text) const {
|
|||
return QSizeF(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
unsigned int Overlays::addPanel(FloatingUIPanel::Pointer panel) {
|
||||
unsigned int Overlays::addPanel(OverlayPanel::Pointer panel) {
|
||||
QWriteLocker lock(&_lock);
|
||||
|
||||
unsigned int thisID = _nextOverlayID;
|
||||
|
@ -521,7 +540,7 @@ unsigned int Overlays::addPanel(FloatingUIPanel::Pointer panel) {
|
|||
}
|
||||
|
||||
unsigned int Overlays::addPanel(const QScriptValue& properties) {
|
||||
FloatingUIPanel::Pointer panel = std::make_shared<FloatingUIPanel>();
|
||||
OverlayPanel::Pointer panel = std::make_shared<OverlayPanel>();
|
||||
panel->init(_scriptEngine);
|
||||
panel->setProperties(properties);
|
||||
return addPanel(panel);
|
||||
|
@ -536,7 +555,7 @@ void Overlays::editPanel(unsigned int panelId, const QScriptValue& properties) {
|
|||
OverlayPropertyResult Overlays::getPanelProperty(unsigned int panelId, const QString& property) {
|
||||
OverlayPropertyResult result;
|
||||
if (_panels.contains(panelId)) {
|
||||
FloatingUIPanel::Pointer thisPanel = _panels[panelId];
|
||||
OverlayPanel::Pointer thisPanel = getPanel(panelId);
|
||||
QReadLocker lock(&_lock);
|
||||
result.value = thisPanel->getProperty(property);
|
||||
}
|
||||
|
@ -545,7 +564,7 @@ OverlayPropertyResult Overlays::getPanelProperty(unsigned int panelId, const QSt
|
|||
|
||||
|
||||
void Overlays::deletePanel(unsigned int panelId) {
|
||||
FloatingUIPanel::Pointer panelToDelete;
|
||||
OverlayPanel::Pointer panelToDelete;
|
||||
|
||||
{
|
||||
QWriteLocker lock(&_lock);
|
||||
|
@ -557,8 +576,14 @@ void Overlays::deletePanel(unsigned int panelId) {
|
|||
}
|
||||
|
||||
while (!panelToDelete->getChildren().isEmpty()) {
|
||||
deleteOverlay(panelToDelete->popLastChild());
|
||||
unsigned int childId = panelToDelete->popLastChild();
|
||||
deleteOverlay(childId);
|
||||
deletePanel(childId);
|
||||
}
|
||||
|
||||
emit panelDeleted(panelId);
|
||||
}
|
||||
|
||||
bool Overlays::isAddedOverlay(unsigned int id) {
|
||||
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// Modified by Zander Otavka on 7/15/15
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Exposes methods for managing `Overlay`s and `FloatingUIPanel`s to scripts.
|
||||
// Exposes methods for managing `Overlay`s and `OverlayPanel`s to scripts.
|
||||
//
|
||||
// YOU SHOULD NOT USE `Overlays` DIRECTLY, unless you like pain and deprecation. Instead, use the
|
||||
// object oriented abstraction layer found in `examples/libraries/overlayUtils.js`.
|
||||
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "Overlay.h"
|
||||
|
||||
#include "FloatingUIPanel.h"
|
||||
#include "OverlayPanel.h"
|
||||
#include "PanelAttachable.h"
|
||||
|
||||
class PickRay;
|
||||
|
@ -67,7 +67,7 @@ public:
|
|||
void renderHUD(RenderArgs* renderArgs);
|
||||
|
||||
Overlay::Pointer getOverlay(unsigned int id) const;
|
||||
FloatingUIPanel::Pointer getPanel(unsigned int id) const { return _panels[id]; }
|
||||
OverlayPanel::Pointer getPanel(unsigned int id) const { return _panels[id]; }
|
||||
|
||||
public slots:
|
||||
/// adds an overlay with the specific properties
|
||||
|
@ -90,8 +90,8 @@ public slots:
|
|||
/// get the string type of the overlay used in addOverlay
|
||||
QString getOverlayType(unsigned int overlayId) const;
|
||||
|
||||
unsigned int getAttachedPanel(unsigned int childId) const;
|
||||
void setAttachedPanel(unsigned int childId, unsigned int panelId);
|
||||
unsigned int getParentPanel(unsigned int childId) const;
|
||||
void setParentPanel(unsigned int childId, unsigned int panelId);
|
||||
|
||||
/// returns the top most 2D overlay at the screen point, or 0 if not overlay at that point
|
||||
unsigned int getOverlayAtPoint(const glm::vec2& point);
|
||||
|
@ -111,7 +111,7 @@ public slots:
|
|||
|
||||
|
||||
/// adds a panel that has already been created
|
||||
unsigned int addPanel(FloatingUIPanel::Pointer panel);
|
||||
unsigned int addPanel(OverlayPanel::Pointer panel);
|
||||
|
||||
/// creates and adds a panel based on a set of properties
|
||||
unsigned int addPanel(const QScriptValue& properties);
|
||||
|
@ -125,6 +125,12 @@ public slots:
|
|||
/// deletes a panel and all child overlays
|
||||
void deletePanel(unsigned int panelId);
|
||||
|
||||
/// return true if there is an overlay with that id else false
|
||||
bool isAddedOverlay(unsigned int id);
|
||||
|
||||
/// return true if there is a panel with that id else false
|
||||
bool isAddedPanel(unsigned int id) { return _panels.contains(id); }
|
||||
|
||||
signals:
|
||||
void overlayDeleted(unsigned int id);
|
||||
void panelDeleted(unsigned int id);
|
||||
|
@ -134,7 +140,7 @@ private:
|
|||
|
||||
QMap<unsigned int, Overlay::Pointer> _overlaysHUD;
|
||||
QMap<unsigned int, Overlay::Pointer> _overlaysWorld;
|
||||
QMap<unsigned int, FloatingUIPanel::Pointer> _panels;
|
||||
QMap<unsigned int, OverlayPanel::Pointer> _panels;
|
||||
QList<Overlay::Pointer> _overlaysToDelete;
|
||||
unsigned int _nextOverlayID;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <LODManager.h>
|
||||
#include <render/Scene.h>
|
||||
|
||||
#include "BillboardOverlay.h"
|
||||
#include "Image3DOverlay.h"
|
||||
#include "Circle3DOverlay.h"
|
||||
#include "Cube3DOverlay.h"
|
||||
#include "ImageOverlay.h"
|
||||
|
|
|
@ -13,25 +13,13 @@
|
|||
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
PanelAttachable::PanelAttachable() :
|
||||
_attachedPanel(nullptr),
|
||||
_facingRotation(1, 0, 0, 0)
|
||||
{
|
||||
}
|
||||
#include "OverlayPanel.h"
|
||||
|
||||
PanelAttachable::PanelAttachable(const PanelAttachable* panelAttachable) :
|
||||
_attachedPanel(panelAttachable->_attachedPanel),
|
||||
_offsetPosition(panelAttachable->_offsetPosition),
|
||||
_facingRotation(panelAttachable->_facingRotation)
|
||||
{
|
||||
}
|
||||
|
||||
void PanelAttachable::setTransforms(Transform& transform) {
|
||||
if (getAttachedPanel()) {
|
||||
transform.setTranslation(getAttachedPanel()->getAnchorPosition());
|
||||
transform.setRotation(getAttachedPanel()->getOffsetRotation());
|
||||
transform.postTranslate(getOffsetPosition() + getAttachedPanel()->getOffsetPosition());
|
||||
transform.postRotate(getFacingRotation() * getAttachedPanel()->getFacingRotation());
|
||||
bool PanelAttachable::getParentVisible() const {
|
||||
if (getParentPanel()) {
|
||||
return getParentPanel()->getVisible() && getParentPanel()->getParentVisible();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,42 +27,60 @@ QScriptValue PanelAttachable::getProperty(QScriptEngine* scriptEngine, const QSt
|
|||
if (property == "offsetPosition") {
|
||||
return vec3toScriptValue(scriptEngine, getOffsetPosition());
|
||||
}
|
||||
if (property == "facingRotation") {
|
||||
return quatToScriptValue(scriptEngine, getFacingRotation());
|
||||
if (property == "offsetRotation") {
|
||||
return quatToScriptValue(scriptEngine, getOffsetRotation());
|
||||
}
|
||||
if (property == "offsetScale") {
|
||||
return vec3toScriptValue(scriptEngine, getOffsetScale());
|
||||
}
|
||||
return QScriptValue();
|
||||
}
|
||||
|
||||
void PanelAttachable::setProperties(const QScriptValue &properties) {
|
||||
QScriptValue offsetPosition = properties.property("offsetPosition");
|
||||
if (offsetPosition.isValid()) {
|
||||
QScriptValue x = offsetPosition.property("x");
|
||||
QScriptValue y = offsetPosition.property("y");
|
||||
QScriptValue z = offsetPosition.property("z");
|
||||
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {
|
||||
glm::vec3 newPosition;
|
||||
newPosition.x = x.toVariant().toFloat();
|
||||
newPosition.y = y.toVariant().toFloat();
|
||||
newPosition.z = z.toVariant().toFloat();
|
||||
setOffsetPosition(newPosition);
|
||||
}
|
||||
if (offsetPosition.isValid() &&
|
||||
offsetPosition.property("x").isValid() &&
|
||||
offsetPosition.property("y").isValid() &&
|
||||
offsetPosition.property("z").isValid()) {
|
||||
glm::vec3 newPosition;
|
||||
vec3FromScriptValue(offsetPosition, newPosition);
|
||||
setOffsetPosition(newPosition);
|
||||
}
|
||||
|
||||
QScriptValue facingRotation = properties.property("facingRotation");
|
||||
if (facingRotation.isValid()) {
|
||||
QScriptValue x = facingRotation.property("x");
|
||||
QScriptValue y = facingRotation.property("y");
|
||||
QScriptValue z = facingRotation.property("z");
|
||||
QScriptValue w = facingRotation.property("w");
|
||||
QScriptValue offsetRotation = properties.property("offsetRotation");
|
||||
if (offsetRotation.isValid() &&
|
||||
offsetRotation.property("x").isValid() &&
|
||||
offsetRotation.property("y").isValid() &&
|
||||
offsetRotation.property("z").isValid() &&
|
||||
offsetRotation.property("w").isValid()) {
|
||||
glm::quat newRotation;
|
||||
quatFromScriptValue(offsetRotation, newRotation);
|
||||
setOffsetRotation(newRotation);
|
||||
}
|
||||
|
||||
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
|
||||
glm::quat newRotation;
|
||||
newRotation.x = x.toVariant().toFloat();
|
||||
newRotation.y = y.toVariant().toFloat();
|
||||
newRotation.z = z.toVariant().toFloat();
|
||||
newRotation.w = w.toVariant().toFloat();
|
||||
setFacingRotation(newRotation);
|
||||
QScriptValue offsetScale = properties.property("offsetScale");
|
||||
if (offsetScale.isValid()) {
|
||||
if (offsetScale.property("x").isValid() &&
|
||||
offsetScale.property("y").isValid() &&
|
||||
offsetScale.property("z").isValid()) {
|
||||
glm::vec3 newScale;
|
||||
vec3FromScriptValue(offsetScale, newScale);
|
||||
setOffsetScale(newScale);
|
||||
} else {
|
||||
setOffsetScale(offsetScale.toVariant().toFloat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PanelAttachable::applyTransformTo(Transform& transform, bool force) {
|
||||
if (force || usecTimestampNow() > _transformExpiry) {
|
||||
const quint64 TRANSFORM_UPDATE_PERIOD = 100000; // frequency is 10 Hz
|
||||
_transformExpiry = usecTimestampNow() + TRANSFORM_UPDATE_PERIOD;
|
||||
if (getParentPanel()) {
|
||||
getParentPanel()->applyTransformTo(transform, true);
|
||||
transform.postTranslate(getOffsetPosition());
|
||||
transform.postRotate(getOffsetRotation());
|
||||
transform.postScale(getOffsetScale());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,34 +12,42 @@
|
|||
#ifndef hifi_PanelAttachable_h
|
||||
#define hifi_PanelAttachable_h
|
||||
|
||||
#include "FloatingUIPanel.h"
|
||||
#include <memory>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <Transform.h>
|
||||
#include <QScriptValue>
|
||||
#include <QScriptEngine>
|
||||
#include <QUuid>
|
||||
|
||||
class OverlayPanel;
|
||||
|
||||
class PanelAttachable {
|
||||
public:
|
||||
PanelAttachable();
|
||||
PanelAttachable(const PanelAttachable* panelAttachable);
|
||||
// getters
|
||||
std::shared_ptr<OverlayPanel> getParentPanel() const { return _parentPanel; }
|
||||
glm::vec3 getOffsetPosition() const { return _offset.getTranslation(); }
|
||||
glm::quat getOffsetRotation() const { return _offset.getRotation(); }
|
||||
glm::vec3 getOffsetScale() const { return _offset.getScale(); }
|
||||
bool getParentVisible() const;
|
||||
|
||||
FloatingUIPanel::Pointer getAttachedPanel() const { return _attachedPanel; }
|
||||
glm::vec3 getOffsetPosition() const { return _offsetPosition; }
|
||||
glm::quat getFacingRotation() const { return _facingRotation; }
|
||||
|
||||
void setAttachedPanel(FloatingUIPanel::Pointer panel) { _attachedPanel = panel; }
|
||||
void setOffsetPosition(const glm::vec3& position) { _offsetPosition = position; }
|
||||
void setFacingRotation(const glm::quat& rotation) { _facingRotation = rotation; }
|
||||
// setters
|
||||
void setParentPanel(std::shared_ptr<OverlayPanel> panel) { _parentPanel = panel; }
|
||||
void setOffsetPosition(const glm::vec3& position) { _offset.setTranslation(position); }
|
||||
void setOffsetRotation(const glm::quat& rotation) { _offset.setRotation(rotation); }
|
||||
void setOffsetScale(float scale) { _offset.setScale(scale); }
|
||||
void setOffsetScale(const glm::vec3& scale) { _offset.setScale(scale); }
|
||||
|
||||
protected:
|
||||
QScriptValue getProperty(QScriptEngine* scriptEngine, const QString& property);
|
||||
void setProperties(const QScriptValue& properties);
|
||||
|
||||
protected:
|
||||
virtual void setTransforms(Transform& transform);
|
||||
virtual void applyTransformTo(Transform& transform, bool force = false);
|
||||
quint64 _transformExpiry = 0;
|
||||
|
||||
private:
|
||||
FloatingUIPanel::Pointer _attachedPanel;
|
||||
glm::vec3 _offsetPosition;
|
||||
glm::quat _facingRotation;
|
||||
std::shared_ptr<OverlayPanel> _parentPanel = nullptr;
|
||||
Transform _offset;
|
||||
};
|
||||
|
||||
#endif // hifi_PanelAttachable_h
|
||||
|
|
|
@ -32,14 +32,13 @@ Text3DOverlay::Text3DOverlay() :
|
|||
_leftMargin(DEFAULT_MARGIN),
|
||||
_topMargin(DEFAULT_MARGIN),
|
||||
_rightMargin(DEFAULT_MARGIN),
|
||||
_bottomMargin(DEFAULT_MARGIN),
|
||||
_isFacingAvatar(false)
|
||||
_bottomMargin(DEFAULT_MARGIN)
|
||||
{
|
||||
_textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
|
||||
}
|
||||
|
||||
Text3DOverlay::Text3DOverlay(const Text3DOverlay* text3DOverlay) :
|
||||
Planar3DOverlay(text3DOverlay),
|
||||
Billboard3DOverlay(text3DOverlay),
|
||||
_text(text3DOverlay->_text),
|
||||
_backgroundColor(text3DOverlay->_backgroundColor),
|
||||
_backgroundAlpha(text3DOverlay->_backgroundAlpha),
|
||||
|
@ -47,8 +46,7 @@ Text3DOverlay::Text3DOverlay(const Text3DOverlay* text3DOverlay) :
|
|||
_leftMargin(text3DOverlay->_leftMargin),
|
||||
_topMargin(text3DOverlay->_topMargin),
|
||||
_rightMargin(text3DOverlay->_rightMargin),
|
||||
_bottomMargin(text3DOverlay->_bottomMargin),
|
||||
_isFacingAvatar(text3DOverlay->_isFacingAvatar)
|
||||
_bottomMargin(text3DOverlay->_bottomMargin)
|
||||
{
|
||||
_textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
|
||||
}
|
||||
|
@ -76,41 +74,30 @@ xColor Text3DOverlay::getBackgroundColor() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void Text3DOverlay::update(float deltatime) {
|
||||
applyTransformTo(_transform);
|
||||
}
|
||||
|
||||
void Text3DOverlay::render(RenderArgs* args) {
|
||||
if (!_visible) {
|
||||
if (!_visible || !getParentVisible()) {
|
||||
return; // do nothing if we're not visible
|
||||
}
|
||||
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
auto& batch = *args->_batch;
|
||||
|
||||
glm::quat rotation;
|
||||
|
||||
if (_isFacingAvatar) {
|
||||
// rotate about vertical to face the camera
|
||||
rotation = args->_viewFrustum->getOrientation();
|
||||
} else {
|
||||
rotation = getRotation();
|
||||
}
|
||||
|
||||
Transform transform;
|
||||
transform.setTranslation(getPosition());
|
||||
transform.setRotation(rotation);
|
||||
transform.setScale(getScale());
|
||||
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
applyTransformTo(_transform, true);
|
||||
batch.setModelTransform(_transform);
|
||||
|
||||
const float MAX_COLOR = 255.0f;
|
||||
xColor backgroundColor = getBackgroundColor();
|
||||
glm::vec4 quadColor(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR,
|
||||
getBackgroundAlpha());
|
||||
glm::vec4 quadColor(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR,
|
||||
backgroundColor.blue / MAX_COLOR, getBackgroundAlpha());
|
||||
|
||||
glm::vec2 dimensions = getDimensions();
|
||||
glm::vec2 halfDimensions = dimensions * 0.5f;
|
||||
|
||||
const float SLIGHTLY_BEHIND = -0.005f;
|
||||
const float SLIGHTLY_BEHIND = -0.001f;
|
||||
|
||||
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
|
||||
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
|
||||
|
@ -125,20 +112,20 @@ void Text3DOverlay::render(RenderArgs* args) {
|
|||
glm::vec2 clipMinimum(0.0f, 0.0f);
|
||||
glm::vec2 clipDimensions((dimensions.x - (_leftMargin + _rightMargin)) / scaleFactor,
|
||||
(dimensions.y - (_topMargin + _bottomMargin)) / scaleFactor);
|
||||
|
||||
transform.setTranslation(getPosition());
|
||||
transform.postTranslate(glm::vec3(-(halfDimensions.x - _leftMargin) , halfDimensions.y - _topMargin, 0.01f));
|
||||
|
||||
Transform transform = _transform;
|
||||
transform.postTranslate(glm::vec3(-(halfDimensions.x - _leftMargin),
|
||||
halfDimensions.y - _topMargin, 0.001f));
|
||||
transform.setScale(scaleFactor);
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, getAlpha() };
|
||||
|
||||
glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR,
|
||||
_color.blue / MAX_COLOR, getAlpha() };
|
||||
_textRenderer->draw(batch, 0, 0, _text, textColor);
|
||||
|
||||
batch.setPipeline(DrawOverlay3D::getOpaquePipeline());
|
||||
}
|
||||
|
||||
void Text3DOverlay::setProperties(const QScriptValue& properties) {
|
||||
Planar3DOverlay::setProperties(properties);
|
||||
Billboard3DOverlay::setProperties(properties);
|
||||
|
||||
QScriptValue text = properties.property("text");
|
||||
if (text.isValid()) {
|
||||
|
@ -180,12 +167,6 @@ void Text3DOverlay::setProperties(const QScriptValue& properties) {
|
|||
if (properties.property("bottomMargin").isValid()) {
|
||||
setBottomMargin(properties.property("bottomMargin").toVariant().toFloat());
|
||||
}
|
||||
|
||||
QScriptValue isFacingAvatarValue = properties.property("isFacingAvatar");
|
||||
if (isFacingAvatarValue.isValid()) {
|
||||
_isFacingAvatar = isFacingAvatarValue.toVariant().toBool();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QScriptValue Text3DOverlay::getProperty(const QString& property) {
|
||||
|
@ -213,10 +194,8 @@ QScriptValue Text3DOverlay::getProperty(const QString& property) {
|
|||
if (property == "bottomMargin") {
|
||||
return _bottomMargin;
|
||||
}
|
||||
if (property == "isFacingAvatar") {
|
||||
return _isFacingAvatar;
|
||||
}
|
||||
return Planar3DOverlay::getProperty(property);
|
||||
|
||||
return Billboard3DOverlay::getProperty(property);
|
||||
}
|
||||
|
||||
Text3DOverlay* Text3DOverlay::createClone() const {
|
||||
|
@ -232,3 +211,7 @@ QSizeF Text3DOverlay::textSize(const QString& text) const {
|
|||
return QSizeF(extents.x, extents.y) * pointToWorldScale;
|
||||
}
|
||||
|
||||
bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3 &direction, float &distance, BoxFace &face) {
|
||||
applyTransformTo(_transform, true);
|
||||
return Billboard3DOverlay::findRayIntersection(origin, direction, distance, face);
|
||||
}
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
|
||||
#include <QString>
|
||||
|
||||
#include "Planar3DOverlay.h"
|
||||
#include "Billboard3DOverlay.h"
|
||||
|
||||
class TextRenderer3D;
|
||||
|
||||
class Text3DOverlay : public Planar3DOverlay {
|
||||
class Text3DOverlay : public Billboard3DOverlay {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -29,6 +29,8 @@ public:
|
|||
~Text3DOverlay();
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
virtual void update(float deltatime);
|
||||
|
||||
// getters
|
||||
const QString& getText() const { return _text; }
|
||||
float getLineHeight() const { return _lineHeight; }
|
||||
|
@ -36,7 +38,6 @@ public:
|
|||
float getTopMargin() const { return _topMargin; }
|
||||
float getRightMargin() const { return _rightMargin; }
|
||||
float getBottomMargin() const { return _bottomMargin; }
|
||||
bool getIsFacingAvatar() const { return _isFacingAvatar; }
|
||||
xColor getBackgroundColor();
|
||||
float getBackgroundAlpha() const { return _backgroundAlpha; }
|
||||
|
||||
|
@ -47,13 +48,14 @@ public:
|
|||
void setTopMargin(float margin) { _topMargin = margin; }
|
||||
void setRightMargin(float margin) { _rightMargin = margin; }
|
||||
void setBottomMargin(float margin) { _bottomMargin = margin; }
|
||||
void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; }
|
||||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
|
||||
QSizeF textSize(const QString& test) const; // Meters
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face);
|
||||
|
||||
virtual Text3DOverlay* createClone() const;
|
||||
|
||||
private:
|
||||
|
@ -67,7 +69,6 @@ private:
|
|||
float _topMargin;
|
||||
float _rightMargin;
|
||||
float _bottomMargin;
|
||||
bool _isFacingAvatar;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -91,6 +91,10 @@ QVector<FBXAnimationFrame> Animation::getFrames() const {
|
|||
return _geometry.animationFrames;
|
||||
}
|
||||
|
||||
const QVector<FBXAnimationFrame>& Animation::getFramesReference() const {
|
||||
return _geometry.animationFrames;
|
||||
}
|
||||
|
||||
void Animation::setGeometry(const FBXGeometry& geometry) {
|
||||
_geometry = geometry;
|
||||
finishedLoading(true);
|
||||
|
|
|
@ -57,6 +57,8 @@ public:
|
|||
Q_INVOKABLE QStringList getJointNames() const;
|
||||
|
||||
Q_INVOKABLE QVector<FBXAnimationFrame> getFrames() const;
|
||||
|
||||
const QVector<FBXAnimationFrame>& getFramesReference() const;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ void AvatarRig::updateJointState(int index, glm::mat4 parentTransform) {
|
|||
return; // bail
|
||||
}
|
||||
JointState& state = _jointStates[index];
|
||||
const FBXJoint& joint = state.getFBXJoint();
|
||||
|
||||
// compute model transforms
|
||||
if (index == _rootJointIndex) {
|
||||
|
@ -26,7 +25,7 @@ void AvatarRig::updateJointState(int index, glm::mat4 parentTransform) {
|
|||
clearJointTransformTranslation(index);
|
||||
} else {
|
||||
// guard against out-of-bounds access to _jointStates
|
||||
int parentIndex = joint.parentIndex;
|
||||
int parentIndex = state.getParentIndex();
|
||||
if (parentIndex >= 0 && parentIndex < _jointStates.size()) {
|
||||
const JointState& parentState = _jointStates.at(parentIndex);
|
||||
state.computeTransform(parentState.getTransform(), parentState.getTransformChanged());
|
||||
|
@ -53,8 +52,8 @@ void AvatarRig::setHandPosition(int jointIndex,
|
|||
}
|
||||
|
||||
// precomputed lengths
|
||||
float upperArmLength = _jointStates[elbowJointIndex].getFBXJoint().distanceToParent * scale;
|
||||
float lowerArmLength = _jointStates[jointIndex].getFBXJoint().distanceToParent * scale;
|
||||
float upperArmLength = _jointStates[elbowJointIndex].getDistanceToParent() * scale;
|
||||
float lowerArmLength = _jointStates[jointIndex].getDistanceToParent() * scale;
|
||||
|
||||
// first set wrist position
|
||||
glm::vec3 wristPosition = position;
|
||||
|
|
|
@ -14,15 +14,14 @@
|
|||
/// Updates the state of the joint at the specified index.
|
||||
void EntityRig::updateJointState(int index, glm::mat4 parentTransform) {
|
||||
JointState& state = _jointStates[index];
|
||||
const FBXJoint& joint = state.getFBXJoint();
|
||||
|
||||
// compute model transforms
|
||||
int parentIndex = joint.parentIndex;
|
||||
int parentIndex = state.getParentIndex();
|
||||
if (parentIndex == -1) {
|
||||
state.computeTransform(parentTransform);
|
||||
} else {
|
||||
// guard against out-of-bounds access to _jointStates
|
||||
if (joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) {
|
||||
if (parentIndex >= 0 && parentIndex < _jointStates.size()) {
|
||||
const JointState& parentState = _jointStates.at(parentIndex);
|
||||
state.computeTransform(parentState.getTransform(), parentState.getTransformChanged());
|
||||
}
|
||||
|
|
|
@ -18,17 +18,14 @@
|
|||
|
||||
#include "JointState.h"
|
||||
|
||||
JointState::JointState() :
|
||||
_animationPriority(0.0f),
|
||||
_transformChanged(true),
|
||||
_rotationIsValid(false),
|
||||
_positionInParentFrame(0.0f),
|
||||
_distanceToParent(0.0f),
|
||||
_fbxJoint(NULL),
|
||||
_constraint(NULL) {
|
||||
JointState::~JointState() {
|
||||
if (_constraint) {
|
||||
delete _constraint;
|
||||
_constraint = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
JointState::JointState(const JointState& other) : _constraint(NULL) {
|
||||
void JointState::copyState(const JointState& other) {
|
||||
_transformChanged = other._transformChanged;
|
||||
_transform = other._transform;
|
||||
_rotationIsValid = other._rotationIsValid;
|
||||
|
@ -37,17 +34,54 @@ JointState::JointState(const JointState& other) : _constraint(NULL) {
|
|||
_positionInParentFrame = other._positionInParentFrame;
|
||||
_distanceToParent = other._distanceToParent;
|
||||
_animationPriority = other._animationPriority;
|
||||
_fbxJoint = other._fbxJoint;
|
||||
|
||||
_visibleTransform = other._visibleTransform;
|
||||
_visibleRotation = extractRotation(_visibleTransform);
|
||||
_visibleRotationInConstrainedFrame = other._visibleRotationInConstrainedFrame;
|
||||
// DO NOT copy _constraint
|
||||
_name = other._name;
|
||||
_isFree = other._isFree;
|
||||
_boneRadius = other._boneRadius;
|
||||
_parentIndex = other._parentIndex;
|
||||
_defaultRotation = other._defaultRotation;
|
||||
_inverseDefaultRotation = other._inverseDefaultRotation;
|
||||
_translation = other._translation;
|
||||
_rotationMin = other._rotationMin;
|
||||
_rotationMax = other._rotationMax;
|
||||
_preRotation = other._preRotation;
|
||||
_postRotation = other._postRotation;
|
||||
_preTransform = other._preTransform;
|
||||
_postTransform = other._postTransform;
|
||||
_inverseBindRotation = other._inverseBindRotation;
|
||||
}
|
||||
JointState::JointState(const FBXJoint& joint) {
|
||||
_rotationInConstrainedFrame = joint.rotation;
|
||||
_name = joint.name;
|
||||
_isFree = joint.isFree;
|
||||
_boneRadius = joint.boneRadius;
|
||||
_parentIndex = joint.parentIndex;
|
||||
_translation = joint.translation;
|
||||
_defaultRotation = joint.rotation;
|
||||
_inverseDefaultRotation = joint.inverseDefaultRotation;
|
||||
_rotationMin = joint.rotationMin;
|
||||
_rotationMax = joint.rotationMax;
|
||||
_preRotation = joint.preRotation;
|
||||
_postRotation = joint.postRotation;
|
||||
_preTransform = joint.preTransform;
|
||||
_postTransform = joint.postTransform;
|
||||
_inverseBindRotation = joint.inverseBindRotation;
|
||||
}
|
||||
|
||||
JointState::~JointState() {
|
||||
delete _constraint;
|
||||
_constraint = NULL;
|
||||
void JointState::buildConstraint() {
|
||||
if (_constraint) {
|
||||
delete _constraint;
|
||||
_constraint = NULL;
|
||||
}
|
||||
if (glm::distance2(glm::vec3(-PI), _rotationMin) > EPSILON ||
|
||||
glm::distance2(glm::vec3(PI), _rotationMax) > EPSILON ) {
|
||||
// this joint has rotation constraints
|
||||
_constraint = AngularConstraint::newAngularConstraint(_rotationMin, _rotationMax);
|
||||
}
|
||||
}
|
||||
|
||||
glm::quat JointState::getRotation() const {
|
||||
|
@ -59,48 +93,6 @@ glm::quat JointState::getRotation() const {
|
|||
return _rotation;
|
||||
}
|
||||
|
||||
void JointState::setFBXJoint(const FBXJoint* joint) {
|
||||
assert(joint != NULL);
|
||||
_rotationInConstrainedFrame = joint->rotation;
|
||||
_transformChanged = true;
|
||||
_rotationIsValid = false;
|
||||
|
||||
// NOTE: JointState does not own the FBXJoint to which it points.
|
||||
_fbxJoint = joint;
|
||||
if (_constraint) {
|
||||
delete _constraint;
|
||||
_constraint = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void JointState::buildConstraint() {
|
||||
if (_constraint) {
|
||||
delete _constraint;
|
||||
_constraint = NULL;
|
||||
}
|
||||
if (glm::distance2(glm::vec3(-PI), _fbxJoint->rotationMin) > EPSILON ||
|
||||
glm::distance2(glm::vec3(PI), _fbxJoint->rotationMax) > EPSILON ) {
|
||||
// this joint has rotation constraints
|
||||
_constraint = AngularConstraint::newAngularConstraint(_fbxJoint->rotationMin, _fbxJoint->rotationMax);
|
||||
}
|
||||
}
|
||||
|
||||
void JointState::copyState(const JointState& state) {
|
||||
_animationPriority = state._animationPriority;
|
||||
_transformChanged = state._transformChanged;
|
||||
_transform = state._transform;
|
||||
_rotationIsValid = state._rotationIsValid;
|
||||
_rotation = state._rotation;
|
||||
_rotationInConstrainedFrame = state._rotationInConstrainedFrame;
|
||||
_positionInParentFrame = state._positionInParentFrame;
|
||||
_distanceToParent = state._distanceToParent;
|
||||
|
||||
_visibleTransform = state._visibleTransform;
|
||||
_visibleRotation = extractRotation(_visibleTransform);
|
||||
_visibleRotationInConstrainedFrame = state._visibleRotationInConstrainedFrame;
|
||||
// DO NOT copy _fbxJoint or _constraint
|
||||
}
|
||||
|
||||
void JointState::initTransform(const glm::mat4& parentTransform) {
|
||||
computeTransform(parentTransform);
|
||||
_positionInParentFrame = glm::inverse(extractRotation(parentTransform)) * (extractTranslation(_transform) - extractTranslation(parentTransform));
|
||||
|
@ -112,9 +104,9 @@ void JointState::computeTransform(const glm::mat4& parentTransform, bool parentT
|
|||
return;
|
||||
}
|
||||
|
||||
glm::quat rotationInParentFrame = _fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation;
|
||||
glm::mat4 transformInParentFrame = _fbxJoint->preTransform * glm::mat4_cast(rotationInParentFrame) * _fbxJoint->postTransform;
|
||||
glm::mat4 newTransform = parentTransform * glm::translate(_fbxJoint->translation) * transformInParentFrame;
|
||||
glm::quat rotationInParentFrame = _preRotation * _rotationInConstrainedFrame * _postRotation;
|
||||
glm::mat4 transformInParentFrame = _preTransform * glm::mat4_cast(rotationInParentFrame) * _postTransform;
|
||||
glm::mat4 newTransform = parentTransform * glm::translate(_translation) * transformInParentFrame;
|
||||
|
||||
if (newTransform != _transform) {
|
||||
_transform = newTransform;
|
||||
|
@ -124,37 +116,35 @@ void JointState::computeTransform(const glm::mat4& parentTransform, bool parentT
|
|||
}
|
||||
|
||||
void JointState::computeVisibleTransform(const glm::mat4& parentTransform) {
|
||||
glm::quat rotationInParentFrame = _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation;
|
||||
glm::mat4 transformInParentFrame = _fbxJoint->preTransform * glm::mat4_cast(rotationInParentFrame) * _fbxJoint->postTransform;
|
||||
_visibleTransform = parentTransform * glm::translate(_fbxJoint->translation) * transformInParentFrame;
|
||||
glm::quat rotationInParentFrame = _preRotation * _visibleRotationInConstrainedFrame * _postRotation;
|
||||
glm::mat4 transformInParentFrame = _preTransform * glm::mat4_cast(rotationInParentFrame) * _postTransform;
|
||||
_visibleTransform = parentTransform * glm::translate(_translation) * transformInParentFrame;
|
||||
_visibleRotation = extractRotation(_visibleTransform);
|
||||
}
|
||||
|
||||
glm::quat JointState::getRotationInBindFrame() const {
|
||||
return getRotation() * _fbxJoint->inverseBindRotation;
|
||||
return getRotation() * _inverseBindRotation;
|
||||
}
|
||||
|
||||
glm::quat JointState::getRotationInParentFrame() const {
|
||||
return _fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation;
|
||||
return _preRotation * _rotationInConstrainedFrame * _postRotation;
|
||||
}
|
||||
|
||||
glm::quat JointState::getVisibleRotationInParentFrame() const {
|
||||
return _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation;
|
||||
return _preRotation * _visibleRotationInConstrainedFrame * _postRotation;
|
||||
}
|
||||
|
||||
void JointState::restoreRotation(float fraction, float priority) {
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority == _animationPriority || _animationPriority == 0.0f) {
|
||||
setRotationInConstrainedFrameInternal(safeMix(_rotationInConstrainedFrame, _fbxJoint->rotation, fraction));
|
||||
setRotationInConstrainedFrameInternal(safeMix(_rotationInConstrainedFrame, _defaultRotation, fraction));
|
||||
_animationPriority = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void JointState::setRotationInBindFrame(const glm::quat& rotation, float priority, bool constrain) {
|
||||
// rotation is from bind- to model-frame
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority >= _animationPriority) {
|
||||
glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * rotation * glm::inverse(_fbxJoint->inverseBindRotation);
|
||||
glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * rotation * glm::inverse(_inverseBindRotation);
|
||||
if (constrain && _constraint) {
|
||||
_constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f);
|
||||
}
|
||||
|
@ -175,7 +165,6 @@ void JointState::clearTransformTranslation() {
|
|||
|
||||
void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) {
|
||||
// NOTE: delta is in model-frame
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority < _animationPriority || delta == glm::quat()) {
|
||||
return;
|
||||
}
|
||||
|
@ -196,14 +185,13 @@ void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, floa
|
|||
/// This helps keep an IK solution stable.
|
||||
void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float priority) {
|
||||
// NOTE: delta is in model-frame
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority < _animationPriority) {
|
||||
return;
|
||||
}
|
||||
_animationPriority = priority;
|
||||
glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * delta * getRotation();
|
||||
if (mixFactor > 0.0f && mixFactor <= 1.0f) {
|
||||
targetRotation = safeMix(targetRotation, _fbxJoint->rotation, mixFactor);
|
||||
targetRotation = safeMix(targetRotation, _defaultRotation, mixFactor);
|
||||
}
|
||||
if (_constraint) {
|
||||
_constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f);
|
||||
|
@ -213,10 +201,8 @@ void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float
|
|||
|
||||
void JointState::mixVisibleRotationDelta(const glm::quat& delta, float mixFactor) {
|
||||
// NOTE: delta is in model-frame
|
||||
assert(_fbxJoint != NULL);
|
||||
glm::quat targetRotation = _visibleRotationInConstrainedFrame * glm::inverse(_visibleRotation) * delta * _visibleRotation;
|
||||
if (mixFactor > 0.0f && mixFactor <= 1.0f) {
|
||||
//targetRotation = safeMix(targetRotation, _fbxJoint->rotation, mixFactor);
|
||||
targetRotation = safeMix(targetRotation, _rotationInConstrainedFrame, mixFactor);
|
||||
}
|
||||
setVisibleRotationInConstrainedFrame(targetRotation);
|
||||
|
@ -225,11 +211,11 @@ void JointState::mixVisibleRotationDelta(const glm::quat& delta, float mixFactor
|
|||
glm::quat JointState::computeParentRotation() const {
|
||||
// R = Rp * Rpre * r * Rpost
|
||||
// Rp = R * (Rpre * r * Rpost)^
|
||||
return getRotation() * glm::inverse(_fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation);
|
||||
return getRotation() * glm::inverse(_preRotation * _rotationInConstrainedFrame * _postRotation);
|
||||
}
|
||||
|
||||
glm::quat JointState::computeVisibleParentRotation() const {
|
||||
return _visibleRotation * glm::inverse(_fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation);
|
||||
return _visibleRotation * glm::inverse(_preRotation * _visibleRotationInConstrainedFrame * _postRotation);
|
||||
}
|
||||
|
||||
void JointState::setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain, float mix) {
|
||||
|
@ -248,17 +234,17 @@ void JointState::setRotationInConstrainedFrameInternal(const glm::quat& targetRo
|
|||
_rotationInConstrainedFrame = targetRotation;
|
||||
_transformChanged = true;
|
||||
// R' = Rp * Rpre * r' * Rpost
|
||||
_rotation = parentRotation * _fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation;
|
||||
_rotation = parentRotation * _preRotation * _rotationInConstrainedFrame * _postRotation;
|
||||
}
|
||||
|
||||
void JointState::setVisibleRotationInConstrainedFrame(const glm::quat& targetRotation) {
|
||||
glm::quat parentRotation = computeVisibleParentRotation();
|
||||
_visibleRotationInConstrainedFrame = targetRotation;
|
||||
_visibleRotation = parentRotation * _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation;
|
||||
_visibleRotation = parentRotation * _preRotation * _visibleRotationInConstrainedFrame * _postRotation;
|
||||
}
|
||||
|
||||
bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) const {
|
||||
glm::quat defaultRotation = _fbxJoint->rotation;
|
||||
glm::quat defaultRotation = _defaultRotation;
|
||||
return glm::abs(rotation.x - defaultRotation.x) < tolerance &&
|
||||
glm::abs(rotation.y - defaultRotation.y) < tolerance &&
|
||||
glm::abs(rotation.z - defaultRotation.z) < tolerance &&
|
||||
|
@ -266,13 +252,12 @@ bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) c
|
|||
}
|
||||
|
||||
glm::quat JointState::getDefaultRotationInParentFrame() const {
|
||||
// NOTE: the result is constant and could be cached in the FBXJoint
|
||||
return _fbxJoint->preRotation * _fbxJoint->rotation * _fbxJoint->postRotation;
|
||||
// NOTE: the result is constant and could be cached
|
||||
return _preRotation * _defaultRotation * _postRotation;
|
||||
}
|
||||
|
||||
const glm::vec3& JointState::getDefaultTranslationInConstrainedFrame() const {
|
||||
assert(_fbxJoint != NULL);
|
||||
return _fbxJoint->translation;
|
||||
return _translation;
|
||||
}
|
||||
|
||||
void JointState::slaveVisibleTransform() {
|
||||
|
|
|
@ -26,16 +26,13 @@ class AngularConstraint;
|
|||
|
||||
class JointState {
|
||||
public:
|
||||
JointState();
|
||||
JointState(const JointState& other);
|
||||
JointState() {}
|
||||
JointState(const JointState& other) : _constraint(NULL) { copyState(other); }
|
||||
JointState(const FBXJoint& joint);
|
||||
~JointState();
|
||||
|
||||
void setFBXJoint(const FBXJoint* joint);
|
||||
const FBXJoint& getFBXJoint() const { return *_fbxJoint; }
|
||||
|
||||
void buildConstraint();
|
||||
void copyState(const JointState& state);
|
||||
|
||||
void buildConstraint();
|
||||
|
||||
void initTransform(const glm::mat4& parentTransform);
|
||||
// if synchronousRotationCompute is true, then _transform is still computed synchronously,
|
||||
// but _rotation will be asynchronously extracted
|
||||
|
@ -61,7 +58,7 @@ public:
|
|||
const glm::vec3& getPositionInParentFrame() const { return _positionInParentFrame; }
|
||||
float getDistanceToParent() const { return _distanceToParent; }
|
||||
|
||||
int getParentIndex() const { return _fbxJoint->parentIndex; }
|
||||
int getParentIndex() const { return _parentIndex; }
|
||||
|
||||
/// \param delta is in the model-frame
|
||||
void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f);
|
||||
|
@ -99,35 +96,61 @@ public:
|
|||
|
||||
void slaveVisibleTransform();
|
||||
|
||||
float _animationPriority; // the priority of the animation affecting this joint
|
||||
|
||||
/// \return parent model-frame rotation
|
||||
/// \return parent model-frame rotation
|
||||
// (used to keep _rotation consistent when modifying _rotationInWorldFrame directly)
|
||||
glm::quat computeParentRotation() const;
|
||||
glm::quat computeVisibleParentRotation() const;
|
||||
|
||||
void setTransform(const glm::mat4& transform) { _transform = transform; }
|
||||
void setVisibleTransform(const glm::mat4& transform) { _visibleTransform = transform; }
|
||||
|
||||
const glm::vec3& getTranslation() const { return _translation; }
|
||||
const glm::mat4& getPreTransform() const { return _preTransform; }
|
||||
const glm::mat4& getPostTransform() const { return _postTransform; }
|
||||
const glm::quat& getPreRotation() const { return _preRotation; }
|
||||
const glm::quat& getPostRotation() const { return _postRotation; }
|
||||
const glm::quat& getDefaultRotation() const { return _defaultRotation; }
|
||||
const glm::quat& getInverseDefaultRotation() const { return _inverseDefaultRotation; }
|
||||
const QString& getName() const { return _name; }
|
||||
float getBoneRadius() const { return _boneRadius; }
|
||||
bool getIsFree() const { return _isFree; }
|
||||
float getAnimationPriority() const { return _animationPriority; }
|
||||
void setAnimationPriority(float priority) { _animationPriority = priority; }
|
||||
|
||||
private:
|
||||
void setRotationInConstrainedFrameInternal(const glm::quat& targetRotation);
|
||||
/// debug helper function
|
||||
void loadBindRotation();
|
||||
|
||||
bool _transformChanged;
|
||||
bool _transformChanged {true};
|
||||
bool _rotationIsValid {false};
|
||||
glm::vec3 _positionInParentFrame {0.0f}; // only changes when the Model is scaled
|
||||
float _animationPriority {0.0f}; // the priority of the animation affecting this joint
|
||||
float _distanceToParent {0.0f};
|
||||
AngularConstraint* _constraint{nullptr}; // JointState owns its AngularConstraint
|
||||
|
||||
glm::mat4 _transform; // joint- to model-frame
|
||||
bool _rotationIsValid;
|
||||
glm::quat _rotation; // joint- to model-frame
|
||||
glm::quat _rotationInConstrainedFrame; // rotation in frame where angular constraints would be applied
|
||||
glm::vec3 _positionInParentFrame; // only changes when the Model is scaled
|
||||
float _distanceToParent;
|
||||
|
||||
glm::mat4 _visibleTransform;
|
||||
glm::quat _visibleRotation;
|
||||
glm::quat _visibleRotationInConstrainedFrame;
|
||||
|
||||
const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint
|
||||
AngularConstraint* _constraint; // JointState owns its AngularConstraint
|
||||
glm::quat _defaultRotation; // Not necessarilly bind rotation. See FBXJoint transform/bindTransform
|
||||
glm::quat _inverseDefaultRotation;
|
||||
glm::vec3 _translation;
|
||||
QString _name;
|
||||
int _parentIndex;
|
||||
bool _isFree;
|
||||
float _boneRadius;
|
||||
glm::vec3 _rotationMin;
|
||||
glm::vec3 _rotationMax;
|
||||
glm::quat _preRotation;
|
||||
glm::quat _postRotation;
|
||||
glm::mat4 _preTransform;
|
||||
glm::mat4 _postTransform;
|
||||
glm::quat _inverseBindRotation;
|
||||
};
|
||||
|
||||
#endif // hifi_JointState_h
|
||||
|
|
|
@ -224,7 +224,7 @@ float Rig::initJointStates(QVector<JointState> states, glm::mat4 parentTransform
|
|||
// Should we be using .fst mapping instead/also?
|
||||
int Rig::indexOfJoint(const QString& jointName) {
|
||||
for (int i = 0; i < _jointStates.count(); i++) {
|
||||
if (_jointStates[i].getFBXJoint().name == jointName) {
|
||||
if (_jointStates[i].getName() == jointName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -237,8 +237,7 @@ void Rig::initJointTransforms(glm::mat4 parentTransform) {
|
|||
int numStates = _jointStates.size();
|
||||
for (int i = 0; i < numStates; ++i) {
|
||||
JointState& state = _jointStates[i];
|
||||
const FBXJoint& joint = state.getFBXJoint();
|
||||
int parentIndex = joint.parentIndex;
|
||||
int parentIndex = state.getParentIndex();
|
||||
if (parentIndex == -1) {
|
||||
state.initTransform(parentTransform);
|
||||
} else {
|
||||
|
@ -302,20 +301,20 @@ void Rig::clearJointStates() {
|
|||
|
||||
void Rig::clearJointAnimationPriority(int index) {
|
||||
if (index != -1 && index < _jointStates.size()) {
|
||||
_jointStates[index]._animationPriority = 0.0f;
|
||||
_jointStates[index].setAnimationPriority(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
float Rig::getJointAnimatinoPriority(int index) {
|
||||
if (index != -1 && index < _jointStates.size()) {
|
||||
return _jointStates[index]._animationPriority;
|
||||
return _jointStates[index].getAnimationPriority();
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void Rig::setJointAnimatinoPriority(int index, float newPriority) {
|
||||
if (index != -1 && index < _jointStates.size()) {
|
||||
_jointStates[index]._animationPriority = newPriority;
|
||||
_jointStates[index].setAnimationPriority(newPriority);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -532,8 +531,7 @@ bool Rig::setJointPosition(int jointIndex, const glm::vec3& position, const glm:
|
|||
for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) {
|
||||
int index = freeLineage.at(j);
|
||||
JointState& state = _jointStates[index];
|
||||
const FBXJoint& joint = state.getFBXJoint();
|
||||
if (!(joint.isFree || allIntermediatesFree)) {
|
||||
if (!(state.getIsFree() || allIntermediatesFree)) {
|
||||
continue;
|
||||
}
|
||||
glm::vec3 jointPosition = extractTranslation(state.getTransform());
|
||||
|
@ -602,8 +600,7 @@ void Rig::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::q
|
|||
{
|
||||
int index = freeLineage.last();
|
||||
const JointState& state = _jointStates.at(index);
|
||||
const FBXJoint& joint = state.getFBXJoint();
|
||||
int parentIndex = joint.parentIndex;
|
||||
int parentIndex = state.getParentIndex();
|
||||
if (parentIndex == -1) {
|
||||
topParentTransform = parentTransform;
|
||||
} else {
|
||||
|
@ -628,8 +625,7 @@ void Rig::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::q
|
|||
for (int j = 1; j < numFree; j++) {
|
||||
int nextIndex = freeLineage.at(j);
|
||||
JointState& nextState = _jointStates[nextIndex];
|
||||
FBXJoint nextJoint = nextState.getFBXJoint();
|
||||
if (! nextJoint.isFree) {
|
||||
if (! nextState.getIsFree()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -803,20 +799,20 @@ void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, floa
|
|||
glm::angleAxis(- RADIANS_PER_DEGREE * leanSideways, inverse * zAxis) *
|
||||
glm::angleAxis(- RADIANS_PER_DEGREE * leanForward, inverse * xAxis) *
|
||||
glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, inverse * yAxis) *
|
||||
getJointState(index).getFBXJoint().rotation, DEFAULT_PRIORITY);
|
||||
getJointState(index).getDefaultRotation(), DEFAULT_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, float leanSideways, float leanForward, float torsoTwist) {
|
||||
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
|
||||
auto& parentState = _jointStates[_jointStates[index].getParentIndex()];
|
||||
auto joint = _jointStates[index].getFBXJoint();
|
||||
auto& state = _jointStates[index];
|
||||
auto& parentState = _jointStates[state.getParentIndex()];
|
||||
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
glm::mat3 axes = glm::mat3_cast(glm::quat());
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() *
|
||||
glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||
state.getPreTransform() * glm::mat4_cast(state.getPreRotation())));
|
||||
glm::vec3 pitchYawRoll = safeEulerAngles(localHeadOrientation);
|
||||
glm::vec3 lean = glm::radians(glm::vec3(leanForward, torsoTwist, leanSideways));
|
||||
pitchYawRoll -= lean;
|
||||
|
@ -824,19 +820,19 @@ void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, floa
|
|||
glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) *
|
||||
glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) *
|
||||
glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) *
|
||||
joint.rotation, DEFAULT_PRIORITY);
|
||||
state.getDefaultRotation(), DEFAULT_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade) {
|
||||
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
|
||||
auto& parentState = _jointStates[_jointStates[index].getParentIndex()];
|
||||
auto joint = _jointStates[index].getFBXJoint();
|
||||
auto& state = _jointStates[index];
|
||||
auto& parentState = _jointStates[state.getParentIndex()];
|
||||
|
||||
// NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual.
|
||||
glm::mat4 inverse = glm::inverse(parentState.getTransform() *
|
||||
glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation));
|
||||
state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getDefaultRotation()));
|
||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(worldHeadOrientation * IDENTITY_FRONT, 0.0f));
|
||||
glm::vec3 lookAtDelta = lookAt;
|
||||
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * saccade, 1.0f));
|
||||
|
@ -844,6 +840,6 @@ void Rig::updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const
|
|||
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE;
|
||||
float angle = glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE);
|
||||
glm::quat rot = glm::angleAxis(angle, glm::axis(between));
|
||||
setJointRotationInConstrainedFrame(index, rot * joint.rotation, DEFAULT_PRIORITY);
|
||||
setJointRotationInConstrainedFrame(index, rot * state.getDefaultRotation(), DEFAULT_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,24 +227,30 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
|
||||
if (hasModel()) {
|
||||
if (_model) {
|
||||
if (QUrl(getModelURL()) != _model->getURL()) {
|
||||
if (getModelURL() != _model->getURLAsString()) {
|
||||
qDebug() << "Updating model URL: " << getModelURL();
|
||||
_model->setURL(getModelURL());
|
||||
}
|
||||
|
||||
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
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
render::PendingChanges pendingChanges;
|
||||
if (_model->needsFixupInScene()) {
|
||||
render::PendingChanges pendingChanges;
|
||||
|
||||
_model->removeFromScene(scene, pendingChanges);
|
||||
|
||||
render::Item::Status::Getters statusGetters;
|
||||
makeEntityItemStatusGetters(this, statusGetters);
|
||||
_model->addToScene(scene, pendingChanges, statusGetters);
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -269,7 +275,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
}
|
||||
|
||||
if (jointsMapped()) {
|
||||
QVector<glm::quat> frameData = getAnimationFrame();
|
||||
auto frameData = getAnimationFrame();
|
||||
for (int i = 0; i < frameData.size(); i++) {
|
||||
_model->setJointState(i, true, frameData[i]);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <DeferredLightingEffect.h>
|
||||
#include <Model.h>
|
||||
#include <PerfStat.h>
|
||||
#include <render/Scene.h>
|
||||
|
||||
#include <PolyVoxCore/CubicSurfaceExtractorWithNormals.h>
|
||||
#include <PolyVoxCore/MarchingCubesSurfaceExtractor.h>
|
||||
|
@ -37,7 +38,11 @@
|
|||
#include "model/Geometry.h"
|
||||
#include "gpu/Context.h"
|
||||
#include "EntityTreeRenderer.h"
|
||||
#include "RenderablePolyVoxEntityItem.h"
|
||||
#include "polyvox_vert.h"
|
||||
#include "polyvox_frag.h"
|
||||
#include "RenderablePolyVoxEntityItem.h"
|
||||
|
||||
gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr;
|
||||
|
||||
EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
return std::make_shared<RenderablePolyVoxEntityItem>(entityID, properties);
|
||||
|
@ -45,8 +50,10 @@ EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entit
|
|||
|
||||
RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID,
|
||||
const EntityItemProperties& properties) :
|
||||
PolyVoxEntityItem(entityItemID, properties) {
|
||||
|
||||
PolyVoxEntityItem(entityItemID, properties),
|
||||
_xTexture(nullptr),
|
||||
_yTexture(nullptr),
|
||||
_zTexture(nullptr) {
|
||||
model::Mesh* mesh = new model::Mesh();
|
||||
model::MeshPointer meshPtr(mesh);
|
||||
_modelGeometry.setMesh(meshPtr);
|
||||
|
@ -275,7 +282,6 @@ void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) {
|
|||
for (int z = 0; z < _voxelVolumeSize.z; z++) {
|
||||
for (int y = 0; y < _voxelVolumeSize.y; y++) {
|
||||
for (int x = 0; x < _voxelVolumeSize.x; x++) {
|
||||
updateOnCount(x, y, z, toValue);
|
||||
setVoxelInternal(x, y, z, toValue);
|
||||
}
|
||||
}
|
||||
|
@ -325,106 +331,6 @@ void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r
|
|||
setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue);
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::getModel() {
|
||||
// A mesh object to hold the result of surface extraction
|
||||
PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> polyVoxMesh;
|
||||
|
||||
switch (_voxelSurfaceStyle) {
|
||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: {
|
||||
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||
surfaceExtractor.execute();
|
||||
break;
|
||||
}
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
||||
case PolyVoxEntityItem::SURFACE_CUBIC: {
|
||||
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||
surfaceExtractor.execute();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert PolyVox mesh to a Sam mesh
|
||||
auto mesh = _modelGeometry.getMesh();
|
||||
|
||||
const std::vector<uint32_t>& vecIndices = polyVoxMesh.getIndices();
|
||||
auto indexBuffer = std::make_shared<gpu::Buffer>(vecIndices.size() * sizeof(uint32_t),
|
||||
(gpu::Byte*)vecIndices.data());
|
||||
auto indexBufferPtr = gpu::BufferPointer(indexBuffer);
|
||||
auto indexBufferView = new gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW));
|
||||
mesh->setIndexBuffer(*indexBufferView);
|
||||
|
||||
|
||||
const std::vector<PolyVox::PositionMaterialNormal>& vecVertices = polyVoxMesh.getVertices();
|
||||
auto vertexBuffer = std::make_shared<gpu::Buffer>(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal),
|
||||
(gpu::Byte*)vecVertices.data());
|
||||
auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer);
|
||||
auto vertexBufferView = new gpu::BufferView(vertexBufferPtr,
|
||||
0,
|
||||
vertexBufferPtr->getSize() - sizeof(float) * 3,
|
||||
sizeof(PolyVox::PositionMaterialNormal),
|
||||
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW));
|
||||
mesh->setVertexBuffer(*vertexBufferView);
|
||||
mesh->addAttribute(gpu::Stream::NORMAL,
|
||||
gpu::BufferView(vertexBufferPtr,
|
||||
sizeof(float) * 3,
|
||||
vertexBufferPtr->getSize() - sizeof(float) * 3,
|
||||
sizeof(PolyVox::PositionMaterialNormal),
|
||||
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
|
||||
|
||||
|
||||
|
||||
// auto normalAttrib = mesh->getAttributeBuffer(gpu::Stream::NORMAL);
|
||||
// for (auto normal = normalAttrib.begin<glm::vec3>(); normal != normalAttrib.end<glm::vec3>(); normal++) {
|
||||
// (*normal) = -(*normal);
|
||||
// }
|
||||
|
||||
|
||||
// mesh->addAttribute(gpu::Stream::TEXCOORD,
|
||||
// gpu::BufferView(vertexBufferPtr,
|
||||
// sizeof(float) * 2,
|
||||
// vertexBufferPtr->getSize() - sizeof(float) * 2,
|
||||
// sizeof(PolyVox::PositionMaterialNormal),
|
||||
// gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::RAW)));
|
||||
|
||||
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug() << "---- vecIndices.size() =" << vecIndices.size();
|
||||
qDebug() << "---- vecVertices.size() =" << vecVertices.size();
|
||||
#endif
|
||||
|
||||
_needsModelReload = false;
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render");
|
||||
assert(getType() == EntityTypes::PolyVox);
|
||||
|
||||
if (_needsModelReload) {
|
||||
getModel();
|
||||
}
|
||||
|
||||
Transform transform(voxelToWorldMatrix());
|
||||
|
||||
auto mesh = _modelGeometry.getMesh();
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
|
||||
batch.setModelTransform(transform);
|
||||
batch.setInputFormat(mesh->getVertexFormat());
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer());
|
||||
batch.setInputBuffer(gpu::Stream::NORMAL,
|
||||
mesh->getVertexBuffer()._buffer,
|
||||
sizeof(float) * 3,
|
||||
mesh->getVertexBuffer()._stride);
|
||||
batch.setIndexBuffer(gpu::UINT32, mesh->getIndexBuffer()._buffer, 0);
|
||||
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
|
||||
|
||||
RenderableDebugableEntityItem::render(this, args);
|
||||
}
|
||||
|
||||
class RaycastFunctor
|
||||
{
|
||||
public:
|
||||
|
@ -709,3 +615,190 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
info.setParams(type, collisionModelDimensions, QString(b64));
|
||||
info.setConvexHulls(_points);
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setXTextureURL(QString xTextureURL) {
|
||||
PolyVoxEntityItem::setXTextureURL(xTextureURL);
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setYTextureURL(QString yTextureURL) {
|
||||
PolyVoxEntityItem::setYTextureURL(yTextureURL);
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) {
|
||||
PolyVoxEntityItem::setZTextureURL(zTextureURL);
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::getModel() {
|
||||
// A mesh object to hold the result of surface extraction
|
||||
PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> polyVoxMesh;
|
||||
|
||||
switch (_voxelSurfaceStyle) {
|
||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: {
|
||||
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||
surfaceExtractor.execute();
|
||||
break;
|
||||
}
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
||||
case PolyVoxEntityItem::SURFACE_CUBIC: {
|
||||
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||
surfaceExtractor.execute();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert PolyVox mesh to a Sam mesh
|
||||
auto mesh = _modelGeometry.getMesh();
|
||||
|
||||
const std::vector<uint32_t>& vecIndices = polyVoxMesh.getIndices();
|
||||
auto indexBuffer = std::make_shared<gpu::Buffer>(vecIndices.size() * sizeof(uint32_t),
|
||||
(gpu::Byte*)vecIndices.data());
|
||||
auto indexBufferPtr = gpu::BufferPointer(indexBuffer);
|
||||
auto indexBufferView = new gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW));
|
||||
mesh->setIndexBuffer(*indexBufferView);
|
||||
|
||||
|
||||
const std::vector<PolyVox::PositionMaterialNormal>& vecVertices = polyVoxMesh.getVertices();
|
||||
auto vertexBuffer = std::make_shared<gpu::Buffer>(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal),
|
||||
(gpu::Byte*)vecVertices.data());
|
||||
auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer);
|
||||
auto vertexBufferView = new gpu::BufferView(vertexBufferPtr,
|
||||
0,
|
||||
vertexBufferPtr->getSize() - sizeof(float) * 3,
|
||||
sizeof(PolyVox::PositionMaterialNormal),
|
||||
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW));
|
||||
mesh->setVertexBuffer(*vertexBufferView);
|
||||
mesh->addAttribute(gpu::Stream::NORMAL,
|
||||
gpu::BufferView(vertexBufferPtr,
|
||||
sizeof(float) * 3,
|
||||
vertexBufferPtr->getSize() - sizeof(float) * 3,
|
||||
sizeof(PolyVox::PositionMaterialNormal),
|
||||
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug() << "---- vecIndices.size() =" << vecIndices.size();
|
||||
qDebug() << "---- vecVertices.size() =" << vecVertices.size();
|
||||
#endif
|
||||
|
||||
_needsModelReload = false;
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render");
|
||||
assert(getType() == EntityTypes::PolyVox);
|
||||
Q_ASSERT(args->_batch);
|
||||
|
||||
if (!_pipeline) {
|
||||
gpu::ShaderPointer vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(polyvox_vert)));
|
||||
gpu::ShaderPointer pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(polyvox_frag)));
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("xMap"), 0));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2));
|
||||
|
||||
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
|
||||
_pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
|
||||
}
|
||||
|
||||
if (_needsModelReload) {
|
||||
getModel();
|
||||
}
|
||||
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setPipeline(_pipeline);
|
||||
|
||||
auto mesh = _modelGeometry.getMesh();
|
||||
Transform transform(voxelToWorldMatrix());
|
||||
batch.setModelTransform(transform);
|
||||
batch.setInputFormat(mesh->getVertexFormat());
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer());
|
||||
batch.setInputBuffer(gpu::Stream::NORMAL,
|
||||
mesh->getVertexBuffer()._buffer,
|
||||
sizeof(float) * 3,
|
||||
mesh->getVertexBuffer()._stride);
|
||||
batch.setIndexBuffer(gpu::UINT32, mesh->getIndexBuffer()._buffer, 0);
|
||||
|
||||
if (!_xTextureURL.isEmpty() && !_xTexture) {
|
||||
_xTexture = DependencyManager::get<TextureCache>()->getTexture(_xTextureURL);
|
||||
}
|
||||
if (!_yTextureURL.isEmpty() && !_yTexture) {
|
||||
_yTexture = DependencyManager::get<TextureCache>()->getTexture(_yTextureURL);
|
||||
}
|
||||
if (!_zTextureURL.isEmpty() && !_zTexture) {
|
||||
_zTexture = DependencyManager::get<TextureCache>()->getTexture(_zTextureURL);
|
||||
}
|
||||
|
||||
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
if (_xTexture) {
|
||||
batch.setResourceTexture(0, _xTexture->getGPUTexture());
|
||||
} else {
|
||||
batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
}
|
||||
if (_yTexture) {
|
||||
batch.setResourceTexture(1, _yTexture->getGPUTexture());
|
||||
} else {
|
||||
batch.setResourceTexture(1, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
}
|
||||
if (_zTexture) {
|
||||
batch.setResourceTexture(2, _zTexture->getGPUTexture());
|
||||
} else {
|
||||
batch.setResourceTexture(2, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
}
|
||||
|
||||
int voxelVolumeSizeLocation = _pipeline->getProgram()->getUniforms().findLocation("voxelVolumeSize");
|
||||
batch._glUniform3f(voxelVolumeSizeLocation, _voxelVolumeSize.x, _voxelVolumeSize.y, _voxelVolumeSize.z);
|
||||
|
||||
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
|
||||
|
||||
RenderableDebugableEntityItem::render(this, args);
|
||||
}
|
||||
|
||||
bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self,
|
||||
std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) {
|
||||
_myItem = scene->allocateID();
|
||||
|
||||
auto renderItem = std::make_shared<PolyVoxPayload>(shared_from_this());
|
||||
auto renderData = PolyVoxPayload::Pointer(renderItem);
|
||||
auto renderPayload = std::make_shared<PolyVoxPayload::Payload>(renderData);
|
||||
|
||||
pendingChanges.resetItem(_myItem, renderPayload);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::removeFromScene(EntityItemPointer self,
|
||||
std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_myItem);
|
||||
}
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const PolyVoxPayload::Pointer& payload) {
|
||||
return ItemKey::Builder::opaqueShape();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const PolyVoxPayload::Pointer& payload) {
|
||||
if (payload && payload->_owner) {
|
||||
auto polyVoxEntity = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(payload->_owner);
|
||||
return polyVoxEntity->getAABox();
|
||||
}
|
||||
return render::Item::Bound();
|
||||
}
|
||||
|
||||
template <> void payloadRender(const PolyVoxPayload::Pointer& payload, RenderArgs* args) {
|
||||
if (args && payload && payload->_owner) {
|
||||
payload->_owner->render(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,11 +13,30 @@
|
|||
#define hifi_RenderablePolyVoxEntityItem_h
|
||||
|
||||
#include <PolyVoxCore/SimpleVolume.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
#include "PolyVoxEntityItem.h"
|
||||
#include "RenderableDebugableEntityItem.h"
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
|
||||
class PolyVoxPayload {
|
||||
public:
|
||||
PolyVoxPayload(EntityItemPointer owner) : _owner(owner), _bounds(AABox()) { }
|
||||
typedef render::Payload<PolyVoxPayload> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
EntityItemPointer _owner;
|
||||
AABox _bounds;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const PolyVoxPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const PolyVoxPayload::Pointer& payload);
|
||||
template <> void payloadRender(const PolyVoxPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
|
||||
class RenderablePolyVoxEntityItem : public PolyVoxEntityItem {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
@ -70,7 +89,16 @@ public:
|
|||
|
||||
virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
virtual void setXTextureURL(QString xTextureURL);
|
||||
virtual void setYTextureURL(QString yTextureURL);
|
||||
virtual void setZTextureURL(QString zTextureURL);
|
||||
|
||||
virtual bool addToScene(EntityItemPointer self,
|
||||
std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges);
|
||||
virtual void removeFromScene(EntityItemPointer self,
|
||||
std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges);
|
||||
|
||||
protected:
|
||||
virtual void updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle);
|
||||
|
@ -90,7 +118,15 @@ private:
|
|||
|
||||
QVector<QVector<glm::vec3>> _points; // XXX
|
||||
|
||||
NetworkTexturePointer _xTexture;
|
||||
NetworkTexturePointer _yTexture;
|
||||
NetworkTexturePointer _zTexture;
|
||||
|
||||
int _onCount = 0; // how many non-zero voxels are in _volData
|
||||
|
||||
const int MATERIAL_GPU_SLOT = 3;
|
||||
render::ItemID _myItem;
|
||||
static gpu::PipelinePointer _pipeline;
|
||||
};
|
||||
|
||||
|
||||
|
|
54
libraries/entities-renderer/src/polyvox.slf
Normal file
54
libraries/entities-renderer/src/polyvox.slf
Normal file
|
@ -0,0 +1,54 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// model.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Seth Alves on 2015-8-3
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
|
||||
layout(location = 0) out vec4 _fragColor0;
|
||||
layout(location = 1) out vec4 _fragColor1;
|
||||
layout(location = 2) out vec4 _fragColor2;
|
||||
|
||||
<@include model/Material.slh@>
|
||||
|
||||
in vec3 _normal;
|
||||
in vec4 _position;
|
||||
in vec4 _inPosition;
|
||||
|
||||
uniform sampler2D xMap;
|
||||
uniform sampler2D yMap;
|
||||
uniform sampler2D zMap;
|
||||
uniform vec3 voxelVolumeSize;
|
||||
|
||||
void main(void) {
|
||||
vec3 worldNormal = cross(dFdy(_inPosition.xyz), dFdx(_inPosition.xyz));
|
||||
worldNormal = normalize(worldNormal);
|
||||
|
||||
float inPositionX = (_inPosition.x - 0.5) / voxelVolumeSize.x;
|
||||
float inPositionY = (_inPosition.y - 0.5) / voxelVolumeSize.y;
|
||||
float inPositionZ = (_inPosition.z - 0.5) / voxelVolumeSize.z;
|
||||
|
||||
vec4 xyDiffuse = texture2D(xMap, vec2(-inPositionX, -inPositionY));
|
||||
vec4 xzDiffuse = texture2D(yMap, vec2(-inPositionX, inPositionZ));
|
||||
vec4 yzDiffuse = texture2D(zMap, vec2(inPositionZ, -inPositionY));
|
||||
|
||||
vec3 xyDiffuseScaled = xyDiffuse.rgb * abs(worldNormal.z);
|
||||
vec3 xzDiffuseScaled = xzDiffuse.rgb * abs(worldNormal.y);
|
||||
vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x);
|
||||
|
||||
vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0);
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
_fragColor0 = vec4(diffuse.rgb, 0.0);
|
||||
_fragColor1 = vec4(_normal, 1.0);
|
||||
_fragColor2 = vec4(getMaterialSpecular(mat), getMaterialShininess(mat) / 128.0);
|
||||
}
|
30
libraries/entities-renderer/src/polyvox.slv
Normal file
30
libraries/entities-renderer/src/polyvox.slv
Normal file
|
@ -0,0 +1,30 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// polyvox.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec4 _position;
|
||||
out vec4 _inPosition;
|
||||
out vec3 _normal;
|
||||
|
||||
void main(void) {
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
|
||||
<$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
|
||||
_inPosition = inPosition;
|
||||
}
|
|
@ -105,6 +105,9 @@ CONSTRUCT_PROPERTY(faceCamera, TextEntityItem::DEFAULT_FACE_CAMERA),
|
|||
CONSTRUCT_PROPERTY(actionData, QByteArray()),
|
||||
CONSTRUCT_PROPERTY(normals, QVector<glm::vec3>()),
|
||||
CONSTRUCT_PROPERTY(strokeWidths, QVector<float>()),
|
||||
CONSTRUCT_PROPERTY(xTextureURL, ""),
|
||||
CONSTRUCT_PROPERTY(yTextureURL, ""),
|
||||
CONSTRUCT_PROPERTY(zTextureURL, ""),
|
||||
|
||||
_id(UNKNOWN_ENTITY_ID),
|
||||
_idSet(false),
|
||||
|
@ -369,6 +372,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_ACTION_DATA, actionData);
|
||||
CHECK_PROPERTY_CHANGE(PROP_NORMALS, normals);
|
||||
CHECK_PROPERTY_CHANGE(PROP_STROKE_WIDTHS, strokeWidths);
|
||||
CHECK_PROPERTY_CHANGE(PROP_X_TEXTURE_URL, xTextureURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_Y_TEXTURE_URL, yTextureURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_Z_TEXTURE_URL, zTextureURL);
|
||||
|
||||
changedProperties += _stage.getChangedProperties();
|
||||
changedProperties += _atmosphere.getChangedProperties();
|
||||
|
@ -508,6 +514,10 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
_atmosphere.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
|
||||
_skybox.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(xTextureURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(yTextureURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(zTextureURL);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
@ -600,6 +610,12 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
_stage.copyFromScriptValue(object, _defaultSettings);
|
||||
_atmosphere.copyFromScriptValue(object, _defaultSettings);
|
||||
_skybox.copyFromScriptValue(object, _defaultSettings);
|
||||
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(xTextureURL, QString, setXTextureURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(zTextureURL, QString, setZTextureURL);
|
||||
|
||||
_lastEdited = usecTimestampNow();
|
||||
}
|
||||
|
||||
|
@ -827,6 +843,9 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent
|
|||
APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, properties.getVoxelVolumeSize());
|
||||
APPEND_ENTITY_PROPERTY(PROP_VOXEL_DATA, properties.getVoxelData());
|
||||
APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, properties.getVoxelSurfaceStyle());
|
||||
APPEND_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, properties.getXTextureURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, properties.getYTextureURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, properties.getZTextureURL());
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Line) {
|
||||
|
@ -1086,6 +1105,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_VOLUME_SIZE, glm::vec3, setVoxelVolumeSize);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_DATA, QByteArray, setVoxelData);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_X_TEXTURE_URL, QString, setXTextureURL);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_TEXTURE_URL, QString, setYTextureURL);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Z_TEXTURE_URL, QString, setZTextureURL);
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Line) {
|
||||
|
@ -1221,6 +1243,10 @@ void EntityItemProperties::markAllChanged() {
|
|||
|
||||
_normalsChanged = true;
|
||||
_strokeWidthsChanged = true;
|
||||
|
||||
_xTextureURLChanged = true;
|
||||
_yTextureURLChanged = true;
|
||||
_zTextureURLChanged = true;
|
||||
}
|
||||
|
||||
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||
|
|
|
@ -157,6 +157,10 @@ public:
|
|||
DEFINE_PROPERTY(PROP_NORMALS, Normals, normals, QVector<glm::vec3>);
|
||||
DEFINE_PROPERTY(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector<float>);
|
||||
DEFINE_PROPERTY_REF(PROP_ACTION_DATA, ActionData, actionData, QByteArray);
|
||||
DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString);
|
||||
|
||||
static QString getBackgroundModeString(BackgroundMode mode);
|
||||
|
||||
|
||||
|
@ -319,6 +323,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Href, href, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Description, description, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ActionData, actionData, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, XTextureURL, xTextureURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, YTextureURL, yTextureURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZTextureURL, zTextureURL, "");
|
||||
|
||||
properties.getStage().debugDump();
|
||||
properties.getAtmosphere().debugDump();
|
||||
|
|
|
@ -127,10 +127,15 @@ enum EntityPropertyList {
|
|||
|
||||
PROP_ACTION_DATA,
|
||||
|
||||
//Used by quad entity
|
||||
PROP_X_TEXTURE_URL, // used by PolyVox
|
||||
PROP_Y_TEXTURE_URL, // used by PolyVox
|
||||
PROP_Z_TEXTURE_URL, // used by PolyVox
|
||||
|
||||
//Used by PolyLine entity
|
||||
PROP_NORMALS,
|
||||
PROP_STROKE_WIDTHS,
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ATTENTION: add new properties to end of list just ABOVE this line
|
||||
PROP_AFTER_LAST_ITEM,
|
||||
|
|
|
@ -61,7 +61,7 @@ public:
|
|||
virtual OctreeEditPacketSender* createPacketSender() { return new EntityEditPacketSender(); }
|
||||
|
||||
void setEntityTree(EntityTree* modelTree);
|
||||
EntityTree* getEntityTree(EntityTree*) { return _entityTree; }
|
||||
EntityTree* getEntityTree() { return _entityTree; }
|
||||
|
||||
public slots:
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityI
|
|||
setProperties(properties);
|
||||
_lastAnimated = usecTimestampNow();
|
||||
_jointMappingCompleted = false;
|
||||
_lastKnownFrameIndex = -1;
|
||||
_color[0] = _color[1] = _color[2] = 0;
|
||||
}
|
||||
|
||||
|
@ -217,15 +218,17 @@ void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
|
|||
}
|
||||
}
|
||||
|
||||
QVector<glm::quat> ModelEntityItem::getAnimationFrame() {
|
||||
QVector<glm::quat> frameData;
|
||||
const QVector<glm::quat>& ModelEntityItem::getAnimationFrame() {
|
||||
|
||||
if (!hasAnimation() || !_jointMappingCompleted) {
|
||||
return frameData;
|
||||
return _lastKnownFrameData;
|
||||
}
|
||||
|
||||
AnimationPointer myAnimation = getAnimation(_animationURL);
|
||||
AnimationPointer myAnimation = getAnimation(_animationURL); // FIXME: this could be optimized
|
||||
if (myAnimation && myAnimation->isLoaded()) {
|
||||
QVector<FBXAnimationFrame> frames = myAnimation->getFrames();
|
||||
|
||||
const QVector<FBXAnimationFrame>& frames = myAnimation->getFramesReference(); // NOTE: getFrames() is too heavy
|
||||
|
||||
int frameCount = frames.size();
|
||||
if (frameCount > 0) {
|
||||
int animationFrameIndex = (int)(glm::floor(getAnimationFrameIndex())) % frameCount;
|
||||
|
@ -233,18 +236,22 @@ QVector<glm::quat> ModelEntityItem::getAnimationFrame() {
|
|||
animationFrameIndex = 0;
|
||||
}
|
||||
|
||||
QVector<glm::quat> rotations = frames[animationFrameIndex].rotations;
|
||||
if (animationFrameIndex != _lastKnownFrameIndex) {
|
||||
_lastKnownFrameIndex = animationFrameIndex;
|
||||
|
||||
const QVector<glm::quat>& rotations = frames[animationFrameIndex].rotations;
|
||||
|
||||
frameData.resize(_jointMapping.size());
|
||||
for (int j = 0; j < _jointMapping.size(); j++) {
|
||||
int rotationIndex = _jointMapping[j];
|
||||
if (rotationIndex != -1 && rotationIndex < rotations.size()) {
|
||||
frameData[j] = rotations[rotationIndex];
|
||||
_lastKnownFrameData.resize(_jointMapping.size());
|
||||
for (int j = 0; j < _jointMapping.size(); j++) {
|
||||
int rotationIndex = _jointMapping[j];
|
||||
if (rotationIndex != -1 && rotationIndex < rotations.size()) {
|
||||
_lastKnownFrameData[j] = rotations[rotationIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return frameData;
|
||||
return _lastKnownFrameData;
|
||||
}
|
||||
|
||||
bool ModelEntityItem::isAnimatingSomething() const {
|
||||
|
|
|
@ -106,7 +106,7 @@ public:
|
|||
float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); }
|
||||
|
||||
void mapJoints(const QStringList& modelJointNames);
|
||||
QVector<glm::quat> getAnimationFrame();
|
||||
const QVector<glm::quat>& getAnimationFrame();
|
||||
bool jointsMapped() const { return _jointMappingCompleted; }
|
||||
|
||||
bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); }
|
||||
|
@ -123,6 +123,9 @@ public:
|
|||
static void cleanupLoadedAnimations();
|
||||
|
||||
protected:
|
||||
QVector<glm::quat> _lastKnownFrameData;
|
||||
int _lastKnownFrameIndex;
|
||||
|
||||
|
||||
bool isAnimatingSomething() const;
|
||||
|
||||
|
|
|
@ -35,10 +35,10 @@ PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID, const E
|
|||
EntityItem(entityItemID) ,
|
||||
_lineWidth(DEFAULT_LINE_WIDTH),
|
||||
_pointsChanged(true),
|
||||
_points(QVector<glm::vec3>(0)),
|
||||
_vertices(QVector<glm::vec3>(0)),
|
||||
_normals(QVector<glm::vec3>(0)),
|
||||
_strokeWidths(QVector<float>(0))
|
||||
_points(QVector<glm::vec3>(0.0f)),
|
||||
_vertices(QVector<glm::vec3>(0.0f)),
|
||||
_normals(QVector<glm::vec3>(0.0f)),
|
||||
_strokeWidths(QVector<float>(0.0f))
|
||||
{
|
||||
_type = EntityTypes::PolyLine;
|
||||
_created = properties.getCreated();
|
||||
|
@ -109,7 +109,7 @@ bool PolyLineEntityItem::setStrokeWidths(const QVector<float>& strokeWidths ) {
|
|||
|
||||
bool PolyLineEntityItem::setNormals(const QVector<glm::vec3>& normals) {
|
||||
_normals = normals;
|
||||
if (_points.size () < 2) {
|
||||
if (_points.size () < 2 || _normals.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,9 @@ const float PolyVoxEntityItem::MAX_VOXEL_DIMENSION = 32.0f;
|
|||
const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(PolyVoxEntityItem::makeEmptyVoxelData());
|
||||
const PolyVoxEntityItem::PolyVoxSurfaceStyle PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE =
|
||||
PolyVoxEntityItem::SURFACE_MARCHING_CUBES;
|
||||
const QString PolyVoxEntityItem::DEFAULT_X_TEXTURE_URL = QString("");
|
||||
const QString PolyVoxEntityItem::DEFAULT_Y_TEXTURE_URL = QString("");
|
||||
const QString PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL = QString("");
|
||||
|
||||
EntityItemPointer PolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
return std::make_shared<PolyVoxEntityItem>(entityID, properties);
|
||||
|
@ -49,7 +52,10 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const Ent
|
|||
EntityItem(entityItemID),
|
||||
_voxelVolumeSize(PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE),
|
||||
_voxelData(PolyVoxEntityItem::DEFAULT_VOXEL_DATA),
|
||||
_voxelSurfaceStyle(PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE)
|
||||
_voxelSurfaceStyle(PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE),
|
||||
_xTextureURL(PolyVoxEntityItem::DEFAULT_X_TEXTURE_URL),
|
||||
_yTextureURL(PolyVoxEntityItem::DEFAULT_Y_TEXTURE_URL),
|
||||
_zTextureURL(PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL)
|
||||
{
|
||||
_type = EntityTypes::PolyVox;
|
||||
setProperties(properties);
|
||||
|
@ -94,6 +100,9 @@ EntityItemProperties PolyVoxEntityItem::getProperties() const {
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelData, getVoxelData);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelSurfaceStyle, getVoxelSurfaceStyle);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(xTextureURL, getXTextureURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(yTextureURL, getYTextureURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(zTextureURL, getZTextureURL);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
@ -103,6 +112,9 @@ bool PolyVoxEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelVolumeSize, setVoxelVolumeSize);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelData, setVoxelData);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelSurfaceStyle, setVoxelSurfaceStyle);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(xTextureURL, setXTextureURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(yTextureURL, setYTextureURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(zTextureURL, setZTextureURL);
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
|
@ -127,6 +139,9 @@ int PolyVoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* dat
|
|||
READ_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, glm::vec3, setVoxelVolumeSize);
|
||||
READ_ENTITY_PROPERTY(PROP_VOXEL_DATA, QByteArray, setVoxelData);
|
||||
READ_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle);
|
||||
READ_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, QString, setXTextureURL);
|
||||
READ_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, QString, setYTextureURL);
|
||||
READ_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, QString, setZTextureURL);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
@ -138,6 +153,9 @@ EntityPropertyFlags PolyVoxEntityItem::getEntityProperties(EncodeBitstreamParams
|
|||
requestedProperties += PROP_VOXEL_VOLUME_SIZE;
|
||||
requestedProperties += PROP_VOXEL_DATA;
|
||||
requestedProperties += PROP_VOXEL_SURFACE_STYLE;
|
||||
requestedProperties += PROP_X_TEXTURE_URL;
|
||||
requestedProperties += PROP_Y_TEXTURE_URL;
|
||||
requestedProperties += PROP_Z_TEXTURE_URL;
|
||||
return requestedProperties;
|
||||
}
|
||||
|
||||
|
@ -153,6 +171,10 @@ void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeB
|
|||
APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, getVoxelVolumeSize());
|
||||
APPEND_ENTITY_PROPERTY(PROP_VOXEL_DATA, getVoxelData());
|
||||
APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, (uint16_t) getVoxelSurfaceStyle());
|
||||
APPEND_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, getXTextureURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, getYTextureURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, getZTextureURL());
|
||||
|
||||
}
|
||||
|
||||
void PolyVoxEntityItem::debugDump() const {
|
||||
|
|
|
@ -87,6 +87,18 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
|
||||
static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16);
|
||||
|
||||
static const QString DEFAULT_X_TEXTURE_URL;
|
||||
virtual void setXTextureURL(QString xTextureURL) { _xTextureURL = xTextureURL; }
|
||||
virtual const QString& getXTextureURL() const { return _xTextureURL; }
|
||||
|
||||
static const QString DEFAULT_Y_TEXTURE_URL;
|
||||
virtual void setYTextureURL(QString yTextureURL) { _yTextureURL = yTextureURL; }
|
||||
virtual const QString& getYTextureURL() const { return _yTextureURL; }
|
||||
|
||||
static const QString DEFAULT_Z_TEXTURE_URL;
|
||||
virtual void setZTextureURL(QString zTextureURL) { _zTextureURL = zTextureURL; }
|
||||
virtual const QString& getZTextureURL() const { return _zTextureURL; }
|
||||
|
||||
protected:
|
||||
virtual void updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {
|
||||
_voxelSurfaceStyle = voxelSurfaceStyle;
|
||||
|
@ -95,6 +107,11 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
|
||||
QByteArray _voxelData;
|
||||
PolyVoxSurfaceStyle _voxelSurfaceStyle;
|
||||
|
||||
QString _xTextureURL;
|
||||
QString _yTextureURL;
|
||||
QString _zTextureURL;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_PolyVoxEntityItem_h
|
||||
|
|
|
@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) {
|
|||
case EntityAdd:
|
||||
case EntityEdit:
|
||||
case EntityData:
|
||||
return VERSION_ENTITIES_NEW_PROTOCOL_LAYER;
|
||||
return VERSION_POLYVOX_TEXTURES;
|
||||
default:
|
||||
return 11;
|
||||
}
|
||||
|
|
|
@ -140,5 +140,6 @@ const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP = 31;
|
|||
const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP_FIX = 32;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE = 33;
|
||||
const PacketVersion VERSION_ENTITIES_NEW_PROTOCOL_LAYER = 35;
|
||||
const PacketVersion VERSION_POLYVOX_TEXTURES = 36;
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
|
@ -47,9 +47,6 @@ public:
|
|||
/// gets the shadow view frustum for rendering the view state
|
||||
virtual ViewFrustum* getShadowViewFrustum() = 0;
|
||||
|
||||
virtual bool getShadowsEnabled() = 0;
|
||||
virtual bool getCascadeShadowsEnabled() = 0;
|
||||
|
||||
virtual QThread* getMainThread() = 0;
|
||||
|
||||
virtual bool shouldRenderMesh(float largestDimension, float distanceToCamera) = 0;
|
||||
|
|
|
@ -279,13 +279,19 @@ void DeferredLightingEffect::render(RenderArgs* args) {
|
|||
|
||||
auto& program = _directionalLight;
|
||||
const LightLocations* locations = &_directionalLightLocations;
|
||||
bool shadowsEnabled = _viewState->getShadowsEnabled();
|
||||
|
||||
// FIXME: Note: we've removed the menu items to enable shadows, so this will always be false for now.
|
||||
// When we add back shadow support, this old approach may likely be removed and completely replaced
|
||||
// but I've left it in for now.
|
||||
bool shadowsEnabled = false;
|
||||
bool cascadeShadowsEnabled = false;
|
||||
|
||||
if (shadowsEnabled) {
|
||||
batch.setResourceTexture(4, framebufferCache->getShadowFramebuffer()->getDepthStencilBuffer());
|
||||
|
||||
program = _directionalLightShadowMap;
|
||||
locations = &_directionalLightShadowMapLocations;
|
||||
if (_viewState->getCascadeShadowsEnabled()) {
|
||||
if (cascadeShadowsEnabled) {
|
||||
program = _directionalLightCascadedShadowMap;
|
||||
locations = &_directionalLightCascadedShadowMapLocations;
|
||||
if (useSkyboxCubemap) {
|
||||
|
|
|
@ -54,6 +54,7 @@ static int modelPointerTypeId = qRegisterMetaType<QPointer<Model> >();
|
|||
static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<QWeakPointer<NetworkGeometry> >();
|
||||
static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
|
||||
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
|
||||
#define HTTP_INVALID_COM "http://invalid.com"
|
||||
|
||||
Model::Model(RigPointer rig, QObject* parent) :
|
||||
QObject(parent),
|
||||
|
@ -67,7 +68,8 @@ Model::Model(RigPointer rig, QObject* parent) :
|
|||
_cauterizeBones(false),
|
||||
_lodDistance(0.0f),
|
||||
_pupilDilation(0.0f),
|
||||
_url("http://invalid.com"),
|
||||
_url(HTTP_INVALID_COM),
|
||||
_urlAsString(HTTP_INVALID_COM),
|
||||
_isVisible(true),
|
||||
_blendNumber(0),
|
||||
_appliedBlendNumber(0),
|
||||
|
@ -181,17 +183,12 @@ void Model::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, Model:
|
|||
locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices");
|
||||
locations.emissiveParams = program->getUniforms().findLocation("emissiveParams");
|
||||
locations.glowIntensity = program->getUniforms().findLocation("glowIntensity");
|
||||
|
||||
locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
|
||||
|
||||
locations.specularTextureUnit = program->getTextures().findLocation("specularMap");
|
||||
locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
|
||||
|
||||
locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer");
|
||||
locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
|
||||
|
||||
locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices");
|
||||
|
||||
locations.clusterIndices = program->getInputs().findLocation("inSkinClusterIndex");
|
||||
locations.clusterWeights = program->getInputs().findLocation("inSkinClusterWeight");
|
||||
}
|
||||
|
@ -230,9 +227,7 @@ QVector<JointState> Model::createJointStates(const FBXGeometry& geometry) {
|
|||
for (int i = 0; i < geometry.joints.size(); ++i) {
|
||||
const FBXJoint& joint = geometry.joints[i];
|
||||
// store a pointer to the FBXJoint in the JointState
|
||||
JointState state;
|
||||
state.setFBXJoint(&joint);
|
||||
|
||||
JointState state(joint);
|
||||
jointStates.append(state);
|
||||
}
|
||||
return jointStates;
|
||||
|
@ -1085,6 +1080,7 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo
|
|||
invalidCalculatedMeshBoxes();
|
||||
|
||||
_url = url;
|
||||
_urlAsString = _url.toString();
|
||||
|
||||
onInvalidate();
|
||||
|
||||
|
@ -1868,8 +1864,9 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f
|
|||
batch._glUniform1f(locations->glowIntensity, DEFAULT_GLOW_INTENSITY);
|
||||
}
|
||||
|
||||
if ((locations->normalFittingMapUnit > -1)) {
|
||||
batch.setResourceTexture(locations->normalFittingMapUnit, DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
if ((locations->normalFittingMapUnit > -1)) {
|
||||
batch.setResourceTexture(locations->normalFittingMapUnit,
|
||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
Q_INVOKABLE void setURL(const QUrl& url, const QUrl& fallback = QUrl(),
|
||||
bool retainCurrent = false, bool delayLoad = false);
|
||||
const QUrl& getURL() const { return _url; }
|
||||
const QString& getURLAsString() const { return _urlAsString; }
|
||||
|
||||
// new Scene/Engine rendering support
|
||||
void setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scene);
|
||||
|
@ -328,6 +329,7 @@ private:
|
|||
QVector<float> _blendshapeCoefficients;
|
||||
|
||||
QUrl _url;
|
||||
QString _urlAsString;
|
||||
QUrl _collisionUrl;
|
||||
bool _isVisible;
|
||||
|
||||
|
|
|
@ -47,39 +47,9 @@
|
|||
#include "AvatarRig.h" // We might later test Rig vs AvatarRig separately, but for now, we're concentrating on the main use case.
|
||||
#include "RigTests.h"
|
||||
|
||||
QTEST_MAIN(RigTests)
|
||||
|
||||
void RigTests::initTestCase() {
|
||||
//#define FROM_FILE "/Users/howardstearns/howardHiFi/Zack.fbx"
|
||||
#ifdef FROM_FILE
|
||||
QFile file(FROM_FILE);
|
||||
QCOMPARE(file.open(QIODevice::ReadOnly), true);
|
||||
FBXGeometry geometry = readFBX(file.readAll(), QVariantHash());
|
||||
#else
|
||||
QUrl fbxUrl("https://s3.amazonaws.com/hifi-public/models/skeletons/Zack/Zack.fbx");
|
||||
QNetworkReply* reply = OBJReader().request(fbxUrl, false); // Just a convenience hack for synchronoud http request
|
||||
auto fbxHttpCode = !reply->isFinished() ? -1 : reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QCOMPARE(fbxHttpCode, 200);
|
||||
FBXGeometry geometry = readFBX(reply->readAll(), QVariantHash());
|
||||
#endif
|
||||
|
||||
QVector<JointState> jointStates;
|
||||
for (int i = 0; i < geometry.joints.size(); ++i) {
|
||||
// Note that if the geometry is stack allocated and goes away, so will the joints. Hence the heap copy here.
|
||||
FBXJoint* joint = new FBXJoint(geometry.joints[i]);
|
||||
JointState state;
|
||||
state.setFBXJoint(joint);
|
||||
jointStates.append(state);
|
||||
}
|
||||
|
||||
_rig = std::make_shared<AvatarRig>();
|
||||
_rig->initJointStates(jointStates, glm::mat4());
|
||||
std::cout << "Rig is ready " << geometry.joints.count() << " joints " << std::endl;
|
||||
}
|
||||
|
||||
static void reportJoint(int index, JointState joint) { // Handy for debugging
|
||||
std::cout << "\n";
|
||||
std::cout << index << " " << joint.getFBXJoint().name.toUtf8().data() << "\n";
|
||||
std::cout << index << " " << joint.getName().toUtf8().data() << "\n";
|
||||
std::cout << " pos:" << joint.getPosition() << "/" << joint.getPositionInParentFrame() << " from " << joint.getParentIndex() << "\n";
|
||||
std::cout << " rot:" << safeEulerAngles(joint.getRotation()) << "/" << safeEulerAngles(joint.getRotationInParentFrame()) << "/" << safeEulerAngles(joint.getRotationInBindFrame()) << "\n";
|
||||
std::cout << "\n";
|
||||
|
@ -101,7 +71,34 @@ static void reportSome(RigPointer rig) {
|
|||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(RigTests)
|
||||
|
||||
void RigTests::initTestCase() {
|
||||
//#define FROM_FILE "/Users/howardstearns/howardHiFi/Zack.fbx"
|
||||
#ifdef FROM_FILE
|
||||
QFile file(FROM_FILE);
|
||||
QCOMPARE(file.open(QIODevice::ReadOnly), true);
|
||||
FBXGeometry geometry = readFBX(file.readAll(), QVariantHash());
|
||||
#else
|
||||
QUrl fbxUrl("https://s3.amazonaws.com/hifi-public/models/skeletons/Zack/Zack.fbx");
|
||||
QNetworkReply* reply = OBJReader().request(fbxUrl, false); // Just a convenience hack for synchronoud http request
|
||||
auto fbxHttpCode = !reply->isFinished() ? -1 : reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QCOMPARE(fbxHttpCode, 200);
|
||||
FBXGeometry geometry = readFBX(reply->readAll(), QVariantHash());
|
||||
#endif
|
||||
|
||||
QVector<JointState> jointStates;
|
||||
for (int i = 0; i < geometry.joints.size(); ++i) {
|
||||
JointState state(geometry.joints[i]);
|
||||
jointStates.append(state);
|
||||
}
|
||||
|
||||
_rig = std::make_shared<AvatarRig>();
|
||||
_rig->initJointStates(jointStates, glm::mat4(), 0, 41, 40, 39, 17, 16, 15); // FIXME? get by name? do we really want to exclude the shoulder blades?
|
||||
std::cout << "Rig is ready " << geometry.joints.count() << " joints " << std::endl;
|
||||
reportAll(_rig);
|
||||
}
|
||||
|
||||
void RigTests::initialPoseArmsDown() {
|
||||
//reportAll(_rig);
|
||||
reportSome(_rig);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue