mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 01:59:59 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into steam
This commit is contained in:
commit
e4dd4c1a41
110 changed files with 2778 additions and 2527 deletions
|
@ -72,6 +72,6 @@ module.exports = {
|
|||
"spaced-comment": ["error", "always", {
|
||||
"line": { "markers": ["/"] }
|
||||
}],
|
||||
"space-before-function-paren": ["error", {"anonymous": "always", "named": "never"}]
|
||||
"space-before-function-paren": ["error", {"anonymous": "ignore", "named": "never"}]
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,13 +23,13 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
|
|||
|
||||
#Extract the unique include shader paths
|
||||
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
|
||||
#message(Hifi for includes ${INCLUDES})
|
||||
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
|
||||
#message(${TARGET_NAME} Hifi for includes ${INCLUDES})
|
||||
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
|
||||
#message(ready for includes ${SHADER_INCLUDES_PATHS})
|
||||
#message(ready for includes ${SHADER_INCLUDES_PATHS})
|
||||
|
||||
# make the scribe include arguments
|
||||
set(SCRIBE_INCLUDES)
|
||||
|
@ -77,6 +77,7 @@ endfunction()
|
|||
|
||||
|
||||
macro(AUTOSCRIBE_SHADER_LIB)
|
||||
set(HIFI_LIBRARIES_SHADER_INCLUDE_FILES "")
|
||||
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
|
||||
foreach(HIFI_LIBRARY ${ARGN})
|
||||
#if (NOT TARGET ${HIFI_LIBRARY})
|
||||
|
@ -86,7 +87,7 @@ macro(AUTOSCRIBE_SHADER_LIB)
|
|||
#file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src/*.slh)
|
||||
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src)
|
||||
endforeach()
|
||||
#message(${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
|
||||
#message("${TARGET_NAME} ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES}")
|
||||
|
||||
file(GLOB_RECURSE SHADER_INCLUDE_FILES src/*.slh)
|
||||
file(GLOB_RECURSE SHADER_SOURCE_FILES src/*.slv src/*.slf src/*.slg)
|
||||
|
@ -95,13 +96,14 @@ macro(AUTOSCRIBE_SHADER_LIB)
|
|||
set(SHADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders/${TARGET_NAME}")
|
||||
file(MAKE_DIRECTORY ${SHADERS_DIR})
|
||||
|
||||
#message(${SHADER_INCLUDE_FILES})
|
||||
#message("${TARGET_NAME} ${SHADER_INCLUDE_FILES}")
|
||||
set(AUTOSCRIBE_SHADER_SRC "")
|
||||
foreach(SHADER_FILE ${SHADER_SOURCE_FILES})
|
||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
||||
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
|
||||
endforeach()
|
||||
#message(${AUTOSCRIBE_SHADER_SRC})
|
||||
#message(${TARGET_NAME} ${AUTOSCRIBE_SHADER_SRC})
|
||||
|
||||
if (WIN32)
|
||||
source_group("Shaders" FILES ${SHADER_INCLUDE_FILES})
|
||||
|
|
|
@ -54,8 +54,9 @@ macro(SETUP_HIFI_LIBRARY)
|
|||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
||||
endforeach()
|
||||
|
||||
# Don't make scribed shaders cumulative
|
||||
# Don't make scribed shaders or QT resource files cumulative
|
||||
set(AUTOSCRIBE_SHADER_LIB_SRC "")
|
||||
set(QT_RESOURCES_FILE "")
|
||||
|
||||
target_glm()
|
||||
|
||||
|
|
|
@ -1233,7 +1233,10 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() {
|
|||
callbackParameters.errorCallbackReceiver = this;
|
||||
callbackParameters.errorCallbackMethod = "handleFailedICEServerAddressUpdate";
|
||||
|
||||
qDebug() << "Updating ice-server address in High Fidelity Metaverse API to" << _iceServerSocket.getAddress().toString();
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Updating ice-server address in High Fidelity Metaverse API to [^ \n]+");
|
||||
qDebug() << "Updating ice-server address in High Fidelity Metaverse API to"
|
||||
<< _iceServerSocket.getAddress().toString();
|
||||
|
||||
static const QString DOMAIN_ICE_ADDRESS_UPDATE = "/api/v1/domains/%1/ice_server_address";
|
||||
|
||||
|
|
|
@ -532,9 +532,12 @@ void DomainServerSettingsManager::unpackPermissions() {
|
|||
// we don't have permissions for one of the standard groups, so we'll add them now
|
||||
NodePermissionsPointer perms { new NodePermissions(standardKey) };
|
||||
|
||||
// the localhost user is granted all permissions by default
|
||||
if (standardKey == NodePermissions::standardNameLocalhost) {
|
||||
// the localhost user is granted all permissions by default
|
||||
perms->setAll(true);
|
||||
} else {
|
||||
// anonymous, logged in, and friend users get connect permissions by default
|
||||
perms->set(NodePermissions::Permission::canConnectToDomain);
|
||||
}
|
||||
|
||||
// add the permissions to the standard map
|
||||
|
|
|
@ -63,6 +63,19 @@
|
|||
["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"]
|
||||
]
|
||||
},
|
||||
"when": "Application.CameraFirstPerson",
|
||||
"to": "Actions.Yaw"
|
||||
},
|
||||
{ "from": { "makeAxis" : [
|
||||
["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"],
|
||||
["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"]
|
||||
]
|
||||
},
|
||||
"when": "Application.CameraThirdPerson",
|
||||
"to": "Actions.Yaw"
|
||||
},
|
||||
{ "from": { "makeAxis" : [ ["Keyboard.A"], ["Keyboard.D"] ] },
|
||||
"when": "Application.CameraFSM",
|
||||
"to": "Actions.Yaw"
|
||||
},
|
||||
|
||||
|
@ -81,9 +94,10 @@
|
|||
{ "from": "Keyboard.Right", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.Down", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" },
|
||||
{ "from": "Keyboard.Up", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" },
|
||||
|
||||
{ "from": "Keyboard.Up", "to": "Actions.LONGITUDINAL_FORWARD" },
|
||||
{ "from": "Keyboard.Down", "to": "Actions.LONGITUDINAL_BACKWARD" },
|
||||
{ "from": "Keyboard.Up", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_FORWARD" },
|
||||
{ "from": "Keyboard.Up", "when": "Application.CameraThirdPerson", "to": "Actions.LONGITUDINAL_FORWARD" },
|
||||
{ "from": "Keyboard.Down", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_BACKWARD" },
|
||||
{ "from": "Keyboard.Down", "when": "Application.CameraThirdPerson", "to": "Actions.LONGITUDINAL_BACKWARD" },
|
||||
|
||||
{ "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" },
|
||||
{ "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" },
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
{
|
||||
"name": "Oculus Touch to Standard",
|
||||
"channels": [
|
||||
{ "from": "OculusTouch.A", "to": "Standard.RightPrimaryThumb" },
|
||||
{ "from": "OculusTouch.X", "to": "Standard.LeftPrimaryThumb" },
|
||||
{ "from": "OculusTouch.A", "to": "Standard.RightPrimaryThumb", "peek": true },
|
||||
{ "from": "OculusTouch.X", "to": "Standard.LeftPrimaryThumb", "peek": true },
|
||||
|
||||
{ "from": "OculusTouch.A", "to": "Standard.A" },
|
||||
{ "from": "OculusTouch.B", "to": "Standard.B" },
|
||||
{ "from": "OculusTouch.X", "to": "Standard.X" },
|
||||
{ "from": "OculusTouch.Y", "to": "Standard.Y" },
|
||||
|
||||
{ "from": "OculusTouch.LY", "to": "Standard.LY",
|
||||
"filters": [
|
||||
|
|
|
@ -32,9 +32,6 @@
|
|||
{ "from": "Standard.Back", "to": "Actions.CycleCamera" },
|
||||
{ "from": "Standard.Start", "to": "Actions.ContextMenu" },
|
||||
|
||||
{ "from": [ "Standard.DU", "Standard.DL", "Standard.DR", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
|
||||
{ "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" },
|
||||
|
||||
{ "from": "Standard.LT", "to": "Actions.LeftHandClick" },
|
||||
{ "from": "Standard.RT", "to": "Actions.RightHandClick" },
|
||||
|
||||
|
|
|
@ -16,11 +16,13 @@
|
|||
{ "from": "GamePad.Back", "to": "Standard.Back" },
|
||||
{ "from": "GamePad.Start", "to": "Standard.Start" },
|
||||
|
||||
{ "from": [ "GamePad.DU", "GamePad.DL", "GamePad.DR", "GamePad.DD" ], "to": "Standard.LeftPrimaryThumb", "peek": true },
|
||||
{ "from": "GamePad.DU", "to": "Standard.DU" },
|
||||
{ "from": "GamePad.DD", "to": "Standard.DD" },
|
||||
{ "from": "GamePad.DL", "to": "Standard.DL" },
|
||||
{ "from": "GamePad.DR", "to": "Standard.DR" },
|
||||
|
||||
{ "from": [ "GamePad.A", "GamePad.B", "GamePad.X", "GamePad.Y" ], "to": "Standard.RightPrimaryThumb", "peek": true },
|
||||
{ "from": "GamePad.A", "to": "Standard.A" },
|
||||
{ "from": "GamePad.B", "to": "Standard.B" },
|
||||
{ "from": "GamePad.X", "to": "Standard.X" },
|
||||
|
|
BIN
interface/resources/images/Default-Sky-9-ambient.jpg
Normal file
BIN
interface/resources/images/Default-Sky-9-ambient.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
BIN
interface/resources/images/Default-Sky-9-cubemap.jpg
Normal file
BIN
interface/resources/images/Default-Sky-9-cubemap.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 394 KiB |
|
@ -521,14 +521,15 @@ ScrollingWindow {
|
|||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
onClicked: {
|
||||
var index = treeView.indexAt(mouse.x, mouse.y);
|
||||
|
||||
treeView.selection.setCurrentIndex(index, 0x0002);
|
||||
|
||||
contextMenu.currentIndex = index;
|
||||
contextMenu.popup();
|
||||
if (!HMD.active) { // Popup only displays properly on desktop
|
||||
var index = treeView.indexAt(mouse.x, mouse.y);
|
||||
treeView.selection.setCurrentIndex(index, 0x0002);
|
||||
contextMenu.currentIndex = index;
|
||||
contextMenu.popup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
HifiControls.ContentSection {
|
||||
id: uploadSection
|
||||
|
|
|
@ -24,6 +24,7 @@ Item {
|
|||
Rectangle { color: hifi.colors.baseGray; anchors.fill: parent; radius: 4 }
|
||||
|
||||
Component.onCompleted: {
|
||||
jointChooser.model = MyAvatar.jointNames;
|
||||
completed = true;
|
||||
}
|
||||
|
||||
|
@ -82,7 +83,6 @@ Item {
|
|||
HifiControls.ComboBox {
|
||||
id: jointChooser;
|
||||
anchors { bottom: parent.bottom; left: parent.left; right: parent.right }
|
||||
model: MyAvatar.jointNames
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
currentIndex: attachment ? model.indexOf(attachment.jointName) : -1
|
||||
onCurrentIndexChanged: {
|
||||
|
|
|
@ -140,7 +140,6 @@
|
|||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
#include "SpeechRecognizer.h"
|
||||
#endif
|
||||
#include "Stars.h"
|
||||
#include "ui/AddressBarDialog.h"
|
||||
#include "ui/AvatarInputs.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
|
@ -392,6 +391,11 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
|
|||
}
|
||||
|
||||
static const QString STATE_IN_HMD = "InHMD";
|
||||
static const QString STATE_CAMERA_FULL_SCREEN_MIRROR = "CameraFSM";
|
||||
static const QString STATE_CAMERA_FIRST_PERSON = "CameraFirstPerson";
|
||||
static const QString STATE_CAMERA_THIRD_PERSON = "CameraThirdPerson";
|
||||
static const QString STATE_CAMERA_ENTITY = "CameraEntity";
|
||||
static const QString STATE_CAMERA_INDEPENDENT = "CameraIndependent";
|
||||
static const QString STATE_SNAP_TURN = "SnapTurn";
|
||||
static const QString STATE_GROUNDED = "Grounded";
|
||||
static const QString STATE_NAV_FOCUSED = "NavigationFocused";
|
||||
|
@ -471,7 +475,9 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
DependencyManager::set<InterfaceActionFactory>();
|
||||
DependencyManager::set<AudioInjectorManager>();
|
||||
DependencyManager::set<MessagesClient>();
|
||||
controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_SNAP_TURN, STATE_GROUNDED, STATE_NAV_FOCUSED } });
|
||||
controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR,
|
||||
STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT,
|
||||
STATE_SNAP_TURN, STATE_GROUNDED, STATE_NAV_FOCUSED } });
|
||||
DependencyManager::set<UserInputMapper>();
|
||||
DependencyManager::set<controller::ScriptingInterface, ControllerScriptingInterface>();
|
||||
DependencyManager::set<InterfaceParentFinder>();
|
||||
|
@ -819,6 +825,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
}
|
||||
UserActivityLogger::getInstance().logAction("launch", properties);
|
||||
|
||||
_connectionMonitor.init();
|
||||
|
||||
// Tell our entity edit sender about our known jurisdictions
|
||||
_entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
|
||||
|
@ -962,6 +969,21 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
_applicationStateDevice->setInputVariant(STATE_IN_HMD, []() -> float {
|
||||
return qApp->isHMDMode() ? 1 : 0;
|
||||
});
|
||||
_applicationStateDevice->setInputVariant(STATE_CAMERA_FULL_SCREEN_MIRROR, []() -> float {
|
||||
return qApp->getCamera()->getMode() == CAMERA_MODE_MIRROR ? 1 : 0;
|
||||
});
|
||||
_applicationStateDevice->setInputVariant(STATE_CAMERA_FIRST_PERSON, []() -> float {
|
||||
return qApp->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON ? 1 : 0;
|
||||
});
|
||||
_applicationStateDevice->setInputVariant(STATE_CAMERA_THIRD_PERSON, []() -> float {
|
||||
return qApp->getCamera()->getMode() == CAMERA_MODE_THIRD_PERSON ? 1 : 0;
|
||||
});
|
||||
_applicationStateDevice->setInputVariant(STATE_CAMERA_ENTITY, []() -> float {
|
||||
return qApp->getCamera()->getMode() == CAMERA_MODE_ENTITY ? 1 : 0;
|
||||
});
|
||||
_applicationStateDevice->setInputVariant(STATE_CAMERA_INDEPENDENT, []() -> float {
|
||||
return qApp->getCamera()->getMode() == CAMERA_MODE_INDEPENDENT ? 1 : 0;
|
||||
});
|
||||
_applicationStateDevice->setInputVariant(STATE_SNAP_TURN, []() -> float {
|
||||
return qApp->getMyAvatar()->getSnapTurn() ? 1 : 0;
|
||||
});
|
||||
|
@ -1212,6 +1234,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
|
||||
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
QString skyboxUrl { PathUtils::resourcesPath() + "images/Default-Sky-9-cubemap.jpg" };
|
||||
QString skyboxAmbientUrl { PathUtils::resourcesPath() + "images/Default-Sky-9-ambient.jpg" };
|
||||
|
||||
_defaultSkyboxTexture = textureCache->getImageTexture(skyboxUrl, NetworkTexture::CUBE_TEXTURE, { { "generateIrradiance", false } });
|
||||
_defaultSkyboxAmbientTexture = textureCache->getImageTexture(skyboxAmbientUrl, NetworkTexture::CUBE_TEXTURE, { { "generateIrradiance", true } });
|
||||
|
||||
_defaultSkybox->setCubemap(_defaultSkyboxTexture);
|
||||
_defaultSkybox->setColor({ 1.0, 1.0, 1.0 });
|
||||
|
||||
// After all of the constructor is completed, then set firstRun to false.
|
||||
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
|
||||
firstRun.set(false);
|
||||
|
@ -2282,7 +2315,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
|
||||
case Qt::Key_Asterisk:
|
||||
Menu::getInstance()->triggerOption(MenuOption::Stars);
|
||||
Menu::getInstance()->triggerOption(MenuOption::DefaultSkybox);
|
||||
break;
|
||||
|
||||
case Qt::Key_S:
|
||||
|
@ -4217,8 +4250,6 @@ public:
|
|||
typedef render::Payload<BackgroundRenderData> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
Stars _stars;
|
||||
|
||||
static render::ItemID _item; // unique WorldBoxRenderData
|
||||
};
|
||||
|
||||
|
@ -4253,15 +4284,26 @@ namespace render {
|
|||
|
||||
// Fall through: if no skybox is available, render the SKY_DOME
|
||||
case model::SunSkyStage::SKY_DOME: {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
|
||||
PerformanceTimer perfTimer("stars");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::payloadRender<BackgroundRenderData>() ... My god, it's full of stars...");
|
||||
// should be the first rendering pass - w/o depth buffer / lighting
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
|
||||
static const glm::vec3 DEFAULT_SKYBOX_COLOR { 255.0f / 255.0f, 220.0f / 255.0f, 194.0f / 255.0f };
|
||||
static const float DEFAULT_SKYBOX_INTENSITY { 0.2f };
|
||||
static const float DEFAULT_SKYBOX_AMBIENT_INTENSITY { 2.0f };
|
||||
static const glm::vec3 DEFAULT_SKYBOX_DIRECTION { 0.0f, 0.0f, -1.0f };
|
||||
|
||||
static const float alpha = 1.0f;
|
||||
background->_stars.render(args, alpha);
|
||||
}
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
scene->setSunModelEnable(false);
|
||||
sceneKeyLight->setColor(DEFAULT_SKYBOX_COLOR);
|
||||
sceneKeyLight->setIntensity(DEFAULT_SKYBOX_INTENSITY);
|
||||
sceneKeyLight->setAmbientIntensity(DEFAULT_SKYBOX_AMBIENT_INTENSITY);
|
||||
sceneKeyLight->setDirection(DEFAULT_SKYBOX_DIRECTION);
|
||||
|
||||
auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
|
||||
sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
|
||||
|
||||
qApp->getDefaultSkybox()->render(batch, args->getViewFrustum());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -4455,7 +4497,6 @@ void Application::updateWindowTitle() const {
|
|||
#endif
|
||||
_window->setWindowTitle(title);
|
||||
}
|
||||
|
||||
void Application::clearDomainOctreeDetails() {
|
||||
|
||||
// if we're about to quit, we really don't need to do any of these things...
|
||||
|
@ -4481,6 +4522,7 @@ void Application::clearDomainOctreeDetails() {
|
|||
getEntities()->clear();
|
||||
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME);
|
||||
|
||||
_recentlyClearedDomain = true;
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "avatar/MyAvatar.h"
|
||||
#include "Bookmarks.h"
|
||||
#include "Camera.h"
|
||||
#include "ConnectionMonitor.h"
|
||||
#include "FileLogger.h"
|
||||
#include "gpu/Context.h"
|
||||
#include "Menu.h"
|
||||
|
@ -64,6 +65,9 @@
|
|||
#include "ui/overlays/Overlays.h"
|
||||
#include "UndoStackScriptingInterface.h"
|
||||
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
#include <model/Skybox.h>
|
||||
|
||||
class OffscreenGLCanvas;
|
||||
class GLCanvas;
|
||||
class FaceTracker;
|
||||
|
@ -248,6 +252,10 @@ public:
|
|||
float getAvatarSimrate() const { return _avatarSimCounter.rate(); }
|
||||
float getAverageSimsPerSecond() const { return _simCounter.rate(); }
|
||||
|
||||
model::SkyboxPointer getDefaultSkybox() const { return _defaultSkybox; }
|
||||
gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; }
|
||||
gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; }
|
||||
|
||||
signals:
|
||||
void svoImportRequested(const QString& url);
|
||||
|
||||
|
@ -562,6 +570,13 @@ private:
|
|||
bool _recentlyClearedDomain { false };
|
||||
|
||||
QString _returnFromFullScreenMirrorTo;
|
||||
|
||||
ConnectionMonitor _connectionMonitor;
|
||||
|
||||
model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() } ;
|
||||
gpu::TexturePointer _defaultSkyboxTexture;
|
||||
gpu::TexturePointer _defaultSkyboxAmbientTexture;
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_Application_h
|
||||
|
|
52
interface/src/ConnectionMonitor.cpp
Normal file
52
interface/src/ConnectionMonitor.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// ConnectionMonitor.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Ryan Huffman on 8/4/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ConnectionMonitor.h"
|
||||
|
||||
#include "ui/DialogsManager.h"
|
||||
|
||||
#include <NodeList.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <DomainHandler.h>
|
||||
#include <AddressManager.h>
|
||||
|
||||
static const int DISPLAY_AFTER_DISCONNECTED_FOR_X_MS = 5000;
|
||||
|
||||
void ConnectionMonitor::init() {
|
||||
// Connect to domain disconnected message
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &ConnectionMonitor::disconnectedFromDomain);
|
||||
connect(&domainHandler, &DomainHandler::connectedToDomain, this, &ConnectionMonitor::connectedToDomain);
|
||||
|
||||
// Connect to AddressManager::hostChanged
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
connect(addressManager.data(), &AddressManager::hostChanged, this, &ConnectionMonitor::hostChanged);
|
||||
|
||||
_timer.setSingleShot(true);
|
||||
_timer.setInterval(DISPLAY_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
_timer.start();
|
||||
|
||||
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||
connect(&_timer, &QTimer::timeout, dialogsManager.data(), &DialogsManager::showAddressBar);
|
||||
}
|
||||
|
||||
void ConnectionMonitor::disconnectedFromDomain() {
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
void ConnectionMonitor::connectedToDomain(const QString& name) {
|
||||
_timer.stop();
|
||||
}
|
||||
|
||||
void ConnectionMonitor::hostChanged(const QString& name) {
|
||||
_timer.start();
|
||||
}
|
34
interface/src/ConnectionMonitor.h
Normal file
34
interface/src/ConnectionMonitor.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// ConnectionMonitor.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Ryan Huffman on 8/4/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_ConnectionMonitor_h
|
||||
#define hifi_ConnectionMonitor_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
class QString;
|
||||
|
||||
class ConnectionMonitor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
void init();
|
||||
|
||||
private slots:
|
||||
void disconnectedFromDomain();
|
||||
void connectedToDomain(const QString& name);
|
||||
void hostChanged(const QString& name);
|
||||
|
||||
private:
|
||||
QTimer _timer;
|
||||
};
|
||||
|
||||
#endif // hifi_ConnectionMonitor_h
|
|
@ -337,7 +337,7 @@ Menu::Menu() {
|
|||
// Developer > Render >>>
|
||||
MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render");
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DefaultSkybox, 0, true);
|
||||
|
||||
// Developer > Render > Throttle FPS If Not Focus
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ThrottleFPSIfNotFocus, 0, true);
|
||||
|
|
|
@ -80,6 +80,7 @@ namespace MenuOption {
|
|||
const QString CrashNewFaultThreaded = "New Fault (threaded)";
|
||||
const QString DeadlockInterface = "Deadlock Interface";
|
||||
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
||||
const QString DefaultSkybox = "Default Skybox";
|
||||
const QString DeleteBookmark = "Delete Bookmark...";
|
||||
const QString DisableActivityLogger = "Disable Activity Logger";
|
||||
const QString DisableEyelidAdjustment = "Disable Eyelid Adjustment";
|
||||
|
@ -175,7 +176,6 @@ namespace MenuOption {
|
|||
const QString StandingHMDSensorMode = "Standing HMD Sensor Mode";
|
||||
const QString SimulateEyeTracking = "Simulate";
|
||||
const QString SMIEyeTracking = "SMI Eye Tracking";
|
||||
const QString Stars = "Stars";
|
||||
const QString Stats = "Stats";
|
||||
const QString StopAllScripts = "Stop All Scripts";
|
||||
const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
|
||||
|
|
|
@ -1,216 +0,0 @@
|
|||
//
|
||||
// Stars.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Tobias Schwinger on 3/22/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Stars.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <NumericalConstants.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <TextureCache.h>
|
||||
#include <RenderArgs.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include <render-utils/stars_vert.h>
|
||||
#include <render-utils/stars_frag.h>
|
||||
|
||||
#include <render-utils/standardTransformPNTC_vert.h>
|
||||
#include <render-utils/starsGrid_frag.h>
|
||||
|
||||
//static const float TILT = 0.23f;
|
||||
static const float TILT = 0.0f;
|
||||
static const unsigned int STARFIELD_NUM_STARS = 50000;
|
||||
static const unsigned int STARFIELD_SEED = 1;
|
||||
static const float STAR_COLORIZATION = 0.1f;
|
||||
|
||||
static const float TAU = 6.28318530717958f;
|
||||
//static const float HALF_TAU = TAU / 2.0f;
|
||||
//static const float QUARTER_TAU = TAU / 4.0f;
|
||||
//static const float MILKY_WAY_WIDTH = TAU / 30.0f; // width in radians of one half of the Milky Way
|
||||
//static const float MILKY_WAY_INCLINATION = 0.0f; // angle of Milky Way from horizontal in degrees
|
||||
//static const float MILKY_WAY_RATIO = 0.4f;
|
||||
static const char* UNIFORM_TIME_NAME = "iGlobalTime";
|
||||
|
||||
// Produce a random float value between 0 and 1
|
||||
static float frand() {
|
||||
return (float)rand() / (float)RAND_MAX;
|
||||
}
|
||||
|
||||
// http://mathworld.wolfram.com/SpherePointPicking.html
|
||||
static vec2 randPolar() {
|
||||
vec2 result(frand(), frand());
|
||||
result.x *= TAU;
|
||||
result.y = powf(result.y, 2.0) / 2.0f;
|
||||
if (frand() > 0.5f) {
|
||||
result.y = 0.5f - result.y;
|
||||
} else {
|
||||
result.y += 0.5f;
|
||||
}
|
||||
result.y = acos((2.0f * result.y) - 1.0f);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static vec3 fromPolar(const vec2& polar) {
|
||||
float sinTheta = sin(polar.x);
|
||||
float cosTheta = cos(polar.x);
|
||||
float sinPhi = sin(polar.y);
|
||||
float cosPhi = cos(polar.y);
|
||||
return vec3(
|
||||
cosTheta * sinPhi,
|
||||
cosPhi,
|
||||
sinTheta * sinPhi);
|
||||
}
|
||||
|
||||
|
||||
// computeStarColor
|
||||
// - Generate a star color.
|
||||
//
|
||||
// colorization can be a value between 0 and 1 specifying how colorful the resulting star color is.
|
||||
//
|
||||
// 0 = completely black & white
|
||||
// 1 = very colorful
|
||||
unsigned computeStarColor(float colorization) {
|
||||
unsigned char red, green, blue;
|
||||
if (randFloat() < 0.3f) {
|
||||
// A few stars are colorful
|
||||
red = 2 + (rand() % 254);
|
||||
green = 2 + round((red * (1 - colorization)) + ((rand() % 254) * colorization));
|
||||
blue = 2 + round((red * (1 - colorization)) + ((rand() % 254) * colorization));
|
||||
} else {
|
||||
// Most stars are dimmer and white
|
||||
red = green = blue = 2 + (rand() % 128);
|
||||
}
|
||||
return red | (green << 8) | (blue << 16);
|
||||
}
|
||||
|
||||
struct StarVertex {
|
||||
vec4 position;
|
||||
vec4 colorAndSize;
|
||||
};
|
||||
|
||||
static const int STARS_VERTICES_SLOT{ 0 };
|
||||
static const int STARS_COLOR_SLOT{ 1 };
|
||||
|
||||
gpu::PipelinePointer Stars::_gridPipeline{};
|
||||
gpu::PipelinePointer Stars::_starsPipeline{};
|
||||
int32_t Stars::_timeSlot{ -1 };
|
||||
|
||||
void Stars::init() {
|
||||
if (!_gridPipeline) {
|
||||
auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert));
|
||||
auto ps = gpu::Shader::createPixel(std::string(starsGrid_frag));
|
||||
auto program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram((*program));
|
||||
_timeSlot = program->getBuffers().findLocation(UNIFORM_TIME_NAME);
|
||||
if (_timeSlot == gpu::Shader::INVALID_LOCATION) {
|
||||
_timeSlot = program->getUniforms().findLocation(UNIFORM_TIME_NAME);
|
||||
}
|
||||
auto state = gpu::StatePointer(new gpu::State());
|
||||
// enable decal blend
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_gridPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
if (!_starsPipeline) {
|
||||
auto vs = gpu::Shader::createVertex(std::string(stars_vert));
|
||||
auto ps = gpu::Shader::createPixel(std::string(stars_frag));
|
||||
auto program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram((*program));
|
||||
auto state = gpu::StatePointer(new gpu::State());
|
||||
// enable decal blend
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
state->setAntialiasedLineEnable(true); // line smoothing also smooth points
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_starsPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
unsigned limit = STARFIELD_NUM_STARS;
|
||||
std::vector<StarVertex> points;
|
||||
points.resize(limit);
|
||||
|
||||
{ // generate stars
|
||||
QElapsedTimer startTime;
|
||||
startTime.start();
|
||||
|
||||
vertexBuffer.reset(new gpu::Buffer);
|
||||
|
||||
srand(STARFIELD_SEED);
|
||||
for (size_t star = 0; star < limit; ++star) {
|
||||
points[star].position = vec4(fromPolar(randPolar()), 1);
|
||||
float size = frand() * 2.5f + 0.5f;
|
||||
if (frand() < STAR_COLORIZATION) {
|
||||
vec3 color(frand() / 2.0f + 0.5f, frand() / 2.0f + 0.5f, frand() / 2.0f + 0.5f);
|
||||
points[star].colorAndSize = vec4(color, size);
|
||||
} else {
|
||||
vec3 color(frand() / 2.0f + 0.5f);
|
||||
points[star].colorAndSize = vec4(color, size);
|
||||
}
|
||||
}
|
||||
|
||||
double timeDiff = (double)startTime.nsecsElapsed() / 1000000.0; // ns to ms
|
||||
qDebug() << "Total time to generate stars: " << timeDiff << " msec";
|
||||
}
|
||||
|
||||
gpu::Element positionElement, colorElement;
|
||||
const size_t VERTEX_STRIDE = sizeof(StarVertex);
|
||||
|
||||
vertexBuffer->append(VERTEX_STRIDE * limit, (const gpu::Byte*)&points[0]);
|
||||
streamFormat.reset(new gpu::Stream::Format()); // 1 for everyone
|
||||
streamFormat->setAttribute(gpu::Stream::POSITION, STARS_VERTICES_SLOT, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW), 0);
|
||||
streamFormat->setAttribute(gpu::Stream::COLOR, STARS_COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::RGBA));
|
||||
positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element;
|
||||
colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element;
|
||||
|
||||
size_t offset = offsetof(StarVertex, position);
|
||||
positionView = gpu::BufferView(vertexBuffer, offset, vertexBuffer->getSize(), VERTEX_STRIDE, positionElement);
|
||||
|
||||
offset = offsetof(StarVertex, colorAndSize);
|
||||
colorView = gpu::BufferView(vertexBuffer, offset, vertexBuffer->getSize(), VERTEX_STRIDE, colorElement);
|
||||
}
|
||||
|
||||
// FIXME star colors
|
||||
void Stars::render(RenderArgs* renderArgs, float alpha) {
|
||||
std::call_once(once, [&]{ init(); });
|
||||
|
||||
|
||||
auto modelCache = DependencyManager::get<ModelCache>();
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
|
||||
gpu::Batch& batch = *renderArgs->_batch;
|
||||
batch.setViewTransform(Transform());
|
||||
batch.setProjectionTransform(renderArgs->getViewFrustum().getProjection());
|
||||
batch.setModelTransform(Transform().setRotation(glm::inverse(renderArgs->getViewFrustum().getOrientation()) *
|
||||
quat(vec3(TILT, 0, 0))));
|
||||
batch.setResourceTexture(0, textureCache->getWhiteTexture());
|
||||
|
||||
// Render the world lines
|
||||
batch.setPipeline(_gridPipeline);
|
||||
static auto start = usecTimestampNow();
|
||||
float msecs = (float)(usecTimestampNow() - start) / (float)USECS_PER_MSEC;
|
||||
float secs = msecs / (float)MSECS_PER_SECOND;
|
||||
batch._glUniform1f(_timeSlot, secs);
|
||||
geometryCache->renderCube(batch);
|
||||
|
||||
// Render the stars
|
||||
batch.setPipeline(_starsPipeline);
|
||||
batch.setInputFormat(streamFormat);
|
||||
batch.setInputBuffer(STARS_VERTICES_SLOT, positionView);
|
||||
batch.setInputBuffer(STARS_COLOR_SLOT, colorView);
|
||||
batch.draw(gpu::Primitive::POINTS, STARFIELD_NUM_STARS);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
//
|
||||
// Stars.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Tobias Schwinger on 3/22/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_Stars_h
|
||||
#define hifi_Stars_h
|
||||
|
||||
#include <gpu/Context.h>
|
||||
|
||||
class RenderArgs;
|
||||
|
||||
// Starfield rendering component.
|
||||
class Stars {
|
||||
public:
|
||||
Stars() = default;
|
||||
~Stars() = default;
|
||||
|
||||
Stars(Stars const&) = delete;
|
||||
Stars& operator=(Stars const&) = delete;
|
||||
|
||||
// Renders the starfield from a local viewer's perspective.
|
||||
// The parameters specifiy the field of view.
|
||||
void render(RenderArgs* args, float alpha);
|
||||
|
||||
private:
|
||||
// Pipelines
|
||||
static gpu::PipelinePointer _gridPipeline;
|
||||
static gpu::PipelinePointer _starsPipeline;
|
||||
static int32_t _timeSlot;
|
||||
|
||||
// Buffers
|
||||
gpu::BufferPointer vertexBuffer;
|
||||
gpu::Stream::FormatPointer streamFormat;
|
||||
gpu::BufferView positionView;
|
||||
gpu::BufferView colorView;
|
||||
std::once_flag once;
|
||||
|
||||
void init();
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_Stars_h
|
|
@ -780,7 +780,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const
|
|||
|
||||
{
|
||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderBevelCornersRect");
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, true, true, true);
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, true, true, true);
|
||||
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
|
||||
bevelDistance, backgroundColor);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include "Util.h"
|
||||
#include "ui/Stats.h"
|
||||
#include "ui/AvatarInputs.h"
|
||||
#include "OffscreenUi.h"
|
||||
#include <QQmlContext>
|
||||
|
||||
const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f };
|
||||
static const float ORTHO_NEAR_CLIP = -1000.0f;
|
||||
|
@ -177,13 +179,11 @@ void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
|
|||
glm::vec2 texCoordMinCorner(0.0f, 0.0f);
|
||||
glm::vec2 texCoordMaxCorner(viewport.width() * renderRatio / float(selfieTexture->getWidth()), viewport.height() * renderRatio / float(selfieTexture->getHeight()));
|
||||
|
||||
|
||||
geometryCache->useSimpleDrawPipeline(batch, true);
|
||||
batch.setResourceTexture(0, selfieTexture);
|
||||
geometryCache->renderQuad(batch, bottomLeft, topRight, texCoordMinCorner, texCoordMaxCorner, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
float alpha = DependencyManager::get<OffscreenUi>()->getDesktop()->property("unpinnedAlpha").toFloat();
|
||||
geometryCache->renderQuad(batch, bottomLeft, topRight, texCoordMinCorner, texCoordMaxCorner, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
|
||||
batch.setResourceTexture(0, renderArgs->_whiteTexture);
|
||||
geometryCache->useSimpleDrawPipeline(batch, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,10 @@ void DialogsManager::toggleAddressBar() {
|
|||
emit addressBarToggled();
|
||||
}
|
||||
|
||||
void DialogsManager::showAddressBar() {
|
||||
AddressBarDialog::show();
|
||||
}
|
||||
|
||||
void DialogsManager::toggleDiskCacheEditor() {
|
||||
maybeCreateDialog(_diskCacheEditor);
|
||||
_diskCacheEditor->toggle();
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
|
||||
public slots:
|
||||
void toggleAddressBar();
|
||||
void showAddressBar();
|
||||
void toggleDiskCacheEditor();
|
||||
void toggleLoginDialog();
|
||||
void showLoginDialog();
|
||||
|
|
|
@ -47,7 +47,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
auto pipeline = args->_pipeline;
|
||||
if (!pipeline) {
|
||||
pipeline = _isSolid ? geometryCache->getShapePipeline() : geometryCache->getWireShapePipeline();
|
||||
pipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
|
||||
}
|
||||
|
||||
if (_isSolid) {
|
||||
|
@ -55,7 +55,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
batch->setModelTransform(transform);
|
||||
geometryCache->renderSolidCubeInstance(*batch, cubeColor, pipeline);
|
||||
} else {
|
||||
geometryCache->bindSimpleProgram(*batch, false, false, true, true);
|
||||
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
|
||||
if (getIsDashedLine()) {
|
||||
transform.setScale(1.0f);
|
||||
batch->setModelTransform(transform);
|
||||
|
|
|
@ -57,12 +57,12 @@ void Line3DOverlay::render(RenderArgs* args) {
|
|||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (getIsDashedLine()) {
|
||||
// TODO: add support for color to renderDashedLine()
|
||||
geometryCache->bindSimpleProgram(*batch, false, false, true, true);
|
||||
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
|
||||
geometryCache->renderDashedLine(*batch, _start, _end, colorv4, _geometryCacheID);
|
||||
} else if (_glow > 0.0f) {
|
||||
geometryCache->renderGlowLine(*batch, _start, _end, colorv4, _glow, _glowWidth, _geometryCacheID);
|
||||
} else {
|
||||
geometryCache->bindSimpleProgram(*batch, false, false, true, true);
|
||||
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
|
||||
geometryCache->renderLine(*batch, _start, _end, colorv4, _geometryCacheID);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ public slots:
|
|||
/// successful edit, if the input id is for an unknown overlay this function will have no effect
|
||||
bool editOverlays(const QVariant& propertiesById);
|
||||
|
||||
/// deletes a particle
|
||||
/// deletes an overlay
|
||||
void deleteOverlay(unsigned int id);
|
||||
|
||||
/// get the string type of the overlay used in addOverlay
|
||||
|
|
|
@ -61,7 +61,7 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
|
|||
geometryCache->bindSimpleProgram(*batch);
|
||||
geometryCache->renderQuad(*batch, topLeft, bottomRight, rectangleColor);
|
||||
} else {
|
||||
geometryCache->bindSimpleProgram(*batch, false, false, true, true);
|
||||
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
|
||||
if (getIsDashedLine()) {
|
||||
glm::vec3 point1(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 point2(halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
|
|
|
@ -47,7 +47,7 @@ void Shape3DOverlay::render(RenderArgs* args) {
|
|||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
auto pipeline = args->_pipeline;
|
||||
if (!pipeline) {
|
||||
pipeline = _isSolid ? geometryCache->getShapePipeline() : geometryCache->getWireShapePipeline();
|
||||
pipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
|
||||
}
|
||||
|
||||
transform.setScale(dimensions);
|
||||
|
|
|
@ -46,7 +46,7 @@ void Sphere3DOverlay::render(RenderArgs* args) {
|
|||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
auto pipeline = args->_pipeline;
|
||||
if (!pipeline) {
|
||||
pipeline = _isSolid ? geometryCache->getShapePipeline() : geometryCache->getWireShapePipeline();
|
||||
pipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
|
||||
}
|
||||
|
||||
if (_isSolid) {
|
||||
|
|
|
@ -1638,7 +1638,9 @@ void AvatarData::setAttachmentsVariant(const QVariantList& variant) {
|
|||
for (const auto& attachmentVar : variant) {
|
||||
AttachmentData attachment;
|
||||
attachment.fromVariant(attachmentVar);
|
||||
newAttachments.append(attachment);
|
||||
if (!attachment.modelURL.isEmpty()) {
|
||||
newAttachments.append(attachment);
|
||||
}
|
||||
}
|
||||
setAttachmentData(newAttachments);
|
||||
}
|
||||
|
|
|
@ -375,7 +375,6 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
}
|
||||
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application background through
|
||||
|
||||
return; // Early exit
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace render {
|
|||
if (payload->entity->getType() == EntityTypes::Light) {
|
||||
return ItemKey::Builder::light();
|
||||
}
|
||||
if (payload && payload->entity->getType() == EntityTypes::PolyLine) {
|
||||
if (payload && payload->entity->isTransparent()) {
|
||||
return ItemKey::Builder::transparentShape();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,8 +96,17 @@ public: \
|
|||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override { _renderHelper.removeFromScene(self, scene, pendingChanges); } \
|
||||
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); _renderHelper.notifyChanged(); } \
|
||||
virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); _renderHelper.notifyChanged(); } \
|
||||
void checkFading() { \
|
||||
bool transparent = isTransparent(); \
|
||||
if (transparent != _prevIsTransparent) { \
|
||||
_renderHelper.notifyChanged(); \
|
||||
_isFading = false; \
|
||||
_prevIsTransparent = transparent; \
|
||||
} \
|
||||
} \
|
||||
private: \
|
||||
SimpleRenderableEntityItem _renderHelper;
|
||||
SimpleRenderableEntityItem _renderHelper; \
|
||||
bool _prevIsTransparent { isTransparent() };
|
||||
|
||||
|
||||
#endif // hifi_RenderableEntityItem_h
|
||||
|
|
|
@ -28,6 +28,8 @@ EntityItemPointer RenderableLightEntityItem::factory(const EntityItemID& entityI
|
|||
void RenderableLightEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableLightEntityItem::render");
|
||||
assert(getType() == EntityTypes::Light);
|
||||
checkFading();
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
|
@ -35,7 +37,7 @@ void RenderableLightEntityItem::render(RenderArgs* args) {
|
|||
|
||||
glm::vec3 color = toGlm(getXColor());
|
||||
|
||||
float intensity = getIntensity();
|
||||
float intensity = getIntensity() * (_isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f);
|
||||
float falloffRadius = getFalloffRadius();
|
||||
float exponent = getExponent();
|
||||
float cutoff = glm::radians(getCutoff());
|
||||
|
|
|
@ -176,25 +176,6 @@ void RenderableModelEntityItem::doInitialModelSimulation() {
|
|||
_needsInitialSimulation = false;
|
||||
}
|
||||
|
||||
|
||||
// TODO: we need a solution for changes to the postion/rotation/etc of a model...
|
||||
// this current code path only addresses that in this setup case... not the changing/moving case
|
||||
bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) {
|
||||
if (!_model && renderArgs) {
|
||||
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
||||
PerformanceTimer perfTimer("getModel");
|
||||
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(renderArgs->_renderer);
|
||||
getModel(renderer);
|
||||
}
|
||||
if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoaded()) {
|
||||
// make sure to simulate so everything gets set up correctly for rendering
|
||||
doInitialModelSimulation();
|
||||
_model->renderSetup(renderArgs);
|
||||
}
|
||||
bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(renderArgs);
|
||||
return ready;
|
||||
}
|
||||
|
||||
class RenderableModelEntityItemMeta {
|
||||
public:
|
||||
RenderableModelEntityItemMeta(EntityItemPointer entity) : entity(entity){ }
|
||||
|
@ -371,6 +352,12 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
PerformanceTimer perfTimer("RMEIrender");
|
||||
assert(getType() == EntityTypes::Model);
|
||||
|
||||
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
|
||||
// we will watch for that and ask the model to update it's render items
|
||||
if (_model && _model->getRenderItemsNeedUpdate()) {
|
||||
_model->updateRenderItems();
|
||||
}
|
||||
|
||||
if (hasModel()) {
|
||||
// Prepare the current frame
|
||||
{
|
||||
|
|
|
@ -40,7 +40,6 @@ public:
|
|||
|
||||
void doInitialModelSimulation();
|
||||
|
||||
virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr);
|
||||
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;
|
||||
|
||||
|
@ -92,6 +91,9 @@ public:
|
|||
|
||||
render::ItemID getMetaRenderItem() { return _myMetaItem; }
|
||||
|
||||
// Transparency is handled in ModelMeshPartPayload
|
||||
bool isTransparent() override { return false; }
|
||||
|
||||
private:
|
||||
QVariantMap parseTexturesToMap(QString textures);
|
||||
void remapTextures();
|
||||
|
|
|
@ -167,6 +167,8 @@ void RenderablePolyLineEntityItem::update(const quint64& now) {
|
|||
}
|
||||
|
||||
void RenderablePolyLineEntityItem::render(RenderArgs* args) {
|
||||
checkFading();
|
||||
|
||||
QWriteLocker lock(&_quadReadWriteLock);
|
||||
if (_points.size() < 2 || _normals.size () < 2 || _strokeWidths.size() < 2) {
|
||||
return;
|
||||
|
@ -204,5 +206,9 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) {
|
|||
batch.setInputFormat(_format);
|
||||
batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride);
|
||||
|
||||
if (_isFading) {
|
||||
batch._glColor4f(1.0f, 1.0f, 1.0f, Interpolate::calculateFadeRatio(_fadeStartTime));
|
||||
}
|
||||
|
||||
batch.draw(gpu::TRIANGLE_STRIP, _numVertices, 0);
|
||||
};
|
||||
|
|
|
@ -30,7 +30,9 @@ public:
|
|||
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual void update(const quint64& now) override;
|
||||
virtual bool needsToCallUpdate() const override { return true; };
|
||||
virtual bool needsToCallUpdate() const override { return true; }
|
||||
|
||||
bool isTransparent() override { return true; }
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
|
@ -47,7 +49,6 @@ protected:
|
|||
gpu::BufferView _uniformBuffer;
|
||||
unsigned int _numVertices;
|
||||
QVector<glm::vec3> _vertices;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
|
||||
void initializePolyVox();
|
||||
|
||||
virtual void somethingChangedNotification() {
|
||||
virtual void somethingChangedNotification() override {
|
||||
// This gets called from EnityItem::readEntityDataFromBuffer every time a packet describing
|
||||
// this entity comes from the entity-server. It gets called even if nothing has actually changed
|
||||
// (see the comment in EntityItem.cpp). If that gets fixed, this could be used to know if we
|
||||
|
@ -58,19 +58,19 @@ public:
|
|||
// _needsModelReload = true;
|
||||
}
|
||||
|
||||
virtual uint8_t getVoxel(int x, int y, int z);
|
||||
virtual bool setVoxel(int x, int y, int z, uint8_t toValue);
|
||||
virtual uint8_t getVoxel(int x, int y, int z) override;
|
||||
virtual bool setVoxel(int x, int y, int z, uint8_t toValue) override;
|
||||
|
||||
void render(RenderArgs* args);
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
void render(RenderArgs* args) override;
|
||||
virtual bool supportsDetailedRayIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
void** intersectedObject, bool precisionPicking) const override;
|
||||
|
||||
virtual void setVoxelData(QByteArray voxelData);
|
||||
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
|
||||
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle);
|
||||
virtual void setVoxelData(QByteArray voxelData) override;
|
||||
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize) override;
|
||||
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) override;
|
||||
|
||||
glm::vec3 getSurfacePositionAdjustment() const;
|
||||
glm::mat4 voxelToWorldMatrix() const;
|
||||
|
@ -78,45 +78,45 @@ public:
|
|||
glm::mat4 voxelToLocalMatrix() const;
|
||||
glm::mat4 localToVoxelMatrix() const;
|
||||
|
||||
virtual ShapeType getShapeType() const;
|
||||
virtual bool shouldBePhysical() const { return !isDead(); }
|
||||
virtual bool isReadyToComputeShape();
|
||||
virtual void computeShapeInfo(ShapeInfo& info);
|
||||
virtual ShapeType getShapeType() const override;
|
||||
virtual bool shouldBePhysical() const override { return !isDead(); }
|
||||
virtual bool isReadyToComputeShape() override;
|
||||
virtual void computeShapeInfo(ShapeInfo& info) override;
|
||||
|
||||
virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3& voxelCoords) const;
|
||||
virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3& worldCoords) const;
|
||||
virtual glm::vec3 voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const;
|
||||
virtual glm::vec3 localCoordsToVoxelCoords(glm::vec3& localCoords) const;
|
||||
virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3& voxelCoords) const override;
|
||||
virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3& worldCoords) const override;
|
||||
virtual glm::vec3 voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const override;
|
||||
virtual glm::vec3 localCoordsToVoxelCoords(glm::vec3& localCoords) const override;
|
||||
|
||||
// coords are in voxel-volume space
|
||||
virtual bool setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue);
|
||||
virtual bool setVoxelInVolume(glm::vec3 position, uint8_t toValue);
|
||||
virtual bool setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) override;
|
||||
virtual bool setVoxelInVolume(glm::vec3 position, uint8_t toValue) override;
|
||||
|
||||
// coords are in world-space
|
||||
virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue);
|
||||
virtual bool setAll(uint8_t toValue);
|
||||
virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue);
|
||||
virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) override;
|
||||
virtual bool setAll(uint8_t toValue) override;
|
||||
virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue) override;
|
||||
|
||||
virtual void setXTextureURL(QString xTextureURL);
|
||||
virtual void setYTextureURL(QString yTextureURL);
|
||||
virtual void setZTextureURL(QString zTextureURL);
|
||||
virtual void setXTextureURL(QString xTextureURL) override;
|
||||
virtual void setYTextureURL(QString yTextureURL) override;
|
||||
virtual void setZTextureURL(QString zTextureURL) override;
|
||||
|
||||
virtual bool addToScene(EntityItemPointer self,
|
||||
std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges);
|
||||
render::PendingChanges& pendingChanges) override;
|
||||
virtual void removeFromScene(EntityItemPointer self,
|
||||
std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges);
|
||||
render::PendingChanges& pendingChanges) override;
|
||||
|
||||
virtual void setXNNeighborID(const EntityItemID& xNNeighborID);
|
||||
virtual void setYNNeighborID(const EntityItemID& yNNeighborID);
|
||||
virtual void setZNNeighborID(const EntityItemID& zNNeighborID);
|
||||
virtual void setXNNeighborID(const EntityItemID& xNNeighborID) override;
|
||||
virtual void setYNNeighborID(const EntityItemID& yNNeighborID) override;
|
||||
virtual void setZNNeighborID(const EntityItemID& zNNeighborID) override;
|
||||
|
||||
virtual void setXPNeighborID(const EntityItemID& xPNeighborID);
|
||||
virtual void setYPNeighborID(const EntityItemID& yPNeighborID);
|
||||
virtual void setZPNeighborID(const EntityItemID& zPNeighborID);
|
||||
virtual void setXPNeighborID(const EntityItemID& xPNeighborID) override;
|
||||
virtual void setYPNeighborID(const EntityItemID& yPNeighborID) override;
|
||||
virtual void setZPNeighborID(const EntityItemID& zPNeighborID) override;
|
||||
|
||||
virtual void updateRegistrationPoint(const glm::vec3& value);
|
||||
virtual void updateRegistrationPoint(const glm::vec3& value) override;
|
||||
|
||||
void setVoxelsFromData(QByteArray uncompressedData, quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize);
|
||||
void forEachVoxelValue(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize,
|
||||
|
@ -131,6 +131,9 @@ public:
|
|||
|
||||
void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; }); }
|
||||
|
||||
// Transparent polyvox didn't seem to be working so disable for now
|
||||
bool isTransparent() override { return false; }
|
||||
|
||||
private:
|
||||
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
|
||||
// may not match _voxelVolumeSize.
|
||||
|
@ -161,7 +164,7 @@ private:
|
|||
// these are run off the main thread
|
||||
void decompressVolumeData();
|
||||
void compressVolumeDataAndSendEditPacket();
|
||||
virtual void getMesh(); // recompute mesh
|
||||
virtual void getMesh() override; // recompute mesh
|
||||
void computeShapeInfoWorker();
|
||||
|
||||
// these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID
|
||||
|
|
|
@ -40,7 +40,6 @@ static std::array<GeometryCache::Shape, entity::NUM_SHAPES> MAPPING { {
|
|||
GeometryCache::Cylinder,
|
||||
} };
|
||||
|
||||
|
||||
RenderableShapeEntityItem::Pointer RenderableShapeEntityItem::baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
Pointer entity = std::make_shared<RenderableShapeEntityItem>(entityID);
|
||||
entity->setProperties(properties);
|
||||
|
@ -72,20 +71,26 @@ void RenderableShapeEntityItem::setUserData(const QString& value) {
|
|||
}
|
||||
}
|
||||
|
||||
bool RenderableShapeEntityItem::isTransparent() {
|
||||
if (_procedural && _procedural->isFading()) {
|
||||
float isFading = Interpolate::calculateFadeRatio(_procedural->getFadeStartTime()) < 1.0f;
|
||||
_procedural->setIsFading(isFading);
|
||||
return isFading;
|
||||
} else {
|
||||
return getLocalRenderAlpha() < 1.0f || EntityItem::isTransparent();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableShapeEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
|
||||
//Q_ASSERT(getType() == EntityTypes::Shape);
|
||||
Q_ASSERT(args->_batch);
|
||||
checkFading();
|
||||
|
||||
if (!_procedural) {
|
||||
_procedural.reset(new Procedural(getUserData()));
|
||||
_procedural->_vertexSource = simple_vert;
|
||||
_procedural->_fragmentSource = simple_frag;
|
||||
_procedural->_state->setCullMode(gpu::State::CULL_NONE);
|
||||
_procedural->_state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
_procedural->_state->setBlendFunction(false,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
}
|
||||
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
@ -102,14 +107,17 @@ void RenderableShapeEntityItem::render(RenderArgs* args) {
|
|||
if (_procedural->ready()) {
|
||||
_procedural->prepare(batch, getPosition(), getDimensions(), getOrientation());
|
||||
auto outColor = _procedural->getColor(color);
|
||||
outColor.a *= _procedural->isFading() ? Interpolate::calculateFadeRatio(_procedural->getFadeStartTime()) : 1.0f;
|
||||
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
|
||||
DependencyManager::get<GeometryCache>()->renderShape(batch, MAPPING[_shape]);
|
||||
} else {
|
||||
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
||||
DependencyManager::get<GeometryCache>()->renderSolidShapeInstance(batch, MAPPING[_shape], color);
|
||||
color.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
auto pipeline = color.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
|
||||
geometryCache->renderSolidShapeInstance(batch, MAPPING[_shape], color, pipeline);
|
||||
}
|
||||
|
||||
|
||||
static const auto triCount = DependencyManager::get<GeometryCache>()->getShapeTriangleCount(MAPPING[_shape]);
|
||||
args->_details._trianglesRendered += (int)triCount;
|
||||
}
|
||||
|
|
|
@ -26,10 +26,12 @@ public:
|
|||
void render(RenderArgs* args) override;
|
||||
void setUserData(const QString& value) override;
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
bool isTransparent() override;
|
||||
|
||||
private:
|
||||
QSharedPointer<Procedural> _procedural;
|
||||
std::unique_ptr<Procedural> _procedural { nullptr };
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
#include <PerfStat.h>
|
||||
#include <Transform.h>
|
||||
|
||||
|
||||
|
||||
#include "RenderableTextEntityItem.h"
|
||||
#include "GLMHelpers.h"
|
||||
|
||||
|
@ -29,10 +27,13 @@ EntityItemPointer RenderableTextEntityItem::factory(const EntityItemID& entityID
|
|||
void RenderableTextEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableTextEntityItem::render");
|
||||
Q_ASSERT(getType() == EntityTypes::Text);
|
||||
checkFading();
|
||||
|
||||
static const float SLIGHTLY_BEHIND = -0.005f;
|
||||
glm::vec4 textColor = glm::vec4(toGlm(getTextColorX()), 1.0f);
|
||||
glm::vec4 backgroundColor = glm::vec4(toGlm(getBackgroundColorX()), 1.0f);
|
||||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
bool transparent = fadeRatio < 1.0f;
|
||||
glm::vec4 textColor = glm::vec4(toGlm(getTextColorX()), fadeRatio);
|
||||
glm::vec4 backgroundColor = glm::vec4(toGlm(getBackgroundColorX()), fadeRatio);
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
|
||||
// Render background
|
||||
|
@ -62,7 +63,7 @@ void RenderableTextEntityItem::render(RenderArgs* args) {
|
|||
|
||||
batch.setModelTransform(transformToTopLeft);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, true);
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, transparent, false, false, true);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, minCorner, maxCorner, backgroundColor);
|
||||
|
||||
float scale = _lineHeight / _textRenderer->getFontSize();
|
||||
|
|
|
@ -164,6 +164,8 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) {
|
|||
}
|
||||
|
||||
void RenderableWebEntityItem::render(RenderArgs* args) {
|
||||
checkFading();
|
||||
|
||||
#ifdef WANT_EXTRA_DEBUGGING
|
||||
{
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
@ -181,6 +183,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
|||
if (!buildWebSurface(static_cast<EntityTreeRenderer*>(args->_renderer))) {
|
||||
return;
|
||||
}
|
||||
_fadeStartTime = usecTimestampNow();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -207,8 +210,11 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
|||
batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _texture);
|
||||
}
|
||||
|
||||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
batch._glColor4f(1.0f, 1.0f, 1.0f, fadeRatio);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(batch);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio));
|
||||
}
|
||||
|
||||
void RenderableWebEntityItem::setSourceUrl(const QString& value) {
|
||||
|
|
|
@ -39,7 +39,7 @@ void main(void) {
|
|||
vec3 color = varColor.rgb;
|
||||
packDeferredFragmentTranslucent(
|
||||
interpolatedNormal * frontCondition,
|
||||
texel.a,
|
||||
texel.a * varColor.a,
|
||||
polyline.color * texel.rgb,
|
||||
vec3(0.01, 0.01, 0.01),
|
||||
10.0);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// model.frag
|
||||
// polyvox.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Seth Alves on 2015-8-3
|
||||
|
@ -41,5 +41,13 @@ void main(void) {
|
|||
vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x);
|
||||
vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0);
|
||||
|
||||
packDeferredFragment(_normal, 1.0, vec3(diffuse), DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_EMISSIVE, DEFAULT_OCCLUSION, DEFAULT_SCATTERING);
|
||||
packDeferredFragment(
|
||||
_normal,
|
||||
1.0,
|
||||
vec3(diffuse),
|
||||
DEFAULT_ROUGHNESS,
|
||||
DEFAULT_METALLIC,
|
||||
DEFAULT_EMISSIVE,
|
||||
DEFAULT_OCCLUSION,
|
||||
DEFAULT_SCATTERING);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ out vec4 varColor;
|
|||
out vec2 varTexcoord;
|
||||
|
||||
const int NUM_VERTICES_PER_PARTICLE = 4;
|
||||
// This ordering ensures that un-rotated particles render upright in the wiewer.
|
||||
// This ordering ensures that un-rotated particles render upright in the viewer.
|
||||
const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE](
|
||||
vec4(-1.0, 1.0, 0.0, 0.0),
|
||||
vec4(-1.0, -1.0, 0.0, 0.0),
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <Transform.h>
|
||||
#include <Sound.h>
|
||||
#include <SpatiallyNestable.h>
|
||||
#include <Interpolate.h>
|
||||
|
||||
#include "EntityItemID.h"
|
||||
#include "EntityItemPropertiesDefaults.h"
|
||||
|
@ -435,6 +436,7 @@ public:
|
|||
QUuid getOwningAvatarID() const { return _owningAvatarID; }
|
||||
void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; }
|
||||
|
||||
virtual bool isTransparent() { return _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f : false; }
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -565,7 +567,8 @@ protected:
|
|||
quint64 _lastUpdatedAngularVelocityTimestamp { 0 };
|
||||
quint64 _lastUpdatedAccelerationTimestamp { 0 };
|
||||
|
||||
|
||||
quint64 _fadeStartTime { usecTimestampNow() };
|
||||
bool _isFading { true };
|
||||
};
|
||||
|
||||
#endif // hifi_EntityItem_h
|
||||
|
|
|
@ -634,8 +634,8 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
|
|||
}
|
||||
} else {
|
||||
// if the entity type doesn't support a detailed intersection, then just return the non-AABox results
|
||||
// Never intersect with particle effect entities
|
||||
if (localDistance < distance && EntityTypes::getEntityTypeName(entity->getType()) != "ParticleEffect") {
|
||||
// Never intersect with particle entities
|
||||
if (localDistance < distance && entity->getType() != EntityTypes::ParticleEffect) {
|
||||
distance = localDistance;
|
||||
face = localFace;
|
||||
surfaceNormal = localSurfaceNormal;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <NumericalConstants.h>
|
||||
#include <Finally.h>
|
||||
#include <PathUtils.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
|
||||
#include "OffscreenGLCanvas.h"
|
||||
#include "GLEscrow.h"
|
||||
|
@ -55,6 +56,22 @@ private:
|
|||
friend class OffscreenQmlSurface;
|
||||
};
|
||||
|
||||
class QmlNetworkAccessManager : public NetworkAccessManager {
|
||||
public:
|
||||
friend class QmlNetworkAccessManagerFactory;
|
||||
protected:
|
||||
QmlNetworkAccessManager(QObject* parent) : NetworkAccessManager(parent) { }
|
||||
};
|
||||
|
||||
class QmlNetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory {
|
||||
public:
|
||||
QNetworkAccessManager* create(QObject* parent);
|
||||
};
|
||||
|
||||
QNetworkAccessManager* QmlNetworkAccessManagerFactory::create(QObject* parent) {
|
||||
return new QmlNetworkAccessManager(parent);
|
||||
}
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(offscreenFocus)
|
||||
Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
|
||||
|
||||
|
@ -402,6 +419,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
|||
// Create a QML engine.
|
||||
_qmlEngine = new QQmlEngine;
|
||||
|
||||
_qmlEngine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory);
|
||||
|
||||
auto importList = _qmlEngine->importPathList();
|
||||
importList.insert(importList.begin(), PathUtils::resourcesPath());
|
||||
_qmlEngine->setImportPathList(importList);
|
||||
|
|
|
@ -596,7 +596,7 @@ int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindin
|
|||
}
|
||||
|
||||
Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER);
|
||||
buffers.insert(Shader::Slot(name, binding, element, Resource::BUFFER));
|
||||
buffers.insert(Shader::Slot(name, binding, element, Resource::BUFFER, size));
|
||||
}
|
||||
return buffersCount;
|
||||
}
|
||||
|
|
|
@ -53,11 +53,12 @@ public:
|
|||
int32 _location{INVALID_LOCATION};
|
||||
Element _element;
|
||||
uint16 _resourceType{Resource::BUFFER};
|
||||
uint32 _size { 0 };
|
||||
|
||||
Slot(const Slot& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType) {}
|
||||
Slot(Slot&& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType) {}
|
||||
Slot(const std::string& name, int32 location, const Element& element, uint16 resourceType = Resource::BUFFER) :
|
||||
_name(name), _location(location), _element(element), _resourceType(resourceType) {}
|
||||
Slot(const Slot& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {}
|
||||
Slot(Slot&& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {}
|
||||
Slot(const std::string& name, int32 location, const Element& element, uint16 resourceType = Resource::BUFFER, uint32 size = 0) :
|
||||
_name(name), _location(location), _element(element), _resourceType(resourceType), _size(size) {}
|
||||
Slot(const std::string& name) : _name(name) {}
|
||||
|
||||
Slot& operator= (const Slot& s) {
|
||||
|
@ -65,7 +66,9 @@ public:
|
|||
_location = s._location;
|
||||
_element = s._element;
|
||||
_resourceType = s._resourceType;
|
||||
return (*this); }
|
||||
_size = s._size;
|
||||
return (*this);
|
||||
}
|
||||
};
|
||||
|
||||
class Binding {
|
||||
|
|
|
@ -700,8 +700,6 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
return false;
|
||||
}
|
||||
|
||||
const float UCHAR_TO_FLOAT = 1.0f / float(std::numeric_limits<unsigned char>::max());
|
||||
|
||||
// for each face of cube texture
|
||||
for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
|
||||
|
||||
|
@ -788,12 +786,9 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
uint pixOffsetIndex = (x + y * width) * numComponents;
|
||||
|
||||
// get color from texture and map to range [0, 1]
|
||||
glm::vec3 clr(float(data[pixOffsetIndex]) * UCHAR_TO_FLOAT,
|
||||
float(data[pixOffsetIndex+1]) * UCHAR_TO_FLOAT,
|
||||
float(data[pixOffsetIndex+2]) * UCHAR_TO_FLOAT);
|
||||
|
||||
// Gamma correct
|
||||
clr = ColorUtils::sRGBToLinearVec3(clr);
|
||||
glm::vec3 clr(ColorUtils::sRGB8ToLinearFloat(data[pixOffsetIndex]),
|
||||
ColorUtils::sRGB8ToLinearFloat(data[pixOffsetIndex + 1]),
|
||||
ColorUtils::sRGB8ToLinearFloat(data[pixOffsetIndex + 2]));
|
||||
|
||||
// scale color and add to previously accumulated coefficients
|
||||
sphericalHarmonicsScale(shBuffB.data(), order,
|
||||
|
|
|
@ -171,7 +171,8 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const
|
|||
}
|
||||
|
||||
|
||||
NetworkTexture::TextureLoaderFunc getTextureLoaderForType(NetworkTexture::Type type) {
|
||||
NetworkTexture::TextureLoaderFunc getTextureLoaderForType(NetworkTexture::Type type,
|
||||
const QVariantMap& options = QVariantMap()) {
|
||||
using Type = NetworkTexture;
|
||||
|
||||
switch (type) {
|
||||
|
@ -188,7 +189,11 @@ NetworkTexture::TextureLoaderFunc getTextureLoaderForType(NetworkTexture::Type t
|
|||
break;
|
||||
}
|
||||
case Type::CUBE_TEXTURE: {
|
||||
return model::TextureUsage::createCubeTextureFromImage;
|
||||
if (options.value("generateIrradiance", true).toBool()) {
|
||||
return model::TextureUsage::createCubeTextureFromImage;
|
||||
} else {
|
||||
return model::TextureUsage::createCubeTextureFromImageWithoutIrradiance;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::BUMP_TEXTURE: {
|
||||
|
@ -225,9 +230,9 @@ NetworkTexture::TextureLoaderFunc getTextureLoaderForType(NetworkTexture::Type t
|
|||
}
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
gpu::TexturePointer TextureCache::getImageTexture(const QString& path, Type type) {
|
||||
gpu::TexturePointer TextureCache::getImageTexture(const QString& path, Type type, QVariantMap options) {
|
||||
QImage image = QImage(path);
|
||||
auto loader = getTextureLoaderForType(type);
|
||||
auto loader = getTextureLoaderForType(type, options);
|
||||
return gpu::TexturePointer(loader(image, QUrl::fromLocalFile(path).fileName().toStdString()));
|
||||
}
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ public:
|
|||
const gpu::TexturePointer& getNormalFittingTexture();
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
static gpu::TexturePointer getImageTexture(const QString& path, Type type = Type::DEFAULT_TEXTURE);
|
||||
static gpu::TexturePointer getImageTexture(const QString& path, Type type = Type::DEFAULT_TEXTURE, QVariantMap options = QVariantMap());
|
||||
|
||||
/// Loads a texture from the specified URL.
|
||||
NetworkTexturePointer getTexture(const QUrl& url, Type type = Type::DEFAULT_TEXTURE,
|
||||
|
|
|
@ -59,31 +59,28 @@ const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& val
|
|||
const uint8 OPAQUE_ALPHA = 255;
|
||||
const uint8 TRANSPARENT_ALPHA = 0;
|
||||
if (image.hasAlphaChannel()) {
|
||||
std::map<uint8, uint32> alphaHistogram;
|
||||
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
// Actual alpha channel? create the histogram
|
||||
for (int y = 0; y < image.height(); ++y) {
|
||||
const QRgb* data = reinterpret_cast<const QRgb*>(image.constScanLine(y));
|
||||
for (int x = 0; x < image.width(); ++x) {
|
||||
auto alpha = qAlpha(data[x]);
|
||||
alphaHistogram[alpha] ++;
|
||||
validAlpha = validAlpha || (alpha != OPAQUE_ALPHA);
|
||||
// Figure out if we can use a mask for alpha or not
|
||||
int numOpaques = 0;
|
||||
int numTranslucents = 0;
|
||||
const int NUM_PIXELS = image.width() * image.height();
|
||||
const int MAX_TRANSLUCENT_PIXELS_FOR_ALPHAMASK = (int)(0.05f * (float)(NUM_PIXELS));
|
||||
const QRgb* data = reinterpret_cast<const QRgb*>(image.constBits());
|
||||
for (int i = 0; i < NUM_PIXELS; ++i) {
|
||||
auto alpha = qAlpha(data[i]);
|
||||
if (alpha == OPAQUE_ALPHA) {
|
||||
numOpaques++;
|
||||
} else if (alpha != TRANSPARENT_ALPHA) {
|
||||
if (++numTranslucents > MAX_TRANSLUCENT_PIXELS_FOR_ALPHAMASK) {
|
||||
alphaAsMask = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If alpha was meaningfull refine
|
||||
if (validAlpha && (alphaHistogram.size() > 1)) {
|
||||
auto totalNumPixels = image.height() * image.width();
|
||||
auto numOpaques = alphaHistogram[OPAQUE_ALPHA];
|
||||
auto numTransparents = alphaHistogram[TRANSPARENT_ALPHA];
|
||||
auto numTranslucents = totalNumPixels - numOpaques - numTransparents;
|
||||
|
||||
alphaAsMask = ((numTranslucents / (double)totalNumPixels) < 0.05);
|
||||
}
|
||||
validAlpha = (numOpaques != NUM_PIXELS);
|
||||
}
|
||||
|
||||
if (!validAlpha && image.format() != QImage::Format_RGB888) {
|
||||
|
@ -660,13 +657,12 @@ const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = {
|
|||
const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
||||
|
||||
gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance) {
|
||||
|
||||
bool validAlpha = false;
|
||||
bool alphaAsMask = true;
|
||||
QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask);
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
||||
QImage image = srcImage;
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
gpu::Element formatGPU;
|
||||
gpu::Element formatMip;
|
||||
|
@ -729,3 +725,7 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
|
|||
gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return processCubeTextureColorFromImage(srcImage, srcImageName, false, true, true, true);
|
||||
}
|
||||
|
||||
gpu::Texture* TextureUsage::createCubeTextureFromImageWithoutIrradiance(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return processCubeTextureColorFromImage(srcImage, srcImageName, false, true, true, false);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
static gpu::Texture* createRoughnessTextureFromGlossImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createMetallicTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createCubeTextureFromImageWithoutIrradiance(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
|
||||
|
||||
|
|
|
@ -33,12 +33,7 @@ bool AssetResourceRequest::urlIsAssetHash() const {
|
|||
}
|
||||
|
||||
void AssetResourceRequest::doSend() {
|
||||
auto parts = _url.path().split(".", QString::SkipEmptyParts);
|
||||
auto hash = parts.length() > 0 ? parts[0] : "";
|
||||
auto extension = parts.length() > 1 ? parts[1] : "";
|
||||
|
||||
// We'll either have a hash or an ATP path to a file (that maps to a hash)
|
||||
|
||||
if (urlIsAssetHash()) {
|
||||
// We've detected that this is a hash - simply use AssetClient to request that asset
|
||||
auto parts = _url.path().split(".", QString::SkipEmptyParts);
|
||||
|
|
88
libraries/networking/src/AtpReply.cpp
Normal file
88
libraries/networking/src/AtpReply.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// AtpReply.cpp
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Zander Otavka on 8/4/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ResourceManager.h"
|
||||
#include "AtpReply.h"
|
||||
|
||||
AtpReply::AtpReply(const QUrl& url, QObject* parent) :
|
||||
_resourceRequest(ResourceManager::createResourceRequest(parent, url)) {
|
||||
setOperation(QNetworkAccessManager::GetOperation);
|
||||
|
||||
connect(_resourceRequest, &AssetResourceRequest::progress, this, &AtpReply::downloadProgress);
|
||||
connect(_resourceRequest, &AssetResourceRequest::finished, this, &AtpReply::handleRequestFinish);
|
||||
|
||||
_resourceRequest->send();
|
||||
}
|
||||
|
||||
AtpReply::~AtpReply() {
|
||||
if (_resourceRequest) {
|
||||
_resourceRequest->deleteLater();
|
||||
_resourceRequest = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
qint64 AtpReply::bytesAvailable() const {
|
||||
return _content.size() - _readOffset + QIODevice::bytesAvailable();
|
||||
}
|
||||
|
||||
qint64 AtpReply::readData(char* data, qint64 maxSize) {
|
||||
if (_readOffset < _content.size()) {
|
||||
qint64 readSize = qMin(maxSize, _content.size() - _readOffset);
|
||||
memcpy(data, _content.constData() + _readOffset, readSize);
|
||||
_readOffset += readSize;
|
||||
return readSize;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void AtpReply::handleRequestFinish() {
|
||||
Q_ASSERT(_resourceRequest->getState() == ResourceRequest::State::Finished);
|
||||
|
||||
switch (_resourceRequest->getResult()) {
|
||||
case ResourceRequest::Result::Success:
|
||||
setError(NoError, "Success");
|
||||
_content = _resourceRequest->getData();
|
||||
break;
|
||||
case ResourceRequest::Result::InvalidURL:
|
||||
setError(ContentNotFoundError, "Invalid URL");
|
||||
break;
|
||||
case ResourceRequest::Result::NotFound:
|
||||
setError(ContentNotFoundError, "Not found");
|
||||
break;
|
||||
case ResourceRequest::Result::ServerUnavailable:
|
||||
setError(ServiceUnavailableError, "Service unavailable");
|
||||
break;
|
||||
case ResourceRequest::Result::AccessDenied:
|
||||
setError(ContentAccessDenied, "Access denied");
|
||||
break;
|
||||
case ResourceRequest::Result::Timeout:
|
||||
setError(TimeoutError, "Timeout");
|
||||
break;
|
||||
default:
|
||||
setError(UnknownNetworkError, "Unknown error");
|
||||
break;
|
||||
}
|
||||
|
||||
open(ReadOnly | Unbuffered);
|
||||
setHeader(QNetworkRequest::ContentLengthHeader, QVariant(_content.size()));
|
||||
|
||||
if (error() != NoError) {
|
||||
emit error(error());
|
||||
}
|
||||
|
||||
setFinished(true);
|
||||
emit readyRead();
|
||||
emit finished();
|
||||
|
||||
_resourceRequest->deleteLater();
|
||||
_resourceRequest = nullptr;
|
||||
}
|
40
libraries/networking/src/AtpReply.h
Normal file
40
libraries/networking/src/AtpReply.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// AtpReply.h
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Zander Otavka on 8/4/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AtpReply_h
|
||||
#define hifi_AtpReply_h
|
||||
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QUrl>
|
||||
|
||||
#include "AssetResourceRequest.h"
|
||||
|
||||
class AtpReply : public QNetworkReply {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AtpReply(const QUrl& url, QObject* parent = Q_NULLPTR);
|
||||
~AtpReply();
|
||||
qint64 bytesAvailable() const override;
|
||||
void abort() override { }
|
||||
bool isSequential() const override { return true; }
|
||||
|
||||
protected:
|
||||
qint64 readData(char* data, qint64 maxSize) override;
|
||||
|
||||
private:
|
||||
void handleRequestFinish();
|
||||
|
||||
ResourceRequest* _resourceRequest { nullptr };
|
||||
QByteArray _content;
|
||||
qint64 _readOffset { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_AtpReply_h
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// NetworkAccessManager.cpp
|
||||
//
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Clement on 7/1/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <QThreadStorage>
|
||||
|
||||
#include "AtpReply.h"
|
||||
#include "NetworkAccessManager.h"
|
||||
|
||||
QThreadStorage<QNetworkAccessManager*> networkAccessManagers;
|
||||
|
@ -23,3 +24,13 @@ QNetworkAccessManager& NetworkAccessManager::getInstance() {
|
|||
|
||||
return *networkAccessManagers.localData();
|
||||
}
|
||||
|
||||
QNetworkReply* NetworkAccessManager::createRequest(Operation operation, const QNetworkRequest& request, QIODevice* device) {
|
||||
if (request.url().scheme() == "atp" && operation == GetOperation) {
|
||||
return new AtpReply(request.url());
|
||||
//auto url = request.url().toString();
|
||||
//return QNetworkAccessManager::createRequest(operation, request, device);
|
||||
} else {
|
||||
return QNetworkAccessManager::createRequest(operation, request, device);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// NetworkAccessManager.h
|
||||
//
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Clement on 7/1/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -13,12 +13,17 @@
|
|||
#define hifi_NetworkAccessManager_h
|
||||
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtQml/QQmlNetworkAccessManagerFactory>
|
||||
|
||||
/// Wrapper around QNetworkAccessManager to restrict at one instance by thread
|
||||
class NetworkAccessManager : public QObject {
|
||||
class NetworkAccessManager : public QNetworkAccessManager {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QNetworkAccessManager& getInstance();
|
||||
protected:
|
||||
NetworkAccessManager(QObject* parent = Q_NULLPTR) : QNetworkAccessManager(parent) {}
|
||||
virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* device = Q_NULLPTR) override;
|
||||
};
|
||||
|
||||
#endif // hifi_NetworkAccessManager_h
|
|
@ -12,12 +12,13 @@
|
|||
#ifndef hifi_OAuthNetworkAccessManager_h
|
||||
#define hifi_OAuthNetworkAccessManager_h
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include "NetworkAccessManager.h"
|
||||
|
||||
class OAuthNetworkAccessManager : public QNetworkAccessManager {
|
||||
class OAuthNetworkAccessManager : public NetworkAccessManager {
|
||||
public:
|
||||
static OAuthNetworkAccessManager* getInstance();
|
||||
protected:
|
||||
OAuthNetworkAccessManager(QObject* parent = Q_NULLPTR) : NetworkAccessManager(parent) { }
|
||||
virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& req, QIODevice* outgoingData = 0);
|
||||
};
|
||||
|
||||
|
|
|
@ -462,6 +462,7 @@ int ResourceCache::getPendingRequestCount() {
|
|||
}
|
||||
|
||||
bool ResourceCache::attemptRequest(QSharedPointer<Resource> resource) {
|
||||
Q_ASSERT(!resource.isNull());
|
||||
auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>();
|
||||
|
||||
if (_requestsActive >= _requestLimit) {
|
||||
|
|
|
@ -63,7 +63,19 @@ QJsonValue Procedural::getProceduralData(const QString& proceduralJson) {
|
|||
return doc.object()[PROCEDURAL_USER_DATA_KEY];
|
||||
}
|
||||
|
||||
Procedural::Procedural() : _state { std::make_shared<gpu::State>() } {
|
||||
Procedural::Procedural() {
|
||||
_opaqueState->setCullMode(gpu::State::CULL_NONE);
|
||||
_opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
_opaqueState->setBlendFunction(false,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
||||
_transparentState->setCullMode(gpu::State::CULL_NONE);
|
||||
_transparentState->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
_transparentState->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
||||
_proceduralDataDirty = false;
|
||||
}
|
||||
|
||||
|
@ -103,6 +115,11 @@ bool Procedural::parseUrl(const QUrl& shaderUrl) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// If the URL hasn't changed, don't mark the shader as dirty
|
||||
if (_shaderUrl == shaderUrl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
_shaderUrl = shaderUrl;
|
||||
_shaderDirty = true;
|
||||
|
||||
|
@ -175,6 +192,10 @@ void Procedural::parse(const QJsonObject& proceduralData) {
|
|||
}
|
||||
|
||||
bool Procedural::ready() {
|
||||
if (!_hasStartedFade) {
|
||||
_fadeStartTime = usecTimestampNow();
|
||||
}
|
||||
|
||||
// Load any changes to the procedural
|
||||
// Check for changes atomically, in case they are currently being made
|
||||
if (_proceduralDataDirty) {
|
||||
|
@ -202,6 +223,10 @@ bool Procedural::ready() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!_hasStartedFade) {
|
||||
_hasStartedFade = true;
|
||||
_isFading = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -222,7 +247,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
|
|||
_shaderSource = _networkShader->_source;
|
||||
}
|
||||
|
||||
if (!_pipeline || _shaderDirty) {
|
||||
if (!_opaquePipeline || !_transparentPipeline || _shaderDirty) {
|
||||
if (!_vertexShader) {
|
||||
_vertexShader = gpu::Shader::createVertex(_vertexSource);
|
||||
}
|
||||
|
@ -260,7 +285,8 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
|
|||
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel3"), 3));
|
||||
gpu::Shader::makeProgram(*_shader, slotBindings);
|
||||
|
||||
_pipeline = gpu::Pipeline::create(_shader, _state);
|
||||
_opaquePipeline = gpu::Pipeline::create(_shader, _opaqueState);
|
||||
_transparentPipeline = gpu::Pipeline::create(_shader, _transparentState);
|
||||
for (size_t i = 0; i < NUM_STANDARD_UNIFORMS; ++i) {
|
||||
const std::string& name = STANDARD_UNIFORM_NAMES[i];
|
||||
_standardUniformSlots[i] = _shader->getUniforms().findLocation(name);
|
||||
|
@ -269,7 +295,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
|
|||
_frameCount = 0;
|
||||
}
|
||||
|
||||
batch.setPipeline(_pipeline);
|
||||
batch.setPipeline(isFading() ? _transparentPipeline : _opaquePipeline);
|
||||
|
||||
if (_shaderDirty || _uniformsDirty) {
|
||||
setupUniforms();
|
||||
|
|
|
@ -42,13 +42,18 @@ public:
|
|||
const gpu::ShaderPointer& getShader() const { return _shader; }
|
||||
|
||||
glm::vec4 getColor(const glm::vec4& entityColor);
|
||||
quint64 getFadeStartTime() { return _fadeStartTime; }
|
||||
bool isFading() { return _doesFade && _isFading; }
|
||||
void setIsFading(bool isFading) { _isFading = isFading; }
|
||||
void setDoesFade(bool doesFade) { _doesFade = doesFade; }
|
||||
|
||||
uint8_t _version { 1 };
|
||||
|
||||
std::string _vertexSource;
|
||||
std::string _fragmentSource;
|
||||
|
||||
gpu::StatePointer _state;
|
||||
gpu::StatePointer _opaqueState { std::make_shared<gpu::State>() };
|
||||
gpu::StatePointer _transparentState { std::make_shared<gpu::State>() };
|
||||
|
||||
enum StandardUniforms {
|
||||
DATE,
|
||||
|
@ -86,7 +91,8 @@ protected:
|
|||
UniformLambdas _uniforms;
|
||||
int32_t _standardUniformSlots[NUM_STANDARD_UNIFORMS];
|
||||
NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS];
|
||||
gpu::PipelinePointer _pipeline;
|
||||
gpu::PipelinePointer _opaquePipeline;
|
||||
gpu::PipelinePointer _transparentPipeline;
|
||||
gpu::ShaderPointer _vertexShader;
|
||||
gpu::ShaderPointer _fragmentShader;
|
||||
gpu::ShaderPointer _shader;
|
||||
|
@ -106,6 +112,11 @@ private:
|
|||
|
||||
void setupUniforms();
|
||||
void setupChannels(bool shouldCreate);
|
||||
|
||||
quint64 _fadeStartTime;
|
||||
bool _hasStartedFade { false };
|
||||
bool _isFading { false };
|
||||
bool _doesFade { true };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,7 +22,8 @@ ProceduralSkybox::ProceduralSkybox() : model::Skybox() {
|
|||
_procedural._vertexSource = skybox_vert;
|
||||
_procedural._fragmentSource = skybox_frag;
|
||||
// Adjust the pipeline state for background using the stencil test
|
||||
_procedural._state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
_procedural.setDoesFade(false);
|
||||
_procedural._opaqueState->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
}
|
||||
|
||||
void ProceduralSkybox::clear() {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
set(TARGET_NAME render-utils)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model render procedural)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model render)
|
||||
# pull in the resources.qrc file
|
||||
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
|
||||
setup_hifi_library(Widgets OpenGL Network Qml Quick Script)
|
||||
link_hifi_libraries(shared gpu procedural model model-networking render animation fbx)
|
||||
link_hifi_libraries(shared gpu model model-networking render animation fbx)
|
||||
|
||||
target_nsight()
|
||||
target_oglplus()
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <qmath.h>
|
||||
|
||||
#include "animdebugdraw_vert.h"
|
||||
#include "animdebugdraw_frag.h"
|
||||
#include <gpu/Batch.h>
|
||||
|
|
|
@ -73,6 +73,8 @@ void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 albedo, vec3
|
|||
discard;
|
||||
}
|
||||
_fragColor0 = vec4(albedo.rgb, alpha);
|
||||
_fragColor1 = vec4(packNormal(normal), clamp(roughness, 0.0, 1.0));
|
||||
|
||||
}
|
||||
|
||||
<@endif@>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "GeometryCache.h"
|
||||
|
||||
|
||||
#include <qmath.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <QtCore/QThreadPool>
|
||||
|
@ -398,26 +398,36 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() {
|
|||
return INSTANCED_SOLID_STREAM_FORMAT;
|
||||
}
|
||||
|
||||
render::ShapePipelinePointer GeometryCache::_simplePipeline;
|
||||
render::ShapePipelinePointer GeometryCache::_simpleOpaquePipeline;
|
||||
render::ShapePipelinePointer GeometryCache::_simpleTransparentPipeline;
|
||||
render::ShapePipelinePointer GeometryCache::_simpleWirePipeline;
|
||||
|
||||
GeometryCache::GeometryCache() :
|
||||
_nextID(0) {
|
||||
buildShapes();
|
||||
GeometryCache::_simplePipeline =
|
||||
std::make_shared<render::ShapePipeline>(getSimplePipeline(), nullptr,
|
||||
[](const render::ShapePipeline&, gpu::Batch& batch) {
|
||||
// Set the defaults needed for a simple program
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
|
||||
DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,
|
||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
);
|
||||
GeometryCache::_simpleOpaquePipeline =
|
||||
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, false, true, false), nullptr,
|
||||
[](const render::ShapePipeline&, gpu::Batch& batch) {
|
||||
// Set the defaults needed for a simple program
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
|
||||
DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,
|
||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
);
|
||||
GeometryCache::_simpleTransparentPipeline =
|
||||
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, true, true, false), nullptr,
|
||||
[](const render::ShapePipeline&, gpu::Batch& batch) {
|
||||
// Set the defaults needed for a simple program
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
|
||||
DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,
|
||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
);
|
||||
GeometryCache::_simpleWirePipeline =
|
||||
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, false, true, true), nullptr,
|
||||
[](const render::ShapePipeline&, gpu::Batch& batch) {}
|
||||
);
|
||||
[](const render::ShapePipeline&, gpu::Batch& batch) {});
|
||||
}
|
||||
|
||||
GeometryCache::~GeometryCache() {
|
||||
|
@ -1704,6 +1714,7 @@ class SimpleProgramKey {
|
|||
public:
|
||||
enum FlagBit {
|
||||
IS_TEXTURED_FLAG = 0,
|
||||
IS_TRANSPARENT_FLAG,
|
||||
IS_CULLED_FLAG,
|
||||
IS_UNLIT_FLAG,
|
||||
HAS_DEPTH_BIAS_FLAG,
|
||||
|
@ -1713,6 +1724,7 @@ public:
|
|||
|
||||
enum Flag {
|
||||
IS_TEXTURED = (1 << IS_TEXTURED_FLAG),
|
||||
IS_TRANSPARENT = (1 << IS_TRANSPARENT_FLAG),
|
||||
IS_CULLED = (1 << IS_CULLED_FLAG),
|
||||
IS_UNLIT = (1 << IS_UNLIT_FLAG),
|
||||
HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG),
|
||||
|
@ -1722,6 +1734,7 @@ public:
|
|||
bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); }
|
||||
|
||||
bool isTextured() const { return isFlag(IS_TEXTURED); }
|
||||
bool isTransparent() const { return isFlag(IS_TRANSPARENT); }
|
||||
bool isCulled() const { return isFlag(IS_CULLED); }
|
||||
bool isUnlit() const { return isFlag(IS_UNLIT); }
|
||||
bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); }
|
||||
|
@ -1732,9 +1745,9 @@ public:
|
|||
int getRaw() const { return *reinterpret_cast<const int*>(this); }
|
||||
|
||||
|
||||
SimpleProgramKey(bool textured = false, bool culled = true,
|
||||
SimpleProgramKey(bool textured = false, bool transparent = false, bool culled = true,
|
||||
bool unlit = false, bool depthBias = false) {
|
||||
_flags = (textured ? IS_TEXTURED : 0) | (culled ? IS_CULLED : 0) |
|
||||
_flags = (textured ? IS_TEXTURED : 0) | (transparent ? IS_TRANSPARENT : 0) | (culled ? IS_CULLED : 0) |
|
||||
(unlit ? IS_UNLIT : 0) | (depthBias ? HAS_DEPTH_BIAS : 0);
|
||||
}
|
||||
|
||||
|
@ -1771,7 +1784,7 @@ gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoTexAlphaPipeline
|
|||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
state->setBlendFunction(false,
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
||||
|
@ -1781,8 +1794,8 @@ gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoTexAlphaPipeline
|
|||
return _simpleSRGBTexturedUnlitNoTexAlphaPipeline;
|
||||
}
|
||||
|
||||
void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool unlit, bool depthBiased) {
|
||||
batch.setPipeline(getSimplePipeline(textured, culled, unlit, depthBiased));
|
||||
void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool transparent, bool culled, bool unlit, bool depthBiased) {
|
||||
batch.setPipeline(getSimplePipeline(textured, transparent, culled, unlit, depthBiased));
|
||||
|
||||
// If not textured, set a default albedo map
|
||||
if (!textured) {
|
||||
|
@ -1794,8 +1807,8 @@ void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool cul
|
|||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
|
||||
gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool culled, bool unlit, bool depthBiased) {
|
||||
SimpleProgramKey config { textured, culled, unlit, depthBiased };
|
||||
gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transparent, bool culled, bool unlit, bool depthBiased) {
|
||||
SimpleProgramKey config { textured, transparent, culled, unlit, depthBiased };
|
||||
|
||||
// Compile the shaders
|
||||
static std::once_flag once;
|
||||
|
@ -1831,7 +1844,7 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool culled
|
|||
state->setDepthBias(1.0f);
|
||||
state->setDepthBiasSlopeScale(1.0f);
|
||||
}
|
||||
state->setBlendFunction(false,
|
||||
state->setBlendFunction(config.isTransparent(),
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
||||
|
|
|
@ -152,16 +152,17 @@ public:
|
|||
|
||||
|
||||
// Bind the pipeline and get the state to render static geometry
|
||||
void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
|
||||
void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool transparent = false, bool culled = true,
|
||||
bool unlit = false, bool depthBias = false);
|
||||
// Get the pipeline to render static geometry
|
||||
gpu::PipelinePointer getSimplePipeline(bool textured = false, bool culled = true,
|
||||
gpu::PipelinePointer getSimplePipeline(bool textured = false, bool transparent = false, bool culled = true,
|
||||
bool unlit = false, bool depthBias = false);
|
||||
|
||||
void bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(gpu::Batch& batch);
|
||||
gpu::PipelinePointer getSimpleSRGBTexturedUnlitNoTexAlphaPipeline();
|
||||
|
||||
render::ShapePipelinePointer getShapePipeline() { return GeometryCache::_simplePipeline; }
|
||||
render::ShapePipelinePointer getOpaqueShapePipeline() { return GeometryCache::_simpleOpaquePipeline; }
|
||||
render::ShapePipelinePointer getTransparentShapePipeline() { return GeometryCache::_simpleTransparentPipeline; }
|
||||
render::ShapePipelinePointer getWireShapePipeline() { return GeometryCache::_simpleWirePipeline; }
|
||||
|
||||
// Static (instanced) geometry
|
||||
|
@ -169,42 +170,42 @@ public:
|
|||
void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
|
||||
|
||||
void renderSolidShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1),
|
||||
const render::ShapePipelinePointer& pipeline = _simplePipeline);
|
||||
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
|
||||
void renderSolidShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec3& color,
|
||||
const render::ShapePipelinePointer& pipeline = _simplePipeline) {
|
||||
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) {
|
||||
renderSolidShapeInstance(batch, shape, glm::vec4(color, 1.0f), pipeline);
|
||||
}
|
||||
|
||||
void renderWireShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1),
|
||||
const render::ShapePipelinePointer& pipeline = _simplePipeline);
|
||||
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
|
||||
void renderWireShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec3& color,
|
||||
const render::ShapePipelinePointer& pipeline = _simplePipeline) {
|
||||
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) {
|
||||
renderWireShapeInstance(batch, shape, glm::vec4(color, 1.0f), pipeline);
|
||||
}
|
||||
|
||||
void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color,
|
||||
const render::ShapePipelinePointer& pipeline = _simplePipeline);
|
||||
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
|
||||
void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec3& color,
|
||||
const render::ShapePipelinePointer& pipeline = _simplePipeline) {
|
||||
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) {
|
||||
renderSolidSphereInstance(batch, glm::vec4(color, 1.0f), pipeline);
|
||||
}
|
||||
|
||||
void renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color,
|
||||
const render::ShapePipelinePointer& pipeline = _simplePipeline);
|
||||
const render::ShapePipelinePointer& pipeline = _simpleWirePipeline);
|
||||
void renderWireSphereInstance(gpu::Batch& batch, const glm::vec3& color,
|
||||
const render::ShapePipelinePointer& pipeline = _simpleWirePipeline) {
|
||||
renderWireSphereInstance(batch, glm::vec4(color, 1.0f), pipeline);
|
||||
}
|
||||
|
||||
void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color,
|
||||
const render::ShapePipelinePointer& pipeline = _simplePipeline);
|
||||
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
|
||||
void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec3& color,
|
||||
const render::ShapePipelinePointer& pipeline = _simplePipeline) {
|
||||
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) {
|
||||
renderSolidCubeInstance(batch, glm::vec4(color, 1.0f), pipeline);
|
||||
}
|
||||
|
||||
void renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color,
|
||||
const render::ShapePipelinePointer& pipeline = _simplePipeline);
|
||||
const render::ShapePipelinePointer& pipeline = _simpleWirePipeline);
|
||||
void renderWireCubeInstance(gpu::Batch& batch, const glm::vec3& color,
|
||||
const render::ShapePipelinePointer& pipeline = _simpleWirePipeline) {
|
||||
renderWireCubeInstance(batch, glm::vec4(color, 1.0f), pipeline);
|
||||
|
@ -416,7 +417,8 @@ private:
|
|||
|
||||
gpu::ShaderPointer _simpleShader;
|
||||
gpu::ShaderPointer _unlitShader;
|
||||
static render::ShapePipelinePointer _simplePipeline;
|
||||
static render::ShapePipelinePointer _simpleOpaquePipeline;
|
||||
static render::ShapePipelinePointer _simpleTransparentPipeline;
|
||||
static render::ShapePipelinePointer _simpleWirePipeline;
|
||||
gpu::PipelinePointer _glowLinePipeline;
|
||||
QHash<SimpleProgramKey, gpu::PipelinePointer> _simplePrograms;
|
||||
|
|
|
@ -352,7 +352,6 @@ void ModelMeshPartPayload::initCache() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
void ModelMeshPartPayload::notifyLocationChanged() {
|
||||
|
||||
}
|
||||
|
@ -392,6 +391,10 @@ ItemKey ModelMeshPartPayload::getKey() const {
|
|||
}
|
||||
}
|
||||
|
||||
if (!_hasFinishedFade) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
@ -443,7 +446,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
|||
}
|
||||
|
||||
ShapeKey::Builder builder;
|
||||
if (isTranslucent) {
|
||||
if (isTranslucent || !_hasFinishedFade) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
if (hasTangents) {
|
||||
|
@ -484,9 +487,9 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
|||
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
|
||||
}
|
||||
|
||||
// TODO: Get rid of that extra call
|
||||
if (!_hasColorAttrib) {
|
||||
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
if (!_hasColorAttrib || fadeRatio < 1.0f) {
|
||||
batch._glColor4f(1.0f, 1.0f, 1.0f, fadeRatio);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -513,14 +516,30 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline:
|
|||
batch.setModelTransform(transform);
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::startFade() {
|
||||
_fadeStartTime = usecTimestampNow();
|
||||
_hasStartedFade = true;
|
||||
_prevHasStartedFade = false;
|
||||
_hasFinishedFade = false;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
|
||||
|
||||
if (!_model->_readyWhenAdded || !_model->_isVisible) {
|
||||
if (!_model->_readyWhenAdded || !_model->_isVisible || !_hasStartedFade) {
|
||||
return; // bail asap
|
||||
}
|
||||
|
||||
// When an individual mesh parts like this finishes its fade, we will mark the Model as
|
||||
// having render items that need updating
|
||||
bool nextIsFading = _isFading ? isStillFading() : false;
|
||||
if (_isFading != nextIsFading || _prevHasStartedFade != _hasStartedFade) {
|
||||
_isFading = nextIsFading || _prevHasStartedFade != _hasStartedFade;
|
||||
_hasFinishedFade = _prevHasStartedFade == _hasStartedFade && !_isFading;
|
||||
_prevHasStartedFade = _hasStartedFade;
|
||||
_model->setRenderItemsNeedUpdate();
|
||||
}
|
||||
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
|
||||
if (!getShapeKey().isValid()) {
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#ifndef hifi_MeshPartPayload_h
|
||||
#define hifi_MeshPartPayload_h
|
||||
|
||||
#include <Interpolate.h>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <render/Scene.h>
|
||||
|
@ -81,6 +83,11 @@ public:
|
|||
void notifyLocationChanged() override;
|
||||
void updateTransformForSkinnedMesh(const Transform& transform, const Transform& offsetTransform, const QVector<glm::mat4>& clusterMatrices);
|
||||
|
||||
// Entity fade in
|
||||
void startFade();
|
||||
bool hasStartedFade() { return _hasStartedFade; }
|
||||
bool isStillFading() const { return Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f; }
|
||||
|
||||
// Render Item interface
|
||||
render::ItemKey getKey() const override;
|
||||
render::ShapeKey getShapeKey() const override; // shape interface
|
||||
|
@ -99,6 +106,13 @@ public:
|
|||
|
||||
bool _isSkinned{ false };
|
||||
bool _isBlendShaped{ false };
|
||||
|
||||
private:
|
||||
quint64 _fadeStartTime { 0 };
|
||||
bool _hasStartedFade { false };
|
||||
mutable bool _prevHasStartedFade{ false };
|
||||
mutable bool _hasFinishedFade { false };
|
||||
mutable bool _isFading { false };
|
||||
};
|
||||
|
||||
namespace render {
|
||||
|
|
|
@ -174,6 +174,7 @@ void Model::setOffset(const glm::vec3& offset) {
|
|||
void Model::updateRenderItems() {
|
||||
|
||||
_needsUpdateClusterMatrices = true;
|
||||
_renderItemsNeedUpdate = false;
|
||||
|
||||
// queue up this work for later processing, at the end of update and just before rendering.
|
||||
// the application will ensure only the last lambda is actually invoked.
|
||||
|
@ -211,6 +212,9 @@ void Model::updateRenderItems() {
|
|||
render::PendingChanges pendingChanges;
|
||||
foreach (auto itemID, self->_modelMeshRenderItems.keys()) {
|
||||
pendingChanges.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, modelMeshOffset, deleteGeometryCounter](ModelMeshPartPayload& data) {
|
||||
if (!data.hasStartedFade() && data._model && data._model->isLoaded() && data._model->getGeometry()->areTexturesLoaded()) {
|
||||
data.startFade();
|
||||
}
|
||||
// Ensure the model geometry was not reset between frames
|
||||
if (data._model && data._model->isLoaded() && deleteGeometryCounter == data._model->_deleteGeometryCounter) {
|
||||
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
||||
|
|
|
@ -103,6 +103,8 @@ public:
|
|||
bool isVisible() const { return _isVisible; }
|
||||
|
||||
void updateRenderItems();
|
||||
void setRenderItemsNeedUpdate() { _renderItemsNeedUpdate = true; }
|
||||
bool getRenderItemsNeedUpdate() { return _renderItemsNeedUpdate; }
|
||||
AABox getRenderableMeshBound() const;
|
||||
|
||||
bool maybeStartBlender();
|
||||
|
@ -408,6 +410,8 @@ protected:
|
|||
bool _visualGeometryRequestFailed { false };
|
||||
bool _collisionGeometryRequestFailed { false };
|
||||
|
||||
bool _renderItemsNeedUpdate { false };
|
||||
|
||||
private:
|
||||
float _loadingPriority { 0.0f };
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ void main() {
|
|||
|
||||
packDeferredFragmentTranslucent(
|
||||
normalize(_normal),
|
||||
a,
|
||||
a * Color.a,
|
||||
Color.rgb,
|
||||
DEFAULT_FRESNEL,
|
||||
DEFAULT_ROUGHNESS);
|
||||
|
|
|
@ -49,11 +49,43 @@ void main(void) {
|
|||
|
||||
#endif
|
||||
|
||||
if (emissiveAmount > 0.0) {
|
||||
packDeferredFragmentLightmap(
|
||||
normal, 1.0, diffuse, max(0, 1.0 - shininess / 128.0), DEFAULT_METALLIC, specular, specular);
|
||||
const float ALPHA_THRESHOLD = 0.999;
|
||||
if (_color.a < ALPHA_THRESHOLD) {
|
||||
if (emissiveAmount > 0.0) {
|
||||
packDeferredFragmentTranslucent(
|
||||
normal,
|
||||
_color.a,
|
||||
specular,
|
||||
DEFAULT_FRESNEL,
|
||||
DEFAULT_ROUGHNESS);
|
||||
} else {
|
||||
packDeferredFragmentTranslucent(
|
||||
normal,
|
||||
_color.a,
|
||||
diffuse,
|
||||
DEFAULT_FRESNEL,
|
||||
DEFAULT_ROUGHNESS);
|
||||
}
|
||||
} else {
|
||||
packDeferredFragment(
|
||||
normal, 1.0, diffuse, max(0, 1.0 - shininess / 128.0), length(specular), DEFAULT_EMISSIVE, DEFAULT_OCCLUSION, DEFAULT_SCATTERING);
|
||||
if (emissiveAmount > 0.0) {
|
||||
packDeferredFragmentLightmap(
|
||||
normal,
|
||||
1.0,
|
||||
diffuse,
|
||||
max(0, 1.0 - shininess / 128.0),
|
||||
DEFAULT_METALLIC,
|
||||
specular,
|
||||
specular);
|
||||
} else {
|
||||
packDeferredFragment(
|
||||
normal,
|
||||
1.0,
|
||||
diffuse,
|
||||
max(0, 1.0 - shininess / 128.0),
|
||||
length(specular),
|
||||
DEFAULT_EMISSIVE,
|
||||
DEFAULT_OCCLUSION,
|
||||
DEFAULT_SCATTERING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,18 @@ void main(void) {
|
|||
vec4 texel = texture(originalTexture, _texCoord0.st);
|
||||
texel = colorToLinearRGBA(texel);
|
||||
|
||||
packDeferredFragmentUnlit(
|
||||
normalize(_normal),
|
||||
1.0,
|
||||
_color.rgb * texel.rgb);
|
||||
const float ALPHA_THRESHOLD = 0.999;
|
||||
if (_color.a < ALPHA_THRESHOLD) {
|
||||
packDeferredFragmentTranslucent(
|
||||
normalize(_normal),
|
||||
_color.a,
|
||||
_color.rgb * texel.rgb,
|
||||
DEFAULT_FRESNEL,
|
||||
DEFAULT_ROUGHNESS);
|
||||
} else {
|
||||
packDeferredFragmentUnlit(
|
||||
normalize(_normal),
|
||||
1.0,
|
||||
_color.rgb * texel.rgb);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,13 +29,24 @@ void main(void) {
|
|||
if (_color.a <= 0.0) {
|
||||
texel = colorToLinearRGBA(texel);
|
||||
}
|
||||
packDeferredFragment(
|
||||
normalize(_normal.xyz),
|
||||
texel.a,
|
||||
_color.rgb * texel.rgb,
|
||||
DEFAULT_ROUGHNESS,
|
||||
DEFAULT_METALLIC,
|
||||
DEFAULT_EMISSIVE,
|
||||
DEFAULT_OCCLUSION,
|
||||
DEFAULT_SCATTERING);
|
||||
|
||||
const float ALPHA_THRESHOLD = 0.999;
|
||||
if (_color.a * texel.a < ALPHA_THRESHOLD) {
|
||||
packDeferredFragmentTranslucent(
|
||||
normalize(_normal),
|
||||
_color.a * texel.a,
|
||||
_color.rgb * texel.rgb,
|
||||
DEFAULT_FRESNEL,
|
||||
DEFAULT_ROUGHNESS);
|
||||
} else {
|
||||
packDeferredFragment(
|
||||
normalize(_normal),
|
||||
1.0,
|
||||
_color.rgb * texel.rgb,
|
||||
DEFAULT_ROUGHNESS,
|
||||
DEFAULT_METALLIC,
|
||||
DEFAULT_EMISSIVE,
|
||||
DEFAULT_OCCLUSION,
|
||||
DEFAULT_SCATTERING);
|
||||
}
|
||||
}
|
|
@ -29,8 +29,18 @@ void main(void) {
|
|||
texel = colorToLinearRGBA(texel);
|
||||
}
|
||||
|
||||
packDeferredFragmentUnlit(
|
||||
normalize(_normal),
|
||||
texel.a,
|
||||
_color.rgb * texel.rgb);
|
||||
const float ALPHA_THRESHOLD = 0.999;
|
||||
if (_color.a * texel.a < ALPHA_THRESHOLD) {
|
||||
packDeferredFragmentTranslucent(
|
||||
normalize(_normal),
|
||||
_color.a * texel.a,
|
||||
_color.rgb * texel.rgb,
|
||||
DEFAULT_FRESNEL,
|
||||
DEFAULT_ROUGHNESS);
|
||||
} else {
|
||||
packDeferredFragmentUnlit(
|
||||
normalize(_normal),
|
||||
1.0,
|
||||
_color.rgb * texel.rgb);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Bradley Austin Davis on 6/10/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
in vec4 varColor;
|
||||
in float varSize;
|
||||
|
||||
out vec4 outFragColor;
|
||||
|
||||
const float EDGE_SIZE = 0.25;
|
||||
const float ALPHA_BOUNDARY = 1.0 - EDGE_SIZE;
|
||||
|
||||
void main(void) {
|
||||
vec2 coord = gl_PointCoord * vec2(2.0) - vec2(1.0);
|
||||
coord = coord * coord;
|
||||
|
||||
float l = coord.x + coord.y;
|
||||
if (l > 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
outFragColor = varColor;
|
||||
if (l >= ALPHA_BOUNDARY) {
|
||||
outFragColor.a = smoothstep(1.0, ALPHA_BOUNDARY, l);
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// standardTransformPNTC.slv
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Sam Gateau on 6/10/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
|
||||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
<@include gpu/Color.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
// TODO we need to get the viewport resolution and FOV passed to us so we can modify the point size
|
||||
// and effectively producing a points that take up a constant angular size regardless of the display resolution
|
||||
// or projection matrix
|
||||
|
||||
out vec4 varColor;
|
||||
out float varSize;
|
||||
|
||||
void main(void) {
|
||||
varColor = colorToLinearRGBA(inColor);
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
|
||||
varSize = inColor.a;
|
||||
gl_PointSize = varSize;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// stars.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/06/19
|
||||
|
||||
in vec2 varTexcoord;
|
||||
in vec3 varNomral;
|
||||
in vec3 varPosition;
|
||||
|
||||
uniform float iGlobalTime;
|
||||
|
||||
const float PI = 3.14159;
|
||||
const float TAU = 3.14159 * 2.0;
|
||||
const int latitudeCount = 5;
|
||||
const float latitudeDist = PI / 2.0 / float(latitudeCount);
|
||||
const int meridianCount = 4;
|
||||
const float merdianDist = PI / float(meridianCount);
|
||||
|
||||
out vec4 outFragColor;
|
||||
|
||||
float clampLine(float val, float target) {
|
||||
return clamp((1.0 - abs((val - target)) - 0.998) * 500.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float latitude(vec2 pos, float angle) {
|
||||
float result = clampLine(pos.y, angle);
|
||||
if (angle != 0.0) {
|
||||
result += clampLine(pos.y, -angle);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float meridian(vec2 pos, float angle) {
|
||||
return clampLine(pos.x, angle) + clampLine(pos.x + PI, angle);
|
||||
}
|
||||
|
||||
vec2 toPolar(in vec3 dir) {
|
||||
vec2 polar = vec2(atan(dir.z, dir.x), asin(dir.y));
|
||||
return polar;
|
||||
}
|
||||
|
||||
void mainVR( out vec4 fragColor, in vec2 fragCoord, in vec3 fragRayOri, in vec3 fragRayDir )
|
||||
{
|
||||
vec2 polar = toPolar(fragRayDir);
|
||||
//polar.x += mod(iGlobalTime / 12.0, PI / 4.0) - PI / 4.0;
|
||||
float c = 0.0;
|
||||
for (int i = 0; i < latitudeCount - 1; ++i) {
|
||||
c += latitude(polar, float(i) * latitudeDist);
|
||||
}
|
||||
for (int i = 0; i < meridianCount; ++i) {
|
||||
c += meridian(polar, float(i) * merdianDist);
|
||||
}
|
||||
const vec3 col_lines = vec3(102.0 / 255.0, 136.0 / 255.0, 221.0 / 255.0);
|
||||
fragColor = vec4(c * col_lines, 0.2);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
mainVR(outFragColor, gl_FragCoord.xy, vec3(0.0), normalize(varPosition));
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
set(TARGET_NAME render)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model procedural)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model)
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries(shared gpu model)
|
||||
|
||||
|
|
|
@ -167,6 +167,7 @@ void ScriptCache::scriptContentAvailable() {
|
|||
Lock lock(_containerLock);
|
||||
allCallbacks = _contentCallbacks.values(url);
|
||||
_contentCallbacks.remove(url);
|
||||
Q_ASSERT(req->getState() == ResourceRequest::Finished);
|
||||
success = req->getResult() == ResourceRequest::Success;
|
||||
|
||||
if (success) {
|
||||
|
|
59
libraries/shared/src/ColorUtils.cpp
Normal file
59
libraries/shared/src/ColorUtils.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// ColorUtils.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Ryan Huffman on 8/8/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ColorUtils.h"
|
||||
|
||||
// Generated from python script in repository at `tools/srgb_gen.py`
|
||||
const float srgbToLinearLookupTable[256] = {
|
||||
0.0f, 0.000303526983549f, 0.000607053967098f, 0.000910580950647f, 0.0012141079342f, 0.00151763491774f, 0.00182116190129f,
|
||||
0.00212468888484f, 0.00242821586839f, 0.00273174285194f, 0.00303526983549f, 0.0033465357639f, 0.00367650732405f,
|
||||
0.0040247170185f, 0.00439144203741f, 0.00477695348069f, 0.00518151670234f, 0.0056053916242f, 0.00604883302286f,
|
||||
0.00651209079259f, 0.00699541018727f, 0.00749903204323f, 0.00802319298538f, 0.00856812561807f, 0.00913405870222f,
|
||||
0.00972121732024f, 0.0103298230296f, 0.0109600940065f, 0.0116122451797f, 0.0122864883569f, 0.0129830323422f,
|
||||
0.0137020830473f, 0.0144438435961f, 0.0152085144229f, 0.0159962933655f, 0.0168073757529f, 0.0176419544884f,
|
||||
0.0185002201284f, 0.0193823609569f, 0.0202885630567f, 0.021219010376f, 0.0221738847934f, 0.0231533661781f,
|
||||
0.0241576324485f, 0.0251868596274f, 0.0262412218948f, 0.0273208916391f, 0.0284260395044f, 0.0295568344378f,
|
||||
0.030713443733f, 0.031896033073f, 0.0331047665709f, 0.0343398068087f, 0.035601314875f, 0.0368894504011f,
|
||||
0.0382043715953f, 0.0395462352767f, 0.0409151969069f, 0.0423114106208f, 0.043735029257f, 0.0451862043857f,
|
||||
0.0466650863369f, 0.0481718242269f, 0.0497065659841f, 0.051269458374f, 0.0528606470232f, 0.0544802764424f,
|
||||
0.0561284900496f, 0.0578054301911f, 0.059511238163f, 0.0612460542316f, 0.0630100176532f, 0.0648032666929f,
|
||||
0.0666259386438f, 0.0684781698444f, 0.0703600956966f, 0.0722718506823f, 0.0742135683801f, 0.0761853814813f,
|
||||
0.0781874218052f, 0.0802198203145f, 0.0822827071298f, 0.0843762115441f, 0.0865004620365f, 0.0886555862858f,
|
||||
0.0908417111834f, 0.0930589628467f, 0.095307466631f, 0.0975873471419f, 0.0998987282471f, 0.102241733088f,
|
||||
0.104616484091f, 0.107023102978f, 0.109461710778f, 0.111932427837f, 0.114435373827f, 0.116970667759f,
|
||||
0.119538427988f, 0.12213877223f, 0.124771817561f, 0.127437680436f, 0.13013647669f, 0.132868321554f,
|
||||
0.135633329655f, 0.138431615032f, 0.14126329114f, 0.144128470858f, 0.147027266498f, 0.149959789811f,
|
||||
0.152926151996f, 0.155926463708f, 0.158960835061f, 0.162029375639f, 0.165132194502f, 0.16826940019f,
|
||||
0.171441100733f, 0.174647403656f, 0.177888415984f, 0.18116424425f, 0.1844749945f, 0.187820772301f,
|
||||
0.191201682741f, 0.194617830442f, 0.19806931956f, 0.201556253794f, 0.20507873639f, 0.208636870145f,
|
||||
0.212230757414f, 0.215860500114f, 0.219526199729f, 0.223227957317f, 0.22696587351f, 0.230740048524f,
|
||||
0.234550582161f, 0.238397573812f, 0.242281122466f, 0.246201326708f, 0.25015828473f, 0.254152094331f,
|
||||
0.258182852922f, 0.26225065753f, 0.266355604803f, 0.270497791013f, 0.27467731206f, 0.278894263477f,
|
||||
0.28314874043f, 0.287440837727f, 0.291770649818f, 0.296138270798f, 0.300543794416f, 0.30498731407f,
|
||||
0.309468922818f, 0.313988713376f, 0.318546778125f, 0.323143209113f, 0.327778098057f, 0.332451536346f,
|
||||
0.337163615048f, 0.341914424909f, 0.346704056355f, 0.3515325995f, 0.356400144146f, 0.361306779784f,
|
||||
0.366252595599f, 0.371237680474f, 0.376262122991f, 0.381326011433f, 0.386429433787f, 0.39157247775f,
|
||||
0.396755230726f, 0.401977779832f, 0.407240211902f, 0.412542613484f, 0.417885070848f, 0.423267669986f,
|
||||
0.428690496614f, 0.434153636175f, 0.439657173841f, 0.445201194516f, 0.450785782838f, 0.45641102318f,
|
||||
0.462076999654f, 0.467783796112f, 0.473531496148f, 0.479320183101f, 0.485149940056f, 0.491020849848f,
|
||||
0.496932995061f, 0.502886458033f, 0.508881320855f, 0.514917665377f, 0.520995573204f, 0.527115125706f,
|
||||
0.533276404011f, 0.539479489012f, 0.54572446137f, 0.552011401512f, 0.558340389634f, 0.564711505705f,
|
||||
0.571124829465f, 0.57758044043f, 0.584078417891f, 0.590618840919f, 0.597201788364f, 0.603827338855f,
|
||||
0.610495570808f, 0.61720656242f, 0.623960391675f, 0.630757136346f, 0.637596873994f, 0.644479681971f,
|
||||
0.65140563742f, 0.658374817279f, 0.665387298282f, 0.672443156958f, 0.679542469633f, 0.686685312435f,
|
||||
0.693871761292f, 0.701101891933f, 0.708375779892f, 0.715693500506f, 0.723055128922f, 0.73046074009f,
|
||||
0.737910408773f, 0.74540420954f, 0.752942216776f, 0.760524504675f, 0.768151147248f, 0.775822218317f,
|
||||
0.783537791526f, 0.791297940333f, 0.799102738014f, 0.806952257669f, 0.814846572216f, 0.822785754396f,
|
||||
0.830769876775f, 0.838799011741f, 0.84687323151f, 0.854992608124f, 0.863157213454f, 0.871367119199f,
|
||||
0.879622396888f, 0.887923117882f, 0.896269353374f, 0.904661174391f, 0.913098651793f, 0.921581856277f,
|
||||
0.930110858375f, 0.938685728458f, 0.947306536733f, 0.955973353249f, 0.964686247894f, 0.973445290398f,
|
||||
0.982250550333f, 0.991102097114f, 1.0f
|
||||
};
|
|
@ -13,10 +13,13 @@
|
|||
#define hifi_ColorUtils_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "SharedUtil.h"
|
||||
|
||||
#include "DependencyManager.h"
|
||||
|
||||
extern const float srgbToLinearLookupTable[256];
|
||||
|
||||
class ColorUtils {
|
||||
public:
|
||||
inline static glm::vec3 toVec3(const xColor& color);
|
||||
|
@ -33,6 +36,7 @@ public:
|
|||
inline static glm::vec4 tosRGBVec4(const glm::vec4& srgb);
|
||||
|
||||
inline static float sRGBToLinearFloat(const float& srgb);
|
||||
inline static float sRGB8ToLinearFloat(const uint8_t srgb);
|
||||
inline static float tosRGBFloat(const float& linear);
|
||||
};
|
||||
|
||||
|
@ -82,6 +86,9 @@ inline float ColorUtils::sRGBToLinearFloat(const float &srgb) {
|
|||
|
||||
return linearValue;
|
||||
}
|
||||
inline float ColorUtils::sRGB8ToLinearFloat(const uint8_t srgb) {
|
||||
return srgbToLinearLookupTable[srgb];
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
|
||||
float Interpolate::bezierInterpolate(float y1, float y2, float y3, float u) {
|
||||
// https://en.wikipedia.org/wiki/Bezier_curve
|
||||
assert(0.0f <= u && u <= 1.0f);
|
||||
|
@ -58,3 +60,13 @@ float Interpolate::interpolate3Points(float y1, float y2, float y3, float u) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
float Interpolate::calculateFadeRatio(quint64 start) {
|
||||
const float FADE_TIME = 1.0f;
|
||||
float t = 2.0f * std::min(((float)(usecTimestampNow() - start)) / ((float)(FADE_TIME * USECS_PER_SECOND)), 1.0f);
|
||||
float fadeRatio = (t < 1.0f) ? 0.5f * powf(2.0f, 10.0f * (t - 1.0f)) : 0.5f * (-powf(2.0f, -10.0f * (t - 1.0f)) + 2.0f);
|
||||
|
||||
// The easing function isn't exactly 1 at t = 2, so we need to scale the whole function up slightly
|
||||
const float EASING_SCALE = 1.001f;
|
||||
return std::min(EASING_SCALE * fadeRatio, 1.0f);
|
||||
}
|
|
@ -12,6 +12,8 @@
|
|||
#ifndef hifi_Interpolate_h
|
||||
#define hifi_Interpolate_h
|
||||
|
||||
#include "SharedUtil.h"
|
||||
|
||||
class Interpolate {
|
||||
|
||||
public:
|
||||
|
@ -22,6 +24,8 @@ public:
|
|||
// Interpolate at position u [0.0 - 1.0] between y values equally spaced along the x-axis such that the interpolated values
|
||||
// pass through all three y values. Return value lies wholly within the range of y values passed in.
|
||||
static float interpolate3Points(float y1, float y2, float y3, float u);
|
||||
|
||||
static float calculateFadeRatio(quint64 start);
|
||||
};
|
||||
|
||||
#endif // hifi_Interpolate_h
|
||||
|
|
|
@ -59,9 +59,10 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) {
|
|||
properties = context->argument(0).toVariant().toMap();
|
||||
}
|
||||
|
||||
QString url = properties[SOURCE_PROPERTY].toString();
|
||||
if (!url.startsWith("http") && !url.startsWith("file://") && !url.startsWith("about:")) {
|
||||
properties[SOURCE_PROPERTY] = QUrl::fromLocalFile(url).toString();
|
||||
QUrl url { properties[SOURCE_PROPERTY].toString() };
|
||||
if (url.scheme() != "http" && url.scheme() != "https" && url.scheme() != "file" && url.scheme() != "about" &&
|
||||
url.scheme() != "atp") {
|
||||
properties[SOURCE_PROPERTY] = QUrl::fromLocalFile(url.toString()).toString();
|
||||
}
|
||||
|
||||
return properties;
|
||||
|
|
|
@ -232,18 +232,10 @@ function Teleporter() {
|
|||
};
|
||||
|
||||
this.rightRay = function() {
|
||||
|
||||
var rightPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getPoseValue(Controller.Standard.RightHand).translation), MyAvatar.position);
|
||||
|
||||
var rightControllerRotation = Controller.getPoseValue(Controller.Standard.RightHand).rotation;
|
||||
|
||||
var rightRotation = Quat.multiply(MyAvatar.orientation, rightControllerRotation);
|
||||
|
||||
var rightFinal = Quat.multiply(rightRotation, Quat.angleAxis(90, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
}));
|
||||
var pose = Controller.getPoseValue(Controller.Standard.RightHand);
|
||||
var rightPosition = pose.valid ? Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position) : MyAvatar.getHeadPosition();
|
||||
var rightRotation = pose.valid ? Quat.multiply(MyAvatar.orientation, pose.rotation) :
|
||||
Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, {x: 1, y: 0, z: 0}));
|
||||
|
||||
var rightPickRay = {
|
||||
origin: rightPosition,
|
||||
|
@ -288,15 +280,10 @@ function Teleporter() {
|
|||
|
||||
|
||||
this.leftRay = function() {
|
||||
var leftPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getPoseValue(Controller.Standard.LeftHand).translation), MyAvatar.position);
|
||||
|
||||
var leftRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(Controller.Standard.LeftHand).rotation)
|
||||
|
||||
var leftFinal = Quat.multiply(leftRotation, Quat.angleAxis(90, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
}));
|
||||
var pose = Controller.getPoseValue(Controller.Standard.LeftHand);
|
||||
var leftPosition = pose.valid ? Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position) : MyAvatar.getHeadPosition();
|
||||
var leftRotation = pose.valid ? Quat.multiply(MyAvatar.orientation, pose.rotation) :
|
||||
Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, {x: 1, y: 0, z: 0}));
|
||||
|
||||
var leftPickRay = {
|
||||
origin: leftPosition,
|
||||
|
|
|
@ -10,51 +10,51 @@
|
|||
|
||||
@font-face {
|
||||
font-family: Raleway-Regular;
|
||||
src: url(../../../resources/fonts/Raleway-Regular.ttf), /* Windows production */
|
||||
url(../../../fonts/Raleway-Regular.ttf), /* OSX production */
|
||||
url(../../../interface/resources/fonts/Raleway-Regular.ttf); /* Development, running script in /HiFi/examples */
|
||||
src: url(../../../../resources/fonts/Raleway-Regular.ttf), /* Windows production */
|
||||
url(../../../../fonts/Raleway-Regular.ttf), /* OSX production */
|
||||
url(../../../../interface/resources/fonts/Raleway-Regular.ttf); /* Development, running script in /HiFi/examples */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Raleway-Light;
|
||||
src: url(../../../resources/fonts/Raleway-Light.ttf),
|
||||
url(../../../fonts/Raleway-Light.ttf),
|
||||
url(../../../interface/resources/fonts/Raleway-Light.ttf);
|
||||
src: url(../../../../resources/fonts/Raleway-Light.ttf),
|
||||
url(../../../../fonts/Raleway-Light.ttf),
|
||||
url(../../../../interface/resources/fonts/Raleway-Light.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Raleway-Bold;
|
||||
src: url(../../../resources/fonts/Raleway-Bold.ttf),
|
||||
url(../../../fonts/Raleway-Bold.ttf),
|
||||
url(../../../interface/resources/fonts/Raleway-Bold.ttf);
|
||||
src: url(../../../../resources/fonts/Raleway-Bold.ttf),
|
||||
url(../../../../fonts/Raleway-Bold.ttf),
|
||||
url(../../../../interface/resources/fonts/Raleway-Bold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Raleway-SemiBold;
|
||||
src: url(../../../resources/fonts/Raleway-SemiBold.ttf),
|
||||
url(../../../fonts/Raleway-SemiBold.ttf),
|
||||
url(../../../interface/resources/fonts/Raleway-SemiBold.ttf);
|
||||
src: url(../../../../resources/fonts/Raleway-SemiBold.ttf),
|
||||
url(../../../../fonts/Raleway-SemiBold.ttf),
|
||||
url(../../../../interface/resources/fonts/Raleway-SemiBold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: FiraSans-SemiBold;
|
||||
src: url(../../../resources/fonts/FiraSans-SemiBold.ttf),
|
||||
url(../../../fonts/FiraSans-SemiBold.ttf),
|
||||
url(../../../interface/resources/fonts/FiraSans-SemiBold.ttf);
|
||||
src: url(../../../../resources/fonts/FiraSans-SemiBold.ttf),
|
||||
url(../../../../fonts/FiraSans-SemiBold.ttf),
|
||||
url(../../../../interface/resources/fonts/FiraSans-SemiBold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: AnonymousPro-Regular;
|
||||
src: url(../../../resources/fonts/AnonymousPro-Regular.ttf),
|
||||
url(../../../fonts/AnonymousPro-Regular.ttf),
|
||||
url(../../../interface/resources/fonts/AnonymousPro-Regular.ttf);
|
||||
src: url(../../../../resources/fonts/AnonymousPro-Regular.ttf),
|
||||
url(../../../../fonts/AnonymousPro-Regular.ttf),
|
||||
url(../../../../interface/resources/fonts/AnonymousPro-Regular.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: HiFi-Glyphs;
|
||||
src: url(../../../resources/fonts/hifi-glyphs.ttf),
|
||||
url(../../../fonts/hifi-glyphs.ttf),
|
||||
url(../../../interface/resources/fonts/hifi-glyphs.ttf);
|
||||
src: url(../../../../resources/fonts/hifi-glyphs.ttf),
|
||||
url(../../../../fonts/hifi-glyphs.ttf),
|
||||
url(../../../../interface/resources/fonts/hifi-glyphs.ttf);
|
||||
}
|
||||
|
||||
* {
|
||||
|
@ -1077,10 +1077,6 @@ input#dimension-rescale-button {
|
|||
input#reset-to-natural-dimensions {
|
||||
margin-right: 0;
|
||||
}
|
||||
input#preview-camera-button {
|
||||
margin-left: 1px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
#animation-fps {
|
||||
margin-top: 48px;
|
|
@ -10,314 +10,12 @@
|
|||
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="edit-style.css">
|
||||
<script src="list.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="css/edit-style.css">
|
||||
<script src="js/list.min.js"></script>
|
||||
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
<script type="text/javascript" src="eventBridgeLoader.js"></script>
|
||||
<script type="text/javascript" src="spinButtons.js"></script>
|
||||
<script>
|
||||
var entities = {};
|
||||
var selectedEntities = [];
|
||||
var currentSortColumn = 'type';
|
||||
var currentSortOrder = 'des';
|
||||
var entityList = null;
|
||||
var refreshEntityListTimer = null;
|
||||
const ASCENDING_STRING = '▾';
|
||||
const DESCENDING_STRING = '▴';
|
||||
const LOCKED_GLYPH = "";
|
||||
const VISIBLE_GLYPH = "";
|
||||
const DELETE = 46; // Key code for the delete key.
|
||||
const MAX_ITEMS = Number.MAX_VALUE; // Used to set the max length of the list of discovered entities.
|
||||
|
||||
debugPrint = function (message) {
|
||||
console.log(message);
|
||||
};
|
||||
|
||||
function loaded() {
|
||||
openEventBridge(function() {
|
||||
entityList = new List('entity-list', { valueNames: ['name', 'type', 'url', 'locked', 'visible'], page: MAX_ITEMS});
|
||||
entityList.clear();
|
||||
elEntityTable = document.getElementById("entity-table");
|
||||
elEntityTableBody = document.getElementById("entity-table-body");
|
||||
elRefresh = document.getElementById("refresh");
|
||||
elToggleLocked = document.getElementById("locked");
|
||||
elToggleVisible = document.getElementById("visible");
|
||||
elDelete = document.getElementById("delete");
|
||||
elTeleport = document.getElementById("teleport");
|
||||
elRadius = document.getElementById("radius");
|
||||
elFooter = document.getElementById("footer-text");
|
||||
elNoEntitiesMessage = document.getElementById("no-entities");
|
||||
elNoEntitiesRadius = document.getElementById("no-entities-radius");
|
||||
elEntityTableScroll = document.getElementById("entity-table-scroll");
|
||||
|
||||
document.getElementById("entity-name").onclick = function() {
|
||||
setSortColumn('name');
|
||||
};
|
||||
document.getElementById("entity-type").onclick = function() {
|
||||
setSortColumn('type');
|
||||
};
|
||||
document.getElementById("entity-url").onclick = function() {
|
||||
setSortColumn('url');
|
||||
};
|
||||
document.getElementById("entity-locked").onclick = function () {
|
||||
setSortColumn('locked');
|
||||
};
|
||||
document.getElementById("entity-visible").onclick = function () {
|
||||
setSortColumn('visible');
|
||||
};
|
||||
|
||||
function onRowClicked(clickEvent) {
|
||||
var id = this.dataset.entityId;
|
||||
var selection = [this.dataset.entityId];
|
||||
if (clickEvent.ctrlKey) {
|
||||
selection = selection.concat(selectedEntities);
|
||||
} else if (clickEvent.shiftKey && selectedEntities.length > 0) {
|
||||
var previousItemFound = -1;
|
||||
var clickedItemFound = -1;
|
||||
for (var entity in entityList.visibleItems) {
|
||||
if (clickedItemFound === -1 && this.dataset.entityId == entityList.visibleItems[entity].values().id) {
|
||||
clickedItemFound = entity;
|
||||
} else if(previousItemFound === -1 && selectedEntities[0] == entityList.visibleItems[entity].values().id) {
|
||||
previousItemFound = entity;
|
||||
}
|
||||
}
|
||||
if (previousItemFound !== -1 && clickedItemFound !== -1) {
|
||||
var betweenItems = [];
|
||||
var toItem = Math.max(previousItemFound, clickedItemFound);
|
||||
// skip first and last item in this loop, we add them to selection after the loop
|
||||
for (var i = (Math.min(previousItemFound, clickedItemFound) + 1); i < toItem; i++) {
|
||||
entityList.visibleItems[i].elm.className = 'selected';
|
||||
betweenItems.push(entityList.visibleItems[i].values().id);
|
||||
}
|
||||
if (previousItemFound > clickedItemFound) {
|
||||
// always make sure that we add the items in the right order
|
||||
betweenItems.reverse();
|
||||
}
|
||||
selection = selection.concat(betweenItems, selectedEntities);
|
||||
}
|
||||
}
|
||||
|
||||
selectedEntities = selection;
|
||||
|
||||
this.className = 'selected';
|
||||
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "selectionUpdate",
|
||||
focus: false,
|
||||
entityIds: selection,
|
||||
}));
|
||||
}
|
||||
|
||||
function onRowDoubleClicked() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "selectionUpdate",
|
||||
focus: true,
|
||||
entityIds: [this.dataset.entityId],
|
||||
}));
|
||||
}
|
||||
|
||||
function addEntity(id, name, type, url, locked, visible) {
|
||||
var urlParts = url.split('/');
|
||||
var filename = urlParts[urlParts.length - 1];
|
||||
|
||||
if (entities[id] === undefined) {
|
||||
entityList.add([{ id: id, name: name, type: type, url: filename, locked: locked, visible: visible }],
|
||||
function (items) {
|
||||
var currentElement = items[0].elm;
|
||||
var id = items[0]._values.id;
|
||||
entities[id] = {
|
||||
id: id,
|
||||
name: name,
|
||||
el: currentElement,
|
||||
item: items[0]
|
||||
};
|
||||
currentElement.setAttribute('id', 'entity_' + id);
|
||||
currentElement.setAttribute('title', url);
|
||||
currentElement.dataset.entityId = id;
|
||||
currentElement.onclick = onRowClicked;
|
||||
currentElement.ondblclick = onRowDoubleClicked;
|
||||
});
|
||||
|
||||
if (refreshEntityListTimer) {
|
||||
clearTimeout(refreshEntityListTimer);
|
||||
}
|
||||
refreshEntityListTimer = setTimeout(refreshEntityListObject, 50);
|
||||
} else {
|
||||
var item = entities[id].item;
|
||||
item.values({ name: name, url: filename, locked: locked, visible: visible });
|
||||
}
|
||||
}
|
||||
|
||||
function clearEntities() {
|
||||
entities = {};
|
||||
entityList.clear();
|
||||
}
|
||||
|
||||
var elSortOrder = {
|
||||
name: document.querySelector('#entity-name .sort-order'),
|
||||
type: document.querySelector('#entity-type .sort-order'),
|
||||
url: document.querySelector('#entity-url .sort-order'),
|
||||
locked: document.querySelector('#entity-locked .sort-order'),
|
||||
visible: document.querySelector('#entity-visible .sort-order')
|
||||
}
|
||||
function setSortColumn(column) {
|
||||
if (currentSortColumn == column) {
|
||||
currentSortOrder = currentSortOrder == "asc" ? "desc" : "asc";
|
||||
} else {
|
||||
elSortOrder[currentSortColumn].innerHTML = "";
|
||||
currentSortColumn = column;
|
||||
currentSortOrder = "asc";
|
||||
}
|
||||
elSortOrder[column].innerHTML = currentSortOrder == "asc" ? ASCENDING_STRING : DESCENDING_STRING;
|
||||
entityList.sort(currentSortColumn, { order: currentSortOrder });
|
||||
}
|
||||
setSortColumn('type');
|
||||
|
||||
function refreshEntities() {
|
||||
clearEntities();
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'refresh' }));
|
||||
}
|
||||
|
||||
function refreshEntityListObject() {
|
||||
refreshEntityListTimer = null;
|
||||
entityList.sort(currentSortColumn, { order: currentSortOrder });
|
||||
entityList.search(document.getElementById("filter").value);
|
||||
}
|
||||
|
||||
function updateSelectedEntities(selectedEntities) {
|
||||
var notFound = false;
|
||||
for (var id in entities) {
|
||||
entities[id].el.className = '';
|
||||
}
|
||||
for (var i = 0; i < selectedEntities.length; i++) {
|
||||
var id = selectedEntities[i];
|
||||
if (id in entities) {
|
||||
var entity = entities[id];
|
||||
entity.el.className = 'selected';
|
||||
} else {
|
||||
notFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedEntities.length > 1) {
|
||||
elFooter.firstChild.nodeValue = selectedEntities.length + " entities selected";
|
||||
} else if (selectedEntities.length === 1) {
|
||||
elFooter.firstChild.nodeValue = "1 entity selected";
|
||||
} else if (entityList.visibleItems.length === 1) {
|
||||
elFooter.firstChild.nodeValue = "1 entity found";
|
||||
} else {
|
||||
elFooter.firstChild.nodeValue = entityList.visibleItems.length + " entities found";
|
||||
}
|
||||
|
||||
// HACK: Fixes the footer and header text sometimes not displaying after adding or deleting entities.
|
||||
// The problem appears to be a bug in the Qt HTML/CSS rendering (Qt 5.5).
|
||||
document.getElementById("radius").focus();
|
||||
document.getElementById("radius").blur();
|
||||
|
||||
return notFound;
|
||||
}
|
||||
|
||||
elRefresh.onclick = function() {
|
||||
refreshEntities();
|
||||
}
|
||||
elToggleLocked.onclick = function () {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleLocked' }));
|
||||
}
|
||||
elToggleVisible.onclick = function () {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleVisible' }));
|
||||
}
|
||||
elTeleport.onclick = function () {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'teleport' }));
|
||||
}
|
||||
elDelete.onclick = function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
||||
refreshEntities();
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", function (keyDownEvent) {
|
||||
if (keyDownEvent.target.nodeName === "INPUT") {
|
||||
return;
|
||||
}
|
||||
var keyCode = keyDownEvent.keyCode;
|
||||
if (keyCode === DELETE) {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
||||
refreshEntities();
|
||||
}
|
||||
}, false);
|
||||
|
||||
elRadius.onchange = function () {
|
||||
elRadius.value = Math.max(elRadius.value, 0);
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'radius', radius: elRadius.value }));
|
||||
refreshEntities();
|
||||
elNoEntitiesRadius.firstChild.nodeValue = elRadius.value;
|
||||
}
|
||||
|
||||
if (window.EventBridge !== undefined) {
|
||||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
|
||||
if (data.type === "clearEntityList") {
|
||||
clearEntities();
|
||||
} else if (data.type == "selectionUpdate") {
|
||||
var notFound = updateSelectedEntities(data.selectedIDs);
|
||||
if (notFound) {
|
||||
refreshEntities();
|
||||
}
|
||||
} else if (data.type == "update") {
|
||||
var newEntities = data.entities;
|
||||
if (newEntities.length == 0) {
|
||||
elNoEntitiesMessage.style.display = "block";
|
||||
elFooter.firstChild.nodeValue = "0 entities found";
|
||||
} else {
|
||||
elNoEntitiesMessage.style.display = "none";
|
||||
for (var i = 0; i < newEntities.length; i++) {
|
||||
var id = newEntities[i].id;
|
||||
addEntity(id, newEntities[i].name, newEntities[i].type, newEntities[i].url,
|
||||
newEntities[i].locked ? LOCKED_GLYPH : null,
|
||||
newEntities[i].visible ? VISIBLE_GLYPH : null);
|
||||
}
|
||||
updateSelectedEntities(data.selectedIDs);
|
||||
resize();
|
||||
}
|
||||
}
|
||||
});
|
||||
setTimeout(refreshEntities, 1000);
|
||||
}
|
||||
|
||||
function resize() {
|
||||
// Take up available window space
|
||||
elEntityTableScroll.style.height = window.innerHeight - 207;
|
||||
|
||||
var tds = document.querySelectorAll("#entity-table-body tr:first-child td");
|
||||
var ths = document.querySelectorAll("#entity-table thead th");
|
||||
if (tds.length >= ths.length) {
|
||||
// Update the widths of the header cells to match the body
|
||||
for (var i = 0; i < ths.length; i++) {
|
||||
ths[i].width = tds[i].offsetWidth;
|
||||
}
|
||||
} else {
|
||||
// Reasonable widths if nothing is displayed
|
||||
var tableWidth = document.getElementById("entity-table").offsetWidth;
|
||||
ths[0].width = 0.16 * tableWidth;
|
||||
ths[1].width = 0.34 * tableWidth;
|
||||
ths[2].width = 0.34 * tableWidth;
|
||||
ths[3].width = 0.08 * tableWidth;
|
||||
ths[4].width = 0.08 * tableWidth;
|
||||
}
|
||||
};
|
||||
|
||||
window.onresize = resize;
|
||||
resize();
|
||||
});
|
||||
|
||||
augmentSpinButtons();
|
||||
|
||||
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
|
||||
document.addEventListener("contextmenu", function (event) {
|
||||
event.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript" src="js/eventBridgeLoader.js"></script>
|
||||
<script type="text/javascript" src="js/spinButtons.js"></script>
|
||||
<script type="text/javascript" src="js/entityList.js"></script>
|
||||
</head>
|
||||
<body onload='loaded();'>
|
||||
<div id="entity-list-header">
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,144 +10,14 @@
|
|||
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="edit-style.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/edit-style.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/colpick.css">
|
||||
<script src="jquery-2.1.4.min.js"></script>
|
||||
<script src="colpick.js"></script>
|
||||
<script src="js/jquery-2.1.4.min.js"></script>
|
||||
<script src="js/colpick.js"></script>
|
||||
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
<script type="text/javascript" src="eventBridgeLoader.js"></script>
|
||||
<script type="text/javascript" src="spinButtons.js"></script>
|
||||
<script>
|
||||
function loaded() {
|
||||
openEventBridge(function() {
|
||||
elPosY = document.getElementById("horiz-y");
|
||||
elMinorSpacing = document.getElementById("minor-spacing");
|
||||
elMajorSpacing = document.getElementById("major-spacing");
|
||||
elSnapToGrid = document.getElementById("snap-to-grid");
|
||||
elHorizontalGridVisible = document.getElementById("horiz-grid-visible");
|
||||
elMoveToSelection = document.getElementById("move-to-selection");
|
||||
elMoveToAvatar = document.getElementById("move-to-avatar");
|
||||
|
||||
if (window.EventBridge !== undefined) {
|
||||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
|
||||
if (data.origin) {
|
||||
var origin = data.origin;
|
||||
elPosY.value = origin.y;
|
||||
}
|
||||
|
||||
if (data.minorGridEvery !== undefined) {
|
||||
elMinorSpacing.value = data.minorGridEvery;
|
||||
}
|
||||
|
||||
if (data.majorGridEvery !== undefined) {
|
||||
elMajorSpacing.value = data.majorGridEvery;
|
||||
}
|
||||
|
||||
if (data.gridColor) {
|
||||
gridColor = data.gridColor;
|
||||
}
|
||||
|
||||
if (data.snapToGrid !== undefined) {
|
||||
elSnapToGrid.checked = data.snapToGrid == true;
|
||||
}
|
||||
|
||||
if (data.visible !== undefined) {
|
||||
elHorizontalGridVisible.checked = data.visible == true;
|
||||
}
|
||||
});
|
||||
|
||||
function emitUpdate() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "update",
|
||||
origin: {
|
||||
y: elPosY.value,
|
||||
},
|
||||
minorGridEvery: elMinorSpacing.value,
|
||||
majorGridEvery: elMajorSpacing.value,
|
||||
gridColor: gridColor,
|
||||
snapToGrid: elSnapToGrid.checked,
|
||||
visible: elHorizontalGridVisible.checked,
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
elPosY.addEventListener("change", emitUpdate);
|
||||
elMinorSpacing.addEventListener("change", emitUpdate);
|
||||
elMajorSpacing.addEventListener("change", emitUpdate);
|
||||
elSnapToGrid.addEventListener("change", emitUpdate);
|
||||
elHorizontalGridVisible.addEventListener("change", emitUpdate);
|
||||
|
||||
elMoveToAvatar.addEventListener("click", function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "action",
|
||||
action: "moveToAvatar",
|
||||
}));
|
||||
});
|
||||
elMoveToSelection.addEventListener("click", function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "action",
|
||||
action: "moveToSelection",
|
||||
}));
|
||||
});
|
||||
|
||||
var gridColor = { red: 255, green: 255, blue: 255 };
|
||||
var elColor = document.getElementById("grid-color");
|
||||
var elColorRed = document.getElementById("grid-color-red");
|
||||
var elColorGreen = document.getElementById("grid-color-green");
|
||||
var elColorBlue = document.getElementById("grid-color-blue");
|
||||
elColor.style.backgroundColor = "rgb(" + gridColor.red + "," + gridColor.green + "," + gridColor.blue + ")";
|
||||
elColorRed.value = gridColor.red;
|
||||
elColorGreen.value = gridColor.green;
|
||||
elColorBlue.value = gridColor.blue;
|
||||
|
||||
var colorChangeFunction = function () {
|
||||
gridColor = { red: elColorRed.value, green: elColorGreen.value, blue: elColorBlue.value };
|
||||
elColor.style.backgroundColor = "rgb(" + gridColor.red + "," + gridColor.green + "," + gridColor.blue + ")";
|
||||
emitUpdate();
|
||||
};
|
||||
|
||||
var colorPickFunction = function (red, green, blue) {
|
||||
elColorRed.value = red;
|
||||
elColorGreen.value = green;
|
||||
elColorBlue.value = blue;
|
||||
gridColor = { red: red, green: green, blue: blue };
|
||||
emitUpdate();
|
||||
}
|
||||
|
||||
elColorRed.addEventListener('change', colorChangeFunction);
|
||||
elColorGreen.addEventListener('change', colorChangeFunction);
|
||||
elColorBlue.addEventListener('change', colorChangeFunction);
|
||||
$('#grid-color').colpick({
|
||||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: { r: gridColor.red, g: gridColor.green, b: gridColor.blue },
|
||||
onShow: function (colpick) {
|
||||
$('#grid-color').attr('active', 'true');
|
||||
},
|
||||
onHide: function (colpick) {
|
||||
$('#grid-color').attr('active', 'false');
|
||||
},
|
||||
onSubmit: function (hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
$(el).colpickHide();
|
||||
colorPickFunction(rgb.r, rgb.g, rgb.b);
|
||||
}
|
||||
});
|
||||
|
||||
augmentSpinButtons();
|
||||
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
|
||||
});
|
||||
|
||||
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
|
||||
document.addEventListener("contextmenu", function (event) {
|
||||
event.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript" src="js/eventBridgeLoader.js"></script>
|
||||
<script type="text/javascript" src="js/spinButtons.js"></script>
|
||||
<script type="text/javascript" src="js/gridControls.js"></script>
|
||||
</head>
|
||||
<body onload='loaded();'>
|
||||
<div id="grid-section">
|
||||
|
|
310
scripts/system/html/js/entityList.js
Normal file
310
scripts/system/html/js/entityList.js
Normal file
|
@ -0,0 +1,310 @@
|
|||
// entityList.js
|
||||
//
|
||||
// Created by Ryan Huffman on 19 Nov 2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
var entities = {};
|
||||
var selectedEntities = [];
|
||||
var currentSortColumn = 'type';
|
||||
var currentSortOrder = 'des';
|
||||
var entityList = null;
|
||||
var refreshEntityListTimer = null;
|
||||
const ASCENDING_STRING = '▾';
|
||||
const DESCENDING_STRING = '▴';
|
||||
const LOCKED_GLYPH = "";
|
||||
const VISIBLE_GLYPH = "";
|
||||
const DELETE = 46; // Key code for the delete key.
|
||||
const MAX_ITEMS = Number.MAX_VALUE; // Used to set the max length of the list of discovered entities.
|
||||
|
||||
debugPrint = function (message) {
|
||||
console.log(message);
|
||||
};
|
||||
|
||||
function loaded() {
|
||||
openEventBridge(function() {
|
||||
entityList = new List('entity-list', { valueNames: ['name', 'type', 'url', 'locked', 'visible'], page: MAX_ITEMS});
|
||||
entityList.clear();
|
||||
elEntityTable = document.getElementById("entity-table");
|
||||
elEntityTableBody = document.getElementById("entity-table-body");
|
||||
elRefresh = document.getElementById("refresh");
|
||||
elToggleLocked = document.getElementById("locked");
|
||||
elToggleVisible = document.getElementById("visible");
|
||||
elDelete = document.getElementById("delete");
|
||||
elTeleport = document.getElementById("teleport");
|
||||
elRadius = document.getElementById("radius");
|
||||
elFooter = document.getElementById("footer-text");
|
||||
elNoEntitiesMessage = document.getElementById("no-entities");
|
||||
elNoEntitiesRadius = document.getElementById("no-entities-radius");
|
||||
elEntityTableScroll = document.getElementById("entity-table-scroll");
|
||||
|
||||
document.getElementById("entity-name").onclick = function() {
|
||||
setSortColumn('name');
|
||||
};
|
||||
document.getElementById("entity-type").onclick = function() {
|
||||
setSortColumn('type');
|
||||
};
|
||||
document.getElementById("entity-url").onclick = function() {
|
||||
setSortColumn('url');
|
||||
};
|
||||
document.getElementById("entity-locked").onclick = function () {
|
||||
setSortColumn('locked');
|
||||
};
|
||||
document.getElementById("entity-visible").onclick = function () {
|
||||
setSortColumn('visible');
|
||||
};
|
||||
|
||||
function onRowClicked(clickEvent) {
|
||||
var id = this.dataset.entityId;
|
||||
var selection = [this.dataset.entityId];
|
||||
if (clickEvent.ctrlKey) {
|
||||
selection = selection.concat(selectedEntities);
|
||||
} else if (clickEvent.shiftKey && selectedEntities.length > 0) {
|
||||
var previousItemFound = -1;
|
||||
var clickedItemFound = -1;
|
||||
for (var entity in entityList.visibleItems) {
|
||||
if (clickedItemFound === -1 && this.dataset.entityId == entityList.visibleItems[entity].values().id) {
|
||||
clickedItemFound = entity;
|
||||
} else if(previousItemFound === -1 && selectedEntities[0] == entityList.visibleItems[entity].values().id) {
|
||||
previousItemFound = entity;
|
||||
}
|
||||
}
|
||||
if (previousItemFound !== -1 && clickedItemFound !== -1) {
|
||||
var betweenItems = [];
|
||||
var toItem = Math.max(previousItemFound, clickedItemFound);
|
||||
// skip first and last item in this loop, we add them to selection after the loop
|
||||
for (var i = (Math.min(previousItemFound, clickedItemFound) + 1); i < toItem; i++) {
|
||||
entityList.visibleItems[i].elm.className = 'selected';
|
||||
betweenItems.push(entityList.visibleItems[i].values().id);
|
||||
}
|
||||
if (previousItemFound > clickedItemFound) {
|
||||
// always make sure that we add the items in the right order
|
||||
betweenItems.reverse();
|
||||
}
|
||||
selection = selection.concat(betweenItems, selectedEntities);
|
||||
}
|
||||
}
|
||||
|
||||
selectedEntities = selection;
|
||||
|
||||
this.className = 'selected';
|
||||
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "selectionUpdate",
|
||||
focus: false,
|
||||
entityIds: selection,
|
||||
}));
|
||||
}
|
||||
|
||||
function onRowDoubleClicked() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "selectionUpdate",
|
||||
focus: true,
|
||||
entityIds: [this.dataset.entityId],
|
||||
}));
|
||||
}
|
||||
|
||||
function addEntity(id, name, type, url, locked, visible) {
|
||||
var urlParts = url.split('/');
|
||||
var filename = urlParts[urlParts.length - 1];
|
||||
|
||||
if (entities[id] === undefined) {
|
||||
entityList.add([{ id: id, name: name, type: type, url: filename, locked: locked, visible: visible }],
|
||||
function (items) {
|
||||
var currentElement = items[0].elm;
|
||||
var id = items[0]._values.id;
|
||||
entities[id] = {
|
||||
id: id,
|
||||
name: name,
|
||||
el: currentElement,
|
||||
item: items[0]
|
||||
};
|
||||
currentElement.setAttribute('id', 'entity_' + id);
|
||||
currentElement.setAttribute('title', url);
|
||||
currentElement.dataset.entityId = id;
|
||||
currentElement.onclick = onRowClicked;
|
||||
currentElement.ondblclick = onRowDoubleClicked;
|
||||
});
|
||||
|
||||
if (refreshEntityListTimer) {
|
||||
clearTimeout(refreshEntityListTimer);
|
||||
}
|
||||
refreshEntityListTimer = setTimeout(refreshEntityListObject, 50);
|
||||
} else {
|
||||
var item = entities[id].item;
|
||||
item.values({ name: name, url: filename, locked: locked, visible: visible });
|
||||
}
|
||||
}
|
||||
|
||||
function clearEntities() {
|
||||
entities = {};
|
||||
entityList.clear();
|
||||
}
|
||||
|
||||
var elSortOrder = {
|
||||
name: document.querySelector('#entity-name .sort-order'),
|
||||
type: document.querySelector('#entity-type .sort-order'),
|
||||
url: document.querySelector('#entity-url .sort-order'),
|
||||
locked: document.querySelector('#entity-locked .sort-order'),
|
||||
visible: document.querySelector('#entity-visible .sort-order')
|
||||
}
|
||||
function setSortColumn(column) {
|
||||
if (currentSortColumn == column) {
|
||||
currentSortOrder = currentSortOrder == "asc" ? "desc" : "asc";
|
||||
} else {
|
||||
elSortOrder[currentSortColumn].innerHTML = "";
|
||||
currentSortColumn = column;
|
||||
currentSortOrder = "asc";
|
||||
}
|
||||
elSortOrder[column].innerHTML = currentSortOrder == "asc" ? ASCENDING_STRING : DESCENDING_STRING;
|
||||
entityList.sort(currentSortColumn, { order: currentSortOrder });
|
||||
}
|
||||
setSortColumn('type');
|
||||
|
||||
function refreshEntities() {
|
||||
clearEntities();
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'refresh' }));
|
||||
}
|
||||
|
||||
function refreshEntityListObject() {
|
||||
refreshEntityListTimer = null;
|
||||
entityList.sort(currentSortColumn, { order: currentSortOrder });
|
||||
entityList.search(document.getElementById("filter").value);
|
||||
}
|
||||
|
||||
function updateSelectedEntities(selectedEntities) {
|
||||
var notFound = false;
|
||||
for (var id in entities) {
|
||||
entities[id].el.className = '';
|
||||
}
|
||||
for (var i = 0; i < selectedEntities.length; i++) {
|
||||
var id = selectedEntities[i];
|
||||
if (id in entities) {
|
||||
var entity = entities[id];
|
||||
entity.el.className = 'selected';
|
||||
} else {
|
||||
notFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedEntities.length > 1) {
|
||||
elFooter.firstChild.nodeValue = selectedEntities.length + " entities selected";
|
||||
} else if (selectedEntities.length === 1) {
|
||||
elFooter.firstChild.nodeValue = "1 entity selected";
|
||||
} else if (entityList.visibleItems.length === 1) {
|
||||
elFooter.firstChild.nodeValue = "1 entity found";
|
||||
} else {
|
||||
elFooter.firstChild.nodeValue = entityList.visibleItems.length + " entities found";
|
||||
}
|
||||
|
||||
// HACK: Fixes the footer and header text sometimes not displaying after adding or deleting entities.
|
||||
// The problem appears to be a bug in the Qt HTML/CSS rendering (Qt 5.5).
|
||||
document.getElementById("radius").focus();
|
||||
document.getElementById("radius").blur();
|
||||
|
||||
return notFound;
|
||||
}
|
||||
|
||||
elRefresh.onclick = function() {
|
||||
refreshEntities();
|
||||
}
|
||||
elToggleLocked.onclick = function () {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleLocked' }));
|
||||
}
|
||||
elToggleVisible.onclick = function () {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleVisible' }));
|
||||
}
|
||||
elTeleport.onclick = function () {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'teleport' }));
|
||||
}
|
||||
elDelete.onclick = function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
||||
refreshEntities();
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", function (keyDownEvent) {
|
||||
if (keyDownEvent.target.nodeName === "INPUT") {
|
||||
return;
|
||||
}
|
||||
var keyCode = keyDownEvent.keyCode;
|
||||
if (keyCode === DELETE) {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
||||
refreshEntities();
|
||||
}
|
||||
}, false);
|
||||
|
||||
elRadius.onchange = function () {
|
||||
elRadius.value = Math.max(elRadius.value, 0);
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'radius', radius: elRadius.value }));
|
||||
refreshEntities();
|
||||
elNoEntitiesRadius.firstChild.nodeValue = elRadius.value;
|
||||
}
|
||||
|
||||
if (window.EventBridge !== undefined) {
|
||||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
|
||||
if (data.type === "clearEntityList") {
|
||||
clearEntities();
|
||||
} else if (data.type == "selectionUpdate") {
|
||||
var notFound = updateSelectedEntities(data.selectedIDs);
|
||||
if (notFound) {
|
||||
refreshEntities();
|
||||
}
|
||||
} else if (data.type == "update") {
|
||||
var newEntities = data.entities;
|
||||
if (newEntities.length == 0) {
|
||||
elNoEntitiesMessage.style.display = "block";
|
||||
elFooter.firstChild.nodeValue = "0 entities found";
|
||||
} else {
|
||||
elNoEntitiesMessage.style.display = "none";
|
||||
for (var i = 0; i < newEntities.length; i++) {
|
||||
var id = newEntities[i].id;
|
||||
addEntity(id, newEntities[i].name, newEntities[i].type, newEntities[i].url,
|
||||
newEntities[i].locked ? LOCKED_GLYPH : null,
|
||||
newEntities[i].visible ? VISIBLE_GLYPH : null);
|
||||
}
|
||||
updateSelectedEntities(data.selectedIDs);
|
||||
resize();
|
||||
}
|
||||
}
|
||||
});
|
||||
setTimeout(refreshEntities, 1000);
|
||||
}
|
||||
|
||||
function resize() {
|
||||
// Take up available window space
|
||||
elEntityTableScroll.style.height = window.innerHeight - 207;
|
||||
|
||||
var tds = document.querySelectorAll("#entity-table-body tr:first-child td");
|
||||
var ths = document.querySelectorAll("#entity-table thead th");
|
||||
if (tds.length >= ths.length) {
|
||||
// Update the widths of the header cells to match the body
|
||||
for (var i = 0; i < ths.length; i++) {
|
||||
ths[i].width = tds[i].offsetWidth;
|
||||
}
|
||||
} else {
|
||||
// Reasonable widths if nothing is displayed
|
||||
var tableWidth = document.getElementById("entity-table").offsetWidth;
|
||||
ths[0].width = 0.16 * tableWidth;
|
||||
ths[1].width = 0.34 * tableWidth;
|
||||
ths[2].width = 0.34 * tableWidth;
|
||||
ths[3].width = 0.08 * tableWidth;
|
||||
ths[4].width = 0.08 * tableWidth;
|
||||
}
|
||||
};
|
||||
|
||||
window.onresize = resize;
|
||||
resize();
|
||||
});
|
||||
|
||||
augmentSpinButtons();
|
||||
|
||||
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
|
||||
document.addEventListener("contextmenu", function (event) {
|
||||
event.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
|
1309
scripts/system/html/js/entityProperties.js
Normal file
1309
scripts/system/html/js/entityProperties.js
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue