mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 14:03:17 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into grab-fixes
This commit is contained in:
commit
99ffb6b79d
82 changed files with 1594 additions and 518 deletions
|
@ -15,7 +15,7 @@
|
|||
viewBox="0 0 1440 200"
|
||||
id="svg4136"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="address-bar.002.svg">
|
||||
sodipodi:docname="address-bar.svg">
|
||||
<metadata
|
||||
id="metadata4144">
|
||||
<rdf:RDF>
|
||||
|
@ -39,16 +39,16 @@
|
|||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1835"
|
||||
inkscape:window-height="1057"
|
||||
inkscape:window-width="1536"
|
||||
inkscape:window-height="687"
|
||||
id="namedview4140"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.61319416"
|
||||
inkscape:cx="132.58366"
|
||||
inkscape:cx="670.06567"
|
||||
inkscape:cy="52.468468"
|
||||
inkscape:window-x="77"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-x="105"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg4136" />
|
||||
<rect
|
||||
style="fill:#ededed;fill-opacity:1;stroke:none;stroke-linejoin:round;stroke-opacity:1"
|
||||
|
@ -60,14 +60,14 @@
|
|||
rx="16.025024"
|
||||
ry="17.019567" />
|
||||
<rect
|
||||
style="fill:#dadada;fill-opacity:1;stroke:#cbcbcb;stroke-width:0.33821851;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
style="fill:#dadada;fill-opacity:1;stroke:#cbcbcb;stroke-width:0.35830048;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4135"
|
||||
width="292.86267"
|
||||
height="139.66179"
|
||||
x="150.32542"
|
||||
y="30.169102"
|
||||
rx="16.817432"
|
||||
ry="20.612938" />
|
||||
width="328.72031"
|
||||
height="139.64169"
|
||||
x="150.33546"
|
||||
y="30.179144"
|
||||
rx="18.876532"
|
||||
ry="20.609974" />
|
||||
<circle
|
||||
style="fill:#b8b8b8;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
id="path4146"
|
||||
|
@ -78,11 +78,4 @@
|
|||
d="m 100,36.000005 c -22.1,0 -40,17.9 -40,39.999995 0,30 40,88 40,88 0,0 40,-58 40,-88 0,-22.099995 -17.9,-39.999995 -40,-39.999995 z m 0,22 c 9.9,0 18,8.099995 18,17.999995 0,9.9 -8.1,18 -18,18 -9.9,0 -18,-8.1 -18,-18 0,-9.9 8.1,-17.999995 18,-17.999995 z"
|
||||
id="path4138"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="fill:#bdbdbd;fill-opacity:1;stroke:none;stroke-width:0.30000001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4136"
|
||||
width="4"
|
||||
height="100"
|
||||
x="310.12924"
|
||||
y="50" />
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.5 KiB |
48
interface/resources/images/home-button.svg
Normal file
48
interface/resources/images/home-button.svg
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 320 280"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="home-button.svg"
|
||||
width="320"
|
||||
height="280"><metadata
|
||||
id="metadata4143"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs4141" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1827"
|
||||
inkscape:window-height="1057"
|
||||
id="namedview4139"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.2263883"
|
||||
inkscape:cx="135.72814"
|
||||
inkscape:cy="175.61874"
|
||||
inkscape:window-x="85"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" /><polyline
|
||||
points="261,116.2 420.4,261.1 361.7,261.1 361.7,394.5 160.4,394.5 160.4,261.1 101.8,261.1 261,116.2 "
|
||||
id="polyline4137"
|
||||
transform="translate(-101.1,-115.35)"
|
||||
style="fill:#535353;fill-opacity:1" /></svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -55,15 +55,35 @@ Window {
|
|||
property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area
|
||||
property int inputAreaStep: (height - inputAreaHeight) / 2
|
||||
|
||||
Image {
|
||||
id: homeButton
|
||||
source: "../images/home-button.svg"
|
||||
width: 29
|
||||
height: 26
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: parent.height + 2 * hifi.layout.spacing
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onClicked: {
|
||||
addressBarDialog.loadHome()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: backArrow
|
||||
source: addressBarDialog.backEnabled ? "../images/left-arrow.svg" : "../images/left-arrow-disabled.svg"
|
||||
width: 22
|
||||
height: 26
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: parent.height + hifi.layout.spacing + 6
|
||||
rightMargin: parent.height + hifi.layout.spacing * 60
|
||||
topMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
|
||||
bottomMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
|
||||
left: homeButton.right
|
||||
leftMargin: 2 * hifi.layout.spacing
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
@ -78,12 +98,12 @@ Window {
|
|||
Image {
|
||||
id: forwardArrow
|
||||
source: addressBarDialog.forwardEnabled ? "../images/right-arrow.svg" : "../images/right-arrow-disabled.svg"
|
||||
width: 22
|
||||
height: 26
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: parent.height + hifi.layout.spacing * 9
|
||||
rightMargin: parent.height + hifi.layout.spacing * 53
|
||||
topMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
|
||||
bottomMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
|
||||
left: backArrow.right
|
||||
leftMargin: 2 * hifi.layout.spacing
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
@ -101,7 +121,7 @@ Window {
|
|||
focus: true
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: parent.height + parent.height + hifi.layout.spacing * 5
|
||||
leftMargin: parent.height + parent.height + hifi.layout.spacing * 7
|
||||
rightMargin: hifi.layout.spacing * 2
|
||||
topMargin: parent.inputAreaStep + hifi.layout.spacing
|
||||
bottomMargin: parent.inputAreaStep + hifi.layout.spacing
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
//
|
||||
// InfoView.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 27 Apr 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import Hifi 1.0 as Hifi
|
||||
|
||||
import "controls"
|
||||
import "windows" as Windows
|
||||
import "controls-uit"
|
||||
import "windows-uit" as Windows
|
||||
|
||||
Windows.Window {
|
||||
id: root
|
||||
|
@ -12,16 +22,16 @@ Windows.Window {
|
|||
|
||||
Hifi.InfoView {
|
||||
id: infoView
|
||||
// Fill the client area
|
||||
anchors.fill: parent
|
||||
|
||||
width: pane.contentWidth
|
||||
implicitHeight: pane.scrollHeight
|
||||
|
||||
WebView {
|
||||
id: webview
|
||||
objectName: "WebView"
|
||||
anchors.fill: parent
|
||||
url: infoView.url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
centerWindow(root);
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
//
|
||||
// QmlWebWindow.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 17 Dec 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtWebEngine 1.1
|
||||
import QtWebChannel 1.0
|
||||
|
||||
import "windows" as Windows
|
||||
import "controls" as Controls
|
||||
import "styles"
|
||||
import "windows-uit" as Windows
|
||||
import "controls-uit" as Controls
|
||||
import "styles-uit"
|
||||
|
||||
Windows.Window {
|
||||
id: root
|
||||
|
@ -29,11 +39,16 @@ Windows.Window {
|
|||
// missing signal
|
||||
signal sendToScript(var message);
|
||||
|
||||
Controls.WebView {
|
||||
id: webview
|
||||
url: "about:blank"
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
Item {
|
||||
width: pane.contentWidth
|
||||
implicitHeight: pane.scrollHeight
|
||||
|
||||
Controls.WebView {
|
||||
id: webview
|
||||
url: "about:blank"
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
}
|
||||
}
|
||||
} // dialog
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ WebEngineView {
|
|||
id: root
|
||||
property var newUrl;
|
||||
|
||||
profile.httpUserAgent: "Mozilla/5.0 Chrome (HighFidelityInterface)"
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging")
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
//
|
||||
// AvatarBrowser.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 30 Aug 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtWebEngine 1.1
|
||||
|
||||
import "../../windows" as Windows
|
||||
import "../../controls" as Controls
|
||||
import "../../styles"
|
||||
import "../../windows-uit" as Windows
|
||||
import "../../controls-uit" as Controls
|
||||
import "../../styles-uit"
|
||||
|
||||
Windows.Window {
|
||||
id: root
|
||||
|
@ -14,20 +24,14 @@ Windows.Window {
|
|||
modality: Qt.ApplicationModal
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
width: pane.contentWidth
|
||||
implicitHeight: pane.scrollHeight
|
||||
|
||||
Controls.WebView {
|
||||
id: webview
|
||||
anchors { top: parent.top; left: parent.left; right: parent.right; bottom: closeButton.top; margins: 8 }
|
||||
anchors.fill: parent
|
||||
url: "https://metaverse.highfidelity.com/marketplace?category=avatars"
|
||||
focus: true
|
||||
}
|
||||
|
||||
Button {
|
||||
id: closeButton
|
||||
anchors { bottom: parent.bottom; right: parent.right; margins: 8 }
|
||||
text: "Close"
|
||||
onClicked: root.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
#include "Bookmarks.h"
|
||||
#include <QtQuick/QQuickWindow>
|
||||
|
||||
|
||||
const QString Bookmarks::HOME_BOOKMARK = "Home";
|
||||
|
||||
|
||||
Bookmarks::Bookmarks() {
|
||||
_bookmarksFilename = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + BOOKMARKS_FILENAME;
|
||||
readFromFile();
|
||||
|
@ -60,6 +64,10 @@ bool Bookmarks::contains(const QString& name) const {
|
|||
return _bookmarks.contains(name);
|
||||
}
|
||||
|
||||
QString Bookmarks::addressForBookmark(const QString& name) const {
|
||||
return _bookmarks.value(name).toString();
|
||||
}
|
||||
|
||||
void Bookmarks::readFromFile() {
|
||||
QFile loadFile(_bookmarksFilename);
|
||||
|
||||
|
@ -95,6 +103,8 @@ void Bookmarks::setupMenus(Menu* menubar, MenuWrapper* menu) {
|
|||
// Add menus/actions
|
||||
auto bookmarkAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::BookmarkLocation);
|
||||
QObject::connect(bookmarkAction, SIGNAL(triggered()), this, SLOT(bookmarkLocation()), Qt::QueuedConnection);
|
||||
auto setHomeAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::SetHomeLocation);
|
||||
QObject::connect(setHomeAction, SIGNAL(triggered()), this, SLOT(setHomeLocation()), Qt::QueuedConnection);
|
||||
_bookmarksMenu = menu->addMenu(MenuOption::Bookmarks);
|
||||
_deleteBookmarksAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::DeleteBookmark);
|
||||
QObject::connect(_deleteBookmarksAction, SIGNAL(triggered()), this, SLOT(deleteBookmark()), Qt::QueuedConnection);
|
||||
|
@ -146,6 +156,18 @@ void Bookmarks::bookmarkLocation() {
|
|||
enableMenuItems(true);
|
||||
}
|
||||
|
||||
void Bookmarks::setHomeLocation() {
|
||||
Menu* menubar = Menu::getInstance();
|
||||
QString bookmarkName = HOME_BOOKMARK;
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
QString bookmarkAddress = addressManager->currentAddress().toString();
|
||||
|
||||
addLocationToMenu(menubar, bookmarkName, bookmarkAddress);
|
||||
insert(bookmarkName, bookmarkAddress); // Overwrites any item with the same bookmarkName.
|
||||
|
||||
enableMenuItems(true);
|
||||
}
|
||||
|
||||
void Bookmarks::teleportToBookmark() {
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
QString address = action->data().toString();
|
||||
|
|
|
@ -29,8 +29,13 @@ public:
|
|||
|
||||
void setupMenus(Menu* menubar, MenuWrapper* menu);
|
||||
|
||||
QString addressForBookmark(const QString& name) const;
|
||||
|
||||
static const QString HOME_BOOKMARK;
|
||||
|
||||
private slots:
|
||||
void bookmarkLocation();
|
||||
void setHomeLocation();
|
||||
void teleportToBookmark();
|
||||
void deleteBookmark();
|
||||
|
||||
|
|
|
@ -170,6 +170,7 @@ namespace MenuOption {
|
|||
const QString RunTimingTests = "Run Timing Tests";
|
||||
const QString ScriptEditor = "Script Editor...";
|
||||
const QString ScriptedMotorControl = "Enable Scripted Motor Control";
|
||||
const QString SetHomeLocation = "Set Home Location";
|
||||
const QString ShowDSConnectTable = "Show Domain Connection Timing";
|
||||
const QString ShowBordersEntityNodes = "Show Entity Nodes";
|
||||
const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats";
|
||||
|
|
|
@ -78,11 +78,11 @@ private:
|
|||
void simulateAvatarFades(float deltaTime);
|
||||
|
||||
// virtual overrides
|
||||
virtual AvatarSharedPointer newSharedAvatar();
|
||||
virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer);
|
||||
virtual AvatarSharedPointer newSharedAvatar() override;
|
||||
virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) override;
|
||||
|
||||
virtual void removeAvatar(const QUuid& sessionUUID);
|
||||
virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar);
|
||||
virtual void removeAvatar(const QUuid& sessionUUID) override;
|
||||
virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar) override;
|
||||
|
||||
QVector<AvatarSharedPointer> _avatarFades;
|
||||
std::shared_ptr<MyAvatar> _myAvatar;
|
||||
|
|
|
@ -663,14 +663,6 @@ void MyAvatar::restoreRoleAnimation(const QString& role) {
|
|||
_rig->restoreRoleAnimation(role);
|
||||
}
|
||||
|
||||
void MyAvatar::prefetchAnimation(const QString& url) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "prefetchAnimation", Q_ARG(const QString&, url));
|
||||
return;
|
||||
}
|
||||
_rig->prefetchAnimation(url);
|
||||
}
|
||||
|
||||
void MyAvatar::saveData() {
|
||||
Settings settings;
|
||||
settings.beginGroup("Avatar");
|
||||
|
|
|
@ -143,9 +143,6 @@ public:
|
|||
// remove an animation role override and return to the standard animation.
|
||||
Q_INVOKABLE void restoreRoleAnimation(const QString& role);
|
||||
|
||||
// prefetch animation
|
||||
Q_INVOKABLE void prefetchAnimation(const QString& url);
|
||||
|
||||
// Adds handler(animStateDictionaryIn) => animStateDictionaryOut, which will be invoked just before each animGraph state update.
|
||||
// The handler will be called with an animStateDictionaryIn that has all those properties specified by the (possibly empty)
|
||||
// propertiesList argument. However for debugging, if the properties argument is null, all internal animGraph state is provided.
|
||||
|
|
|
@ -85,12 +85,23 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
// Called within Model::simulate call, below.
|
||||
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
|
||||
Head* head = _owningAvatar->getHead();
|
||||
|
||||
|
||||
// make sure lookAt is not too close to face (avoid crosseyes)
|
||||
glm::vec3 lookAt = _owningAvatar->isMyAvatar() ? head->getLookAtPosition() : head->getCorrectedLookAtPosition();
|
||||
glm::vec3 focusOffset = lookAt - _owningAvatar->getHead()->getEyePosition();
|
||||
float focusDistance = glm::length(focusOffset);
|
||||
const float MIN_LOOK_AT_FOCUS_DISTANCE = 1.0f;
|
||||
if (focusDistance < MIN_LOOK_AT_FOCUS_DISTANCE && focusDistance > EPSILON) {
|
||||
lookAt = _owningAvatar->getHead()->getEyePosition() + (MIN_LOOK_AT_FOCUS_DISTANCE / focusDistance) * focusOffset;
|
||||
}
|
||||
|
||||
if (_owningAvatar->isMyAvatar()) {
|
||||
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
||||
|
||||
|
@ -164,7 +175,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
|
||||
Rig::EyeParameters eyeParams;
|
||||
eyeParams.worldHeadOrientation = headParams.worldHeadOrientation;
|
||||
eyeParams.eyeLookAt = head->getLookAtPosition();
|
||||
eyeParams.eyeLookAt = lookAt;
|
||||
eyeParams.eyeSaccade = head->getSaccade();
|
||||
eyeParams.modelRotation = getRotation();
|
||||
eyeParams.modelTranslation = getTranslation();
|
||||
|
@ -196,8 +207,8 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
|
||||
Rig::EyeParameters eyeParams;
|
||||
eyeParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame();
|
||||
eyeParams.eyeLookAt = head->getCorrectedLookAtPosition();
|
||||
eyeParams.eyeSaccade = glm::vec3();
|
||||
eyeParams.eyeLookAt = lookAt;
|
||||
eyeParams.eyeSaccade = glm::vec3(0.0f);
|
||||
eyeParams.modelRotation = getRotation();
|
||||
eyeParams.modelTranslation = getTranslation();
|
||||
eyeParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
|
||||
#include "AddressBarDialog.h"
|
||||
#include "Application.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
|
@ -50,6 +51,16 @@ void AddressBarDialog::loadAddress(const QString& address) {
|
|||
}
|
||||
}
|
||||
|
||||
void AddressBarDialog::loadHome() {
|
||||
qDebug() << "Called LoadHome";
|
||||
QString homeLocation = qApp->getBookmarks()->addressForBookmark(Bookmarks::HOME_BOOKMARK);
|
||||
const QString DEFAULT_HOME_LOCATION = "localhost";
|
||||
if (homeLocation == "") {
|
||||
homeLocation = DEFAULT_HOME_LOCATION;
|
||||
}
|
||||
DependencyManager::get<AddressManager>()->handleLookupString(homeLocation);
|
||||
}
|
||||
|
||||
void AddressBarDialog::loadBack() {
|
||||
qDebug() << "Called LoadBack";
|
||||
DependencyManager::get<AddressManager>()->goBack();
|
||||
|
|
|
@ -36,6 +36,7 @@ protected:
|
|||
void hide();
|
||||
|
||||
Q_INVOKABLE void loadAddress(const QString& address);
|
||||
Q_INVOKABLE void loadHome();
|
||||
Q_INVOKABLE void loadBack();
|
||||
Q_INVOKABLE void loadForward();
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
Base3DOverlay(const Base3DOverlay* base3DOverlay);
|
||||
|
||||
// getters
|
||||
virtual bool is3D() const { return true; }
|
||||
virtual bool is3D() const override { return true; }
|
||||
const glm::vec3& getPosition() const { return _transform.getTranslation(); }
|
||||
const glm::quat& getRotation() const { return _transform.getRotation(); }
|
||||
const glm::vec3& getScale() const { return _transform.getScale(); }
|
||||
|
@ -50,7 +50,7 @@ public:
|
|||
void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; }
|
||||
void setDrawInFront(bool value) { _drawInFront = value; }
|
||||
|
||||
virtual AABox getBounds() const = 0;
|
||||
virtual AABox getBounds() const override = 0;
|
||||
|
||||
void setProperties(const QVariantMap& properties) override;
|
||||
QVariant getProperty(const QString& property) override;
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
QVariant getProperty(const QString& property) override;
|
||||
|
||||
protected:
|
||||
virtual void applyTransformTo(Transform& transform, bool force = false);
|
||||
virtual void applyTransformTo(Transform& transform, bool force = false) override;
|
||||
};
|
||||
|
||||
#endif // hifi_Billboard3DOverlay_h
|
||||
|
|
|
@ -19,12 +19,12 @@ class Circle3DOverlay : public Planar3DOverlay {
|
|||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
Circle3DOverlay();
|
||||
Circle3DOverlay(const Circle3DOverlay* circle3DOverlay);
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
void setProperties(const QVariantMap& properties) override;
|
||||
QVariant getProperty(const QString& property) override;
|
||||
|
@ -54,9 +54,9 @@ public:
|
|||
void setMinorTickMarksColor(const xColor& value) { _minorTickMarksColor = value; }
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
|
||||
virtual Circle3DOverlay* createClone() const;
|
||||
virtual Circle3DOverlay* createClone() const override;
|
||||
|
||||
protected:
|
||||
float _startAt;
|
||||
|
|
|
@ -18,15 +18,15 @@ class Cube3DOverlay : public Volume3DOverlay {
|
|||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
Cube3DOverlay() {}
|
||||
Cube3DOverlay(const Cube3DOverlay* cube3DOverlay);
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
|
||||
virtual Cube3DOverlay* createClone() const;
|
||||
virtual Cube3DOverlay* createClone() const override;
|
||||
|
||||
float getBorderSize() const { return _borderSize; }
|
||||
|
||||
|
|
|
@ -19,22 +19,22 @@ class Grid3DOverlay : public Planar3DOverlay {
|
|||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
Grid3DOverlay();
|
||||
Grid3DOverlay(const Grid3DOverlay* grid3DOverlay);
|
||||
|
||||
virtual AABox getBounds() const;
|
||||
virtual AABox getBounds() const override;
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
void setProperties(const QVariantMap& properties) override;
|
||||
QVariant getProperty(const QString& property) override;
|
||||
|
||||
virtual Grid3DOverlay* createClone() const;
|
||||
virtual Grid3DOverlay* createClone() const override;
|
||||
|
||||
// Grids are UI tools, and may not be intersected (pickable)
|
||||
virtual bool findRayIntersection(const glm::vec3&, const glm::vec3&, float&, BoxFace&, glm::vec3&) { return false; }
|
||||
virtual bool findRayIntersection(const glm::vec3&, const glm::vec3&, float&, BoxFace&, glm::vec3&) override { return false; }
|
||||
|
||||
private:
|
||||
void updateGrid();
|
||||
|
|
|
@ -22,14 +22,14 @@ class Image3DOverlay : public Billboard3DOverlay {
|
|||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
Image3DOverlay();
|
||||
Image3DOverlay(const Image3DOverlay* image3DOverlay);
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void render(RenderArgs* args) override;
|
||||
|
||||
virtual void update(float deltatime);
|
||||
virtual void update(float deltatime) override;
|
||||
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
|
||||
|
@ -41,9 +41,9 @@ public:
|
|||
QVariant getProperty(const QString& property) override;
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
|
||||
virtual Image3DOverlay* createClone() const;
|
||||
virtual Image3DOverlay* createClone() const override;
|
||||
|
||||
private:
|
||||
QString _url;
|
||||
|
|
|
@ -18,14 +18,14 @@ class Line3DOverlay : public Base3DOverlay {
|
|||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
Line3DOverlay();
|
||||
Line3DOverlay(const Line3DOverlay* line3DOverlay);
|
||||
~Line3DOverlay();
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
virtual AABox getBounds() const;
|
||||
virtual AABox getBounds() const override;
|
||||
|
||||
// getters
|
||||
const glm::vec3& getStart() const { return _start; }
|
||||
|
@ -38,7 +38,7 @@ public:
|
|||
void setProperties(const QVariantMap& properties) override;
|
||||
QVariant getProperty(const QString& property) override;
|
||||
|
||||
virtual Line3DOverlay* createClone() const;
|
||||
virtual Line3DOverlay* createClone() const override;
|
||||
|
||||
protected:
|
||||
glm::vec3 _start;
|
||||
|
|
|
@ -20,24 +20,24 @@ class ModelOverlay : public Volume3DOverlay {
|
|||
Q_OBJECT
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
ModelOverlay();
|
||||
ModelOverlay(const ModelOverlay* modelOverlay);
|
||||
|
||||
virtual void update(float deltatime);
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void update(float deltatime) override;
|
||||
virtual void render(RenderArgs* args) override;
|
||||
void setProperties(const QVariantMap& properties) override;
|
||||
QVariant getProperty(const QString& property) override;
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo);
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo) override;
|
||||
|
||||
virtual ModelOverlay* createClone() const;
|
||||
virtual ModelOverlay* createClone() const override;
|
||||
|
||||
virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
|
||||
virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@ public:
|
|||
Overlay2D() {}
|
||||
Overlay2D(const Overlay2D* overlay2D);
|
||||
|
||||
virtual AABox getBounds() const;
|
||||
virtual AABox getBounds() const override;
|
||||
|
||||
virtual bool is3D() const { return false; }
|
||||
virtual bool is3D() const override { return false; }
|
||||
|
||||
// getters
|
||||
int getX() const { return _bounds.x(); }
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
Planar3DOverlay();
|
||||
Planar3DOverlay(const Planar3DOverlay* planar3DOverlay);
|
||||
|
||||
virtual AABox getBounds() const;
|
||||
virtual AABox getBounds() const override;
|
||||
|
||||
glm::vec2 getDimensions() const { return _dimensions; }
|
||||
void setDimensions(float value) { _dimensions = glm::vec2(value); }
|
||||
|
@ -30,7 +30,7 @@ public:
|
|||
QVariant getProperty(const QString& property) override;
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
|
||||
protected:
|
||||
glm::vec2 _dimensions;
|
||||
|
|
|
@ -18,16 +18,16 @@ class Rectangle3DOverlay : public Planar3DOverlay {
|
|||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
Rectangle3DOverlay();
|
||||
Rectangle3DOverlay(const Rectangle3DOverlay* rectangle3DOverlay);
|
||||
~Rectangle3DOverlay();
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
void setProperties(const QVariantMap& properties) override;
|
||||
|
||||
virtual Rectangle3DOverlay* createClone() const;
|
||||
virtual Rectangle3DOverlay* createClone() const override;
|
||||
private:
|
||||
int _geometryCacheID;
|
||||
glm::vec2 _previousHalfDimensions;
|
||||
|
|
|
@ -18,15 +18,15 @@ class Sphere3DOverlay : public Volume3DOverlay {
|
|||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
Sphere3DOverlay() {}
|
||||
Sphere3DOverlay(const Sphere3DOverlay* Sphere3DOverlay);
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
|
||||
virtual Sphere3DOverlay* createClone() const;
|
||||
virtual Sphere3DOverlay* createClone() const override;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -22,14 +22,14 @@ class Text3DOverlay : public Billboard3DOverlay {
|
|||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
Text3DOverlay();
|
||||
Text3DOverlay(const Text3DOverlay* text3DOverlay);
|
||||
~Text3DOverlay();
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void render(RenderArgs* args) override;
|
||||
|
||||
virtual void update(float deltatime);
|
||||
virtual void update(float deltatime) override;
|
||||
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
|
||||
|
@ -59,9 +59,9 @@ public:
|
|||
QSizeF textSize(const QString& test) const; // Meters
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
|
||||
virtual Text3DOverlay* createClone() const;
|
||||
virtual Text3DOverlay* createClone() const override;
|
||||
|
||||
private:
|
||||
TextRenderer3D* _textRenderer = nullptr;
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
Volume3DOverlay() {}
|
||||
Volume3DOverlay(const Volume3DOverlay* volume3DOverlay);
|
||||
|
||||
virtual AABox getBounds() const;
|
||||
virtual AABox getBounds() const override;
|
||||
|
||||
const glm::vec3& getDimensions() const { return _localBoundingBox.getDimensions(); }
|
||||
void setDimensions(float value) { _localBoundingBox.setBox(glm::vec3(-value / 2.0f), value); }
|
||||
|
@ -30,7 +30,7 @@ public:
|
|||
QVariant getProperty(const QString& property) override;
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
|
||||
protected:
|
||||
// Centered local bounding box
|
||||
|
|
|
@ -18,16 +18,16 @@ class Web3DOverlay : public Billboard3DOverlay {
|
|||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
Web3DOverlay();
|
||||
Web3DOverlay(const Web3DOverlay* Web3DOverlay);
|
||||
virtual ~Web3DOverlay();
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
|
||||
virtual void update(float deltatime);
|
||||
virtual void update(float deltatime) override;
|
||||
|
||||
// setters
|
||||
void setURL(const QString& url);
|
||||
|
@ -36,9 +36,9 @@ public:
|
|||
QVariant getProperty(const QString& property) override;
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
|
||||
virtual Web3DOverlay* createClone() const;
|
||||
virtual Web3DOverlay* createClone() const override;
|
||||
|
||||
private:
|
||||
OffscreenQmlSurface* _webSurface{ nullptr };
|
||||
|
|
|
@ -152,14 +152,6 @@ void Rig::restoreRoleAnimation(const QString& role) {
|
|||
}
|
||||
}
|
||||
|
||||
void Rig::prefetchAnimation(const QString& url) {
|
||||
|
||||
// This will begin loading the NetworkGeometry for the given URL.
|
||||
// which should speed us up if we request it later via overrideAnimation.
|
||||
auto clipNode = std::make_shared<AnimClip>("prefetch", url, 0, 0, 1.0, false, false);
|
||||
_prefetchedAnimations.push_back(clipNode);
|
||||
}
|
||||
|
||||
void Rig::destroyAnimGraph() {
|
||||
_animSkeleton.reset();
|
||||
_animLoader.reset();
|
||||
|
|
|
@ -94,7 +94,6 @@ public:
|
|||
QStringList getAnimationRoles() const;
|
||||
void overrideRoleAnimation(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
void restoreRoleAnimation(const QString& role);
|
||||
void prefetchAnimation(const QString& url);
|
||||
|
||||
void initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset);
|
||||
void reset(const FBXGeometry& geometry);
|
||||
|
@ -203,8 +202,6 @@ public:
|
|||
// rig space
|
||||
bool getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const;
|
||||
|
||||
const glm::vec3& getEyesInRootFrame() const { return _eyesInRootFrame; }
|
||||
|
||||
// rig space
|
||||
AnimPose getAbsoluteDefaultPose(int index) const;
|
||||
|
||||
|
@ -275,7 +272,6 @@ protected:
|
|||
glm::vec3 _lastFront;
|
||||
glm::vec3 _lastPosition;
|
||||
glm::vec3 _lastVelocity;
|
||||
glm::vec3 _eyesInRootFrame { Vectors::ZERO };
|
||||
|
||||
QUrl _animGraphURL;
|
||||
std::shared_ptr<AnimNode> _animNode;
|
||||
|
@ -322,7 +318,6 @@ protected:
|
|||
SimpleMovingAverage _averageLateralSpeed { 10 };
|
||||
|
||||
std::map<QString, AnimNode::Pointer> _origRoleAnimations;
|
||||
std::vector<AnimNode::Pointer> _prefetchedAnimations;
|
||||
|
||||
bool _lastEnableInverseKinematics { true };
|
||||
bool _enableInverseKinematics { true };
|
||||
|
|
|
@ -380,7 +380,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
_pendingAmbientTexture = false;
|
||||
_ambientTexture.clear();
|
||||
} else {
|
||||
_ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), CUBE_TEXTURE);
|
||||
_ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), NetworkTexture::CUBE_TEXTURE);
|
||||
_pendingAmbientTexture = true;
|
||||
|
||||
if (_ambientTexture && _ambientTexture->isLoaded()) {
|
||||
|
@ -410,7 +410,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
_skyboxTexture.clear();
|
||||
} else {
|
||||
// Update the Texture of the Skybox with the one pointed by this zone
|
||||
_skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE);
|
||||
_skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), NetworkTexture::CUBE_TEXTURE);
|
||||
_pendingSkyboxTexture = true;
|
||||
|
||||
if (_skyboxTexture && _skyboxTexture->isLoaded()) {
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
QObject* getEventHandler();
|
||||
|
||||
void update(const quint64& now) override;
|
||||
bool needsToCallUpdate() const { return _webSurface != nullptr; }
|
||||
bool needsToCallUpdate() const override { return _webSurface != nullptr; }
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
|
|
|
@ -27,19 +27,19 @@ public:
|
|||
_needsInitialSimulation(true)
|
||||
{ }
|
||||
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
virtual bool setProperties(const EntityItemProperties& properties) override;
|
||||
virtual void somethingChangedNotification() override;
|
||||
|
||||
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged);
|
||||
bool& somethingChanged) override;
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual bool contains(const glm::vec3& point) const;
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual bool contains(const glm::vec3& point) const override;
|
||||
|
||||
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);
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
|
||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
|
||||
|
||||
private:
|
||||
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); }
|
||||
|
|
|
@ -54,6 +54,9 @@ public:
|
|||
virtual bool lifetimeIsOver() { return false; }
|
||||
virtual quint64 getExpires() { return 0; }
|
||||
|
||||
virtual bool isMine() { return _isMine; }
|
||||
virtual void setIsMine(bool value) { _isMine = value; }
|
||||
|
||||
bool locallyAddedButNotYetReceived = false;
|
||||
|
||||
virtual bool shouldSuppressLocationEdits() { return false; }
|
||||
|
@ -89,6 +92,7 @@ protected:
|
|||
QUuid _id;
|
||||
EntityActionType _type;
|
||||
bool _active { false };
|
||||
bool _isMine { false }; // did this interface create / edit this action?
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -658,6 +658,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
if (_simulationOwner.set(newSimOwner)) {
|
||||
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
|
||||
somethingChanged = true;
|
||||
// recompute weOwnSimulation so that if this is the packet that tells use we are the owner,
|
||||
// we ignore the physics changes from this packet.
|
||||
weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
|
||||
}
|
||||
}
|
||||
{ // When we own the simulation we don't accept updates to the entity's transform/velocities
|
||||
|
@ -1702,6 +1705,7 @@ bool EntityItem::updateAction(EntitySimulation* simulation, const QUuid& actionI
|
|||
|
||||
success = action->updateArguments(arguments);
|
||||
if (success) {
|
||||
action->setIsMine(true);
|
||||
serializeActions(success, _allActionsDataCache);
|
||||
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||
} else {
|
||||
|
@ -1808,7 +1812,9 @@ void EntityItem::deserializeActionsInternal() {
|
|||
EntityActionPointer action = _objectActions[actionID];
|
||||
// TODO: make sure types match? there isn't currently a way to
|
||||
// change the type of an existing action.
|
||||
action->deserialize(serializedAction);
|
||||
if (!action->isMine()) {
|
||||
action->deserialize(serializedAction);
|
||||
}
|
||||
action->locallyAddedButNotYetReceived = false;
|
||||
updated << actionID;
|
||||
} else {
|
||||
|
|
|
@ -361,7 +361,7 @@ public:
|
|||
void setPhysicsInfo(void* data) { _physicsInfo = data; }
|
||||
EntityTreeElementPointer getElement() const { return _element; }
|
||||
EntityTreePointer getTree() const;
|
||||
virtual SpatialParentTree* getParentTree() const;
|
||||
virtual SpatialParentTree* getParentTree() const override;
|
||||
bool wantTerseEditLogging() const;
|
||||
|
||||
glm::mat4 getEntityToWorldMatrix() const;
|
||||
|
|
|
@ -830,6 +830,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
|
|||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
action->setIsMine(true);
|
||||
success = entity->addAction(simulation, action);
|
||||
entity->grabSimulationOwnership();
|
||||
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||
|
|
|
@ -127,7 +127,7 @@ public:
|
|||
EntityItemPointer findClosestEntity(glm::vec3 position, float targetRadius);
|
||||
EntityItemPointer findEntityByID(const QUuid& id);
|
||||
EntityItemPointer findEntityByEntityItemID(const EntityItemID& entityID);
|
||||
virtual SpatiallyNestablePointer findByID(const QUuid& id) { return findEntityByID(id); }
|
||||
virtual SpatiallyNestablePointer findByID(const QUuid& id) override { return findEntityByID(id); }
|
||||
|
||||
EntityItemID assignEntityID(const EntityItemID& entityItemID); /// Assigns a known ID for a creator token ID
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
|
||||
const rgbColor& getColor() const { return _color; }
|
||||
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||
glm::vec3 getColorRGB() const { return ColorUtils::toLinearVec3(toGlm(getXColor())); }
|
||||
glm::vec3 getColorRGB() const { return ColorUtils::sRGBToLinearVec3(toGlm(getXColor())); }
|
||||
|
||||
static const xColor DEFAULT_COLOR;
|
||||
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
|
||||
|
@ -62,17 +62,17 @@ public:
|
|||
bool _isColorStartInitialized = false;
|
||||
void setColorStart(const xColor& colorStart) { _colorStart = colorStart; _isColorStartInitialized = true; }
|
||||
xColor getColorStart() const { return _isColorStartInitialized ? _colorStart : getXColor(); }
|
||||
glm::vec3 getColorStartRGB() const { return _isColorStartInitialized ? ColorUtils::toLinearVec3(toGlm(_colorStart)) : getColorRGB(); }
|
||||
glm::vec3 getColorStartRGB() const { return _isColorStartInitialized ? ColorUtils::sRGBToLinearVec3(toGlm(_colorStart)) : getColorRGB(); }
|
||||
|
||||
bool _isColorFinishInitialized = false;
|
||||
void setColorFinish(const xColor& colorFinish) { _colorFinish = colorFinish; _isColorFinishInitialized = true; }
|
||||
xColor getColorFinish() const { return _isColorFinishInitialized ? _colorFinish : getXColor(); }
|
||||
glm::vec3 getColorFinishRGB() const { return _isColorStartInitialized ? ColorUtils::toLinearVec3(toGlm(_colorFinish)) : getColorRGB(); }
|
||||
glm::vec3 getColorFinishRGB() const { return _isColorStartInitialized ? ColorUtils::sRGBToLinearVec3(toGlm(_colorFinish)) : getColorRGB(); }
|
||||
|
||||
static const xColor DEFAULT_COLOR_SPREAD;
|
||||
void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; }
|
||||
xColor getColorSpread() const { return _colorSpread; }
|
||||
glm::vec3 getColorSpreadRGB() const { return ColorUtils::toLinearVec3(toGlm(_colorSpread)); }
|
||||
glm::vec3 getColorSpreadRGB() const { return ColorUtils::sRGBToLinearVec3(toGlm(_colorSpread)); }
|
||||
|
||||
static const float MAXIMUM_ALPHA;
|
||||
static const float MINIMUM_ALPHA;
|
||||
|
|
|
@ -11,9 +11,14 @@
|
|||
<@if not GPU_COLOR_SLH@>
|
||||
<@def GPU_COLOR_SLH@>
|
||||
|
||||
float sRGBFloatToLinear(float value) {
|
||||
const float SRGB_ELBOW = 0.04045;
|
||||
|
||||
return (value <= SRGB_ELBOW) ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4);
|
||||
}
|
||||
|
||||
vec3 colorToLinearRGB(vec3 srgb) {
|
||||
const float GAMMA_22 = 2.2;
|
||||
return pow(srgb, vec3(GAMMA_22));
|
||||
return vec3(sRGBFloatToLinear(srgb.r), sRGBFloatToLinear(srgb.g), sRGBFloatToLinear(srgb.b));
|
||||
}
|
||||
|
||||
vec4 colorToLinearRGBA(vec4 srgba) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
using namespace gpu;
|
||||
|
||||
const Element Element::COLOR_RGBA_32{ VEC4, NUINT8, RGBA };
|
||||
const Element Element::COLOR_SRGBA_32{ VEC4, NUINT8, SRGBA };
|
||||
const Element Element::VEC4F_COLOR_RGBA{ VEC4, FLOAT, RGBA };
|
||||
const Element Element::VEC2F_UV{ VEC2, FLOAT, UV };
|
||||
const Element Element::VEC2F_XY{ VEC2, FLOAT, XY };
|
||||
|
|
|
@ -245,6 +245,7 @@ public:
|
|||
}
|
||||
|
||||
static const Element COLOR_RGBA_32;
|
||||
static const Element COLOR_SRGBA_32;
|
||||
static const Element VEC4F_COLOR_RGBA;
|
||||
static const Element VEC2F_UV;
|
||||
static const Element VEC2F_XY;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "GPULogging.h"
|
||||
#include "Context.h"
|
||||
|
||||
#include "ColorUtils.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
static int TexturePointerMetaTypeId = qRegisterMetaType<TexturePointer>();
|
||||
|
@ -637,18 +639,6 @@ void SphericalHarmonics::assignPreset(int p) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
glm::vec3 sRGBToLinear(glm::vec3& color) {
|
||||
const float GAMMA_CORRECTION = 2.2f;
|
||||
return glm::pow(color, glm::vec3(GAMMA_CORRECTION));
|
||||
}
|
||||
|
||||
glm::vec3 linearTosRGB(glm::vec3& color) {
|
||||
const float GAMMA_CORRECTION_INV = 1.0f / 2.2f;
|
||||
return glm::pow(color, glm::vec3(GAMMA_CORRECTION_INV));
|
||||
}
|
||||
|
||||
// Originial code for the Spherical Harmonics taken from "Sun and Black Cat- Igor Dykhta (igor dykhta email) <20> 2007-2014 "
|
||||
void sphericalHarmonicsAdd(float * result, int order, const float * inputA, const float * inputB) {
|
||||
const int numCoeff = order * order;
|
||||
|
@ -803,7 +793,7 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
float(data[pixOffsetIndex+2]) * UCHAR_TO_FLOAT);
|
||||
|
||||
// Gamma correct
|
||||
clr = sRGBToLinear(clr);
|
||||
clr = ColorUtils::sRGBToLinearVec3(clr);
|
||||
|
||||
// scale color and add to previously accumulated coefficients
|
||||
sphericalHarmonicsScale(shBuffB.data(), order,
|
||||
|
|
|
@ -237,13 +237,14 @@ ModelCache::ModelCache() {
|
|||
|
||||
QSharedPointer<Resource> ModelCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
bool delayLoad, const void* extra) {
|
||||
const GeometryExtra* geometryExtra = static_cast<const GeometryExtra*>(extra);
|
||||
|
||||
Resource* resource = nullptr;
|
||||
if (url.path().toLower().endsWith(".fst")) {
|
||||
resource = new GeometryMappingResource(url);
|
||||
} else {
|
||||
resource = new GeometryDefinitionResource(url, geometryExtra->mapping, geometryExtra->textureBaseUrl);
|
||||
const GeometryExtra* geometryExtra = static_cast<const GeometryExtra*>(extra);
|
||||
auto mapping = geometryExtra ? geometryExtra->mapping : QVariantHash();
|
||||
auto textureBaseUrl = geometryExtra ? geometryExtra->textureBaseUrl : QUrl();
|
||||
resource = new GeometryDefinitionResource(url, mapping, textureBaseUrl);
|
||||
}
|
||||
|
||||
return QSharedPointer<Resource>(resource, &Resource::deleter);
|
||||
|
@ -424,7 +425,7 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur
|
|||
{
|
||||
_textures = Textures(MapChannel::NUM_MAP_CHANNELS);
|
||||
if (!material.albedoTexture.filename.isEmpty()) {
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, NetworkTexture::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||
_albedoTransform = material.albedoTexture.transform;
|
||||
map->setTextureTransform(_albedoTransform);
|
||||
|
||||
|
@ -441,39 +442,39 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur
|
|||
|
||||
|
||||
if (!material.normalTexture.filename.isEmpty()) {
|
||||
auto type = (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE);
|
||||
auto type = (material.normalTexture.isBumpmap ? NetworkTexture::BUMP_TEXTURE : NetworkTexture::NORMAL_TEXTURE);
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.normalTexture, type, MapChannel::NORMAL_MAP);
|
||||
setTextureMap(MapChannel::NORMAL_MAP, map);
|
||||
}
|
||||
|
||||
if (!material.roughnessTexture.filename.isEmpty()) {
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.roughnessTexture, ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP);
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.roughnessTexture, NetworkTexture::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP);
|
||||
setTextureMap(MapChannel::ROUGHNESS_MAP, map);
|
||||
} else if (!material.glossTexture.filename.isEmpty()) {
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.glossTexture, GLOSS_TEXTURE, MapChannel::ROUGHNESS_MAP);
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.glossTexture, NetworkTexture::GLOSS_TEXTURE, MapChannel::ROUGHNESS_MAP);
|
||||
setTextureMap(MapChannel::ROUGHNESS_MAP, map);
|
||||
}
|
||||
|
||||
if (!material.metallicTexture.filename.isEmpty()) {
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.metallicTexture, METALLIC_TEXTURE, MapChannel::METALLIC_MAP);
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.metallicTexture, NetworkTexture::METALLIC_TEXTURE, MapChannel::METALLIC_MAP);
|
||||
setTextureMap(MapChannel::METALLIC_MAP, map);
|
||||
} else if (!material.specularTexture.filename.isEmpty()) {
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.specularTexture, SPECULAR_TEXTURE, MapChannel::METALLIC_MAP);
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.specularTexture, NetworkTexture::SPECULAR_TEXTURE, MapChannel::METALLIC_MAP);
|
||||
setTextureMap(MapChannel::METALLIC_MAP, map);
|
||||
}
|
||||
|
||||
if (!material.occlusionTexture.filename.isEmpty()) {
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.occlusionTexture, OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.occlusionTexture, NetworkTexture::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
|
||||
setTextureMap(MapChannel::OCCLUSION_MAP, map);
|
||||
}
|
||||
|
||||
if (!material.emissiveTexture.filename.isEmpty()) {
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.emissiveTexture, EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP);
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.emissiveTexture, NetworkTexture::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP);
|
||||
setTextureMap(MapChannel::EMISSIVE_MAP, map);
|
||||
}
|
||||
|
||||
if (!material.lightmapTexture.filename.isEmpty()) {
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.lightmapTexture, LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP);
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.lightmapTexture, NetworkTexture::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP);
|
||||
_lightmapTransform = material.lightmapTexture.transform;
|
||||
_lightmapParams = material.lightmapParams;
|
||||
map->setTextureTransform(_lightmapTransform);
|
||||
|
@ -495,7 +496,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) {
|
|||
|
||||
if (!albedoName.isEmpty()) {
|
||||
auto url = textureMap.contains(albedoName) ? textureMap[albedoName].toUrl() : QUrl();
|
||||
auto map = fetchTextureMap(url, ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||
auto map = fetchTextureMap(url, NetworkTexture::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||
map->setTextureTransform(_albedoTransform);
|
||||
// when reassigning the albedo texture we also check for the alpha channel used as opacity
|
||||
map->setUseAlphaChannel(true);
|
||||
|
@ -504,39 +505,39 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) {
|
|||
|
||||
if (!normalName.isEmpty()) {
|
||||
auto url = textureMap.contains(normalName) ? textureMap[normalName].toUrl() : QUrl();
|
||||
auto map = fetchTextureMap(url, NORMAL_TEXTURE, MapChannel::NORMAL_MAP);
|
||||
auto map = fetchTextureMap(url, NetworkTexture::NORMAL_TEXTURE, MapChannel::NORMAL_MAP);
|
||||
setTextureMap(MapChannel::NORMAL_MAP, map);
|
||||
}
|
||||
|
||||
if (!roughnessName.isEmpty()) {
|
||||
auto url = textureMap.contains(roughnessName) ? textureMap[roughnessName].toUrl() : QUrl();
|
||||
// FIXME: If passing a gloss map instead of a roughmap how do we know?
|
||||
auto map = fetchTextureMap(url, ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP);
|
||||
auto map = fetchTextureMap(url, NetworkTexture::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP);
|
||||
setTextureMap(MapChannel::ROUGHNESS_MAP, map);
|
||||
}
|
||||
|
||||
if (!metallicName.isEmpty()) {
|
||||
auto url = textureMap.contains(metallicName) ? textureMap[metallicName].toUrl() : QUrl();
|
||||
// FIXME: If passing a specular map instead of a metallic how do we know?
|
||||
auto map = fetchTextureMap(url, METALLIC_TEXTURE, MapChannel::METALLIC_MAP);
|
||||
auto map = fetchTextureMap(url, NetworkTexture::METALLIC_TEXTURE, MapChannel::METALLIC_MAP);
|
||||
setTextureMap(MapChannel::METALLIC_MAP, map);
|
||||
}
|
||||
|
||||
if (!occlusionName.isEmpty()) {
|
||||
auto url = textureMap.contains(occlusionName) ? textureMap[occlusionName].toUrl() : QUrl();
|
||||
auto map = fetchTextureMap(url, OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
|
||||
auto map = fetchTextureMap(url, NetworkTexture::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
|
||||
setTextureMap(MapChannel::OCCLUSION_MAP, map);
|
||||
}
|
||||
|
||||
if (!emissiveName.isEmpty()) {
|
||||
auto url = textureMap.contains(emissiveName) ? textureMap[emissiveName].toUrl() : QUrl();
|
||||
auto map = fetchTextureMap(url, EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP);
|
||||
auto map = fetchTextureMap(url, NetworkTexture::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP);
|
||||
setTextureMap(MapChannel::EMISSIVE_MAP, map);
|
||||
}
|
||||
|
||||
if (!lightmapName.isEmpty()) {
|
||||
auto url = textureMap.contains(lightmapName) ? textureMap[lightmapName].toUrl() : QUrl();
|
||||
auto map = fetchTextureMap(url, LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP);
|
||||
auto map = fetchTextureMap(url, NetworkTexture::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP);
|
||||
map->setTextureTransform(_lightmapTransform);
|
||||
map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y);
|
||||
setTextureMap(MapChannel::LIGHTMAP_MAP, map);
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
GeometryResource(const QUrl& url, const QUrl& textureBaseUrl = QUrl()) :
|
||||
Resource(url), _textureBaseUrl(textureBaseUrl) {}
|
||||
|
||||
virtual bool areTexturesLoaded() const { return isLoaded() && Geometry::areTexturesLoaded(); }
|
||||
virtual bool areTexturesLoaded() const override { return isLoaded() && Geometry::areTexturesLoaded(); }
|
||||
|
||||
virtual void deleter() override;
|
||||
|
||||
|
@ -170,6 +170,8 @@ protected:
|
|||
const bool& isOriginal() const { return _isOriginal; }
|
||||
|
||||
private:
|
||||
using TextureType = NetworkTexture::Type;
|
||||
|
||||
// Helpers for the ctors
|
||||
QUrl getTextureUrl(const QUrl& baseUrl, const FBXTexture& fbxTexture);
|
||||
model::TextureMapPointer fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture,
|
||||
|
|
|
@ -35,6 +35,16 @@ TextureCache::TextureCache() {
|
|||
const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE;
|
||||
setUnusedResourceCacheSize(TEXTURE_DEFAULT_UNUSED_MAX_SIZE);
|
||||
setObjectName("TextureCache");
|
||||
|
||||
// Expose enum Type to JS/QML via properties
|
||||
// Despite being one-off, this should be fine, because TextureCache is a SINGLETON_DEPENDENCY
|
||||
QObject* type = new QObject(this);
|
||||
type->setObjectName("TextureType");
|
||||
setProperty("Type", QVariant::fromValue(type));
|
||||
auto metaEnum = QMetaEnum::fromType<Type>();
|
||||
for (int i = 0; i < metaEnum.keyCount(); ++i) {
|
||||
type->setProperty(metaEnum.key(i), metaEnum.value(i));
|
||||
}
|
||||
}
|
||||
|
||||
TextureCache::~TextureCache() {
|
||||
|
@ -145,60 +155,68 @@ const gpu::TexturePointer& TextureCache::getNormalFittingTexture() {
|
|||
/// Extra data for creating textures.
|
||||
class TextureExtra {
|
||||
public:
|
||||
TextureType type;
|
||||
NetworkTexture::Type type;
|
||||
const QByteArray& content;
|
||||
};
|
||||
|
||||
NetworkTexturePointer TextureCache::getTexture(const QUrl& url, TextureType type, const QByteArray& content) {
|
||||
ScriptableResource* TextureCache::prefetch(const QUrl& url, int type) {
|
||||
auto byteArray = QByteArray();
|
||||
TextureExtra extra = { (Type)type, byteArray };
|
||||
return ResourceCache::prefetch(url, &extra);
|
||||
}
|
||||
|
||||
NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content) {
|
||||
TextureExtra extra = { type, content };
|
||||
return ResourceCache::getResource(url, QUrl(), content.isEmpty(), &extra).staticCast<NetworkTexture>();
|
||||
}
|
||||
|
||||
|
||||
TextureCache::TextureLoaderFunc getTextureLoaderForType(TextureType type) {
|
||||
NetworkTexture::TextureLoaderFunc getTextureLoaderForType(NetworkTexture::Type type) {
|
||||
using Type = NetworkTexture;
|
||||
|
||||
switch (type) {
|
||||
case ALBEDO_TEXTURE: {
|
||||
case Type::ALBEDO_TEXTURE: {
|
||||
return model::TextureUsage::createAlbedoTextureFromImage;
|
||||
break;
|
||||
}
|
||||
case EMISSIVE_TEXTURE: {
|
||||
case Type::EMISSIVE_TEXTURE: {
|
||||
return model::TextureUsage::createEmissiveTextureFromImage;
|
||||
break;
|
||||
}
|
||||
case LIGHTMAP_TEXTURE: {
|
||||
case Type::LIGHTMAP_TEXTURE: {
|
||||
return model::TextureUsage::createLightmapTextureFromImage;
|
||||
break;
|
||||
}
|
||||
case CUBE_TEXTURE: {
|
||||
case Type::CUBE_TEXTURE: {
|
||||
return model::TextureUsage::createCubeTextureFromImage;
|
||||
break;
|
||||
}
|
||||
case BUMP_TEXTURE: {
|
||||
case Type::BUMP_TEXTURE: {
|
||||
return model::TextureUsage::createNormalTextureFromBumpImage;
|
||||
break;
|
||||
}
|
||||
case NORMAL_TEXTURE: {
|
||||
case Type::NORMAL_TEXTURE: {
|
||||
return model::TextureUsage::createNormalTextureFromNormalImage;
|
||||
break;
|
||||
}
|
||||
case ROUGHNESS_TEXTURE: {
|
||||
case Type::ROUGHNESS_TEXTURE: {
|
||||
return model::TextureUsage::createRoughnessTextureFromImage;
|
||||
break;
|
||||
}
|
||||
case GLOSS_TEXTURE: {
|
||||
case Type::GLOSS_TEXTURE: {
|
||||
return model::TextureUsage::createRoughnessTextureFromGlossImage;
|
||||
break;
|
||||
}
|
||||
case SPECULAR_TEXTURE: {
|
||||
case Type::SPECULAR_TEXTURE: {
|
||||
return model::TextureUsage::createMetallicTextureFromImage;
|
||||
break;
|
||||
}
|
||||
case CUSTOM_TEXTURE: {
|
||||
case Type::CUSTOM_TEXTURE: {
|
||||
Q_ASSERT(false);
|
||||
return TextureCache::TextureLoaderFunc();
|
||||
return NetworkTexture::TextureLoaderFunc();
|
||||
break;
|
||||
}
|
||||
case DEFAULT_TEXTURE:
|
||||
case Type::DEFAULT_TEXTURE:
|
||||
default: {
|
||||
return model::TextureUsage::create2DTextureFromImage;
|
||||
break;
|
||||
|
@ -207,7 +225,7 @@ TextureCache::TextureLoaderFunc getTextureLoaderForType(TextureType type) {
|
|||
}
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
gpu::TexturePointer TextureCache::getImageTexture(const QString& path, TextureType type) {
|
||||
gpu::TexturePointer TextureCache::getImageTexture(const QString& path, Type type) {
|
||||
QImage image = QImage(path);
|
||||
auto loader = getTextureLoaderForType(type);
|
||||
return gpu::TexturePointer(loader(image, QUrl::fromLocalFile(path).fileName().toStdString()));
|
||||
|
@ -216,11 +234,13 @@ gpu::TexturePointer TextureCache::getImageTexture(const QString& path, TextureTy
|
|||
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
|
||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
||||
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);
|
||||
return QSharedPointer<Resource>(new NetworkTexture(url, textureExtra->type, textureExtra->content),
|
||||
auto type = textureExtra ? textureExtra->type : Type::DEFAULT_TEXTURE;
|
||||
auto content = textureExtra ? textureExtra->content : QByteArray();
|
||||
return QSharedPointer<Resource>(new NetworkTexture(url, type, content),
|
||||
&Resource::deleter);
|
||||
}
|
||||
|
||||
NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content) :
|
||||
NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content) :
|
||||
Resource(url, !content.isEmpty()),
|
||||
_type(type)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <QImage>
|
||||
#include <QMap>
|
||||
#include <QColor>
|
||||
#include <QMetaEnum>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <ResourceCache.h>
|
||||
|
@ -25,79 +26,6 @@
|
|||
namespace gpu {
|
||||
class Batch;
|
||||
}
|
||||
class NetworkTexture;
|
||||
|
||||
typedef QSharedPointer<NetworkTexture> NetworkTexturePointer;
|
||||
|
||||
enum TextureType {
|
||||
DEFAULT_TEXTURE,
|
||||
ALBEDO_TEXTURE,
|
||||
NORMAL_TEXTURE,
|
||||
BUMP_TEXTURE,
|
||||
SPECULAR_TEXTURE,
|
||||
METALLIC_TEXTURE = SPECULAR_TEXTURE, // for now spec and metallic texture are the same, converted to grey
|
||||
ROUGHNESS_TEXTURE,
|
||||
GLOSS_TEXTURE,
|
||||
EMISSIVE_TEXTURE,
|
||||
CUBE_TEXTURE,
|
||||
OCCLUSION_TEXTURE,
|
||||
LIGHTMAP_TEXTURE,
|
||||
CUSTOM_TEXTURE
|
||||
};
|
||||
|
||||
/// Stores cached textures, including render-to-texture targets.
|
||||
class TextureCache : public ResourceCache, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
/// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture
|
||||
/// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and
|
||||
/// the second, a set of random unit vectors to be used as noise gradients.
|
||||
const gpu::TexturePointer& getPermutationNormalTexture();
|
||||
|
||||
/// Returns an opaque white texture (useful for a default).
|
||||
const gpu::TexturePointer& getWhiteTexture();
|
||||
|
||||
/// Returns an opaque gray texture (useful for a default).
|
||||
const gpu::TexturePointer& getGrayTexture();
|
||||
|
||||
/// Returns the a pale blue texture (useful for a normal map).
|
||||
const gpu::TexturePointer& getBlueTexture();
|
||||
|
||||
/// Returns the a black texture (useful for a default).
|
||||
const gpu::TexturePointer& getBlackTexture();
|
||||
|
||||
// Returns a map used to compress the normals through a fitting scale algorithm
|
||||
const gpu::TexturePointer& getNormalFittingTexture();
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
static gpu::TexturePointer getImageTexture(const QString& path, TextureType type = DEFAULT_TEXTURE);
|
||||
|
||||
/// Loads a texture from the specified URL.
|
||||
NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE,
|
||||
const QByteArray& content = QByteArray());
|
||||
|
||||
typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName);
|
||||
|
||||
typedef std::function<TextureLoader> TextureLoaderFunc;
|
||||
protected:
|
||||
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra);
|
||||
|
||||
private:
|
||||
TextureCache();
|
||||
virtual ~TextureCache();
|
||||
friend class DilatableNetworkTexture;
|
||||
|
||||
gpu::TexturePointer _permutationNormalTexture;
|
||||
gpu::TexturePointer _whiteTexture;
|
||||
gpu::TexturePointer _grayTexture;
|
||||
gpu::TexturePointer _blueTexture;
|
||||
gpu::TexturePointer _blackTexture;
|
||||
gpu::TexturePointer _normalFittingTexture;
|
||||
};
|
||||
|
||||
/// A simple object wrapper for an OpenGL texture.
|
||||
class Texture {
|
||||
|
@ -107,15 +35,31 @@ public:
|
|||
};
|
||||
|
||||
/// A texture loaded from the network.
|
||||
|
||||
class NetworkTexture : public Resource, public Texture {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
typedef TextureCache::TextureLoaderFunc TextureLoaderFunc;
|
||||
|
||||
NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content);
|
||||
enum Type {
|
||||
DEFAULT_TEXTURE,
|
||||
ALBEDO_TEXTURE,
|
||||
NORMAL_TEXTURE,
|
||||
BUMP_TEXTURE,
|
||||
SPECULAR_TEXTURE,
|
||||
METALLIC_TEXTURE = SPECULAR_TEXTURE, // for now spec and metallic texture are the same, converted to grey
|
||||
ROUGHNESS_TEXTURE,
|
||||
GLOSS_TEXTURE,
|
||||
EMISSIVE_TEXTURE,
|
||||
CUBE_TEXTURE,
|
||||
OCCLUSION_TEXTURE,
|
||||
LIGHTMAP_TEXTURE,
|
||||
CUSTOM_TEXTURE
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName);
|
||||
using TextureLoaderFunc = std::function<TextureLoader>;
|
||||
|
||||
NetworkTexture(const QUrl& url, Type type, const QByteArray& content);
|
||||
NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content);
|
||||
|
||||
int getOriginalWidth() const { return _originalWidth; }
|
||||
|
@ -138,12 +82,69 @@ protected:
|
|||
Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight);
|
||||
|
||||
private:
|
||||
TextureType _type;
|
||||
TextureLoaderFunc _textureLoader;
|
||||
Type _type;
|
||||
TextureLoaderFunc _textureLoader { [](const QImage&, const std::string&){ return nullptr; } };
|
||||
int _originalWidth { 0 };
|
||||
int _originalHeight { 0 };
|
||||
int _width { 0 };
|
||||
int _height { 0 };
|
||||
};
|
||||
|
||||
using NetworkTexturePointer = QSharedPointer<NetworkTexture>;
|
||||
|
||||
/// Stores cached textures, including render-to-texture targets.
|
||||
class TextureCache : public ResourceCache, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
using Type = NetworkTexture::Type;
|
||||
|
||||
public:
|
||||
/// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture
|
||||
/// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and
|
||||
/// the second, a set of random unit vectors to be used as noise gradients.
|
||||
const gpu::TexturePointer& getPermutationNormalTexture();
|
||||
|
||||
/// Returns an opaque white texture (useful for a default).
|
||||
const gpu::TexturePointer& getWhiteTexture();
|
||||
|
||||
/// Returns an opaque gray texture (useful for a default).
|
||||
const gpu::TexturePointer& getGrayTexture();
|
||||
|
||||
/// Returns the a pale blue texture (useful for a normal map).
|
||||
const gpu::TexturePointer& getBlueTexture();
|
||||
|
||||
/// Returns the a black texture (useful for a default).
|
||||
const gpu::TexturePointer& getBlackTexture();
|
||||
|
||||
// Returns a map used to compress the normals through a fitting scale algorithm
|
||||
const gpu::TexturePointer& getNormalFittingTexture();
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
static gpu::TexturePointer getImageTexture(const QString& path, Type type = Type::DEFAULT_TEXTURE);
|
||||
|
||||
/// Loads a texture from the specified URL.
|
||||
NetworkTexturePointer getTexture(const QUrl& url, Type type = Type::DEFAULT_TEXTURE,
|
||||
const QByteArray& content = QByteArray());
|
||||
|
||||
protected:
|
||||
// Overload ResourceCache::prefetch to allow specifying texture type for loads
|
||||
Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type);
|
||||
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra);
|
||||
|
||||
private:
|
||||
TextureCache();
|
||||
virtual ~TextureCache();
|
||||
friend class DilatableNetworkTexture;
|
||||
|
||||
gpu::TexturePointer _permutationNormalTexture;
|
||||
gpu::TexturePointer _whiteTexture;
|
||||
gpu::TexturePointer _grayTexture;
|
||||
gpu::TexturePointer _blueTexture;
|
||||
gpu::TexturePointer _blackTexture;
|
||||
gpu::TexturePointer _normalFittingTexture;
|
||||
};
|
||||
|
||||
#endif // hifi_TextureCache_h
|
||||
|
|
|
@ -65,7 +65,7 @@ Material::~Material() {
|
|||
void Material::setEmissive(const Color& emissive, bool isSRGB) {
|
||||
_key.setEmissive(glm::any(glm::greaterThan(emissive, Color(0.0f))));
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32) _key._flags.to_ulong();
|
||||
_schemaBuffer.edit<Schema>()._emissive = (isSRGB ? ColorUtils::toLinearVec3(emissive) : emissive);
|
||||
_schemaBuffer.edit<Schema>()._emissive = (isSRGB ? ColorUtils::sRGBToLinearVec3(emissive) : emissive);
|
||||
}
|
||||
|
||||
void Material::setOpacity(float opacity) {
|
||||
|
@ -77,7 +77,7 @@ void Material::setOpacity(float opacity) {
|
|||
void Material::setAlbedo(const Color& albedo, bool isSRGB) {
|
||||
_key.setAlbedo(glm::any(glm::greaterThan(albedo, Color(0.0f))));
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
_schemaBuffer.edit<Schema>()._albedo = (isSRGB ? ColorUtils::toLinearVec3(albedo) : albedo);
|
||||
_schemaBuffer.edit<Schema>()._albedo = (isSRGB ? ColorUtils::sRGBToLinearVec3(albedo) : albedo);
|
||||
}
|
||||
|
||||
void Material::setRoughness(float roughness) {
|
||||
|
@ -89,7 +89,7 @@ void Material::setRoughness(float roughness) {
|
|||
|
||||
void Material::setFresnel(const Color& fresnel, bool isSRGB) {
|
||||
//_key.setAlbedo(glm::any(glm::greaterThan(albedo, Color(0.0f))));
|
||||
_schemaBuffer.edit<Schema>()._fresnel = (isSRGB ? ColorUtils::toLinearVec3(fresnel) : fresnel);
|
||||
_schemaBuffer.edit<Schema>()._fresnel = (isSRGB ? ColorUtils::sRGBToLinearVec3(fresnel) : fresnel);
|
||||
}
|
||||
|
||||
void Material::setMetallic(float metallic) {
|
||||
|
|
|
@ -245,16 +245,16 @@ public:
|
|||
const MaterialKey& getKey() const { return _key; }
|
||||
|
||||
void setEmissive(const Color& emissive, bool isSRGB = true);
|
||||
Color getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get<Schema>()._emissive) : _schemaBuffer.get<Schema>()._emissive); }
|
||||
Color getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_schemaBuffer.get<Schema>()._emissive) : _schemaBuffer.get<Schema>()._emissive); }
|
||||
|
||||
void setOpacity(float opacity);
|
||||
float getOpacity() const { return _schemaBuffer.get<Schema>()._opacity; }
|
||||
|
||||
void setAlbedo(const Color& albedo, bool isSRGB = true);
|
||||
Color getAlbedo(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get<Schema>()._albedo) : _schemaBuffer.get<Schema>()._albedo); }
|
||||
Color getAlbedo(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_schemaBuffer.get<Schema>()._albedo) : _schemaBuffer.get<Schema>()._albedo); }
|
||||
|
||||
void setFresnel(const Color& fresnel, bool isSRGB = true);
|
||||
Color getFresnel(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get<Schema>()._fresnel) : _schemaBuffer.get<Schema>()._fresnel); }
|
||||
Color getFresnel(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_schemaBuffer.get<Schema>()._fresnel) : _schemaBuffer.get<Schema>()._fresnel); }
|
||||
|
||||
void setMetallic(float metallic);
|
||||
float getMetallic() const { return _schemaBuffer.get<Schema>()._metallic; }
|
||||
|
|
|
@ -119,6 +119,92 @@ QSharedPointer<Resource> ResourceCacheSharedItems::getHighestPendingRequest() {
|
|||
return highestResource;
|
||||
}
|
||||
|
||||
ScriptableResource::ScriptableResource(const QUrl& url) :
|
||||
QObject(nullptr),
|
||||
_url(url) { }
|
||||
|
||||
void ScriptableResource::release() {
|
||||
disconnectHelper();
|
||||
_resource.reset();
|
||||
}
|
||||
|
||||
bool ScriptableResource::isInScript() const {
|
||||
return _resource && _resource->isInScript();
|
||||
}
|
||||
|
||||
void ScriptableResource::setInScript(bool isInScript) {
|
||||
if (_resource) {
|
||||
_resource->setInScript(isInScript);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptableResource::loadingChanged() {
|
||||
emit stateChanged(LOADING);
|
||||
}
|
||||
|
||||
void ScriptableResource::loadedChanged() {
|
||||
emit stateChanged(LOADED);
|
||||
}
|
||||
|
||||
void ScriptableResource::finished(bool success) {
|
||||
disconnectHelper();
|
||||
|
||||
emit stateChanged(success ? FINISHED : FAILED);
|
||||
}
|
||||
|
||||
void ScriptableResource::disconnectHelper() {
|
||||
if (_progressConnection) {
|
||||
disconnect(_progressConnection);
|
||||
}
|
||||
if (_loadingConnection) {
|
||||
disconnect(_loadingConnection);
|
||||
}
|
||||
if (_loadedConnection) {
|
||||
disconnect(_loadedConnection);
|
||||
}
|
||||
if (_finishedConnection) {
|
||||
disconnect(_finishedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptableResource* ResourceCache::prefetch(const QUrl& url, void* extra) {
|
||||
ScriptableResource* result = nullptr;
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
// Must be called in thread to ensure getResource returns a valid pointer
|
||||
QMetaObject::invokeMethod(this, "prefetch", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(ScriptableResource*, result),
|
||||
Q_ARG(QUrl, url), Q_ARG(void*, extra));
|
||||
return result;
|
||||
}
|
||||
|
||||
result = new ScriptableResource(url);
|
||||
|
||||
auto resource = getResource(url, QUrl(), false, extra);
|
||||
result->_resource = resource;
|
||||
result->setObjectName(url.toString());
|
||||
|
||||
result->_resource = resource;
|
||||
if (resource->isLoaded()) {
|
||||
result->finished(!resource->_failedToLoad);
|
||||
} else {
|
||||
result->_progressConnection = connect(
|
||||
resource.data(), &Resource::onProgress,
|
||||
result, &ScriptableResource::progressChanged);
|
||||
result->_loadingConnection = connect(
|
||||
resource.data(), &Resource::loading,
|
||||
result, &ScriptableResource::loadingChanged);
|
||||
result->_loadedConnection = connect(
|
||||
resource.data(), &Resource::loaded,
|
||||
result, &ScriptableResource::loadedChanged);
|
||||
result->_finishedConnection = connect(
|
||||
resource.data(), &Resource::finished,
|
||||
result, &ScriptableResource::finished);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ResourceCache::ResourceCache(QObject* parent) : QObject(parent) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
if (nodeList) {
|
||||
|
@ -219,7 +305,7 @@ QVariantList ResourceCache::getResourceList() {
|
|||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
void ResourceCache::setRequestLimit(int limit) {
|
||||
_requestLimit = limit;
|
||||
|
||||
|
@ -272,6 +358,7 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
|||
getResource(fallback, QUrl(), true) : QSharedPointer<Resource>(), delayLoad, extra);
|
||||
resource->setSelf(resource);
|
||||
resource->setCache(this);
|
||||
connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize);
|
||||
{
|
||||
QWriteLocker locker(&_resourcesLock);
|
||||
_resources.insert(url, resource);
|
||||
|
@ -357,8 +444,13 @@ void ResourceCache::removeResource(const QUrl& url, qint64 size) {
|
|||
_totalResourcesSize -= size;
|
||||
}
|
||||
|
||||
void ResourceCache::updateTotalSize(const qint64& oldSize, const qint64& newSize) {
|
||||
_totalResourcesSize += (newSize - oldSize);
|
||||
void ResourceCache::updateTotalSize(const qint64& deltaSize) {
|
||||
_totalResourcesSize += deltaSize;
|
||||
|
||||
// Sanity checks
|
||||
assert(_totalResourcesSize >= 0);
|
||||
assert(_totalResourcesSize < (1024 * BYTES_PER_GIGABYTES));
|
||||
|
||||
emit dirty();
|
||||
}
|
||||
|
||||
|
@ -543,7 +635,7 @@ void Resource::finishedLoading(bool success) {
|
|||
}
|
||||
|
||||
void Resource::setSize(const qint64& bytes) {
|
||||
QMetaObject::invokeMethod(_cache.data(), "updateTotalSize", Q_ARG(qint64, _bytes), Q_ARG(qint64, bytes));
|
||||
emit updateSize(bytes - _bytes);
|
||||
_bytes = bytes;
|
||||
}
|
||||
|
||||
|
@ -569,8 +661,11 @@ void Resource::makeRequest() {
|
|||
}
|
||||
|
||||
qCDebug(networking).noquote() << "Starting request for:" << _url.toDisplayString();
|
||||
emit loading();
|
||||
|
||||
connect(_request, &ResourceRequest::progress, this, &Resource::onProgress);
|
||||
connect(this, &Resource::onProgress, this, &Resource::handleDownloadProgress);
|
||||
|
||||
connect(_request, &ResourceRequest::progress, this, &Resource::handleDownloadProgress);
|
||||
connect(_request, &ResourceRequest::finished, this, &Resource::handleReplyFinished);
|
||||
|
||||
_bytesReceived = _bytesTotal = _bytes = 0;
|
||||
|
|
|
@ -24,9 +24,12 @@
|
|||
#include <QtCore/QWeakPointer>
|
||||
#include <QtCore/QReadWriteLock>
|
||||
#include <QtCore/QQueue>
|
||||
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
||||
#include <QScriptEngine>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "ResourceManager.h"
|
||||
|
@ -50,7 +53,7 @@ static const qint64 DEFAULT_UNUSED_MAX_SIZE = 100 * BYTES_PER_MEGABYTES;
|
|||
static const qint64 DEFAULT_UNUSED_MAX_SIZE = 1024 * BYTES_PER_MEGABYTES;
|
||||
#endif
|
||||
static const qint64 MIN_UNUSED_MAX_SIZE = 0;
|
||||
static const qint64 MAX_UNUSED_MAX_SIZE = 10 * BYTES_PER_GIGABYTES;
|
||||
static const qint64 MAX_UNUSED_MAX_SIZE = MAXIMUM_CACHE_SIZE;
|
||||
|
||||
// We need to make sure that these items are available for all instances of
|
||||
// ResourceCache derived classes. Since we can't count on the ordering of
|
||||
|
@ -78,6 +81,61 @@ private:
|
|||
QList<QWeakPointer<Resource>> _loadingRequests;
|
||||
};
|
||||
|
||||
/// Wrapper to expose resources to JS/QML
|
||||
class ScriptableResource : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QUrl url READ getUrl)
|
||||
Q_PROPERTY(int state READ getState NOTIFY stateChanged)
|
||||
|
||||
public:
|
||||
enum State {
|
||||
QUEUED,
|
||||
LOADING,
|
||||
LOADED,
|
||||
FINISHED,
|
||||
FAILED,
|
||||
};
|
||||
Q_ENUM(State)
|
||||
|
||||
ScriptableResource(const QUrl& url);
|
||||
virtual ~ScriptableResource() = default;
|
||||
|
||||
Q_INVOKABLE void release();
|
||||
|
||||
const QUrl& getUrl() const { return _url; }
|
||||
int getState() const { return (int)_state; }
|
||||
const QSharedPointer<Resource>& getResource() const { return _resource; }
|
||||
|
||||
bool isInScript() const;
|
||||
void setInScript(bool isInScript);
|
||||
|
||||
signals:
|
||||
void progressChanged(uint64_t bytesReceived, uint64_t bytesTotal);
|
||||
void stateChanged(int state);
|
||||
|
||||
private slots:
|
||||
void loadingChanged();
|
||||
void loadedChanged();
|
||||
void finished(bool success);
|
||||
|
||||
private:
|
||||
void disconnectHelper();
|
||||
|
||||
friend class ResourceCache;
|
||||
|
||||
// Holds a ref to the resource to keep it in scope
|
||||
QSharedPointer<Resource> _resource;
|
||||
|
||||
QMetaObject::Connection _progressConnection;
|
||||
QMetaObject::Connection _loadingConnection;
|
||||
QMetaObject::Connection _loadedConnection;
|
||||
QMetaObject::Connection _finishedConnection;
|
||||
|
||||
QUrl _url;
|
||||
State _state{ QUEUED };
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ScriptableResource*);
|
||||
|
||||
/// Base class for resource caches.
|
||||
class ResourceCache : public QObject {
|
||||
|
@ -121,12 +179,23 @@ public slots:
|
|||
void checkAsynchronousGets();
|
||||
|
||||
protected slots:
|
||||
void updateTotalSize(const qint64& oldSize, const qint64& newSize);
|
||||
void updateTotalSize(const qint64& deltaSize);
|
||||
|
||||
// Prefetches a resource to be held by the QScriptEngine.
|
||||
// Left as a protected member so subclasses can overload prefetch
|
||||
// and delegate to it (see TextureCache::prefetch(const QUrl&, int).
|
||||
ScriptableResource* prefetch(const QUrl& url, void* extra);
|
||||
|
||||
private slots:
|
||||
void clearATPAssets();
|
||||
|
||||
protected:
|
||||
// Prefetches a resource to be held by the QScriptEngine.
|
||||
// Pointers created through this method should be owned by the caller,
|
||||
// which should be a QScriptEngine with ScriptableResource registered, so that
|
||||
// the QScriptEngine will delete the pointer when it is garbage collected.
|
||||
Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url) { return prefetch(url, nullptr); }
|
||||
|
||||
/// Loads a resource from the specified URL.
|
||||
/// \param fallback a fallback URL to load if the desired one is unavailable
|
||||
/// \param delayLoad if true, don't load the resource immediately; wait until load is first requested
|
||||
|
@ -231,6 +300,9 @@ public:
|
|||
const QUrl& getURL() const { return _url; }
|
||||
|
||||
signals:
|
||||
/// Fired when the resource begins downloading.
|
||||
void loading();
|
||||
|
||||
/// Fired when the resource has been downloaded.
|
||||
/// This can be used instead of downloadFinished to access data before it is processed.
|
||||
void loaded(const QByteArray request);
|
||||
|
@ -244,6 +316,12 @@ signals:
|
|||
/// Fired when the resource is refreshed.
|
||||
void onRefresh();
|
||||
|
||||
/// Fired on progress updates.
|
||||
void onProgress(uint64_t bytesReceived, uint64_t bytesTotal);
|
||||
|
||||
/// Fired when the size changes (through setSize).
|
||||
void updateSize(qint64 deltaSize);
|
||||
|
||||
protected slots:
|
||||
void attemptRequest();
|
||||
|
||||
|
@ -280,21 +358,26 @@ private slots:
|
|||
void handleReplyFinished();
|
||||
|
||||
private:
|
||||
friend class ResourceCache;
|
||||
friend class ScriptableResource;
|
||||
|
||||
void setLRUKey(int lruKey) { _lruKey = lruKey; }
|
||||
|
||||
void makeRequest();
|
||||
void retry();
|
||||
void reinsert();
|
||||
|
||||
bool isInScript() const { return _isInScript; }
|
||||
void setInScript(bool isInScript) { _isInScript = isInScript; }
|
||||
|
||||
friend class ResourceCache;
|
||||
|
||||
ResourceRequest* _request = nullptr;
|
||||
int _lruKey = 0;
|
||||
QTimer* _replyTimer = nullptr;
|
||||
qint64 _bytesReceived = 0;
|
||||
qint64 _bytesTotal = 0;
|
||||
qint64 _bytes = 0;
|
||||
int _attempts = 0;
|
||||
ResourceRequest* _request{ nullptr };
|
||||
int _lruKey{ 0 };
|
||||
QTimer* _replyTimer{ nullptr };
|
||||
qint64 _bytesReceived{ 0 };
|
||||
qint64 _bytesTotal{ 0 };
|
||||
qint64 _bytes{ 0 };
|
||||
int _attempts{ 0 };
|
||||
bool _isInScript{ false };
|
||||
};
|
||||
|
||||
uint qHash(const QPointer<QObject>& value, uint seed = 0);
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
virtual void clear() override;
|
||||
|
||||
virtual void render(gpu::Batch& batch, const ViewFrustum& frustum) const;
|
||||
virtual void render(gpu::Batch& batch, const ViewFrustum& frustum) const override;
|
||||
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const ProceduralSkybox& skybox);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -363,7 +363,7 @@ void Font::drawString(gpu::Batch& batch, float x, float y, const QString& str, c
|
|||
batch._glUniform1i(_outlineLoc, (effectType == OUTLINE_EFFECT));
|
||||
|
||||
// need the gamma corrected color here
|
||||
glm::vec4 lrgba = glm::vec4(ColorUtils::toLinearVec3(glm::vec3(*color)), color->a);
|
||||
glm::vec4 lrgba = ColorUtils::sRGBToLinearVec4(*color);
|
||||
batch._glUniform4fv(_colorLoc, 1, (const float*)&lrgba);
|
||||
|
||||
batch.setInputFormat(_format);
|
||||
|
|
|
@ -105,6 +105,9 @@ void render::renderStateSortShapes(const SceneContextPointer& sceneContext, cons
|
|||
for (auto& pipelineKey : sortedPipelines) {
|
||||
auto& bucket = sortedShapes[pipelineKey];
|
||||
args->_pipeline = shapeContext->pickPipeline(args, pipelineKey);
|
||||
if (!args->_pipeline) {
|
||||
continue;
|
||||
}
|
||||
for (auto& item : bucket) {
|
||||
item.render(args);
|
||||
}
|
||||
|
|
|
@ -140,6 +140,8 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
|
|||
connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) {
|
||||
hadUncaughtExceptions(*this, _fileNameString);
|
||||
});
|
||||
|
||||
setProcessEventsInterval(MSECS_PER_SECOND);
|
||||
}
|
||||
|
||||
ScriptEngine::~ScriptEngine() {
|
||||
|
@ -170,7 +172,7 @@ void ScriptEngine::runInThread() {
|
|||
}
|
||||
|
||||
_isThreaded = true;
|
||||
QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete
|
||||
QThread* workerThread = new QThread(this); // thread is not owned, so we need to manage the delete
|
||||
QString scriptEngineName = QString("Script Thread:") + getFilename();
|
||||
workerThread->setObjectName(scriptEngineName);
|
||||
|
||||
|
@ -184,9 +186,6 @@ void ScriptEngine::runInThread() {
|
|||
// tell the thread to stop when the script engine is done
|
||||
connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit);
|
||||
|
||||
// when the thread is finished, add thread to the deleteLater queue
|
||||
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
||||
|
||||
moveToThread(workerThread);
|
||||
|
||||
// Starts an event loop, and emits workerThread->started()
|
||||
|
@ -199,11 +198,30 @@ void ScriptEngine::waitTillDoneRunning() {
|
|||
|
||||
// NOTE: waitTillDoneRunning() will be called on the main Application thread, inside of stopAllScripts()
|
||||
// we want the application thread to continue to process events, because the scripts will likely need to
|
||||
// marshall messages across to the main thread. For example if they access Settings or Meny in any of their
|
||||
// marshall messages across to the main thread. For example if they access Settings or Menu in any of their
|
||||
// shutdown code.
|
||||
QString scriptName = getFilename();
|
||||
|
||||
auto startedWaiting = usecTimestampNow();
|
||||
while (thread()->isRunning()) {
|
||||
// process events for the main application thread, allowing invokeMethod calls to pass between threads
|
||||
QCoreApplication::processEvents();
|
||||
auto stillWaiting = usecTimestampNow();
|
||||
auto elapsedUsecs = stillWaiting - startedWaiting;
|
||||
|
||||
// if we've been waiting a second or more, then tell the script engine to stop evaluating
|
||||
static const auto MAX_SCRIPT_EVALUATION_TIME = USECS_PER_SECOND;
|
||||
static const auto WAITING_TOO_LONG = MAX_SCRIPT_EVALUATION_TIME * 5;
|
||||
|
||||
// if we've been waiting for more than 5 seconds then we should be more aggessive about stopping
|
||||
if (elapsedUsecs > WAITING_TOO_LONG) {
|
||||
qCDebug(scriptengine) << "Script " << scriptName << " has been running too long [" << elapsedUsecs << " usecs] quitting.";
|
||||
thread()->quit();
|
||||
break;
|
||||
} else if (elapsedUsecs > MAX_SCRIPT_EVALUATION_TIME) {
|
||||
qCDebug(scriptengine) << "Script " << scriptName << " has been running too long [" << elapsedUsecs << " usecs] aborting evaluation.";
|
||||
QMetaObject::invokeMethod(this, "abortEvaluation");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,6 +288,48 @@ static void resultHandlerFromScriptValue(const QScriptValue& value, AnimVariantR
|
|||
assert(false);
|
||||
}
|
||||
|
||||
// Templated qScriptRegisterMetaType fails to compile with raw pointers
|
||||
using ScriptableResourceRawPtr = ScriptableResource*;
|
||||
|
||||
static QScriptValue scriptableResourceToScriptValue(QScriptEngine* engine, const ScriptableResourceRawPtr& resource) {
|
||||
// The first script to encounter this resource will track its memory.
|
||||
// In this way, it will be more likely to GC.
|
||||
// This fails in the case that the resource is used across many scripts, but
|
||||
// in that case it would be too difficult to tell which one should track the memory, and
|
||||
// this serves the common case (use in a single script).
|
||||
auto data = resource->getResource();
|
||||
if (data && !resource->isInScript()) {
|
||||
resource->setInScript(true);
|
||||
QObject::connect(data.data(), SIGNAL(updateSize(qint64)), engine, SLOT(updateMemoryCost(qint64)));
|
||||
}
|
||||
|
||||
auto object = engine->newQObject(
|
||||
const_cast<ScriptableResourceRawPtr>(resource),
|
||||
QScriptEngine::ScriptOwnership);
|
||||
return object;
|
||||
}
|
||||
|
||||
static void scriptableResourceFromScriptValue(const QScriptValue& value, ScriptableResourceRawPtr& resource) {
|
||||
resource = static_cast<ScriptableResourceRawPtr>(value.toQObject());
|
||||
}
|
||||
|
||||
static QScriptValue createScriptableResourcePrototype(QScriptEngine* engine) {
|
||||
auto prototype = engine->newObject();
|
||||
|
||||
// Expose enum State to JS/QML via properties
|
||||
QObject* state = new QObject(engine);
|
||||
state->setObjectName("ResourceState");
|
||||
auto metaEnum = QMetaEnum::fromType<ScriptableResource::State>();
|
||||
for (int i = 0; i < metaEnum.keyCount(); ++i) {
|
||||
state->setProperty(metaEnum.key(i), metaEnum.value(i));
|
||||
}
|
||||
|
||||
auto prototypeState = engine->newQObject(state, QScriptEngine::QtOwnership, QScriptEngine::ExcludeSlots | QScriptEngine::ExcludeSuperClassMethods);
|
||||
prototype.setProperty("State", prototypeState);
|
||||
|
||||
return prototype;
|
||||
}
|
||||
|
||||
void ScriptEngine::init() {
|
||||
if (_isInitialized) {
|
||||
return; // only initialize once
|
||||
|
@ -327,11 +387,16 @@ void ScriptEngine::init() {
|
|||
registerGlobalObject("Vec3", &_vec3Library);
|
||||
registerGlobalObject("Mat4", &_mat4Library);
|
||||
registerGlobalObject("Uuid", &_uuidLibrary);
|
||||
registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
registerGlobalObject("Messages", DependencyManager::get<MessagesClient>().data());
|
||||
qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue);
|
||||
qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue);
|
||||
|
||||
// Scriptable cache access
|
||||
auto resourcePrototype = createScriptableResourcePrototype(this);
|
||||
globalObject().setProperty("Resource", resourcePrototype);
|
||||
setDefaultPrototype(qMetaTypeId<ScriptableResource*>(), resourcePrototype);
|
||||
qScriptRegisterMetaType(this, scriptableResourceToScriptValue, scriptableResourceFromScriptValue);
|
||||
|
||||
// constants
|
||||
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
|
||||
|
||||
|
@ -367,7 +432,6 @@ void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
|
|||
if (partsToGo > 0) {
|
||||
//QObject *object = new QObject;
|
||||
QScriptValue partValue = newArray(); //newQObject(object, QScriptEngine::ScriptOwnership);
|
||||
qDebug() << "partValue[" << pathPart<<"].isArray() :" << partValue.isArray();
|
||||
partObject.setProperty(pathPart, partValue);
|
||||
} else {
|
||||
partObject.setProperty(pathPart, value);
|
||||
|
@ -793,6 +857,12 @@ void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantM
|
|||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::updateMemoryCost(const qint64& deltaSize) {
|
||||
if (deltaSize > 0) {
|
||||
reportAdditionalMemoryCost(deltaSize);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::timerFired() {
|
||||
QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());
|
||||
CallbackData timerData = _timerFunctionMap.value(callingTimer);
|
||||
|
@ -1060,11 +1130,6 @@ void ScriptEngine::loadEntityScript(QWeakPointer<ScriptEngine> theEngine, const
|
|||
<< QThread::currentThread() << "] expected thread [" << strongEngine->thread() << "]";
|
||||
#endif
|
||||
strongEngine->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);
|
||||
} else {
|
||||
// FIXME - I'm leaving this in for testing, so that QA can confirm that sometimes the script contents
|
||||
// returns after the ScriptEngine has been deleted, we can remove this after QA verifies the
|
||||
// repro case.
|
||||
qDebug() << "ScriptCache::getScriptContents() returned after our ScriptEngine was deleted... script:" << scriptOrURL;
|
||||
}
|
||||
}, forceRedownload);
|
||||
}
|
||||
|
|
|
@ -131,6 +131,8 @@ public:
|
|||
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const MouseEvent& event);
|
||||
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision);
|
||||
|
||||
Q_INVOKABLE void requestGarbageCollection() { collectGarbage(); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE - this is intended to be a public interface for Agent scripts, and local scripts, but not for EntityScripts
|
||||
Q_INVOKABLE void stop();
|
||||
|
@ -156,6 +158,7 @@ public:
|
|||
|
||||
public slots:
|
||||
void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler);
|
||||
void updateMemoryCost(const qint64&);
|
||||
|
||||
signals:
|
||||
void scriptLoaded(const QString& scriptFilename);
|
||||
|
|
|
@ -129,20 +129,7 @@ void ScriptEngines::shutdownScripting() {
|
|||
// "entities sandbox" which is only used to evaluate entities scripts to test their validity before using
|
||||
// them. We don't need to stop scripts that aren't running.
|
||||
if (scriptEngine->isRunning()) {
|
||||
|
||||
// If the script is running, but still evaluating then we need to wait for its evaluation step to
|
||||
// complete. After that we can handle the stop process appropriately
|
||||
if (scriptEngine->evaluatePending()) {
|
||||
while (scriptEngine->evaluatePending()) {
|
||||
|
||||
// This event loop allows any started, but not yet finished evaluate() calls to complete
|
||||
// we need to let these complete so that we can be guaranteed that the script engine isn't
|
||||
// in a partially setup state, which can confuse our shutdown unwinding.
|
||||
QEventLoop loop;
|
||||
QObject::connect(scriptEngine, &ScriptEngine::evaluationFinished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
}
|
||||
}
|
||||
qCDebug(scriptengine) << "about to shutdown script:" << scriptName;
|
||||
|
||||
// We disconnect any script engine signals from the application because we don't want to do any
|
||||
// extra stopScript/loadScript processing that the Application normally does when scripts start
|
||||
|
|
|
@ -21,9 +21,19 @@ class ColorUtils {
|
|||
public:
|
||||
inline static glm::vec3 toVec3(const xColor& color);
|
||||
|
||||
// Convert from gamma 2.2 space to linear
|
||||
inline static glm::vec3 toLinearVec3(const glm::vec3& srgb);
|
||||
// Convert to gamma 2.2 space from linear
|
||||
inline static glm::vec3 toGamma22Vec3(const glm::vec3& linear);
|
||||
|
||||
// Convert from sRGB gamma space to linear.
|
||||
// This is pretty different from converting from 2.2.
|
||||
inline static glm::vec3 sRGBToLinearVec3(const glm::vec3& srgb);
|
||||
inline static glm::vec3 tosRGBVec3(const glm::vec3& srgb);
|
||||
|
||||
inline static glm::vec4 sRGBToLinearVec4(const glm::vec4& srgb);
|
||||
inline static glm::vec4 tosRGBVec4(const glm::vec4& srgb);
|
||||
|
||||
inline static float sRGBToLinearFloat(const float& srgb);
|
||||
inline static float tosRGBFloat(const float& linear);
|
||||
};
|
||||
|
||||
inline glm::vec3 ColorUtils::toVec3(const xColor& color) {
|
||||
|
@ -31,16 +41,66 @@ inline glm::vec3 ColorUtils::toVec3(const xColor& color) {
|
|||
return glm::vec3(color.red * ONE_OVER_255, color.green * ONE_OVER_255, color.blue * ONE_OVER_255);
|
||||
}
|
||||
|
||||
inline glm::vec3 ColorUtils::toLinearVec3(const glm::vec3& srgb) {
|
||||
const float GAMMA_22 = 2.2f;
|
||||
// Couldn't find glm::pow(vec3, vec3) ? so did it myself...
|
||||
return glm::vec3(glm::pow(srgb.x, GAMMA_22), glm::pow(srgb.y, GAMMA_22), glm::pow(srgb.z, GAMMA_22));
|
||||
}
|
||||
|
||||
inline glm::vec3 ColorUtils::toGamma22Vec3(const glm::vec3& linear) {
|
||||
const float INV_GAMMA_22 = 1.0f / 2.2f;
|
||||
// Couldn't find glm::pow(vec3, vec3) ? so did it myself...
|
||||
return glm::vec3(glm::pow(linear.x, INV_GAMMA_22), glm::pow(linear.y, INV_GAMMA_22), glm::pow(linear.z, INV_GAMMA_22));
|
||||
}
|
||||
|
||||
// Convert from sRGB color space to linear color space.
|
||||
inline glm::vec3 ColorUtils::sRGBToLinearVec3(const glm::vec3& srgb) {
|
||||
return glm::vec3(sRGBToLinearFloat(srgb.x), sRGBToLinearFloat(srgb.y), sRGBToLinearFloat(srgb.z));
|
||||
}
|
||||
|
||||
// Convert from linear color space to sRGB color space.
|
||||
inline glm::vec3 ColorUtils::tosRGBVec3(const glm::vec3& linear) {
|
||||
return glm::vec3(tosRGBFloat(linear.x), tosRGBFloat(linear.y), tosRGBFloat(linear.z));
|
||||
}
|
||||
|
||||
// Convert from sRGB color space with alpha to linear color space with alpha.
|
||||
inline glm::vec4 ColorUtils::sRGBToLinearVec4(const glm::vec4& srgb) {
|
||||
return glm::vec4(sRGBToLinearFloat(srgb.x), sRGBToLinearFloat(srgb.y), sRGBToLinearFloat(srgb.z), srgb.w);
|
||||
}
|
||||
|
||||
// Convert from linear color space with alpha to sRGB color space with alpha.
|
||||
inline glm::vec4 ColorUtils::tosRGBVec4(const glm::vec4& linear) {
|
||||
return glm::vec4(tosRGBFloat(linear.x), tosRGBFloat(linear.y), tosRGBFloat(linear.z), linear.w);
|
||||
}
|
||||
|
||||
// This is based upon the conversions found in section 8.24 of the OpenGL 4.4 4.4 specification.
|
||||
// glm::pow(color, 2.2f) is approximate, and will cause subtle differences when used with sRGB framebuffers.
|
||||
inline float ColorUtils::sRGBToLinearFloat(const float &srgb) {
|
||||
const float SRGB_ELBOW = 0.04045f;
|
||||
float linearValue = 0.0f;
|
||||
|
||||
// This should mirror the conversion table found in section 8.24: sRGB Texture Color Conversion
|
||||
if (srgb <= SRGB_ELBOW) {
|
||||
linearValue = srgb / 12.92f;
|
||||
} else {
|
||||
linearValue = powf(((srgb + 0.055f) / 1.055f), 2.4f);
|
||||
}
|
||||
|
||||
return linearValue;
|
||||
}
|
||||
|
||||
// This is based upon the conversions found in section 17.3.9 of the OpenGL 4.4 specification.
|
||||
// glm::pow(color, 1.0f/2.2f) is approximate, and will cause subtle differences when used with sRGB framebuffers.
|
||||
inline float ColorUtils::tosRGBFloat(const float &linear) {
|
||||
const float SRGB_ELBOW_INV = 0.0031308f;
|
||||
float sRGBValue = 0.0f;
|
||||
|
||||
// This should mirror the conversion table found in section 17.3.9: sRGB Conversion
|
||||
if (linear <= 0.0f) {
|
||||
sRGBValue = 0.0f;
|
||||
} else if (0 < linear && linear < SRGB_ELBOW_INV) {
|
||||
sRGBValue = 12.92f * linear;
|
||||
} else if (SRGB_ELBOW_INV <= linear && linear < 1) {
|
||||
sRGBValue = 1.055f * powf(linear, 0.41666f - 0.055f);
|
||||
} else {
|
||||
sRGBValue = 1.0f;
|
||||
}
|
||||
|
||||
return sRGBValue;
|
||||
}
|
||||
|
||||
#endif // hifi_ColorUtils_h
|
|
@ -20,8 +20,6 @@ for (i = 0; i < l; i++) {
|
|||
print(roles[i]);
|
||||
}
|
||||
|
||||
MyAvatar.prefetchAnimation(THE_BIRD_RIGHT_URL);
|
||||
|
||||
// replace point animations with the bird!
|
||||
MyAvatar.overrideRoleAnimation("rightHandPointIntro", THE_BIRD_RIGHT_URL, 30, false, 0, 12);
|
||||
MyAvatar.overrideRoleAnimation("rightHandPointHold", THE_BIRD_RIGHT_URL, 30, false, 12, 12);
|
||||
|
|
99
scripts/developer/tests/scriptableResource/lib.js
Normal file
99
scripts/developer/tests/scriptableResource/lib.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// lib.js
|
||||
// scripts/developer/tests/scriptableResource
|
||||
//
|
||||
// Created by Zach Pomerantz on 4/20/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Preloads textures to play a simple movie, plays it, and frees those textures.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var NUM_FRAMES = 158; // 158 available
|
||||
var FRAME_RATE = 30; // 30 default
|
||||
|
||||
function getFrame(callback) {
|
||||
// A model exported from blender with a texture named 'Picture' on one face.
|
||||
var FRAME_URL = "http://hifi-production.s3.amazonaws.com/tutorials/pictureFrame/finalFrame.fbx";
|
||||
|
||||
var model = ModelCache.prefetch(FRAME_URL);
|
||||
if (model.state === Resource.State.FINISHED) {
|
||||
makeFrame(Resource.State.FINISHED);
|
||||
} else {
|
||||
model.stateChanged.connect(makeFrame);
|
||||
}
|
||||
|
||||
function makeFrame(state) {
|
||||
if (state == Resource.State.FAILED) { throw "Failed to load frame"; }
|
||||
if (state != Resource.State.FINISHED) { return; }
|
||||
|
||||
var pictureFrameProperties = {
|
||||
name: 'scriptableResourceTest Picture Frame',
|
||||
type: 'Model',
|
||||
position: getPosition(),
|
||||
modelURL: FRAME_URL,
|
||||
dynamic: true,
|
||||
};
|
||||
|
||||
callback(Entities.addEntity(pictureFrameProperties));
|
||||
}
|
||||
|
||||
function getPosition() {
|
||||
// Always put it 5 meters in front of you
|
||||
var position = MyAvatar.position;
|
||||
var yaw = MyAvatar.bodyYaw + MyAvatar.getHeadFinalYaw();
|
||||
var rads = (yaw / 180) * Math.PI;
|
||||
|
||||
position.y += 0.5;
|
||||
position.x += - 5 * Math.sin(rads);
|
||||
position.z += - 5 * Math.cos(rads);
|
||||
|
||||
print(JSON.stringify(position));
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
function prefetch(callback) {
|
||||
// A folder full of individual frames.
|
||||
var MOVIE_URL = "http://hifi-content.s3.amazonaws.com/james/vidtest/";
|
||||
|
||||
var frames = [];
|
||||
|
||||
var numLoading = 0;
|
||||
for (var i = 1; i <= NUM_FRAMES; ++i) {
|
||||
var padded = pad(i, 3);
|
||||
var filepath = MOVIE_URL + padded + '.jpg';
|
||||
var texture = TextureCache.prefetch(filepath);
|
||||
frames.push(texture);
|
||||
if (!texture.state == Resource.State.FINISHED) {
|
||||
numLoading++;
|
||||
texture.stateChanged.connect(function(state) {
|
||||
if (state == Resource.State.FAILED || state == Resource.State.FINISHED) {
|
||||
--numLoading;
|
||||
if (!numLoading) { callback(frames); }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!numLoading) { callback(frames); }
|
||||
|
||||
function pad(num, size) { // left-pad num with zeros until it is size digits
|
||||
var s = num.toString();
|
||||
while (s.length < size) { s = "0" + s; }
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
function play(model, frames, callback) {
|
||||
var frame = 0;
|
||||
var movieInterval = Script.setInterval(function() {
|
||||
Entities.editEntity(model, { textures: JSON.stringify({ Picture: frames[frame].url }) });
|
||||
if (++frame >= frames.length) {
|
||||
Script.clearInterval(movieInterval);
|
||||
callback();
|
||||
}
|
||||
}, 1000 / FRAME_RATE);
|
||||
}
|
||||
|
42
scripts/developer/tests/scriptableResource/movieTest.js
Normal file
42
scripts/developer/tests/scriptableResource/movieTest.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// testMovie.js
|
||||
// scripts/developer/tests/scriptableResource
|
||||
//
|
||||
// Created by Zach Pomerantz on 4/27/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Preloads textures, plays them on a frame model, and unloads them.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var entity;
|
||||
|
||||
Script.include([
|
||||
'../../../developer/utilities/cache/cacheStats.js',
|
||||
'lib.js',
|
||||
], function() {
|
||||
getFrame(function(frame) {
|
||||
entity = frame;
|
||||
prefetch(function(frames) {
|
||||
play(frame, frames, function() {
|
||||
// Delete each texture, so the next garbage collection cycle will release them.
|
||||
|
||||
// Setting frames = null breaks the reference,
|
||||
// but will not delete frames from the calling scope.
|
||||
// Instead, we must mutate it in-place to free its elements for GC
|
||||
// (assuming the elements are not held elsewhere).
|
||||
while (frames.length) { frames.pop(); }
|
||||
|
||||
// Alternatively, forcibly release each texture without relying on GC.
|
||||
// frames.forEach(function(texture) { texture.release(); });
|
||||
|
||||
Entities.deleteEntity(entity);
|
||||
Script.requestGarbageCollection();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(function() { entity && Entities.deleteEntity(entity); });
|
33
scripts/developer/tests/scriptableResource/prefetchTest.js
Normal file
33
scripts/developer/tests/scriptableResource/prefetchTest.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// testPrefetch.js
|
||||
// scripts/developer/tests/scriptableResource
|
||||
//
|
||||
// Created by Zach Pomerantz on 4/27/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Preloads textures and unloads them.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include([
|
||||
'../../../developer/utilities/cache/cacheStats.js',
|
||||
'lib.js',
|
||||
], function() {
|
||||
prefetch(function(frames) {
|
||||
// Delete each texture, so the next garbage collection cycle will release them.
|
||||
|
||||
// Setting frames = null breaks the reference,
|
||||
// but will not delete frames from the calling scope.
|
||||
// Instead, we must mutate it in-place to free its elements for GC
|
||||
// (assuming the elements are not held elsewhere).
|
||||
while (frames.length) { frames.pop(); }
|
||||
|
||||
// Alternatively, forcibly release each texture without relying on GC.
|
||||
// frames.forEach(function(texture) { texture.release(); });
|
||||
|
||||
Script.requestGarbageCollection();
|
||||
});
|
||||
});
|
||||
|
|
@ -46,8 +46,8 @@ var AWAY_INTRO = {
|
|||
endFrame: 83.0
|
||||
};
|
||||
|
||||
// prefetch the kneel animation so it's resident in memory when we need it.
|
||||
MyAvatar.prefetchAnimation(AWAY_INTRO.url);
|
||||
// prefetch the kneel animation and hold a ref so it's always resident in memory when we need it.
|
||||
var _animation = AnimationCache.prefetch(AWAY_INTRO.url);
|
||||
|
||||
function playAwayAnimation() {
|
||||
MyAvatar.overrideAnimation(AWAY_INTRO.url, AWAY_INTRO.playbackRate, AWAY_INTRO.loopFlag, AWAY_INTRO.startFrame, AWAY_INTRO.endFrame);
|
||||
|
|
|
@ -17,7 +17,7 @@ var toolIconUrl = Script.resolvePath("assets/images/tools/");
|
|||
|
||||
var DIRECTORY_WINDOW_URL = "https://metaverse.highfidelity.com/directory";
|
||||
var directoryWindow = new OverlayWebWindow({
|
||||
title: 'directory',
|
||||
title: 'Directory',
|
||||
source: "about:blank",
|
||||
width: 900,
|
||||
height: 700,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
|
||||
|
||||
var spriteURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Sprites/nucleosomes_sprite.fbx";
|
||||
var spriteURL = "https://hifi-production.s3.amazonaws.com/DomainContent/CellScience/Sprites/nucleosomes_sprite.fbx";
|
||||
var spriteDimensions = {
|
||||
x: 10,
|
||||
y: 10,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
z: -1
|
||||
}
|
||||
|
||||
var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/";
|
||||
var baseURL = "https://hifi-production.s3.amazonaws.com/DomainContent/CellScience/";
|
||||
|
||||
var self = this;
|
||||
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
|
||||
var version = 12;
|
||||
|
||||
var baseURL = "https://hifi-production.s3.amazonaws.com/DomainContent/CellScience/";
|
||||
var button;
|
||||
var _this;
|
||||
|
||||
function NavButton() {
|
||||
_this = this;
|
||||
}
|
||||
|
||||
NavButton.prototype = {
|
||||
button: null,
|
||||
buttonImageURL: baseURL + "GUI/GUI_Cells.png?" + version,
|
||||
hasButton: false,
|
||||
entryPoint: {
|
||||
x: 13500,
|
||||
y: 13500,
|
||||
z: 13500
|
||||
},
|
||||
target: {
|
||||
x: 13501,
|
||||
y: 13501,
|
||||
z: 13501
|
||||
},
|
||||
preload: function(entityId) {
|
||||
print('CELL PRELOAD CeLLS 1 ')
|
||||
this.entityId = entityId;
|
||||
this.addButton();
|
||||
Controller.mousePressEvent.connect(this.onClick);
|
||||
print('CELL PRELOAD CeLLS 2 ')
|
||||
},
|
||||
addButton: function() {
|
||||
if (this.hasButton === false) {
|
||||
print('CELL ADDBuTTON CeLLS 1 ')
|
||||
var windowDimensions = Controller.getViewportDimensions();
|
||||
var buttonWidth = 150;
|
||||
var buttonHeight = 50;
|
||||
var buttonPadding = 10;
|
||||
var offset = 0;
|
||||
var buttonPositionX = (offset + 1) * (buttonWidth + buttonPadding) + (windowDimensions.x / 2) - (buttonWidth * 3 + buttonPadding * 2.5);
|
||||
var buttonPositionY = (windowDimensions.y - buttonHeight) - 50;
|
||||
button = Overlays.addOverlay("image", {
|
||||
x: buttonPositionX,
|
||||
y: buttonPositionY,
|
||||
width: buttonWidth,
|
||||
height: buttonHeight,
|
||||
imageURL: this.buttonImageURL,
|
||||
visible: true,
|
||||
alpha: 1.0
|
||||
});
|
||||
this.hasButton = true;
|
||||
print('CELL ADDBuTTON CeLLS 2 button id is : ' +button)
|
||||
} else {
|
||||
print('CELL ADDBUTTON CeLLS FAIL - hasButton is' + this.hasButton)
|
||||
}
|
||||
},
|
||||
onClick: function(event) {
|
||||
//call to an internal function to get our scope back;
|
||||
_this.handleClick(event);
|
||||
},
|
||||
handleClick: function(event) {
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||
x: event.x,
|
||||
y: event.y
|
||||
});
|
||||
|
||||
if (clickedOverlay === button) {
|
||||
this.lookAtTarget();
|
||||
}
|
||||
},
|
||||
lookAtTarget: function() {
|
||||
var direction = Vec3.normalize(Vec3.subtract(this.target, this.entryPoint));
|
||||
var pitch = Quat.angleAxis(Math.asin(-direction.y) * 180.0 / Math.PI, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * 180.0 / Math.PI, {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
});
|
||||
|
||||
MyAvatar.goToLocation(this.target, true, yaw);
|
||||
|
||||
MyAvatar.headYaw = 0;
|
||||
},
|
||||
unload: function() {
|
||||
this.hasButton = false;
|
||||
Overlays.deleteOverlay(button);
|
||||
Controller.mousePressEvent.disconnect(this.onClick);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new NavButton();
|
||||
|
||||
|
||||
|
||||
});
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
|
||||
var version = 12;
|
||||
|
||||
var baseURL = "https://hifi-production.s3.amazonaws.com/DomainContent/CellScience/";
|
||||
var button;
|
||||
var _this;
|
||||
|
||||
function NavButton() {
|
||||
_this = this;
|
||||
}
|
||||
|
||||
NavButton.prototype = {
|
||||
button: null,
|
||||
buttonImageURL: baseURL + "GUI/GUI_Hexokinase.png?" + version,
|
||||
hasButton: false,
|
||||
entryPoint: {
|
||||
x: 3000,
|
||||
y: 3000,
|
||||
z: 13500
|
||||
},
|
||||
target: {
|
||||
x: 2755,
|
||||
y: 3121,
|
||||
z: 13501
|
||||
},
|
||||
preload: function(entityId) {
|
||||
print('CELL PRELOAD HEXOKINASE 1')
|
||||
this.entityId = entityId;
|
||||
this.addButton();
|
||||
Controller.mousePressEvent.connect(this.onClick);
|
||||
print('CELL PRELOAD HEXOKINASE 2')
|
||||
},
|
||||
addButton: function() {
|
||||
if (this.hasButton === false) {
|
||||
print('CELL ADDBUTTON HEXOKINASE 1')
|
||||
var windowDimensions = Controller.getViewportDimensions();
|
||||
var buttonWidth = 150;
|
||||
var buttonHeight = 50;
|
||||
var buttonPadding = 10;
|
||||
var offset = 3;
|
||||
var buttonPositionX = (offset + 1) * (buttonWidth + buttonPadding) + (windowDimensions.x / 2) - (buttonWidth * 3 + buttonPadding * 2.5);
|
||||
var buttonPositionY = (windowDimensions.y - buttonHeight) - 50;
|
||||
button = Overlays.addOverlay("image", {
|
||||
x: buttonPositionX,
|
||||
y: buttonPositionY,
|
||||
width: buttonWidth,
|
||||
height: buttonHeight,
|
||||
imageURL: this.buttonImageURL,
|
||||
visible: true,
|
||||
alpha: 1.0
|
||||
});
|
||||
this.hasButton = true;
|
||||
print('CELL ADDBUTTON HEXOKINASE 2 button id is : ' +button)
|
||||
} else {
|
||||
print('CELL ADDBUTTON HEXOKINASE FAIL hasButton is' + this.hasButton)
|
||||
}
|
||||
},
|
||||
onClick: function(event) {
|
||||
//call to an internal function to get our scope back;
|
||||
_this.handleClick(event);
|
||||
},
|
||||
handleClick: function(event) {
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||
x: event.x,
|
||||
y: event.y
|
||||
});
|
||||
|
||||
if (clickedOverlay === button) {
|
||||
this.lookAtTarget();
|
||||
}
|
||||
},
|
||||
lookAtTarget: function() {
|
||||
var direction = Vec3.normalize(Vec3.subtract(this.target, this.entryPoint));
|
||||
var pitch = Quat.angleAxis(Math.asin(-direction.y) * 180.0 / Math.PI, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * 180.0 / Math.PI, {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
});
|
||||
|
||||
MyAvatar.goToLocation(this.target, true, yaw);
|
||||
|
||||
MyAvatar.headYaw = 0;
|
||||
},
|
||||
unload: function() {
|
||||
this.hasButton = false;
|
||||
Overlays.deleteOverlay(button);
|
||||
Controller.mousePressEvent.disconnect(this.onClick);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new NavButton();
|
||||
|
||||
|
||||
|
||||
});
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
|
||||
var version = 12;
|
||||
|
||||
var baseURL = "https://hifi-production.s3.amazonaws.com/DomainContent/CellScience/";
|
||||
var button;
|
||||
var _this;
|
||||
|
||||
function NavButton() {
|
||||
_this = this;
|
||||
}
|
||||
|
||||
NavButton.prototype = {
|
||||
button: null,
|
||||
buttonImageURL: baseURL + "GUI/GUI_CellLayout.png?" + version,
|
||||
hasButton: false,
|
||||
entryPoint: {
|
||||
x: 3000,
|
||||
y: 13500,
|
||||
z: 3000
|
||||
},
|
||||
target: {
|
||||
x: 3276.6,
|
||||
y: 13703.3,
|
||||
z: 4405.6
|
||||
},
|
||||
preload: function(entityId) {
|
||||
print('CeLL PRELOAD INSIDECELL 1')
|
||||
this.entityId = entityId;
|
||||
this.addButton();
|
||||
Controller.mousePressEvent.connect(this.onClick);
|
||||
print('CeLL PRELOAD INSIDECELL 2')
|
||||
},
|
||||
addButton: function() {
|
||||
if (this.hasButton === false) {
|
||||
print('CELL ADDBUTTON INSIDECELL 1')
|
||||
var windowDimensions = Controller.getViewportDimensions();
|
||||
var buttonWidth = 150;
|
||||
var buttonHeight = 50;
|
||||
var buttonPadding = 10;
|
||||
var offset = 1;
|
||||
var buttonPositionX = (offset + 1) * (buttonWidth + buttonPadding) + (windowDimensions.x / 2) - (buttonWidth * 3 + buttonPadding * 2.5);
|
||||
var buttonPositionY = (windowDimensions.y - buttonHeight) - 50;
|
||||
button = Overlays.addOverlay("image", {
|
||||
x: buttonPositionX,
|
||||
y: buttonPositionY,
|
||||
width: buttonWidth,
|
||||
height: buttonHeight,
|
||||
imageURL: this.buttonImageURL,
|
||||
visible: true,
|
||||
alpha: 1.0
|
||||
});
|
||||
this.hasButton = true;
|
||||
print('CELL ADDBUTTON INSIDECELL 2 button id is : ' +button)
|
||||
} else {
|
||||
print('CELL ADDBUTTON INSIDECELL FAIL - hasButton is' + this.hasButton)
|
||||
}
|
||||
},
|
||||
onClick: function(event) {
|
||||
//call to an internal function to get our scope back;
|
||||
_this.handleClick(event);
|
||||
},
|
||||
handleClick: function(event) {
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||
x: event.x,
|
||||
y: event.y
|
||||
});
|
||||
|
||||
if (clickedOverlay === button) {
|
||||
this.lookAtTarget();
|
||||
}
|
||||
},
|
||||
lookAtTarget: function() {
|
||||
var direction = Vec3.normalize(Vec3.subtract(this.target, this.entryPoint));
|
||||
var pitch = Quat.angleAxis(Math.asin(-direction.y) * 180.0 / Math.PI, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * 180.0 / Math.PI, {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
});
|
||||
|
||||
MyAvatar.goToLocation(this.target, true, yaw);
|
||||
|
||||
MyAvatar.headYaw = 0;
|
||||
},
|
||||
unload: function() {
|
||||
this.hasButton = false;
|
||||
Overlays.deleteOverlay(button);
|
||||
Controller.mousePressEvent.disconnect(this.onClick);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new NavButton();
|
||||
|
||||
|
||||
|
||||
});
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
(function() {
|
||||
|
||||
var version = 12;
|
||||
|
||||
var baseURL = "https://hifi-production.s3.amazonaws.com/DomainContent/CellScience/";
|
||||
var button;
|
||||
var _this;
|
||||
|
||||
function NavButton() {
|
||||
_this = this;
|
||||
}
|
||||
|
||||
NavButton.prototype = {
|
||||
button: null,
|
||||
buttonImageURL: baseURL + "GUI/GUI_Ribosome.png?" + version,
|
||||
hasButton: false,
|
||||
entryPoint: {
|
||||
x: 13500,
|
||||
y: 3000,
|
||||
z: 3000
|
||||
},
|
||||
target: {
|
||||
x: 3276.6,
|
||||
y: 13703.3,
|
||||
z: 4405.6
|
||||
},
|
||||
preload: function(entityId) {
|
||||
print('CELL PRELOAD RIBOSOME 1')
|
||||
this.entityId = entityId;
|
||||
this.addButton();
|
||||
Controller.mousePressEvent.connect(this.onClick);
|
||||
print('CELL PRELOAD RIBOSOME 2')
|
||||
},
|
||||
addButton: function() {
|
||||
if (this.hasButton === false) {
|
||||
print('CELL ADBUTTON RIBOSOME 1')
|
||||
var windowDimensions = Controller.getViewportDimensions();
|
||||
var buttonWidth = 150;
|
||||
var buttonHeight = 50;
|
||||
var buttonPadding = 10;
|
||||
var offset = 2;
|
||||
var buttonPositionX = (offset + 1) * (buttonWidth + buttonPadding) + (windowDimensions.x / 2) - (buttonWidth * 3 + buttonPadding * 2.5);
|
||||
var buttonPositionY = (windowDimensions.y - buttonHeight) - 50;
|
||||
button = Overlays.addOverlay("image", {
|
||||
x: buttonPositionX,
|
||||
y: buttonPositionY,
|
||||
width: buttonWidth,
|
||||
height: buttonHeight,
|
||||
imageURL: this.buttonImageURL,
|
||||
visible: true,
|
||||
alpha: 1.0
|
||||
});
|
||||
this.hasButton = true;
|
||||
print('CELL ADDBUTTON RIBOSOME 2 button id is : ' +button)
|
||||
} else {
|
||||
print('CELL ADDBUTTON RIBOSOME FAIL - hasButton is' + this.hasButton)
|
||||
}
|
||||
},
|
||||
onClick: function(event) {
|
||||
//call to an internal function to get our scope back;
|
||||
_this.handleClick(event);
|
||||
},
|
||||
handleClick: function(event) {
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||
x: event.x,
|
||||
y: event.y
|
||||
});
|
||||
|
||||
if (clickedOverlay === button) {
|
||||
this.lookAtTarget();
|
||||
}
|
||||
},
|
||||
lookAtTarget: function() {
|
||||
var direction = Vec3.normalize(Vec3.subtract(this.target, this.entryPoint));
|
||||
var pitch = Quat.angleAxis(Math.asin(-direction.y) * 180.0 / Math.PI, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * 180.0 / Math.PI, {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
});
|
||||
|
||||
MyAvatar.goToLocation(this.target, true, yaw);
|
||||
|
||||
MyAvatar.headYaw = 0;
|
||||
},
|
||||
unload: function() {
|
||||
this.hasButton = false;
|
||||
Overlays.deleteOverlay(button);
|
||||
Controller.mousePressEvent.disconnect(this.onClick);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new NavButton();
|
||||
|
||||
|
||||
|
||||
});
|
|
@ -14,7 +14,7 @@
|
|||
Script.include(utilsScript);
|
||||
|
||||
var self = this;
|
||||
var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/";
|
||||
var baseURL = "https://hifi-production.s3.amazonaws.com/DomainContent/CellScience/";
|
||||
|
||||
this.preload = function(entityId) {
|
||||
this.entityId = entityId;
|
||||
|
|
|
@ -6,113 +6,114 @@
|
|||
//
|
||||
|
||||
(function() {
|
||||
var baseURL = "https://hifi-content.s3.amazonaws.com/hifi-content/DomainContent/CellScience/";
|
||||
var self = this;
|
||||
this.buttonImageURL = baseURL + "GUI/play_audio.svg?2";
|
||||
var baseURL = "https://hifi-production.s3.amazonaws.com/hifi-production/DomainContent/CellScience/";
|
||||
var self = this;
|
||||
this.buttonImageURL = baseURL + "GUI/play_audio.svg?2";
|
||||
|
||||
this.preload = function(entityId) {
|
||||
this.entityId = entityId;
|
||||
this.initialize(entityId)
|
||||
this.initTimeout = null;
|
||||
}
|
||||
|
||||
this.initialize = function(entityId) {
|
||||
//print(' should initialize' + entityId)
|
||||
var properties = Entities.getEntityProperties(entityId);
|
||||
if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) {
|
||||
self.initTimeout = Script.setTimeout(function() {
|
||||
// print(' no user data yet, try again in one second')
|
||||
self.initialize(entityId);
|
||||
}, 1000)
|
||||
|
||||
} else {
|
||||
//print(' userdata before parse attempt' + properties.userData)
|
||||
self.userData = null;
|
||||
try {
|
||||
self.userData = JSON.parse(properties.userData);
|
||||
} catch (err) {
|
||||
// print(' error parsing json');
|
||||
// print(' properties are:' + properties.userData);
|
||||
return;
|
||||
}
|
||||
|
||||
self.addButton();
|
||||
self.buttonShowing = false;
|
||||
self.showDistance = self.userData.showDistance;
|
||||
self.soundURL = baseURL + "Audio/" + self.userData.soundName + ".wav";
|
||||
// print("distance = " + self.userData.showDistance + ", sound = " + self.soundURL);
|
||||
self.soundOptions = {
|
||||
stereo: true,
|
||||
loop: false,
|
||||
localOnly: true,
|
||||
volume: 1
|
||||
};
|
||||
self.sound = SoundCache.getSound(this.soundURL);
|
||||
|
||||
this.preload = function(entityId) {
|
||||
this.entityId = entityId;
|
||||
this.initialize(entityId)
|
||||
this.initTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
this.initialize = function(entityId) {
|
||||
//print(' should initialize' + entityId)
|
||||
var properties = Entities.getEntityProperties(entityId);
|
||||
if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) {
|
||||
self.initTimeout = Script.setTimeout(function() {
|
||||
// print(' no user data yet, try again in one second')
|
||||
self.initialize(entityId);
|
||||
}, 1000)
|
||||
this.addButton = function() {
|
||||
this.windowDimensions = Controller.getViewportDimensions();
|
||||
this.buttonWidth = 100;
|
||||
this.buttonHeight = 100;
|
||||
this.buttonPadding = 0;
|
||||
|
||||
this.buttonPositionX = (self.windowDimensions.x - self.buttonPadding) / 2 - self.buttonWidth;
|
||||
this.buttonPositionY = (self.windowDimensions.y - self.buttonHeight) - (self.buttonHeight + self.buttonPadding);
|
||||
this.button = Overlays.addOverlay("image", {
|
||||
x: self.buttonPositionX,
|
||||
y: self.buttonPositionY,
|
||||
width: self.buttonWidth,
|
||||
height: self.buttonHeight,
|
||||
imageURL: self.buttonImageURL,
|
||||
visible: false,
|
||||
alpha: 1.0
|
||||
});
|
||||
}
|
||||
|
||||
this.update = function(deltaTime) {
|
||||
|
||||
self.distance = Vec3.distance(MyAvatar.position, Entities.getEntityProperties(self.entityId).position);
|
||||
//print(self.distance);
|
||||
if (!self.buttonShowing && self.distance < self.userData.showDistance) {
|
||||
self.buttonShowing = true;
|
||||
Overlays.editOverlay(self.button, {
|
||||
visible: true
|
||||
});
|
||||
} else if (self.buttonShowing && self.distance > self.userData.showDistance) {
|
||||
self.buttonShowing = false;
|
||||
Overlays.editOverlay(self.button, {
|
||||
visible: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.onClick = function(event) {
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||
x: event.x,
|
||||
y: event.y
|
||||
});
|
||||
if (clickedOverlay === self.button) {
|
||||
//print("button was clicked");
|
||||
if (self.sound.downloaded) {
|
||||
//print("play sound");
|
||||
Audio.playSound(self.sound, self.soundOptions);
|
||||
} else {
|
||||
//print(' userdata before parse attempt' + properties.userData)
|
||||
self.userData = null;
|
||||
try {
|
||||
self.userData = JSON.parse(properties.userData);
|
||||
} catch (err) {
|
||||
// print(' error parsing json');
|
||||
// print(' properties are:' + properties.userData);
|
||||
return;
|
||||
}
|
||||
|
||||
self.addButton();
|
||||
self.buttonShowing = false;
|
||||
self.showDistance = self.userData.showDistance;
|
||||
self.soundURL = baseURL + "Audio/" + self.userData.soundName + ".wav";
|
||||
// print("distance = " + self.userData.showDistance + ", sound = " + self.soundURL);
|
||||
self.soundOptions = {
|
||||
stereo: true,
|
||||
loop: false,
|
||||
localOnly: true,
|
||||
volume: 1
|
||||
};
|
||||
self.sound = SoundCache.getSound(this.soundURL);
|
||||
|
||||
//print("not downloaded");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.addButton = function() {
|
||||
this.windowDimensions = Controller.getViewportDimensions();
|
||||
this.buttonWidth = 100;
|
||||
this.buttonHeight = 100;
|
||||
this.buttonPadding = 0;
|
||||
this.unload = function() {
|
||||
Overlays.deleteOverlay(self.button);
|
||||
Controller.mousePressEvent.disconnect(this.onClick);
|
||||
Script.update.disconnect(this.update);
|
||||
if (this.initTimeout !== null) {
|
||||
Script.clearTimeout(this.initTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
this.buttonPositionX = (self.windowDimensions.x - self.buttonPadding) / 2 - self.buttonWidth;
|
||||
this.buttonPositionY = (self.windowDimensions.y - self.buttonHeight) - (self.buttonHeight + self.buttonPadding);
|
||||
this.button = Overlays.addOverlay("image", {
|
||||
x: self.buttonPositionX,
|
||||
y: self.buttonPositionY,
|
||||
width: self.buttonWidth,
|
||||
height: self.buttonHeight,
|
||||
imageURL: self.buttonImageURL,
|
||||
visible: false,
|
||||
alpha: 1.0
|
||||
});
|
||||
}
|
||||
Controller.mousePressEvent.connect(this.onClick);
|
||||
Script.update.connect(this.update);
|
||||
|
||||
this.update = function(deltaTime) {
|
||||
|
||||
self.distance = Vec3.distance(MyAvatar.position, Entities.getEntityProperties(self.entityId).position);
|
||||
//print(self.distance);
|
||||
if (!self.buttonShowing && self.distance < self.userData.showDistance) {
|
||||
self.buttonShowing = true;
|
||||
Overlays.editOverlay(self.button, {
|
||||
visible: true
|
||||
});
|
||||
} else if (self.buttonShowing && self.distance > self.userData.showDistance) {
|
||||
self.buttonShowing = false;
|
||||
Overlays.editOverlay(self.button, {
|
||||
visible: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.onClick = function(event) {
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||
x: event.x,
|
||||
y: event.y
|
||||
});
|
||||
if (clickedOverlay === self.button) {
|
||||
//print("button was clicked");
|
||||
if (self.sound.downloaded) {
|
||||
//print("play sound");
|
||||
Audio.playSound(self.sound, self.soundOptions);
|
||||
} else {
|
||||
//print("not downloaded");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.unload = function() {
|
||||
Overlays.deleteOverlay(self.button);
|
||||
Controller.mousePressEvent.disconnect(this.onClick);
|
||||
Script.update.disconnect(this.update);
|
||||
if (this.initTimeout !== null) {
|
||||
Script.clearTimeout(this.initTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(this.onClick);
|
||||
Script.update.connect(this.update);
|
||||
|
||||
});
|
||||
});
|
|
@ -8,7 +8,7 @@
|
|||
(function() {
|
||||
|
||||
var self = this;
|
||||
var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/";
|
||||
var baseURL = "https://hifi-production.s3.amazonaws.com/DomainContent/CellScience/";
|
||||
|
||||
var version = 3;
|
||||
this.preload = function(entityId) {
|
||||
|
|
|
@ -22,9 +22,14 @@
|
|||
this.initialize = function(entityID) {
|
||||
// print(' should initialize')
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) {
|
||||
if (properties.hasOwnProperty('userData') === false) {
|
||||
self.initTimeout = Script.setTimeout(function() {
|
||||
// print(' no user data yet, try again in one second')
|
||||
// print(' no user data yet, try again in one second')
|
||||
self.initialize(entityID);
|
||||
}, 1000)
|
||||
} else if (properties.userData.length === 0) {
|
||||
self.initTimeout = Script.setTimeout(function() {
|
||||
// print(' no user data yet, try again in one second')
|
||||
self.initialize(entityID);
|
||||
}, 1000)
|
||||
} else {
|
||||
|
@ -39,7 +44,7 @@
|
|||
volume: 0.5
|
||||
};
|
||||
|
||||
self.teleportSound = SoundCache.getSound("https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/whoosh.wav");
|
||||
self.teleportSound = SoundCache.getSound("https://hifi-production.s3.amazonaws.com/DomainContent/CellScience/Audio/whoosh.wav");
|
||||
// print(" portal destination is " + self.portalDestination);
|
||||
}
|
||||
}
|
||||
|
@ -51,13 +56,13 @@
|
|||
if (data != null) {
|
||||
print("Teleporting to (" + data.location.x + ", " + data.location.y + ", " + data.location.z + ")");
|
||||
|
||||
MyAvatar.position = data.location;
|
||||
MyAvatar.position = data.location;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.lookAtTarget = function(entryPoint,target) {
|
||||
this.lookAtTarget = function(entryPoint, target) {
|
||||
//print('SHOULD LOOK AT TARGET')
|
||||
var direction = Vec3.normalize(Vec3.subtract(entryPoint, target));
|
||||
var pitch = Quat.angleAxis(Math.asin(-direction.y) * 180.0 / Math.PI, {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
var soundMap = [{
|
||||
name: 'Cells',
|
||||
url: "http://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/Cells.wav",
|
||||
url: "http://hifi-production.s3.amazonaws.com/DomainContent/CellScience/Audio/Cells.wav",
|
||||
audioOptions: {
|
||||
position: {
|
||||
x: 15850,
|
||||
|
@ -12,7 +12,7 @@ var soundMap = [{
|
|||
}
|
||||
}, {
|
||||
name: 'Cell Layout',
|
||||
url: "http://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/CellLayout.wav",
|
||||
url: "http://hifi-production.s3.amazonaws.com/DomainContent/CellScience/Audio/CellLayout.wav",
|
||||
audioOptions: {
|
||||
position: {
|
||||
x: 15950,
|
||||
|
@ -24,7 +24,7 @@ var soundMap = [{
|
|||
}
|
||||
}, {
|
||||
name: 'Ribsome',
|
||||
url: "http://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/Ribosome.wav",
|
||||
url: "http://hifi-production.s3.amazonaws.com/DomainContent/CellScience/Audio/Ribosome.wav",
|
||||
audioOptions: {
|
||||
position: {
|
||||
x: 15650,
|
||||
|
@ -36,7 +36,7 @@ var soundMap = [{
|
|||
}
|
||||
}, {
|
||||
name: 'Hexokinase',
|
||||
url: "http://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/Hexokinase.wav",
|
||||
url: "http://hifi-production.s3.amazonaws.com/DomainContent/CellScience/Audio/Hexokinase.wav",
|
||||
audioOptions: {
|
||||
position: {
|
||||
x: 15750,
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -9,12 +9,8 @@ var numDynein = 2;
|
|||
var numKinesin = 2;
|
||||
var percentOnMainMT = 100;
|
||||
|
||||
var baseLocation;
|
||||
if (USE_LOCAL_HOST === true) {
|
||||
baseLocation = "http://localhost:8080/";
|
||||
} else {
|
||||
baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"
|
||||
}
|
||||
|
||||
baseLocation = "https://hifi-production.s3.amazonaws.com/DomainContent/CellScience/"
|
||||
|
||||
var WORLD_OFFSET = {
|
||||
x: 0,
|
||||
|
|
|
@ -18,7 +18,6 @@ function offsetVectorToWorld(vector) {
|
|||
|
||||
newVector = Vec3.sum(vector, WORLD_OFFSET);
|
||||
|
||||
print('JBP NEW VECTOR IS:: ' + JSON.stringify(newVector))
|
||||
return newVector
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ function offsetVectorToWorld(vector) {
|
|||
|
||||
newVector = Vec3.sum(vector, WORLD_OFFSET);
|
||||
|
||||
print('JBP NEW VECTOR IS:: ' + JSON.stringify(newVector))
|
||||
return newVector
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue