mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 02:23:57 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into ambient-bis
This commit is contained in:
commit
48eb30936e
39 changed files with 1193 additions and 1134 deletions
|
@ -5423,9 +5423,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
entityScriptingInterface->setPacketSender(&_entityEditSender);
|
||||
entityScriptingInterface->setEntityTree(getEntities()->getTree());
|
||||
|
||||
// AvatarManager has some custom types
|
||||
AvatarManager::registerMetaTypes(scriptEngine);
|
||||
|
||||
// give the script engine to the RecordingScriptingInterface for its callbacks
|
||||
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(scriptEngine);
|
||||
|
||||
|
|
|
@ -13,9 +13,8 @@
|
|||
|
||||
#include "Camera.h"
|
||||
|
||||
#include <EntityItem.h>
|
||||
#include <EntityTypes.h>
|
||||
|
||||
// TODO: come up with a better name than "FancyCamera"
|
||||
class FancyCamera : public Camera {
|
||||
Q_OBJECT
|
||||
|
||||
|
|
|
@ -495,12 +495,15 @@ Menu::Menu() {
|
|||
qApp, SLOT(setActiveEyeTracker()));
|
||||
#endif
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false,
|
||||
avatarManager.data(), SLOT(setShouldShowReceiveStats(bool)));
|
||||
action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false);
|
||||
connect(action, &QAction::triggered, [this]{ Avatar::setShowReceiveStats(isOptionChecked(MenuOption::AvatarReceiveStats)); });
|
||||
action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowBoundingCollisionShapes, 0, false);
|
||||
connect(action, &QAction::triggered, [this]{ Avatar::setShowCollisionShapes(isOptionChecked(MenuOption::ShowBoundingCollisionShapes)); });
|
||||
action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowMyLookAtVectors, 0, false);
|
||||
connect(action, &QAction::triggered, [this]{ Avatar::setShowMyLookAtVectors(isOptionChecked(MenuOption::ShowMyLookAtVectors)); });
|
||||
action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowOtherLookAtVectors, 0, false);
|
||||
connect(action, &QAction::triggered, [this]{ Avatar::setShowOtherLookAtVectors(isOptionChecked(MenuOption::ShowOtherLookAtVectors)); });
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderMyLookAtVectors, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderOtherLookAtVectors, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::FixGaze, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawDefaultPose, 0, false,
|
||||
avatar.get(), SLOT(setEnableDebugDrawDefaultPose(bool)));
|
||||
|
|
|
@ -145,9 +145,6 @@ namespace MenuOption {
|
|||
const QString Quit = "Quit";
|
||||
const QString ReloadAllScripts = "Reload All Scripts";
|
||||
const QString ReloadContent = "Reload Content (Clears all caches)";
|
||||
const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes";
|
||||
const QString RenderMyLookAtVectors = "Show My Eye Vectors";
|
||||
const QString RenderOtherLookAtVectors = "Show Other Eye Vectors";
|
||||
const QString RenderMaxTextureMemory = "Maximum Texture Memory";
|
||||
const QString RenderMaxTextureAutomatic = "Automatic Texture Memory";
|
||||
const QString RenderMaxTexture4MB = "4 MB";
|
||||
|
@ -173,8 +170,11 @@ namespace MenuOption {
|
|||
const QString SendWrongDSConnectVersion = "Send wrong DS connect version";
|
||||
const QString SendWrongProtocolVersion = "Send wrong protocol version";
|
||||
const QString SetHomeLocation = "Set Home Location";
|
||||
const QString ShowDSConnectTable = "Show Domain Connection Timing";
|
||||
const QString ShowBordersEntityNodes = "Show Entity Nodes";
|
||||
const QString ShowBoundingCollisionShapes = "Show Bounding Collision Shapes";
|
||||
const QString ShowDSConnectTable = "Show Domain Connection Timing";
|
||||
const QString ShowMyLookAtVectors = "Show My Eye Vectors";
|
||||
const QString ShowOtherLookAtVectors = "Show Other Eye Vectors";
|
||||
const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats";
|
||||
const QString StandingHMDSensorMode = "Standing HMD Sensor Mode";
|
||||
const QString SimulateEyeTracking = "Simulate";
|
||||
|
|
|
@ -28,10 +28,8 @@
|
|||
#include <VariantMapToScriptValue.h>
|
||||
#include <DebugDraw.h>
|
||||
|
||||
#include "AvatarManager.h"
|
||||
#include "AvatarMotionState.h"
|
||||
#include "Camera.h"
|
||||
#include "Menu.h"
|
||||
#include "InterfaceLogging.h"
|
||||
#include "SceneScriptingInterface.h"
|
||||
#include "SoftAttachmentModel.h"
|
||||
|
@ -59,7 +57,6 @@ namespace render {
|
|||
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
|
||||
if (avatarPtr->isInitialized() && args) {
|
||||
PROFILE_RANGE_BATCH(*args->_batch, "renderAvatarPayload");
|
||||
// TODO AVATARS_RENDERER: remove need for qApp
|
||||
avatarPtr->render(args);
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +71,31 @@ namespace render {
|
|||
}
|
||||
}
|
||||
|
||||
static bool showReceiveStats = false;
|
||||
void Avatar::setShowReceiveStats(bool receiveStats) {
|
||||
showReceiveStats = receiveStats;
|
||||
}
|
||||
|
||||
static bool showMyLookAtVectors = false;
|
||||
void Avatar::setShowMyLookAtVectors(bool showMine) {
|
||||
showMyLookAtVectors = showMine;
|
||||
}
|
||||
|
||||
static bool showOtherLookAtVectors = false;
|
||||
void Avatar::setShowOtherLookAtVectors(bool showOthers) {
|
||||
showOtherLookAtVectors = showOthers;
|
||||
}
|
||||
|
||||
static bool showCollisionShapes = false;
|
||||
void Avatar::setShowCollisionShapes(bool render) {
|
||||
showCollisionShapes = render;
|
||||
}
|
||||
|
||||
static bool showNamesAboveHeads = false;
|
||||
void Avatar::setShowNamesAboveHeads(bool show) {
|
||||
showNamesAboveHeads = show;
|
||||
}
|
||||
|
||||
Avatar::Avatar(QThread* thread, RigPointer rig) :
|
||||
AvatarData(),
|
||||
_skeletonOffset(0.0f),
|
||||
|
@ -126,11 +148,6 @@ Avatar::~Avatar() {
|
|||
});
|
||||
}
|
||||
|
||||
if (_motionState) {
|
||||
delete _motionState;
|
||||
_motionState = nullptr;
|
||||
}
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_nameRectGeometryID);
|
||||
|
@ -350,7 +367,7 @@ void Avatar::simulate(float deltaTime, bool inView) {
|
|||
_smoothPositionTimer += deltaTime;
|
||||
if (_smoothPositionTimer < _smoothPositionTime) {
|
||||
AvatarData::setPosition(
|
||||
lerp(_smoothPositionInitial,
|
||||
lerp(_smoothPositionInitial,
|
||||
_smoothPositionTarget,
|
||||
easeInOutQuad(glm::clamp(_smoothPositionTimer / _smoothPositionTime, 0.0f, 1.0f)))
|
||||
);
|
||||
|
@ -363,7 +380,7 @@ void Avatar::simulate(float deltaTime, bool inView) {
|
|||
_smoothOrientationTimer += deltaTime;
|
||||
if (_smoothOrientationTimer < _smoothOrientationTime) {
|
||||
AvatarData::setOrientation(
|
||||
slerp(_smoothOrientationInitial,
|
||||
slerp(_smoothOrientationInitial,
|
||||
_smoothOrientationTarget,
|
||||
easeInOutQuad(glm::clamp(_smoothOrientationTimer / _smoothOrientationTime, 0.0f, 1.0f)))
|
||||
);
|
||||
|
@ -535,14 +552,7 @@ void Avatar::updateRenderItem(render::Transaction& transaction) {
|
|||
|
||||
void Avatar::postUpdate(float deltaTime) {
|
||||
|
||||
bool renderLookAtVectors;
|
||||
if (isMyAvatar()) {
|
||||
renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderMyLookAtVectors);
|
||||
} else {
|
||||
renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderOtherLookAtVectors);
|
||||
}
|
||||
|
||||
if (renderLookAtVectors) {
|
||||
if (isMyAvatar() ? showMyLookAtVectors : showOtherLookAtVectors) {
|
||||
const float EYE_RAY_LENGTH = 10.0;
|
||||
const glm::vec4 BLUE(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
const glm::vec4 RED(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
@ -583,7 +593,6 @@ void Avatar::render(RenderArgs* renderArgs) {
|
|||
bool havePosition, haveRotation;
|
||||
|
||||
if (_handState & LEFT_HAND_POINTING_FLAG) {
|
||||
|
||||
if (_handState & IS_FINGER_POINTING_FLAG) {
|
||||
int leftIndexTip = getJointIndex("LeftHandIndex4");
|
||||
int leftIndexTipJoint = getJointIndex("LeftHandIndex3");
|
||||
|
@ -636,44 +645,25 @@ void Avatar::render(RenderArgs* renderArgs) {
|
|||
return;
|
||||
}
|
||||
|
||||
glm::vec3 toTarget = frustum.getPosition() - getPosition();
|
||||
float distanceToTarget = glm::length(toTarget);
|
||||
fixupModelsInScene(renderArgs->_scene);
|
||||
|
||||
{
|
||||
fixupModelsInScene(renderArgs->_scene);
|
||||
|
||||
if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) {
|
||||
// add local lights
|
||||
const float BASE_LIGHT_DISTANCE = 2.0f;
|
||||
const float LIGHT_FALLOFF_RADIUS = 0.01f;
|
||||
const float LIGHT_EXPONENT = 1.0f;
|
||||
const float LIGHT_CUTOFF = glm::radians(80.0f);
|
||||
float distance = BASE_LIGHT_DISTANCE * getUniformScale();
|
||||
glm::vec3 position = _skeletonModel->getTranslation();
|
||||
glm::quat orientation = getOrientation();
|
||||
foreach (const AvatarManager::LocalLight& light, DependencyManager::get<AvatarManager>()->getLocalLights()) {
|
||||
glm::vec3 direction = orientation * light.direction;
|
||||
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position - direction * distance,
|
||||
distance * 2.0f, light.color, 0.5f, LIGHT_FALLOFF_RADIUS, orientation, LIGHT_EXPONENT, LIGHT_CUTOFF);
|
||||
}
|
||||
}
|
||||
|
||||
bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes);
|
||||
if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel->isRenderable()) {
|
||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes");
|
||||
const float BOUNDING_SHAPE_ALPHA = 0.7f;
|
||||
_skeletonModel->renderBoundingCollisionShapes(*renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA);
|
||||
}
|
||||
if (showCollisionShapes && shouldRenderHead(renderArgs) && _skeletonModel->isRenderable()) {
|
||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes");
|
||||
const float BOUNDING_SHAPE_ALPHA = 0.7f;
|
||||
_skeletonModel->renderBoundingCollisionShapes(*renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA);
|
||||
}
|
||||
|
||||
const float DISPLAYNAME_DISTANCE = 20.0f;
|
||||
setShowDisplayName(distanceToTarget < DISPLAYNAME_DISTANCE);
|
||||
|
||||
if (!isMyAvatar() || renderArgs->_cameraMode != (int8_t)CAMERA_MODE_FIRST_PERSON) {
|
||||
auto& frustum = renderArgs->getViewFrustum();
|
||||
auto textPosition = getDisplayNamePosition();
|
||||
if (frustum.pointIntersectsFrustum(textPosition)) {
|
||||
renderDisplayName(batch, frustum, textPosition);
|
||||
if (showReceiveStats || showNamesAboveHeads) {
|
||||
glm::vec3 toTarget = frustum.getPosition() - getPosition();
|
||||
float distanceToTarget = glm::length(toTarget);
|
||||
const float DISPLAYNAME_DISTANCE = 20.0f;
|
||||
updateDisplayNameAlpha(distanceToTarget < DISPLAYNAME_DISTANCE);
|
||||
if (!isMyAvatar() || renderArgs->_cameraMode != (int8_t)CAMERA_MODE_FIRST_PERSON) {
|
||||
auto& frustum = renderArgs->getViewFrustum();
|
||||
auto textPosition = getDisplayNamePosition();
|
||||
if (frustum.pointIntersectsFrustum(textPosition)) {
|
||||
renderDisplayName(batch, frustum, textPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -829,7 +819,7 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& view, const g
|
|||
void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition) const {
|
||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__);
|
||||
|
||||
bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar();
|
||||
bool shouldShowReceiveStats = showReceiveStats && !isMyAvatar();
|
||||
|
||||
// If we have nothing to draw, or it's totally transparent, or it's too close or behind the camera, return
|
||||
static const float CLIP_DISTANCE = 0.2f;
|
||||
|
@ -1200,8 +1190,8 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
|
||||
const float MOVE_DISTANCE_THRESHOLD = 0.001f;
|
||||
_moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD;
|
||||
if (_moving && _motionState) {
|
||||
_motionState->addDirtyFlags(Simulation::DIRTY_POSITION);
|
||||
if (_moving) {
|
||||
addPhysicsFlags(Simulation::DIRTY_POSITION);
|
||||
}
|
||||
if (_moving || _hasNewJointData) {
|
||||
locationChanged();
|
||||
|
@ -1284,8 +1274,8 @@ float Avatar::getPelvisFloatingHeight() const {
|
|||
return -_skeletonModel->getBindExtents().minimum.y;
|
||||
}
|
||||
|
||||
void Avatar::setShowDisplayName(bool showDisplayName) {
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::NamesAboveHeads)) {
|
||||
void Avatar::updateDisplayNameAlpha(bool showDisplayName) {
|
||||
if (!(showNamesAboveHeads || showReceiveStats)) {
|
||||
_displayNameAlpha = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
@ -1323,14 +1313,18 @@ void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) {
|
|||
radius = halfExtents.x;
|
||||
}
|
||||
|
||||
void Avatar::setMotionState(AvatarMotionState* motionState) {
|
||||
_motionState = motionState;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void Avatar::rebuildCollisionShape() {
|
||||
if (_motionState) {
|
||||
_motionState->addDirtyFlags(Simulation::DIRTY_SHAPE);
|
||||
addPhysicsFlags(Simulation::DIRTY_SHAPE);
|
||||
}
|
||||
|
||||
void Avatar::setPhysicsCallback(AvatarPhysicsCallback cb) {
|
||||
_physicsCallback = cb;
|
||||
}
|
||||
|
||||
void Avatar::addPhysicsFlags(uint32_t flags) {
|
||||
if (_physicsCallback) {
|
||||
_physicsCallback(flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1493,16 +1487,16 @@ QList<QVariant> Avatar::getSkeleton() {
|
|||
|
||||
void Avatar::addToScene(AvatarSharedPointer myHandle, const render::ScenePointer& scene) {
|
||||
if (scene) {
|
||||
render::Transaction transaction;
|
||||
auto nodelist = DependencyManager::get<NodeList>();
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()
|
||||
&& !nodelist->isIgnoringNode(getSessionUUID())
|
||||
&& !nodelist->isRadiusIgnoringNode(getSessionUUID())) {
|
||||
render::Transaction transaction;
|
||||
addToScene(myHandle, scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
} else {
|
||||
qCWarning(interfaceapp) << "AvatarManager::addAvatar() : Unexpected null scene, possibly during application shutdown";
|
||||
qCWarning(interfaceapp) << "Avatar::addAvatar() : Unexpected null scene, possibly during application shutdown";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#ifndef hifi_Avatar_h
|
||||
#define hifi_Avatar_h
|
||||
|
||||
#include <functional>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
|
@ -48,9 +49,10 @@ enum ScreenTintLayer {
|
|||
NUM_SCREEN_TINT_LAYERS
|
||||
};
|
||||
|
||||
class AvatarMotionState;
|
||||
class Texture;
|
||||
|
||||
using AvatarPhysicsCallback = std::function<void(uint32_t)>;
|
||||
|
||||
class Avatar : public AvatarData {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -66,6 +68,12 @@ class Avatar : public AvatarData {
|
|||
Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset)
|
||||
|
||||
public:
|
||||
static void setShowReceiveStats(bool receiveStats);
|
||||
static void setShowMyLookAtVectors(bool showMine);
|
||||
static void setShowOtherLookAtVectors(bool showOthers);
|
||||
static void setShowCollisionShapes(bool render);
|
||||
static void setShowNamesAboveHeads(bool show);
|
||||
|
||||
explicit Avatar(QThread* thread, RigPointer rig = nullptr);
|
||||
~Avatar();
|
||||
|
||||
|
@ -148,7 +156,7 @@ public:
|
|||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
|
||||
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
|
||||
|
||||
void setShowDisplayName(bool showDisplayName);
|
||||
void updateDisplayNameAlpha(bool showDisplayName);
|
||||
virtual void setSessionDisplayName(const QString& sessionDisplayName) override { }; // no-op
|
||||
|
||||
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
|
||||
|
@ -185,8 +193,6 @@ public:
|
|||
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
|
||||
void getCapsule(glm::vec3& start, glm::vec3& end, float& radius);
|
||||
|
||||
AvatarMotionState* getMotionState() { return _motionState; }
|
||||
|
||||
using SpatiallyNestable::setPosition;
|
||||
virtual void setPosition(const glm::vec3& position) override;
|
||||
using SpatiallyNestable::setOrientation;
|
||||
|
@ -238,6 +244,17 @@ public:
|
|||
|
||||
return (lerpValue*(4.0f - 2.0f * lerpValue) - 1.0f);
|
||||
}
|
||||
float getBoundingRadius() const;
|
||||
|
||||
void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene);
|
||||
void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene);
|
||||
bool isInScene() const { return render::Item::isValidID(_renderItemID); }
|
||||
bool isMoving() const { return _moving; }
|
||||
|
||||
//void setMotionState(AvatarMotionState* motionState);
|
||||
void setPhysicsCallback(AvatarPhysicsCallback cb);
|
||||
void addPhysicsFlags(uint32_t flags);
|
||||
bool isInPhysicsSimulation() const { return _physicsCallback != nullptr; }
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -251,7 +268,6 @@ public slots:
|
|||
void setModelURLFinished(bool success);
|
||||
|
||||
protected:
|
||||
friend class AvatarManager;
|
||||
|
||||
const float SMOOTH_TIME_POSITION = 0.125f;
|
||||
const float SMOOTH_TIME_ORIENTATION = 0.075f;
|
||||
|
@ -260,8 +276,6 @@ protected:
|
|||
QString _empty{};
|
||||
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
|
||||
|
||||
void setMotionState(AvatarMotionState* motionState);
|
||||
|
||||
SkeletonModelPointer _skeletonModel;
|
||||
glm::vec3 _skeletonOffset;
|
||||
std::vector<std::shared_ptr<Model>> _attachmentModels;
|
||||
|
@ -315,10 +329,6 @@ protected:
|
|||
ThreadSafeValueCache<glm::vec3> _rightPalmPositionCache { glm::vec3() };
|
||||
ThreadSafeValueCache<glm::quat> _rightPalmRotationCache { glm::quat() };
|
||||
|
||||
void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene);
|
||||
void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene);
|
||||
bool isInScene() const { return render::Item::isValidID(_renderItemID); }
|
||||
|
||||
// Some rate tracking support
|
||||
RateCounter<> _simulationRate;
|
||||
RateCounter<> _simulationInViewRate;
|
||||
|
@ -354,13 +364,15 @@ private:
|
|||
bool _isLookAtTarget { false };
|
||||
bool _isAnimatingScale { false };
|
||||
|
||||
float getBoundingRadius() const;
|
||||
|
||||
static int _jointConesID;
|
||||
|
||||
int _voiceSphereID;
|
||||
|
||||
AvatarMotionState* _motionState = nullptr;
|
||||
AvatarPhysicsCallback _physicsCallback { nullptr };
|
||||
|
||||
float _displayNameTargetAlpha { 1.0f };
|
||||
float _displayNameAlpha { 1.0f };
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_Avatar_h
|
||||
|
|
|
@ -50,23 +50,6 @@ static const quint64 MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS = USECS_PER_SECOND /
|
|||
// We add _myAvatar into the hash with all the other AvatarData, and we use the default NULL QUid as the key.
|
||||
const QUuid MY_AVATAR_KEY; // NULL key
|
||||
|
||||
static QScriptValue localLightToScriptValue(QScriptEngine* engine, const AvatarManager::LocalLight& light) {
|
||||
QScriptValue object = engine->newObject();
|
||||
object.setProperty("direction", vec3toScriptValue(engine, light.direction));
|
||||
object.setProperty("color", vec3toScriptValue(engine, light.color));
|
||||
return object;
|
||||
}
|
||||
|
||||
static void localLightFromScriptValue(const QScriptValue& value, AvatarManager::LocalLight& light) {
|
||||
vec3FromScriptValue(value.property("direction"), light.direction);
|
||||
vec3FromScriptValue(value.property("color"), light.color);
|
||||
}
|
||||
|
||||
void AvatarManager::registerMetaTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, localLightToScriptValue, localLightFromScriptValue);
|
||||
qScriptRegisterSequenceMetaType<QVector<AvatarManager::LocalLight> >(engine);
|
||||
}
|
||||
|
||||
AvatarManager::AvatarManager(QObject* parent) :
|
||||
_avatarsToFade(),
|
||||
_myAvatar(std::make_shared<MyAvatar>(qApp->thread(), std::make_shared<Rig>()))
|
||||
|
@ -91,6 +74,7 @@ AvatarManager::AvatarManager(QObject* parent) :
|
|||
}
|
||||
|
||||
AvatarManager::~AvatarManager() {
|
||||
assert(_motionStates.empty());
|
||||
}
|
||||
|
||||
void AvatarManager::init() {
|
||||
|
@ -145,10 +129,9 @@ float AvatarManager::getAvatarUpdateRate(const QUuid& sessionID, const QString&
|
|||
|
||||
float AvatarManager::getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName) const {
|
||||
auto avatar = std::static_pointer_cast<Avatar>(getAvatarBySessionID(sessionID));
|
||||
return avatar ? avatar->getSimulationRate(rateName) : 0.0f;
|
||||
return avatar ? avatar->getSimulationRate(rateName) : 0.0f;
|
||||
}
|
||||
|
||||
|
||||
void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||
// lock the hash for read to check the size
|
||||
QReadLocker lock(&_hashLock);
|
||||
|
@ -200,16 +183,15 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
if (_shouldRender) {
|
||||
avatar->ensureInScene(avatar, qApp->getMain3DScene());
|
||||
}
|
||||
if (!avatar->getMotionState()) {
|
||||
if (!avatar->isInPhysicsSimulation()) {
|
||||
ShapeInfo shapeInfo;
|
||||
avatar->computeShapeInfo(shapeInfo);
|
||||
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
||||
if (shape) {
|
||||
// don't add to the simulation now, instead put it on a list to be added later
|
||||
AvatarMotionState* motionState = new AvatarMotionState(avatar.get(), shape);
|
||||
avatar->setMotionState(motionState);
|
||||
AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
|
||||
avatar->setPhysicsCallback([=] (uint32_t flags) { motionState->addDirtyFlags(flags); });
|
||||
_motionStates.insert(avatar.get(), motionState);
|
||||
_motionStatesToAddToPhysics.insert(motionState);
|
||||
_motionStatesThatMightUpdate.insert(motionState);
|
||||
}
|
||||
}
|
||||
avatar->animateScaleChanges(deltaTime);
|
||||
|
@ -294,30 +276,24 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
|
|||
const float MIN_FADE_SCALE = MIN_AVATAR_SCALE;
|
||||
|
||||
QReadLocker locker(&_hashLock);
|
||||
QVector<AvatarSharedPointer>::iterator itr = _avatarsToFade.begin();
|
||||
while (itr != _avatarsToFade.end()) {
|
||||
auto avatar = std::static_pointer_cast<Avatar>(*itr);
|
||||
QVector<AvatarSharedPointer>::iterator avatarItr = _avatarsToFade.begin();
|
||||
while (avatarItr != _avatarsToFade.end()) {
|
||||
auto avatar = std::static_pointer_cast<Avatar>(*avatarItr);
|
||||
avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE);
|
||||
avatar->animateScaleChanges(deltaTime);
|
||||
if (avatar->getTargetScale() <= MIN_FADE_SCALE) {
|
||||
// fading to zero is such a rare event we push unique transaction for each one
|
||||
// fading to zero is such a rare event we push a unique transaction for each
|
||||
if (avatar->isInScene()) {
|
||||
const render::ScenePointer& scene = qApp->getMain3DScene();
|
||||
render::Transaction transaction;
|
||||
avatar->removeFromScene(*itr, scene, transaction);
|
||||
avatar->removeFromScene(*avatarItr, scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
// only remove from _avatarsToFade if we're sure its motionState has been removed from PhysicsEngine
|
||||
if (_motionStatesToRemoveFromPhysics.empty()) {
|
||||
itr = _avatarsToFade.erase(itr);
|
||||
} else {
|
||||
++itr;
|
||||
}
|
||||
avatarItr = _avatarsToFade.erase(avatarItr);
|
||||
} else {
|
||||
const bool inView = true; // HACK
|
||||
avatar->simulate(deltaTime, inView);
|
||||
++itr;
|
||||
++avatarItr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -329,15 +305,15 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() {
|
|||
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
|
||||
AvatarHashMap::handleRemovedAvatar(removedAvatar, removalReason);
|
||||
|
||||
// removedAvatar is a shared pointer to an AvatarData but we need to get to the derived Avatar
|
||||
// class in this context so we can call methods that don't exist at the base class.
|
||||
// remove from physics
|
||||
auto avatar = std::static_pointer_cast<Avatar>(removedAvatar);
|
||||
|
||||
AvatarMotionState* motionState = avatar->getMotionState();
|
||||
if (motionState) {
|
||||
_motionStatesThatMightUpdate.remove(motionState);
|
||||
avatar->setPhysicsCallback(nullptr);
|
||||
AvatarMotionStateMap::iterator itr = _motionStates.find(avatar.get());
|
||||
if (itr != _motionStates.end()) {
|
||||
AvatarMotionState* motionState = *itr;
|
||||
_motionStatesToAddToPhysics.remove(motionState);
|
||||
_motionStatesToRemoveFromPhysics.push_back(motionState);
|
||||
_motionStates.erase(itr);
|
||||
}
|
||||
|
||||
if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) {
|
||||
|
@ -373,11 +349,15 @@ void AvatarManager::clearOtherAvatars() {
|
|||
++avatarIterator;
|
||||
}
|
||||
}
|
||||
assert(scene);
|
||||
scene->enqueueTransaction(transaction);
|
||||
_myAvatar->clearLookAtTargetAvatar();
|
||||
}
|
||||
|
||||
void AvatarManager::deleteAllAvatars() {
|
||||
assert(_motionStates.empty()); // should have called clearOtherAvatars() before getting here
|
||||
deleteMotionStates();
|
||||
|
||||
QReadLocker locker(&_hashLock);
|
||||
AvatarHash::iterator avatarIterator = _avatarHash.begin();
|
||||
while (avatarIterator != _avatarHash.end()) {
|
||||
|
@ -387,27 +367,18 @@ void AvatarManager::deleteAllAvatars() {
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarManager::setLocalLights(const QVector<AvatarManager::LocalLight>& localLights) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setLocalLights", Q_ARG(const QVector<AvatarManager::LocalLight>&, localLights));
|
||||
return;
|
||||
void AvatarManager::deleteMotionStates() {
|
||||
// delete motionstates that were removed from physics last frame
|
||||
for (auto state : _motionStatesToDelete) {
|
||||
delete state;
|
||||
}
|
||||
_localLights = localLights;
|
||||
}
|
||||
|
||||
QVector<AvatarManager::LocalLight> AvatarManager::getLocalLights() const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QVector<AvatarManager::LocalLight> result;
|
||||
QMetaObject::invokeMethod(const_cast<AvatarManager*>(this), "getLocalLights", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVector<AvatarManager::LocalLight>, result));
|
||||
return result;
|
||||
}
|
||||
return _localLights;
|
||||
_motionStatesToDelete.clear();
|
||||
}
|
||||
|
||||
void AvatarManager::getObjectsToRemoveFromPhysics(VectorOfMotionStates& result) {
|
||||
result.clear();
|
||||
result.swap(_motionStatesToRemoveFromPhysics);
|
||||
deleteMotionStates();
|
||||
result = _motionStatesToRemoveFromPhysics;
|
||||
_motionStatesToDelete.swap(_motionStatesToRemoveFromPhysics);
|
||||
}
|
||||
|
||||
void AvatarManager::getObjectsToAddToPhysics(VectorOfMotionStates& result) {
|
||||
|
@ -420,10 +391,12 @@ void AvatarManager::getObjectsToAddToPhysics(VectorOfMotionStates& result) {
|
|||
|
||||
void AvatarManager::getObjectsToChange(VectorOfMotionStates& result) {
|
||||
result.clear();
|
||||
for (auto state : _motionStatesThatMightUpdate) {
|
||||
if (state->_dirtyFlags > 0) {
|
||||
result.push_back(state);
|
||||
AvatarMotionStateMap::iterator motionStateItr = _motionStates.begin();
|
||||
while (motionStateItr != _motionStates.end()) {
|
||||
if ((*motionStateItr)->getIncomingDirtyFlags() != 0) {
|
||||
result.push_back(*motionStateItr);
|
||||
}
|
||||
++motionStateItr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,18 +62,6 @@ public:
|
|||
void clearOtherAvatars();
|
||||
void deleteAllAvatars();
|
||||
|
||||
bool shouldShowReceiveStats() const { return _shouldShowReceiveStats; }
|
||||
|
||||
class LocalLight {
|
||||
public:
|
||||
glm::vec3 color;
|
||||
glm::vec3 direction;
|
||||
};
|
||||
|
||||
Q_INVOKABLE void setLocalLights(const QVector<AvatarManager::LocalLight>& localLights);
|
||||
Q_INVOKABLE QVector<AvatarManager::LocalLight> getLocalLights() const;
|
||||
|
||||
|
||||
void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates);
|
||||
void getObjectsToAddToPhysics(VectorOfMotionStates& motionStates);
|
||||
void getObjectsToChange(VectorOfMotionStates& motionStates);
|
||||
|
@ -95,7 +83,6 @@ public:
|
|||
float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); }
|
||||
|
||||
public slots:
|
||||
void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; }
|
||||
void updateAvatarRenderStatus(bool shouldRenderAvatars);
|
||||
|
||||
private:
|
||||
|
@ -105,21 +92,20 @@ private:
|
|||
void simulateAvatarFades(float deltaTime);
|
||||
|
||||
AvatarSharedPointer newSharedAvatar() override;
|
||||
void deleteMotionStates();
|
||||
void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
|
||||
|
||||
QVector<AvatarSharedPointer> _avatarsToFade;
|
||||
|
||||
QSet<AvatarMotionState*> _motionStatesThatMightUpdate;
|
||||
using AvatarMotionStateMap = QMap<Avatar*, AvatarMotionState*>;
|
||||
AvatarMotionStateMap _motionStates;
|
||||
VectorOfMotionStates _motionStatesToRemoveFromPhysics;
|
||||
VectorOfMotionStates _motionStatesToDelete;
|
||||
SetOfMotionStates _motionStatesToAddToPhysics;
|
||||
|
||||
std::shared_ptr<MyAvatar> _myAvatar;
|
||||
quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate.
|
||||
|
||||
QVector<AvatarManager::LocalLight> _localLights;
|
||||
|
||||
bool _shouldShowReceiveStats = false;
|
||||
|
||||
std::list<QPointer<AudioInjector>> _collisionInjectors;
|
||||
|
||||
RateCounter<> _myAvatarSendRate;
|
||||
|
@ -129,7 +115,4 @@ private:
|
|||
bool _shouldRender { true };
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(AvatarManager::LocalLight)
|
||||
Q_DECLARE_METATYPE(QVector<AvatarManager::LocalLight>)
|
||||
|
||||
#endif // hifi_AvatarManager_h
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "AvatarMotionState.h"
|
||||
#include "BulletUtil.h"
|
||||
|
||||
AvatarMotionState::AvatarMotionState(Avatar* avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
|
||||
AvatarMotionState::AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
|
||||
assert(_avatar);
|
||||
_type = MOTIONSTATE_TYPE_AVATAR;
|
||||
if (_shape) {
|
||||
|
@ -49,7 +49,7 @@ PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const {
|
|||
// virtual and protected
|
||||
const btCollisionShape* AvatarMotionState::computeNewShape() {
|
||||
ShapeInfo shapeInfo;
|
||||
_avatar->computeShapeInfo(shapeInfo);
|
||||
std::static_pointer_cast<Avatar>(_avatar)->computeShapeInfo(shapeInfo);
|
||||
return getShapeManager()->getShape(shapeInfo);
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ glm::vec3 AvatarMotionState::getObjectAngularVelocity() const {
|
|||
|
||||
// virtual
|
||||
glm::vec3 AvatarMotionState::getObjectGravity() const {
|
||||
return _avatar->getAcceleration();
|
||||
return std::static_pointer_cast<Avatar>(_avatar)->getAcceleration();
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
|
|
@ -20,7 +20,7 @@ class Avatar;
|
|||
|
||||
class AvatarMotionState : public ObjectMotionState {
|
||||
public:
|
||||
AvatarMotionState(Avatar* avatar, const btCollisionShape* shape);
|
||||
AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape);
|
||||
|
||||
virtual PhysicsMotionType getMotionType() const override { return _motionType; }
|
||||
|
||||
|
@ -74,11 +74,7 @@ protected:
|
|||
virtual bool isReadyToComputeShape() const override { return true; }
|
||||
virtual const btCollisionShape* computeNewShape() override;
|
||||
|
||||
// The AvatarMotionState keeps a RAW backpointer to its Avatar because all AvatarMotionState
|
||||
// instances are "owned" by their corresponding Avatar instance and are deleted in the Avatar dtor.
|
||||
// In other words, it is impossible for the Avatar to be deleted out from under its MotionState.
|
||||
// In conclusion: weak pointer shennanigans would be pure overhead.
|
||||
Avatar* _avatar; // do NOT use smartpointer here, no need for weakpointer
|
||||
AvatarSharedPointer _avatar;
|
||||
|
||||
uint32_t _dirtyFlags;
|
||||
};
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <PerfStat.h>
|
||||
|
||||
#include "CauterizedMeshPartPayload.h"
|
||||
#include "RenderUtilsLogging.h"
|
||||
|
||||
|
||||
CauterizedModel::CauterizedModel(RigPointer rig, QObject* parent) :
|
||||
|
@ -51,7 +52,7 @@ void CauterizedModel::createVisibleRenderItemSet() {
|
|||
|
||||
// all of our mesh vectors must match in size
|
||||
if ((int)meshes.size() != _meshStates.size()) {
|
||||
qCDebug(renderlogging) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
|
||||
qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ void setupPreferences() {
|
|||
static const QString SNAPSHOTS { "Snapshots" };
|
||||
{
|
||||
auto getter = []()->QString { return Snapshot::snapshotsLocation.get(); };
|
||||
auto setter = [](const QString& value) { Snapshot::snapshotsLocation.set(value); };
|
||||
auto setter = [](const QString& value) { Snapshot::snapshotsLocation.set(value); emit DependencyManager::get<Snapshot>()->snapshotLocationSet(value); };
|
||||
auto preference = new BrowsePreference(SNAPSHOTS, "Put my snapshots here", getter, setter);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,9 @@ public:
|
|||
static Setting::Handle<QString> snapshotsLocation;
|
||||
static void uploadSnapshot(const QString& filename, const QUrl& href = QUrl(""));
|
||||
|
||||
signals:
|
||||
void snapshotLocationSet(const QString& value);
|
||||
|
||||
public slots:
|
||||
Q_INVOKABLE QString getSnapshotsLocation();
|
||||
Q_INVOKABLE void setSnapshotsLocation(const QString& location);
|
||||
|
|
|
@ -63,8 +63,6 @@ AvatarData::AvatarData() :
|
|||
_keyState(NO_KEY_DOWN),
|
||||
_forceFaceTrackerConnected(false),
|
||||
_headData(NULL),
|
||||
_displayNameTargetAlpha(1.0f),
|
||||
_displayNameAlpha(1.0f),
|
||||
_errorLogExpiry(0),
|
||||
_owningAvatarMixer(),
|
||||
_targetVelocity(0.0f)
|
||||
|
|
|
@ -692,9 +692,6 @@ protected:
|
|||
QString _sessionDisplayName { };
|
||||
QUrl cannonicalSkeletonModelURL(const QUrl& empty) const;
|
||||
|
||||
float _displayNameTargetAlpha;
|
||||
float _displayNameAlpha;
|
||||
|
||||
QHash<QString, int> _jointIndices; ///< 1-based, since zero is returned for missing keys
|
||||
QStringList _jointNames; ///< in order of depth-first traversal
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ protected:
|
|||
bool _hasInternalKinematicChanges { false };
|
||||
};
|
||||
|
||||
typedef QSet<ObjectMotionState*> SetOfMotionStates;
|
||||
typedef QVector<ObjectMotionState*> VectorOfMotionStates;
|
||||
using SetOfMotionStates = QSet<ObjectMotionState*>;
|
||||
using VectorOfMotionStates = QVector<ObjectMotionState*>;
|
||||
|
||||
#endif // hifi_ObjectMotionState_h
|
||||
|
|
|
@ -220,6 +220,7 @@ void PhysicsEngine::removeObjects(const SetOfMotionStates& objects) {
|
|||
body->setMotionState(nullptr);
|
||||
delete body;
|
||||
}
|
||||
object->clearIncomingDirtyFlags();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ public:
|
|||
void* _b; // ObjectMotionState pointer
|
||||
};
|
||||
|
||||
typedef std::map<ContactKey, ContactInfo> ContactMap;
|
||||
typedef std::vector<Collision> CollisionEvents;
|
||||
using ContactMap = std::map<ContactKey, ContactInfo>;
|
||||
using CollisionEvents = std::vector<Collision>;
|
||||
|
||||
class PhysicsEngine {
|
||||
public:
|
||||
|
|
|
@ -71,7 +71,7 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent {
|
|||
Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius)
|
||||
|
||||
public:
|
||||
AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent("Ambient Occlusion", false) {}
|
||||
AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false) {}
|
||||
|
||||
const int MAX_RESOLUTION_LEVEL = 4;
|
||||
const int MAX_BLUR_RADIUS = 6;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "model/Light.h"
|
||||
#include "model/Geometry.h"
|
||||
|
||||
#include "render/Context.h"
|
||||
#include <render/CullTask.h>
|
||||
|
||||
#include "DeferredFrameTransform.h"
|
||||
|
|
|
@ -1194,7 +1194,7 @@ void Model::createVisibleRenderItemSet() {
|
|||
|
||||
// all of our mesh vectors must match in size
|
||||
if ((int)meshes.size() != _meshStates.size()) {
|
||||
qCDebug(renderlogging) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
|
||||
qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include <render/Context.h>
|
||||
#include <render/CullTask.h>
|
||||
#include <render/SortTask.h>
|
||||
#include <render/DrawTask.h>
|
||||
|
|
|
@ -35,7 +35,7 @@ class RenderShadowTaskConfig : public render::Task::Config::Persistent {
|
|||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
|
||||
public:
|
||||
RenderShadowTaskConfig() : render::Task::Config::Persistent("Shadows", false) {}
|
||||
RenderShadowTaskConfig() : render::Task::Config::Persistent(QStringList() << "Render" << "Engine" << "Shadows", false) {}
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
//
|
||||
// Context.h
|
||||
// render/src/render
|
||||
//
|
||||
// Created by Zach Pomerantz on 1/6/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
|
||||
//
|
||||
|
||||
#ifndef hifi_render_Context_h
|
||||
#define hifi_render_Context_h
|
||||
|
||||
#include "Scene.h"
|
||||
|
||||
namespace render {
|
||||
|
||||
class JobConfig;
|
||||
|
||||
class RenderContext {
|
||||
public:
|
||||
RenderArgs* args;
|
||||
std::shared_ptr<JobConfig> jobConfig{ nullptr };
|
||||
ScenePointer _scene;
|
||||
};
|
||||
using RenderContextPointer = std::shared_ptr<RenderContext>;
|
||||
|
||||
}
|
||||
|
||||
#endif // hifi_render_Context_h
|
||||
|
|
@ -14,10 +14,67 @@
|
|||
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include "Context.h"
|
||||
#include "Task.h"
|
||||
#include "Scene.h"
|
||||
#include "../task/Task.h"
|
||||
#include "gpu/Batch.h"
|
||||
|
||||
namespace render {
|
||||
|
||||
|
||||
|
||||
class RenderContext : public task::JobContext {
|
||||
public:
|
||||
virtual ~RenderContext() {}
|
||||
|
||||
RenderArgs* args;
|
||||
ScenePointer _scene;
|
||||
};
|
||||
using RenderContextPointer = std::shared_ptr<RenderContext>;
|
||||
|
||||
Task_DeclareTypeAliases(RenderContext)
|
||||
|
||||
// Versions of the COnfig integrating a gpu & batch timer
|
||||
class GPUJobConfig : public JobConfig {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuRunTime READ getGPURunTime)
|
||||
Q_PROPERTY(double batchRunTime READ getBatchRunTime)
|
||||
|
||||
double _msGPURunTime { 0.0 };
|
||||
double _msBatchRunTime { 0.0 };
|
||||
public:
|
||||
using Persistent = PersistentConfig<GPUJobConfig>;
|
||||
|
||||
GPUJobConfig() = default;
|
||||
GPUJobConfig(bool enabled) : JobConfig(enabled) {}
|
||||
|
||||
// Running Time measurement on GPU and for Batch execution
|
||||
void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; }
|
||||
double getGPURunTime() const { return _msGPURunTime; }
|
||||
double getBatchRunTime() const { return _msBatchRunTime; }
|
||||
};
|
||||
|
||||
class GPUTaskConfig : public TaskConfig {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuRunTime READ getGPURunTime)
|
||||
Q_PROPERTY(double batchRunTime READ getBatchRunTime)
|
||||
|
||||
double _msGPURunTime { 0.0 };
|
||||
double _msBatchRunTime { 0.0 };
|
||||
public:
|
||||
|
||||
using Persistent = PersistentConfig<GPUTaskConfig>;
|
||||
|
||||
|
||||
GPUTaskConfig() = default;
|
||||
GPUTaskConfig(bool enabled) : TaskConfig(enabled) {}
|
||||
|
||||
// Running Time measurement on GPU and for Batch execution
|
||||
void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; }
|
||||
double getGPURunTime() const { return _msGPURunTime; }
|
||||
double getBatchRunTime() const { return _msBatchRunTime; }
|
||||
};
|
||||
|
||||
|
||||
// The render engine holds all render tasks, and is itself a render task.
|
||||
// State flows through tasks to jobs via the render and scene contexts -
|
||||
// the engine should not be known from its jobs.
|
||||
|
@ -43,6 +100,8 @@ namespace render {
|
|||
|
||||
protected:
|
||||
RenderContextPointer _renderContext;
|
||||
|
||||
void run(const RenderContextPointer& context) override { assert(_renderContext); Task::run(_renderContext); }
|
||||
};
|
||||
using EnginePointer = std::shared_ptr<Engine>;
|
||||
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
#define hifi_RenderFetchCullSortTask_h
|
||||
|
||||
#include <gpu/Pipeline.h>
|
||||
|
||||
#include "Task.h"
|
||||
#include "CullTask.h"
|
||||
|
||||
class RenderFetchCullSortTask {
|
||||
|
|
|
@ -1,745 +0,0 @@
|
|||
//
|
||||
// Task.h
|
||||
// render/src/render
|
||||
//
|
||||
// Created by Zach Pomerantz on 1/6/2016.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_render_Task_h
|
||||
#define hifi_render_Task_h
|
||||
#include <tuple>
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
|
||||
#include <QtCore/qjsondocument.h>
|
||||
#include <QtCore/qjsonobject.h>
|
||||
#include <QtCore/qjsonvalue.h>
|
||||
#include <shared/JSONHelpers.h>
|
||||
|
||||
#include "SettingHandle.h"
|
||||
|
||||
#include "Context.h"
|
||||
#include "Logging.h"
|
||||
|
||||
#include "gpu/Batch.h"
|
||||
#include <PerfStat.h>
|
||||
|
||||
namespace render {
|
||||
|
||||
class Varying;
|
||||
|
||||
|
||||
// A varying piece of data, to be used as Job/Task I/O
|
||||
// TODO: Task IO
|
||||
class Varying {
|
||||
public:
|
||||
Varying() {}
|
||||
Varying(const Varying& var) : _concept(var._concept) {}
|
||||
Varying& operator=(const Varying& var) {
|
||||
_concept = var._concept;
|
||||
return (*this);
|
||||
}
|
||||
template <class T> Varying(const T& data) : _concept(std::make_shared<Model<T>>(data)) {}
|
||||
|
||||
template <class T> bool canCast() const { return !!std::dynamic_pointer_cast<Model<T>>(_concept); }
|
||||
template <class T> const T& get() const { return std::static_pointer_cast<const Model<T>>(_concept)->_data; }
|
||||
template <class T> T& edit() { return std::static_pointer_cast<Model<T>>(_concept)->_data; }
|
||||
|
||||
|
||||
// access potential sub varyings contained in this one.
|
||||
Varying operator[] (uint8_t index) const { return (*_concept)[index]; }
|
||||
uint8_t length() const { return (*_concept).length(); }
|
||||
|
||||
template <class T> Varying getN (uint8_t index) const { return get<T>()[index]; }
|
||||
template <class T> Varying editN (uint8_t index) { return edit<T>()[index]; }
|
||||
|
||||
protected:
|
||||
class Concept {
|
||||
public:
|
||||
virtual ~Concept() = default;
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const = 0;
|
||||
virtual uint8_t length() const = 0;
|
||||
};
|
||||
template <class T> class Model : public Concept {
|
||||
public:
|
||||
using Data = T;
|
||||
|
||||
Model(const Data& data) : _data(data) {}
|
||||
virtual ~Model() = default;
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const override {
|
||||
Varying var;
|
||||
return var;
|
||||
}
|
||||
virtual uint8_t length() const override { return 0; }
|
||||
|
||||
Data _data;
|
||||
};
|
||||
|
||||
std::shared_ptr<Concept> _concept;
|
||||
};
|
||||
|
||||
using VaryingPairBase = std::pair<Varying, Varying>;
|
||||
template < typename T0, typename T1 >
|
||||
class VaryingSet2 : public VaryingPairBase {
|
||||
public:
|
||||
using Parent = VaryingPairBase;
|
||||
typedef void is_proxy_tag;
|
||||
|
||||
VaryingSet2() : Parent(Varying(T0()), Varying(T1())) {}
|
||||
VaryingSet2(const VaryingSet2& pair) : Parent(pair.first, pair.second) {}
|
||||
VaryingSet2(const Varying& first, const Varying& second) : Parent(first, second) {}
|
||||
|
||||
const T0& get0() const { return first.get<T0>(); }
|
||||
T0& edit0() { return first.edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return second.get<T1>(); }
|
||||
T1& edit1() { return second.edit<T1>(); }
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const {
|
||||
if (index == 1) {
|
||||
return std::get<1>((*this));
|
||||
} else {
|
||||
return std::get<0>((*this));
|
||||
}
|
||||
}
|
||||
virtual uint8_t length() const { return 2; }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
|
||||
template <class T0, class T1, class T2>
|
||||
class VaryingSet3 : public std::tuple<Varying, Varying,Varying>{
|
||||
public:
|
||||
using Parent = std::tuple<Varying, Varying, Varying>;
|
||||
|
||||
VaryingSet3() : Parent(Varying(T0()), Varying(T1()), Varying(T2())) {}
|
||||
VaryingSet3(const VaryingSet3& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src)) {}
|
||||
VaryingSet3(const Varying& first, const Varying& second, const Varying& third) : Parent(first, second, third) {}
|
||||
|
||||
const T0& get0() const { return std::get<0>((*this)).template get<T0>(); }
|
||||
T0& edit0() { return std::get<0>((*this)).template edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return std::get<1>((*this)).template get<T1>(); }
|
||||
T1& edit1() { return std::get<1>((*this)).template edit<T1>(); }
|
||||
|
||||
const T2& get2() const { return std::get<2>((*this)).template get<T2>(); }
|
||||
T2& edit2() { return std::get<2>((*this)).template edit<T2>(); }
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const {
|
||||
if (index == 2) {
|
||||
return std::get<2>((*this));
|
||||
} else if (index == 1) {
|
||||
return std::get<1>((*this));
|
||||
} else {
|
||||
return std::get<0>((*this));
|
||||
}
|
||||
}
|
||||
virtual uint8_t length() const { return 3; }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
template <class T0, class T1, class T2, class T3>
|
||||
class VaryingSet4 : public std::tuple<Varying, Varying, Varying, Varying>{
|
||||
public:
|
||||
using Parent = std::tuple<Varying, Varying, Varying, Varying>;
|
||||
|
||||
VaryingSet4() : Parent(Varying(T0()), Varying(T1()), Varying(T2()), Varying(T3())) {}
|
||||
VaryingSet4(const VaryingSet4& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src), std::get<3>(src)) {}
|
||||
VaryingSet4(const Varying& first, const Varying& second, const Varying& third, const Varying& fourth) : Parent(first, second, third, fourth) {}
|
||||
|
||||
const T0& get0() const { return std::get<0>((*this)).template get<T0>(); }
|
||||
T0& edit0() { return std::get<0>((*this)).template edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return std::get<1>((*this)).template get<T1>(); }
|
||||
T1& edit1() { return std::get<1>((*this)).template edit<T1>(); }
|
||||
|
||||
const T2& get2() const { return std::get<2>((*this)).template get<T2>(); }
|
||||
T2& edit2() { return std::get<2>((*this)).template edit<T2>(); }
|
||||
|
||||
const T3& get3() const { return std::get<3>((*this)).template get<T3>(); }
|
||||
T3& edit3() { return std::get<3>((*this)).template edit<T3>(); }
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const {
|
||||
if (index == 3) {
|
||||
return std::get<3>((*this));
|
||||
} else if (index == 2) {
|
||||
return std::get<2>((*this));
|
||||
} else if (index == 1) {
|
||||
return std::get<1>((*this));
|
||||
} else {
|
||||
return std::get<0>((*this));
|
||||
}
|
||||
}
|
||||
virtual uint8_t length() const { return 4; }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
|
||||
template <class T0, class T1, class T2, class T3, class T4>
|
||||
class VaryingSet5 : public std::tuple<Varying, Varying, Varying, Varying, Varying>{
|
||||
public:
|
||||
using Parent = std::tuple<Varying, Varying, Varying, Varying, Varying>;
|
||||
|
||||
VaryingSet5() : Parent(Varying(T0()), Varying(T1()), Varying(T2()), Varying(T3()), Varying(T4())) {}
|
||||
VaryingSet5(const VaryingSet5& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src), std::get<3>(src), std::get<4>(src)) {}
|
||||
VaryingSet5(const Varying& first, const Varying& second, const Varying& third, const Varying& fourth, const Varying& fifth) : Parent(first, second, third, fourth, fifth) {}
|
||||
|
||||
const T0& get0() const { return std::get<0>((*this)).template get<T0>(); }
|
||||
T0& edit0() { return std::get<0>((*this)).template edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return std::get<1>((*this)).template get<T1>(); }
|
||||
T1& edit1() { return std::get<1>((*this)).template edit<T1>(); }
|
||||
|
||||
const T2& get2() const { return std::get<2>((*this)).template get<T2>(); }
|
||||
T2& edit2() { return std::get<2>((*this)).template edit<T2>(); }
|
||||
|
||||
const T3& get3() const { return std::get<3>((*this)).template get<T3>(); }
|
||||
T3& edit3() { return std::get<3>((*this)).template edit<T3>(); }
|
||||
|
||||
const T4& get4() const { return std::get<4>((*this)).template get<T4>(); }
|
||||
T4& edit4() { return std::get<4>((*this)).template edit<T4>(); }
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const {
|
||||
if (index == 4) {
|
||||
return std::get<4>((*this));
|
||||
} else if (index == 3) {
|
||||
return std::get<3>((*this));
|
||||
} else if (index == 2) {
|
||||
return std::get<2>((*this));
|
||||
} else if (index == 1) {
|
||||
return std::get<1>((*this));
|
||||
} else {
|
||||
return std::get<0>((*this));
|
||||
}
|
||||
}
|
||||
virtual uint8_t length() const { return 5; }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
template <class T0, class T1, class T2, class T3, class T4, class T5>
|
||||
class VaryingSet6 : public std::tuple<Varying, Varying, Varying, Varying, Varying, Varying>{
|
||||
public:
|
||||
using Parent = std::tuple<Varying, Varying, Varying, Varying, Varying, Varying>;
|
||||
|
||||
VaryingSet6() : Parent(Varying(T0()), Varying(T1()), Varying(T2()), Varying(T3()), Varying(T4()), Varying(T5())) {}
|
||||
VaryingSet6(const VaryingSet6& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src), std::get<3>(src), std::get<4>(src), std::get<5>(src)) {}
|
||||
VaryingSet6(const Varying& first, const Varying& second, const Varying& third, const Varying& fourth, const Varying& fifth, const Varying& sixth) : Parent(first, second, third, fourth, fifth, sixth) {}
|
||||
|
||||
const T0& get0() const { return std::get<0>((*this)).template get<T0>(); }
|
||||
T0& edit0() { return std::get<0>((*this)).template edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return std::get<1>((*this)).template get<T1>(); }
|
||||
T1& edit1() { return std::get<1>((*this)).template edit<T1>(); }
|
||||
|
||||
const T2& get2() const { return std::get<2>((*this)).template get<T2>(); }
|
||||
T2& edit2() { return std::get<2>((*this)).template edit<T2>(); }
|
||||
|
||||
const T3& get3() const { return std::get<3>((*this)).template get<T3>(); }
|
||||
T3& edit3() { return std::get<3>((*this)).template edit<T3>(); }
|
||||
|
||||
const T4& get4() const { return std::get<4>((*this)).template get<T4>(); }
|
||||
T4& edit4() { return std::get<4>((*this)).template edit<T4>(); }
|
||||
|
||||
const T5& get5() const { return std::get<5>((*this)).template get<T5>(); }
|
||||
T5& edit5() { return std::get<5>((*this)).template edit<T5>(); }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
template <class T0, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
class VaryingSet7 : public std::tuple<Varying, Varying, Varying, Varying, Varying, Varying, Varying>{
|
||||
public:
|
||||
using Parent = std::tuple<Varying, Varying, Varying, Varying, Varying, Varying, Varying>;
|
||||
|
||||
VaryingSet7() : Parent(Varying(T0()), Varying(T1()), Varying(T2()), Varying(T3()), Varying(T4()), Varying(T5()), Varying(T6())) {}
|
||||
VaryingSet7(const VaryingSet7& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src), std::get<3>(src), std::get<4>(src), std::get<5>(src), std::get<6>(src)) {}
|
||||
VaryingSet7(const Varying& first, const Varying& second, const Varying& third, const Varying& fourth, const Varying& fifth, const Varying& sixth, const Varying& seventh) : Parent(first, second, third, fourth, fifth, sixth, seventh) {}
|
||||
|
||||
const T0& get0() const { return std::get<0>((*this)).template get<T0>(); }
|
||||
T0& edit0() { return std::get<0>((*this)).template edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return std::get<1>((*this)).template get<T1>(); }
|
||||
T1& edit1() { return std::get<1>((*this)).template edit<T1>(); }
|
||||
|
||||
const T2& get2() const { return std::get<2>((*this)).template get<T2>(); }
|
||||
T2& edit2() { return std::get<2>((*this)).template edit<T2>(); }
|
||||
|
||||
const T3& get3() const { return std::get<3>((*this)).template get<T3>(); }
|
||||
T3& edit3() { return std::get<3>((*this)).template edit<T3>(); }
|
||||
|
||||
const T4& get4() const { return std::get<4>((*this)).template get<T4>(); }
|
||||
T4& edit4() { return std::get<4>((*this)).template edit<T4>(); }
|
||||
|
||||
const T5& get5() const { return std::get<5>((*this)).template get<T5>(); }
|
||||
T5& edit5() { return std::get<5>((*this)).template edit<T5>(); }
|
||||
|
||||
const T6& get6() const { return std::get<6>((*this)).template get<T6>(); }
|
||||
T6& edit6() { return std::get<6>((*this)).template edit<T6>(); }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
|
||||
template < class T, int NUM >
|
||||
class VaryingArray : public std::array<Varying, NUM> {
|
||||
public:
|
||||
VaryingArray() {
|
||||
for (size_t i = 0; i < NUM; i++) {
|
||||
(*this)[i] = Varying(T());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Job;
|
||||
class JobConcept;
|
||||
class Task;
|
||||
class JobNoIO {};
|
||||
|
||||
template <class C> class PersistentConfig : public C {
|
||||
public:
|
||||
const QString DEFAULT = "Default";
|
||||
const QString NONE = "None";
|
||||
|
||||
PersistentConfig() = delete;
|
||||
PersistentConfig(const QString& path) :
|
||||
_preset(QStringList() << "Render" << "Engine" << path, DEFAULT) { }
|
||||
PersistentConfig(const QStringList& path) :
|
||||
_preset(QStringList() << "Render" << "Engine" << path, DEFAULT) { }
|
||||
PersistentConfig(const QString& path, bool enabled) : C(enabled),
|
||||
_preset(QStringList() << "Render" << "Engine" << path, enabled ? DEFAULT : NONE) { }
|
||||
PersistentConfig(const QStringList& path, bool enabled) : C(enabled),
|
||||
_preset(QStringList() << "Render" << "Engine" << path, enabled ? DEFAULT : NONE) { }
|
||||
|
||||
QStringList getPresetList() {
|
||||
if (_presets.empty()) {
|
||||
setPresetList(QJsonObject());
|
||||
}
|
||||
return _presets.keys();
|
||||
}
|
||||
|
||||
virtual void setPresetList(const QJsonObject& list) override {
|
||||
assert(_presets.empty());
|
||||
|
||||
_default = toJsonValue(*this).toObject().toVariantMap();
|
||||
|
||||
_presets.unite(list.toVariantMap());
|
||||
if (C::alwaysEnabled || C::enabled) {
|
||||
_presets.insert(DEFAULT, _default);
|
||||
}
|
||||
if (!C::alwaysEnabled) {
|
||||
_presets.insert(NONE, QVariantMap{{ "enabled", false }});
|
||||
}
|
||||
|
||||
auto preset = _preset.get();
|
||||
if (preset != _preset.getDefault() && _presets.contains(preset)) {
|
||||
// Load the persisted configuration
|
||||
C::load(_presets[preset].toMap());
|
||||
}
|
||||
}
|
||||
|
||||
QString getPreset() { return _preset.get(); }
|
||||
|
||||
void setPreset(const QString& preset) {
|
||||
_preset.set(preset);
|
||||
if (_presets.contains(preset)) {
|
||||
// Always start back at default to remain deterministic
|
||||
QVariantMap config = _default;
|
||||
QVariantMap presetConfig = _presets[preset].toMap();
|
||||
for (auto it = presetConfig.cbegin(); it != presetConfig.cend(); it++) {
|
||||
config.insert(it.key(), it.value());
|
||||
}
|
||||
C::load(config);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
QVariantMap _default;
|
||||
QVariantMap _presets;
|
||||
Setting::Handle<QString> _preset;
|
||||
};
|
||||
|
||||
// A default Config is always on; to create an enableable Config, use the ctor JobConfig(bool enabled)
|
||||
class JobConfig : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double cpuRunTime READ getCPURunTime NOTIFY newStats()) //ms
|
||||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
|
||||
|
||||
double _msCPURunTime{ 0.0 };
|
||||
public:
|
||||
using Persistent = PersistentConfig<JobConfig>;
|
||||
|
||||
JobConfig() = default;
|
||||
JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {}
|
||||
|
||||
bool isEnabled() { return alwaysEnabled || enabled; }
|
||||
void setEnabled(bool enable) { enabled = alwaysEnabled || enable; }
|
||||
|
||||
bool alwaysEnabled{ true };
|
||||
bool enabled{ true };
|
||||
|
||||
virtual void setPresetList(const QJsonObject& object) {
|
||||
for (auto it = object.begin(); it != object.end(); it++) {
|
||||
JobConfig* child = findChild<JobConfig*>(it.key(), Qt::FindDirectChildrenOnly);
|
||||
if (child) {
|
||||
child->setPresetList(it.value().toObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This must be named toJSON to integrate with the global scripting JSON object
|
||||
Q_INVOKABLE QString toJSON() { return QJsonDocument(toJsonValue(*this).toObject()).toJson(QJsonDocument::Compact); }
|
||||
Q_INVOKABLE void load(const QVariantMap& map) { qObjectFromJsonValue(QJsonObject::fromVariantMap(map), *this); emit loaded(); }
|
||||
|
||||
// Running Time measurement
|
||||
// The new stats signal is emitted once per run time of a job when stats (cpu runtime) are updated
|
||||
void setCPURunTime(double mstime) { _msCPURunTime = mstime; emit newStats(); }
|
||||
double getCPURunTime() const { return _msCPURunTime; }
|
||||
|
||||
public slots:
|
||||
void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); emit loaded(); }
|
||||
|
||||
signals:
|
||||
void loaded();
|
||||
void newStats();
|
||||
};
|
||||
|
||||
class TaskConfig : public JobConfig {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using QConfigPointer = std::shared_ptr<QObject>;
|
||||
|
||||
using Persistent = PersistentConfig<TaskConfig>;
|
||||
|
||||
TaskConfig() = default ;
|
||||
TaskConfig(bool enabled) : JobConfig(enabled) {}
|
||||
|
||||
// getter for qml integration, prefer the templated getter
|
||||
Q_INVOKABLE QObject* getConfig(const QString& name) { return QObject::findChild<JobConfig*>(name); }
|
||||
// getter for cpp (strictly typed), prefer this getter
|
||||
template <class T> typename T::Config* getConfig(std::string job = "") const {
|
||||
QString name = job.empty() ? QString() : QString(job.c_str()); // an empty string is not a null string
|
||||
return findChild<typename T::Config*>(name);
|
||||
}
|
||||
|
||||
void connectChildConfig(QConfigPointer childConfig, const std::string& name);
|
||||
void transferChildrenConfigs(QConfigPointer source);
|
||||
|
||||
public slots:
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
friend Task;
|
||||
JobConcept* _task;
|
||||
};
|
||||
|
||||
template <class T, class C> void jobConfigure(T& data, const C& configuration) {
|
||||
data.configure(configuration);
|
||||
}
|
||||
template<class T> void jobConfigure(T&, const JobConfig&) {
|
||||
// nop, as the default JobConfig was used, so the data does not need a configure method
|
||||
}
|
||||
template<class T> void jobConfigure(T&, const TaskConfig&) {
|
||||
// nop, as the default TaskConfig was used, so the data does not need a configure method
|
||||
}
|
||||
template <class T> void jobRun(T& data, const RenderContextPointer& renderContext, const JobNoIO& input, JobNoIO& output) {
|
||||
data.run(renderContext);
|
||||
}
|
||||
template <class T, class I> void jobRun(T& data, const RenderContextPointer& renderContext, const I& input, JobNoIO& output) {
|
||||
data.run(renderContext, input);
|
||||
}
|
||||
template <class T, class O> void jobRun(T& data, const RenderContextPointer& renderContext, const JobNoIO& input, O& output) {
|
||||
data.run(renderContext, output);
|
||||
}
|
||||
template <class T, class I, class O> void jobRun(T& data, const RenderContextPointer& renderContext, const I& input, O& output) {
|
||||
data.run(renderContext, input, output);
|
||||
}
|
||||
|
||||
// The guts of a job
|
||||
class JobConcept {
|
||||
public:
|
||||
using Config = JobConfig;
|
||||
using QConfigPointer = std::shared_ptr<QObject>;
|
||||
|
||||
JobConcept(QConfigPointer config) : _config(config) {}
|
||||
virtual ~JobConcept() = default;
|
||||
|
||||
virtual const Varying getInput() const { return Varying(); }
|
||||
virtual const Varying getOutput() const { return Varying(); }
|
||||
|
||||
virtual QConfigPointer& getConfiguration() { return _config; }
|
||||
virtual void applyConfiguration() = 0;
|
||||
|
||||
virtual void run(const RenderContextPointer& renderContext) = 0;
|
||||
|
||||
protected:
|
||||
void setCPURunTime(double mstime) { std::static_pointer_cast<Config>(_config)->setCPURunTime(mstime); }
|
||||
|
||||
QConfigPointer _config;
|
||||
|
||||
friend class Job;
|
||||
};
|
||||
|
||||
class Job {
|
||||
public:
|
||||
using Concept = JobConcept;
|
||||
using Config = JobConfig;
|
||||
using QConfigPointer = std::shared_ptr<QObject>;
|
||||
using None = JobNoIO;
|
||||
using ConceptPointer = std::shared_ptr<Concept>;
|
||||
|
||||
template <class T, class C = Config, class I = None, class O = None> class Model : public Concept {
|
||||
public:
|
||||
using Data = T;
|
||||
using Input = I;
|
||||
using Output = O;
|
||||
|
||||
Data _data;
|
||||
Varying _input;
|
||||
Varying _output;
|
||||
|
||||
const Varying getInput() const override { return _input; }
|
||||
const Varying getOutput() const override { return _output; }
|
||||
|
||||
template <class... A>
|
||||
Model(const Varying& input, QConfigPointer config, A&&... args) :
|
||||
Concept(config),
|
||||
_data(Data(std::forward<A>(args)...)),
|
||||
_input(input),
|
||||
_output(Output()) {
|
||||
applyConfiguration();
|
||||
}
|
||||
|
||||
template <class... A>
|
||||
static std::shared_ptr<Model> create(const Varying& input, A&&... args) {
|
||||
return std::make_shared<Model>(input, std::make_shared<C>(), std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
|
||||
void applyConfiguration() override {
|
||||
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
|
||||
}
|
||||
|
||||
void run(const RenderContextPointer& renderContext) override {
|
||||
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
|
||||
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->isEnabled()) {
|
||||
jobRun(_data, renderContext, _input.get<I>(), _output.edit<O>());
|
||||
}
|
||||
renderContext->jobConfig.reset();
|
||||
}
|
||||
};
|
||||
template <class T, class I, class C = Config> using ModelI = Model<T, C, I, None>;
|
||||
template <class T, class O, class C = Config> using ModelO = Model<T, C, None, O>;
|
||||
template <class T, class I, class O, class C = Config> using ModelIO = Model<T, C, I, O>;
|
||||
|
||||
Job(std::string name, ConceptPointer concept) : _concept(concept), _name(name) {}
|
||||
|
||||
const Varying getInput() const { return _concept->getInput(); }
|
||||
const Varying getOutput() const { return _concept->getOutput(); }
|
||||
QConfigPointer& getConfiguration() const { return _concept->getConfiguration(); }
|
||||
void applyConfiguration() { return _concept->applyConfiguration(); }
|
||||
|
||||
template <class T> T& edit() {
|
||||
auto concept = std::static_pointer_cast<typename T::JobModel>(_concept);
|
||||
assert(concept);
|
||||
return concept->_data;
|
||||
}
|
||||
|
||||
void run(const RenderContextPointer& renderContext) {
|
||||
PerformanceTimer perfTimer(_name.c_str());
|
||||
PROFILE_RANGE(render, _name.c_str());
|
||||
auto start = usecTimestampNow();
|
||||
|
||||
_concept->run(renderContext);
|
||||
|
||||
_concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0);
|
||||
}
|
||||
|
||||
protected:
|
||||
ConceptPointer _concept;
|
||||
std::string _name = "";
|
||||
};
|
||||
|
||||
// A task is a specialized job to run a collection of other jobs
|
||||
// It can be created on any type T by aliasing the type JobModel in the class T
|
||||
// using JobModel = Task::Model<T>
|
||||
// The class T is expected to have a "build" method acting as a constructor.
|
||||
// The build method is where child Jobs can be added internally to the task
|
||||
// where the input of the task can be setup to feed the child jobs
|
||||
// and where the output of the task is defined
|
||||
class Task : public Job {
|
||||
public:
|
||||
using Config = TaskConfig;
|
||||
using QConfigPointer = Job::QConfigPointer;
|
||||
using None = Job::None;
|
||||
using Concept = Job::Concept;
|
||||
using Jobs = std::vector<Job>;
|
||||
|
||||
Task(std::string name, ConceptPointer concept) : Job(name, concept) {}
|
||||
|
||||
class TaskConcept : public Concept {
|
||||
public:
|
||||
Varying _input;
|
||||
Varying _output;
|
||||
Jobs _jobs;
|
||||
|
||||
const Varying getInput() const override { return _input; }
|
||||
const Varying getOutput() const override { return _output; }
|
||||
|
||||
TaskConcept(const Varying& input, QConfigPointer config) : Concept(config), _input(input) {}
|
||||
|
||||
// Create a new job in the container's queue; returns the job's output
|
||||
template <class NT, class... NA> const Varying addJob(std::string name, const Varying& input, NA&&... args) {
|
||||
_jobs.emplace_back(name, (NT::JobModel::create(input, std::forward<NA>(args)...)));
|
||||
|
||||
// Conect the child config to this task's config
|
||||
std::static_pointer_cast<TaskConfig>(getConfiguration())->connectChildConfig(_jobs.back().getConfiguration(), name);
|
||||
|
||||
return _jobs.back().getOutput();
|
||||
}
|
||||
template <class NT, class... NA> const Varying addJob(std::string name, NA&&... args) {
|
||||
const auto input = Varying(typename NT::JobModel::Input());
|
||||
return addJob<NT>(name, input, std::forward<NA>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class C = Config, class I = None, class O = None> class TaskModel : public TaskConcept {
|
||||
public:
|
||||
using Data = T;
|
||||
using Input = I;
|
||||
using Output = O;
|
||||
|
||||
Data _data;
|
||||
|
||||
TaskModel(const Varying& input, QConfigPointer config) :
|
||||
TaskConcept(input, config),
|
||||
_data(Data()) {}
|
||||
|
||||
template <class... A>
|
||||
static std::shared_ptr<TaskModel> create(const Varying& input, A&&... args) {
|
||||
auto model = std::make_shared<TaskModel>(input, std::make_shared<C>());
|
||||
// std::static_pointer_cast<C>(model->_config)->_task = model.get();
|
||||
|
||||
model->_data.build(*(model), model->_input, model->_output, std::forward<A>(args)...);
|
||||
|
||||
// Recreate the Config to use the templated type
|
||||
model->createConfiguration();
|
||||
model->applyConfiguration();
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
template <class... A>
|
||||
static std::shared_ptr<TaskModel> create(A&&... args) {
|
||||
const auto input = Varying(Input());
|
||||
return create(input, std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
void createConfiguration() {
|
||||
// A brand new config
|
||||
auto config = std::make_shared<C>();
|
||||
// Make sure we transfer the former children configs to the new config
|
||||
config->transferChildrenConfigs(_config);
|
||||
// swap
|
||||
_config = config;
|
||||
// Capture this
|
||||
std::static_pointer_cast<C>(_config)->_task = this;
|
||||
}
|
||||
|
||||
QConfigPointer& getConfiguration() override {
|
||||
if (!_config) {
|
||||
createConfiguration();
|
||||
}
|
||||
return _config;
|
||||
}
|
||||
|
||||
void applyConfiguration() override {
|
||||
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
|
||||
for (auto& job : _jobs) {
|
||||
job.applyConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
void run(const RenderContextPointer& renderContext) override {
|
||||
auto config = std::static_pointer_cast<C>(_config);
|
||||
if (config->alwaysEnabled || config->enabled) {
|
||||
for (auto job : _jobs) {
|
||||
job.run(renderContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
template <class T, class C = Config> using Model = TaskModel<T, C, None, None>;
|
||||
template <class T, class I, class C = Config> using ModelI = TaskModel<T, C, I, None>;
|
||||
template <class T, class O, class C = Config> using ModelO = TaskModel<T, C, None, O>;
|
||||
template <class T, class I, class O, class C = Config> using ModelIO = TaskModel<T, C, I, O>;
|
||||
|
||||
// Create a new job in the Task's queue; returns the job's output
|
||||
template <class T, class... A> const Varying addJob(std::string name, const Varying& input, A&&... args) {
|
||||
return std::static_pointer_cast<TaskConcept>( _concept)->addJob<T>(name, input, std::forward<A>(args)...);
|
||||
}
|
||||
template <class T, class... A> const Varying addJob(std::string name, A&&... args) {
|
||||
const auto input = Varying(typename T::JobModel::Input());
|
||||
return std::static_pointer_cast<TaskConcept>( _concept)->addJob<T>(name, input, std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
std::shared_ptr<Config> getConfiguration() {
|
||||
return std::static_pointer_cast<Config>(_concept->getConfiguration());
|
||||
}
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
// Versions of the COnfig integrating a gpu & batch timer
|
||||
class GPUJobConfig : public JobConfig {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuRunTime READ getGPURunTime)
|
||||
Q_PROPERTY(double batchRunTime READ getBatchRunTime)
|
||||
|
||||
double _msGPURunTime { 0.0 };
|
||||
double _msBatchRunTime { 0.0 };
|
||||
public:
|
||||
using Persistent = PersistentConfig<GPUJobConfig>;
|
||||
|
||||
GPUJobConfig() = default;
|
||||
GPUJobConfig(bool enabled) : JobConfig(enabled) {}
|
||||
|
||||
// Running Time measurement on GPU and for Batch execution
|
||||
void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; }
|
||||
double getGPURunTime() const { return _msGPURunTime; }
|
||||
double getBatchRunTime() const { return _msBatchRunTime; }
|
||||
};
|
||||
|
||||
class GPUTaskConfig : public TaskConfig {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuRunTime READ getGPURunTime)
|
||||
Q_PROPERTY(double batchRunTime READ getBatchRunTime)
|
||||
|
||||
double _msGPURunTime { 0.0 };
|
||||
double _msBatchRunTime { 0.0 };
|
||||
public:
|
||||
|
||||
using Persistent = PersistentConfig<GPUTaskConfig>;
|
||||
|
||||
|
||||
GPUTaskConfig() = default;
|
||||
GPUTaskConfig(bool enabled) : TaskConfig(enabled) {}
|
||||
|
||||
// Running Time measurement on GPU and for Batch execution
|
||||
void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; }
|
||||
double getGPURunTime() const { return _msGPURunTime; }
|
||||
double getBatchRunTime() const { return _msBatchRunTime; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // hifi_render_Task_h
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// Task.cpp
|
||||
// render/src/render
|
||||
// Config.cpp
|
||||
// render/src/task
|
||||
//
|
||||
// Created by Zach Pomerantz on 1/21/2016.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
|
@ -8,12 +8,21 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QtCore/QThread>
|
||||
#include "Config.h"
|
||||
|
||||
#include "Task.h"
|
||||
#include <QtCore/QThread>
|
||||
|
||||
using namespace render;
|
||||
using namespace task;
|
||||
|
||||
void JobConfig::setPresetList(const QJsonObject& object) {
|
||||
for (auto it = object.begin(); it != object.end(); it++) {
|
||||
JobConfig* child = findChild<JobConfig*>(it.key(), Qt::FindDirectChildrenOnly);
|
||||
if (child) {
|
||||
child->setPresetList(it.value().toObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TaskConfig::connectChildConfig(QConfigPointer childConfig, const std::string& name) {
|
||||
childConfig->setParent(this);
|
157
libraries/render/src/task/Config.h
Normal file
157
libraries/render/src/task/Config.h
Normal file
|
@ -0,0 +1,157 @@
|
|||
//
|
||||
// Config.h
|
||||
// render/src/render
|
||||
//
|
||||
// Created by Zach Pomerantz on 1/6/2016.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_task_Config_h
|
||||
#define hifi_task_Config_h
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qjsondocument.h>
|
||||
#include <QtCore/qjsonobject.h>
|
||||
#include <QtCore/qjsonvalue.h>
|
||||
#include <shared/JSONHelpers.h>
|
||||
|
||||
#include "SettingHandle.h"
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
namespace task {
|
||||
|
||||
class JobConcept;
|
||||
|
||||
template <class C> class PersistentConfig : public C {
|
||||
public:
|
||||
const QString DEFAULT = "Default";
|
||||
const QString NONE = "None";
|
||||
|
||||
PersistentConfig() = delete;
|
||||
PersistentConfig(const QStringList& path) :
|
||||
_preset(path, DEFAULT) { }
|
||||
PersistentConfig(const QStringList& path, bool enabled) : C(enabled),
|
||||
_preset(path, enabled ? DEFAULT : NONE) { }
|
||||
|
||||
QStringList getPresetList() {
|
||||
if (_presets.empty()) {
|
||||
setPresetList(QJsonObject());
|
||||
}
|
||||
return _presets.keys();
|
||||
}
|
||||
|
||||
virtual void setPresetList(const QJsonObject& list) override {
|
||||
assert(_presets.empty());
|
||||
|
||||
_default = toJsonValue(*this).toObject().toVariantMap();
|
||||
|
||||
_presets.unite(list.toVariantMap());
|
||||
if (C::alwaysEnabled || C::enabled) {
|
||||
_presets.insert(DEFAULT, _default);
|
||||
}
|
||||
if (!C::alwaysEnabled) {
|
||||
_presets.insert(NONE, QVariantMap{{ "enabled", false }});
|
||||
}
|
||||
|
||||
auto preset = _preset.get();
|
||||
if (preset != _preset.getDefault() && _presets.contains(preset)) {
|
||||
// Load the persisted configuration
|
||||
C::load(_presets[preset].toMap());
|
||||
}
|
||||
}
|
||||
|
||||
QString getPreset() { return _preset.get(); }
|
||||
|
||||
void setPreset(const QString& preset) {
|
||||
_preset.set(preset);
|
||||
if (_presets.contains(preset)) {
|
||||
// Always start back at default to remain deterministic
|
||||
QVariantMap config = _default;
|
||||
QVariantMap presetConfig = _presets[preset].toMap();
|
||||
for (auto it = presetConfig.cbegin(); it != presetConfig.cend(); it++) {
|
||||
config.insert(it.key(), it.value());
|
||||
}
|
||||
C::load(config);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
QVariantMap _default;
|
||||
QVariantMap _presets;
|
||||
Setting::Handle<QString> _preset;
|
||||
};
|
||||
|
||||
// A default Config is always on; to create an enableable Config, use the ctor JobConfig(bool enabled)
|
||||
class JobConfig : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double cpuRunTime READ getCPURunTime NOTIFY newStats()) //ms
|
||||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
|
||||
|
||||
double _msCPURunTime{ 0.0 };
|
||||
public:
|
||||
using Persistent = PersistentConfig<JobConfig>;
|
||||
|
||||
JobConfig() = default;
|
||||
JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {}
|
||||
|
||||
bool isEnabled() { return alwaysEnabled || enabled; }
|
||||
void setEnabled(bool enable) { enabled = alwaysEnabled || enable; }
|
||||
|
||||
bool alwaysEnabled{ true };
|
||||
bool enabled{ true };
|
||||
|
||||
virtual void setPresetList(const QJsonObject& object);
|
||||
|
||||
// This must be named toJSON to integrate with the global scripting JSON object
|
||||
Q_INVOKABLE QString toJSON() { return QJsonDocument(toJsonValue(*this).toObject()).toJson(QJsonDocument::Compact); }
|
||||
Q_INVOKABLE void load(const QVariantMap& map) { qObjectFromJsonValue(QJsonObject::fromVariantMap(map), *this); emit loaded(); }
|
||||
|
||||
// Running Time measurement
|
||||
// The new stats signal is emitted once per run time of a job when stats (cpu runtime) are updated
|
||||
void setCPURunTime(double mstime) { _msCPURunTime = mstime; emit newStats(); }
|
||||
double getCPURunTime() const { return _msCPURunTime; }
|
||||
|
||||
public slots:
|
||||
void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); emit loaded(); }
|
||||
|
||||
signals:
|
||||
void loaded();
|
||||
void newStats();
|
||||
};
|
||||
|
||||
class TaskConfig : public JobConfig {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using QConfigPointer = std::shared_ptr<QObject>;
|
||||
|
||||
using Persistent = PersistentConfig<TaskConfig>;
|
||||
|
||||
TaskConfig() = default ;
|
||||
TaskConfig(bool enabled) : JobConfig(enabled) {}
|
||||
|
||||
// getter for qml integration, prefer the templated getter
|
||||
Q_INVOKABLE QObject* getConfig(const QString& name) { return QObject::findChild<JobConfig*>(name); }
|
||||
// getter for cpp (strictly typed), prefer this getter
|
||||
template <class T> typename T::Config* getConfig(std::string job = "") const {
|
||||
QString name = job.empty() ? QString() : QString(job.c_str()); // an empty string is not a null string
|
||||
return findChild<typename T::Config*>(name);
|
||||
}
|
||||
|
||||
void connectChildConfig(QConfigPointer childConfig, const std::string& name);
|
||||
void transferChildrenConfigs(QConfigPointer source);
|
||||
|
||||
JobConcept* _task;
|
||||
|
||||
public slots:
|
||||
void refresh();
|
||||
};
|
||||
|
||||
using QConfigPointer = std::shared_ptr<QObject>;
|
||||
|
||||
}
|
||||
|
||||
#endif // hifi_task_Config_h
|
323
libraries/render/src/task/Task.h
Normal file
323
libraries/render/src/task/Task.h
Normal file
|
@ -0,0 +1,323 @@
|
|||
//
|
||||
// Task.h
|
||||
// render/src/task
|
||||
//
|
||||
// Created by Zach Pomerantz on 1/6/2016.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_task_Task_h
|
||||
#define hifi_task_Task_h
|
||||
|
||||
#include "Config.h"
|
||||
#include "Varying.h"
|
||||
|
||||
#include "SettingHandle.h"
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
#include <Profile.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
namespace task {
|
||||
|
||||
class JobConcept;
|
||||
template <class RC> class JobT;
|
||||
template <class RC> class TaskT;
|
||||
class JobNoIO {};
|
||||
|
||||
class JobContext {
|
||||
public:
|
||||
virtual ~JobContext() {}
|
||||
|
||||
std::shared_ptr<JobConfig> jobConfig { nullptr };
|
||||
};
|
||||
using JobContextPointer = std::shared_ptr<JobContext>;
|
||||
|
||||
// The guts of a job
|
||||
class JobConcept {
|
||||
public:
|
||||
using Config = JobConfig;
|
||||
|
||||
JobConcept(QConfigPointer config) : _config(config) {}
|
||||
virtual ~JobConcept() = default;
|
||||
|
||||
virtual const Varying getInput() const { return Varying(); }
|
||||
virtual const Varying getOutput() const { return Varying(); }
|
||||
|
||||
virtual QConfigPointer& getConfiguration() { return _config; }
|
||||
virtual void applyConfiguration() = 0;
|
||||
|
||||
void setCPURunTime(double mstime) { std::static_pointer_cast<Config>(_config)->setCPURunTime(mstime); }
|
||||
|
||||
QConfigPointer _config;
|
||||
protected:
|
||||
};
|
||||
|
||||
|
||||
template <class T, class C> void jobConfigure(T& data, const C& configuration) {
|
||||
data.configure(configuration);
|
||||
}
|
||||
template<class T> void jobConfigure(T&, const JobConfig&) {
|
||||
// nop, as the default JobConfig was used, so the data does not need a configure method
|
||||
}
|
||||
template<class T> void jobConfigure(T&, const TaskConfig&) {
|
||||
// nop, as the default TaskConfig was used, so the data does not need a configure method
|
||||
}
|
||||
|
||||
template <class T, class RC> void jobRun(T& data, const RC& renderContext, const JobNoIO& input, JobNoIO& output) {
|
||||
data.run(renderContext);
|
||||
}
|
||||
template <class T, class RC, class I> void jobRun(T& data, const RC& renderContext, const I& input, JobNoIO& output) {
|
||||
data.run(renderContext, input);
|
||||
}
|
||||
template <class T, class RC, class O> void jobRun(T& data, const RC& renderContext, const JobNoIO& input, O& output) {
|
||||
data.run(renderContext, output);
|
||||
}
|
||||
template <class T, class RC, class I, class O> void jobRun(T& data, const RC& renderContext, const I& input, O& output) {
|
||||
data.run(renderContext, input, output);
|
||||
}
|
||||
|
||||
template <class RC>
|
||||
class Job {
|
||||
public:
|
||||
using Context = RC;
|
||||
using ContextPointer = std::shared_ptr<Context>;
|
||||
using Config = JobConfig;
|
||||
using None = JobNoIO;
|
||||
|
||||
class Concept : public JobConcept {
|
||||
public:
|
||||
Concept(QConfigPointer config) : JobConcept(config) {}
|
||||
virtual ~Concept() = default;
|
||||
|
||||
virtual void run(const ContextPointer& renderContext) = 0;
|
||||
};
|
||||
using ConceptPointer = std::shared_ptr<Concept>;
|
||||
|
||||
template <class T, class C = Config, class I = None, class O = None> class Model : public Concept {
|
||||
public:
|
||||
using Data = T;
|
||||
using Input = I;
|
||||
using Output = O;
|
||||
|
||||
Data _data;
|
||||
Varying _input;
|
||||
Varying _output;
|
||||
|
||||
const Varying getInput() const override { return _input; }
|
||||
const Varying getOutput() const override { return _output; }
|
||||
|
||||
template <class... A>
|
||||
Model(const Varying& input, QConfigPointer config, A&&... args) :
|
||||
Concept(config),
|
||||
_data(Data(std::forward<A>(args)...)),
|
||||
_input(input),
|
||||
_output(Output()) {
|
||||
applyConfiguration();
|
||||
}
|
||||
|
||||
template <class... A>
|
||||
static std::shared_ptr<Model> create(const Varying& input, A&&... args) {
|
||||
return std::make_shared<Model>(input, std::make_shared<C>(), std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
|
||||
void applyConfiguration() override {
|
||||
jobConfigure(_data, *std::static_pointer_cast<C>(Concept::_config));
|
||||
}
|
||||
|
||||
void run(const ContextPointer& renderContext) override {
|
||||
renderContext->jobConfig = std::static_pointer_cast<Config>(Concept::_config);
|
||||
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->isEnabled()) {
|
||||
jobRun(_data, renderContext, _input.get<I>(), _output.edit<O>());
|
||||
}
|
||||
renderContext->jobConfig.reset();
|
||||
}
|
||||
};
|
||||
template <class T, class I, class C = Config> using ModelI = Model<T, C, I, None>;
|
||||
template <class T, class O, class C = Config> using ModelO = Model<T, C, None, O>;
|
||||
template <class T, class I, class O, class C = Config> using ModelIO = Model<T, C, I, O>;
|
||||
|
||||
Job(std::string name, ConceptPointer concept) : _concept(concept), _name(name) {}
|
||||
|
||||
const Varying getInput() const { return _concept->getInput(); }
|
||||
const Varying getOutput() const { return _concept->getOutput(); }
|
||||
QConfigPointer& getConfiguration() const { return _concept->getConfiguration(); }
|
||||
void applyConfiguration() { return _concept->applyConfiguration(); }
|
||||
|
||||
template <class T> T& edit() {
|
||||
auto concept = std::static_pointer_cast<typename T::JobModel>(_concept);
|
||||
assert(concept);
|
||||
return concept->_data;
|
||||
}
|
||||
|
||||
virtual void run(const ContextPointer& renderContext) {
|
||||
PerformanceTimer perfTimer(_name.c_str());
|
||||
PROFILE_RANGE(render, _name.c_str());
|
||||
auto start = usecTimestampNow();
|
||||
|
||||
_concept->run(renderContext);
|
||||
|
||||
_concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0);
|
||||
}
|
||||
|
||||
protected:
|
||||
ConceptPointer _concept;
|
||||
std::string _name = "";
|
||||
};
|
||||
|
||||
// A task is a specialized job to run a collection of other jobs
|
||||
// It can be created on any type T by aliasing the type JobModel in the class T
|
||||
// using JobModel = Task::Model<T>
|
||||
// The class T is expected to have a "build" method acting as a constructor.
|
||||
// The build method is where child Jobs can be added internally to the task
|
||||
// where the input of the task can be setup to feed the child jobs
|
||||
// and where the output of the task is defined
|
||||
template <class RC>
|
||||
class Task : public Job<RC> {
|
||||
public:
|
||||
using Context = RC;
|
||||
using ContextPointer = std::shared_ptr<Context>;
|
||||
using Config = TaskConfig;
|
||||
using JobType = Job<RC>;
|
||||
using None = typename JobType::None;
|
||||
using Concept = typename JobType::Concept;
|
||||
using ConceptPointer = typename JobType::ConceptPointer;
|
||||
using Jobs = std::vector<JobType>;
|
||||
|
||||
Task(std::string name, ConceptPointer concept) : JobType(name, concept) {}
|
||||
|
||||
class TaskConcept : public Concept {
|
||||
public:
|
||||
Varying _input;
|
||||
Varying _output;
|
||||
Jobs _jobs;
|
||||
|
||||
const Varying getInput() const override { return _input; }
|
||||
const Varying getOutput() const override { return _output; }
|
||||
|
||||
TaskConcept(const Varying& input, QConfigPointer config) : Concept(config), _input(input) {}
|
||||
|
||||
// Create a new job in the container's queue; returns the job's output
|
||||
template <class NT, class... NA> const Varying addJob(std::string name, const Varying& input, NA&&... args) {
|
||||
_jobs.emplace_back(name, (NT::JobModel::create(input, std::forward<NA>(args)...)));
|
||||
|
||||
// Conect the child config to this task's config
|
||||
std::static_pointer_cast<TaskConfig>(Concept::getConfiguration())->connectChildConfig(_jobs.back().getConfiguration(), name);
|
||||
|
||||
return _jobs.back().getOutput();
|
||||
}
|
||||
template <class NT, class... NA> const Varying addJob(std::string name, NA&&... args) {
|
||||
const auto input = Varying(typename NT::JobModel::Input());
|
||||
return addJob<NT>(name, input, std::forward<NA>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class C = Config, class I = None, class O = None> class TaskModel : public TaskConcept {
|
||||
public:
|
||||
using Data = T;
|
||||
using Input = I;
|
||||
using Output = O;
|
||||
|
||||
Data _data;
|
||||
|
||||
TaskModel(const Varying& input, QConfigPointer config) :
|
||||
TaskConcept(input, config),
|
||||
_data(Data()) {}
|
||||
|
||||
template <class... A>
|
||||
static std::shared_ptr<TaskModel> create(const Varying& input, A&&... args) {
|
||||
auto model = std::make_shared<TaskModel>(input, std::make_shared<C>());
|
||||
|
||||
model->_data.build(*(model), model->_input, model->_output, std::forward<A>(args)...);
|
||||
|
||||
// Recreate the Config to use the templated type
|
||||
model->createConfiguration();
|
||||
model->applyConfiguration();
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
template <class... A>
|
||||
static std::shared_ptr<TaskModel> create(A&&... args) {
|
||||
const auto input = Varying(Input());
|
||||
return create(input, std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
void createConfiguration() {
|
||||
// A brand new config
|
||||
auto config = std::make_shared<C>();
|
||||
// Make sure we transfer the former children configs to the new config
|
||||
config->transferChildrenConfigs(Concept::_config);
|
||||
// swap
|
||||
Concept::_config = config;
|
||||
// Capture this
|
||||
std::static_pointer_cast<C>(Concept::_config)->_task = this;
|
||||
}
|
||||
|
||||
QConfigPointer& getConfiguration() override {
|
||||
if (!Concept::_config) {
|
||||
createConfiguration();
|
||||
}
|
||||
return Concept::_config;
|
||||
}
|
||||
|
||||
void applyConfiguration() override {
|
||||
jobConfigure(_data, *std::static_pointer_cast<C>(Concept::_config));
|
||||
for (auto& job : TaskConcept::_jobs) {
|
||||
job.applyConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
void run(const ContextPointer& renderContext) override {
|
||||
auto config = std::static_pointer_cast<C>(Concept::_config);
|
||||
if (config->alwaysEnabled || config->enabled) {
|
||||
for (auto job : TaskConcept::_jobs) {
|
||||
job.run(renderContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
template <class T, class C = Config> using Model = TaskModel<T, C, None, None>;
|
||||
template <class T, class I, class C = Config> using ModelI = TaskModel<T, C, I, None>;
|
||||
template <class T, class O, class C = Config> using ModelO = TaskModel<T, C, None, O>;
|
||||
template <class T, class I, class O, class C = Config> using ModelIO = TaskModel<T, C, I, O>;
|
||||
|
||||
// Create a new job in the Task's queue; returns the job's output
|
||||
template <class T, class... A> const Varying addJob(std::string name, const Varying& input, A&&... args) {
|
||||
return std::static_pointer_cast<TaskConcept>(JobType::_concept)->template addJob<T>(name, input, std::forward<A>(args)...);
|
||||
}
|
||||
template <class T, class... A> const Varying addJob(std::string name, A&&... args) {
|
||||
const auto input = Varying(typename T::JobModel::Input());
|
||||
return std::static_pointer_cast<TaskConcept>(JobType::_concept)->template addJob<T>(name, input, std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
std::shared_ptr<Config> getConfiguration() {
|
||||
return std::static_pointer_cast<Config>(JobType::_concept->getConfiguration());
|
||||
}
|
||||
|
||||
protected:
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#define Task_DeclareTypeAliases(ContextType) \
|
||||
using JobConfig = task::JobConfig; \
|
||||
using TaskConfig = task::TaskConfig; \
|
||||
template <class T> using PersistentConfig = task::PersistentConfig<T>; \
|
||||
using Job = task::Job<ContextType>; \
|
||||
using Task = task::Task<ContextType>; \
|
||||
using Varying = task::Varying; \
|
||||
template < typename T0, typename T1 > using VaryingSet2 = task::VaryingSet2<T0, T1>; \
|
||||
template < typename T0, typename T1, typename T2 > using VaryingSet3 = task::VaryingSet3<T0, T1, T2>; \
|
||||
template < typename T0, typename T1, typename T2, typename T3 > using VaryingSet4 = task::VaryingSet4<T0, T1, T2, T3>; \
|
||||
template < typename T0, typename T1, typename T2, typename T3, typename T4 > using VaryingSet5 = task::VaryingSet5<T0, T1, T2, T3, T4>; \
|
||||
template < typename T0, typename T1, typename T2, typename T3, typename T4, typename T5 > using VaryingSet6 = task::VaryingSet6<T0, T1, T2, T3, T4, T5>; \
|
||||
template < typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6 > using VaryingSet7 = task::VaryingSet7<T0, T1, T2, T3, T4, T5, T6>; \
|
||||
template < class T, int NUM > using VaryingArray = task::VaryingArray<T, NUM>;
|
||||
|
||||
#endif // hifi_task_Task_h
|
287
libraries/render/src/task/Varying.h
Normal file
287
libraries/render/src/task/Varying.h
Normal file
|
@ -0,0 +1,287 @@
|
|||
//
|
||||
// Varying.h
|
||||
// render/src/task
|
||||
//
|
||||
// Created by Zach Pomerantz on 1/6/2016.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_task_Varying_h
|
||||
#define hifi_task_Varying_h
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
|
||||
namespace task {
|
||||
|
||||
// A varying piece of data, to be used as Job/Task I/O
|
||||
class Varying {
|
||||
public:
|
||||
Varying() {}
|
||||
Varying(const Varying& var) : _concept(var._concept) {}
|
||||
Varying& operator=(const Varying& var) {
|
||||
_concept = var._concept;
|
||||
return (*this);
|
||||
}
|
||||
template <class T> Varying(const T& data) : _concept(std::make_shared<Model<T>>(data)) {}
|
||||
|
||||
template <class T> bool canCast() const { return !!std::dynamic_pointer_cast<Model<T>>(_concept); }
|
||||
template <class T> const T& get() const { return std::static_pointer_cast<const Model<T>>(_concept)->_data; }
|
||||
template <class T> T& edit() { return std::static_pointer_cast<Model<T>>(_concept)->_data; }
|
||||
|
||||
|
||||
// access potential sub varyings contained in this one.
|
||||
Varying operator[] (uint8_t index) const { return (*_concept)[index]; }
|
||||
uint8_t length() const { return (*_concept).length(); }
|
||||
|
||||
template <class T> Varying getN (uint8_t index) const { return get<T>()[index]; }
|
||||
template <class T> Varying editN (uint8_t index) { return edit<T>()[index]; }
|
||||
|
||||
protected:
|
||||
class Concept {
|
||||
public:
|
||||
virtual ~Concept() = default;
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const = 0;
|
||||
virtual uint8_t length() const = 0;
|
||||
};
|
||||
template <class T> class Model : public Concept {
|
||||
public:
|
||||
using Data = T;
|
||||
|
||||
Model(const Data& data) : _data(data) {}
|
||||
virtual ~Model() = default;
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const override {
|
||||
Varying var;
|
||||
return var;
|
||||
}
|
||||
virtual uint8_t length() const override { return 0; }
|
||||
|
||||
Data _data;
|
||||
};
|
||||
|
||||
std::shared_ptr<Concept> _concept;
|
||||
};
|
||||
|
||||
using VaryingPairBase = std::pair<Varying, Varying>;
|
||||
template < typename T0, typename T1 >
|
||||
class VaryingSet2 : public VaryingPairBase {
|
||||
public:
|
||||
using Parent = VaryingPairBase;
|
||||
typedef void is_proxy_tag;
|
||||
|
||||
VaryingSet2() : Parent(Varying(T0()), Varying(T1())) {}
|
||||
VaryingSet2(const VaryingSet2& pair) : Parent(pair.first, pair.second) {}
|
||||
VaryingSet2(const Varying& first, const Varying& second) : Parent(first, second) {}
|
||||
|
||||
const T0& get0() const { return first.get<T0>(); }
|
||||
T0& edit0() { return first.edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return second.get<T1>(); }
|
||||
T1& edit1() { return second.edit<T1>(); }
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const {
|
||||
if (index == 1) {
|
||||
return std::get<1>((*this));
|
||||
} else {
|
||||
return std::get<0>((*this));
|
||||
}
|
||||
}
|
||||
virtual uint8_t length() const { return 2; }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
|
||||
template <class T0, class T1, class T2>
|
||||
class VaryingSet3 : public std::tuple<Varying, Varying,Varying>{
|
||||
public:
|
||||
using Parent = std::tuple<Varying, Varying, Varying>;
|
||||
|
||||
VaryingSet3() : Parent(Varying(T0()), Varying(T1()), Varying(T2())) {}
|
||||
VaryingSet3(const VaryingSet3& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src)) {}
|
||||
VaryingSet3(const Varying& first, const Varying& second, const Varying& third) : Parent(first, second, third) {}
|
||||
|
||||
const T0& get0() const { return std::get<0>((*this)).template get<T0>(); }
|
||||
T0& edit0() { return std::get<0>((*this)).template edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return std::get<1>((*this)).template get<T1>(); }
|
||||
T1& edit1() { return std::get<1>((*this)).template edit<T1>(); }
|
||||
|
||||
const T2& get2() const { return std::get<2>((*this)).template get<T2>(); }
|
||||
T2& edit2() { return std::get<2>((*this)).template edit<T2>(); }
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const {
|
||||
if (index == 2) {
|
||||
return std::get<2>((*this));
|
||||
} else if (index == 1) {
|
||||
return std::get<1>((*this));
|
||||
} else {
|
||||
return std::get<0>((*this));
|
||||
}
|
||||
}
|
||||
virtual uint8_t length() const { return 3; }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
template <class T0, class T1, class T2, class T3>
|
||||
class VaryingSet4 : public std::tuple<Varying, Varying, Varying, Varying>{
|
||||
public:
|
||||
using Parent = std::tuple<Varying, Varying, Varying, Varying>;
|
||||
|
||||
VaryingSet4() : Parent(Varying(T0()), Varying(T1()), Varying(T2()), Varying(T3())) {}
|
||||
VaryingSet4(const VaryingSet4& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src), std::get<3>(src)) {}
|
||||
VaryingSet4(const Varying& first, const Varying& second, const Varying& third, const Varying& fourth) : Parent(first, second, third, fourth) {}
|
||||
|
||||
const T0& get0() const { return std::get<0>((*this)).template get<T0>(); }
|
||||
T0& edit0() { return std::get<0>((*this)).template edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return std::get<1>((*this)).template get<T1>(); }
|
||||
T1& edit1() { return std::get<1>((*this)).template edit<T1>(); }
|
||||
|
||||
const T2& get2() const { return std::get<2>((*this)).template get<T2>(); }
|
||||
T2& edit2() { return std::get<2>((*this)).template edit<T2>(); }
|
||||
|
||||
const T3& get3() const { return std::get<3>((*this)).template get<T3>(); }
|
||||
T3& edit3() { return std::get<3>((*this)).template edit<T3>(); }
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const {
|
||||
if (index == 3) {
|
||||
return std::get<3>((*this));
|
||||
} else if (index == 2) {
|
||||
return std::get<2>((*this));
|
||||
} else if (index == 1) {
|
||||
return std::get<1>((*this));
|
||||
} else {
|
||||
return std::get<0>((*this));
|
||||
}
|
||||
}
|
||||
virtual uint8_t length() const { return 4; }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
|
||||
template <class T0, class T1, class T2, class T3, class T4>
|
||||
class VaryingSet5 : public std::tuple<Varying, Varying, Varying, Varying, Varying>{
|
||||
public:
|
||||
using Parent = std::tuple<Varying, Varying, Varying, Varying, Varying>;
|
||||
|
||||
VaryingSet5() : Parent(Varying(T0()), Varying(T1()), Varying(T2()), Varying(T3()), Varying(T4())) {}
|
||||
VaryingSet5(const VaryingSet5& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src), std::get<3>(src), std::get<4>(src)) {}
|
||||
VaryingSet5(const Varying& first, const Varying& second, const Varying& third, const Varying& fourth, const Varying& fifth) : Parent(first, second, third, fourth, fifth) {}
|
||||
|
||||
const T0& get0() const { return std::get<0>((*this)).template get<T0>(); }
|
||||
T0& edit0() { return std::get<0>((*this)).template edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return std::get<1>((*this)).template get<T1>(); }
|
||||
T1& edit1() { return std::get<1>((*this)).template edit<T1>(); }
|
||||
|
||||
const T2& get2() const { return std::get<2>((*this)).template get<T2>(); }
|
||||
T2& edit2() { return std::get<2>((*this)).template edit<T2>(); }
|
||||
|
||||
const T3& get3() const { return std::get<3>((*this)).template get<T3>(); }
|
||||
T3& edit3() { return std::get<3>((*this)).template edit<T3>(); }
|
||||
|
||||
const T4& get4() const { return std::get<4>((*this)).template get<T4>(); }
|
||||
T4& edit4() { return std::get<4>((*this)).template edit<T4>(); }
|
||||
|
||||
virtual Varying operator[] (uint8_t index) const {
|
||||
if (index == 4) {
|
||||
return std::get<4>((*this));
|
||||
} else if (index == 3) {
|
||||
return std::get<3>((*this));
|
||||
} else if (index == 2) {
|
||||
return std::get<2>((*this));
|
||||
} else if (index == 1) {
|
||||
return std::get<1>((*this));
|
||||
} else {
|
||||
return std::get<0>((*this));
|
||||
}
|
||||
}
|
||||
virtual uint8_t length() const { return 5; }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
template <class T0, class T1, class T2, class T3, class T4, class T5>
|
||||
class VaryingSet6 : public std::tuple<Varying, Varying, Varying, Varying, Varying, Varying>{
|
||||
public:
|
||||
using Parent = std::tuple<Varying, Varying, Varying, Varying, Varying, Varying>;
|
||||
|
||||
VaryingSet6() : Parent(Varying(T0()), Varying(T1()), Varying(T2()), Varying(T3()), Varying(T4()), Varying(T5())) {}
|
||||
VaryingSet6(const VaryingSet6& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src), std::get<3>(src), std::get<4>(src), std::get<5>(src)) {}
|
||||
VaryingSet6(const Varying& first, const Varying& second, const Varying& third, const Varying& fourth, const Varying& fifth, const Varying& sixth) : Parent(first, second, third, fourth, fifth, sixth) {}
|
||||
|
||||
const T0& get0() const { return std::get<0>((*this)).template get<T0>(); }
|
||||
T0& edit0() { return std::get<0>((*this)).template edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return std::get<1>((*this)).template get<T1>(); }
|
||||
T1& edit1() { return std::get<1>((*this)).template edit<T1>(); }
|
||||
|
||||
const T2& get2() const { return std::get<2>((*this)).template get<T2>(); }
|
||||
T2& edit2() { return std::get<2>((*this)).template edit<T2>(); }
|
||||
|
||||
const T3& get3() const { return std::get<3>((*this)).template get<T3>(); }
|
||||
T3& edit3() { return std::get<3>((*this)).template edit<T3>(); }
|
||||
|
||||
const T4& get4() const { return std::get<4>((*this)).template get<T4>(); }
|
||||
T4& edit4() { return std::get<4>((*this)).template edit<T4>(); }
|
||||
|
||||
const T5& get5() const { return std::get<5>((*this)).template get<T5>(); }
|
||||
T5& edit5() { return std::get<5>((*this)).template edit<T5>(); }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
template <class T0, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
class VaryingSet7 : public std::tuple<Varying, Varying, Varying, Varying, Varying, Varying, Varying>{
|
||||
public:
|
||||
using Parent = std::tuple<Varying, Varying, Varying, Varying, Varying, Varying, Varying>;
|
||||
|
||||
VaryingSet7() : Parent(Varying(T0()), Varying(T1()), Varying(T2()), Varying(T3()), Varying(T4()), Varying(T5()), Varying(T6())) {}
|
||||
VaryingSet7(const VaryingSet7& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src), std::get<3>(src), std::get<4>(src), std::get<5>(src), std::get<6>(src)) {}
|
||||
VaryingSet7(const Varying& first, const Varying& second, const Varying& third, const Varying& fourth, const Varying& fifth, const Varying& sixth, const Varying& seventh) : Parent(first, second, third, fourth, fifth, sixth, seventh) {}
|
||||
|
||||
const T0& get0() const { return std::get<0>((*this)).template get<T0>(); }
|
||||
T0& edit0() { return std::get<0>((*this)).template edit<T0>(); }
|
||||
|
||||
const T1& get1() const { return std::get<1>((*this)).template get<T1>(); }
|
||||
T1& edit1() { return std::get<1>((*this)).template edit<T1>(); }
|
||||
|
||||
const T2& get2() const { return std::get<2>((*this)).template get<T2>(); }
|
||||
T2& edit2() { return std::get<2>((*this)).template edit<T2>(); }
|
||||
|
||||
const T3& get3() const { return std::get<3>((*this)).template get<T3>(); }
|
||||
T3& edit3() { return std::get<3>((*this)).template edit<T3>(); }
|
||||
|
||||
const T4& get4() const { return std::get<4>((*this)).template get<T4>(); }
|
||||
T4& edit4() { return std::get<4>((*this)).template edit<T4>(); }
|
||||
|
||||
const T5& get5() const { return std::get<5>((*this)).template get<T5>(); }
|
||||
T5& edit5() { return std::get<5>((*this)).template edit<T5>(); }
|
||||
|
||||
const T6& get6() const { return std::get<6>((*this)).template get<T6>(); }
|
||||
T6& edit6() { return std::get<6>((*this)).template edit<T6>(); }
|
||||
|
||||
Varying hasVarying() const { return Varying((*this)); }
|
||||
};
|
||||
|
||||
|
||||
template < class T, int NUM >
|
||||
class VaryingArray : public std::array<Varying, NUM> {
|
||||
public:
|
||||
VaryingArray() {
|
||||
for (size_t i = 0; i < NUM; i++) {
|
||||
(*this)[i] = Varying(T());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // hifi_task_Varying_h
|
|
@ -130,8 +130,8 @@ public:
|
|||
bool _enableTexturing { true };
|
||||
|
||||
RenderDetails _details;
|
||||
render::ScenePointer _scene; // HACK
|
||||
int8_t _cameraMode { -1 }; // HACK
|
||||
render::ScenePointer _scene;
|
||||
int8_t _cameraMode { -1 };
|
||||
};
|
||||
|
||||
#endif // hifi_RenderArgs_h
|
||||
|
|
|
@ -80,6 +80,9 @@ input[type=button].naked:active {
|
|||
|
||||
#snapshot-images {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#snapshot-images img {
|
||||
|
@ -108,7 +111,7 @@ input[type=button].naked:active {
|
|||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
height: 45px;
|
||||
line-height: 60px;
|
||||
width: calc(100% - 8px);
|
||||
position: absolute;
|
||||
|
@ -119,13 +122,13 @@ input[type=button].naked:active {
|
|||
.shareButtons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 30px;
|
||||
margin-left: 15px;
|
||||
height: 100%;
|
||||
width: 80%;
|
||||
width: 75%;
|
||||
}
|
||||
.blastToConnections {
|
||||
text-align: left;
|
||||
margin-right: 25px;
|
||||
margin-right: 20px;
|
||||
height: 29px;
|
||||
}
|
||||
.shareWithEveryone {
|
||||
|
@ -158,10 +161,11 @@ input[type=button].naked:active {
|
|||
font-family: Raleway-SemiBold;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
text-shadow: 2px 2px 3px #000000;
|
||||
height: 100%;
|
||||
margin-right: 10px;
|
||||
width: 20%;
|
||||
}
|
||||
.showShareButtonsButtonDiv > label {
|
||||
text-shadow: 2px 2px 3px #000000;
|
||||
}
|
||||
.showShareButton {
|
||||
width: 40px;
|
||||
|
@ -193,23 +197,17 @@ input[type=button].naked:active {
|
|||
background-color: white;
|
||||
}
|
||||
.showShareButtonDots {
|
||||
display: flex;
|
||||
width: 32px;
|
||||
display: block;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-family: HiFi-Glyphs;
|
||||
font-size: 60px;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 14px;
|
||||
right: 20px;
|
||||
bottom: 12px;
|
||||
color: #00b4ef;
|
||||
pointer-events: none;
|
||||
}
|
||||
.showShareButtonDots > span {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin: auto;
|
||||
background-color: #0093C5;
|
||||
border-radius: 50%;
|
||||
border-width: 0;
|
||||
display: inline;
|
||||
}
|
||||
/*
|
||||
// END styling of share overlay
|
||||
*/
|
||||
|
|
|
@ -101,9 +101,11 @@ input[type=radio] {
|
|||
opacity: 0;
|
||||
}
|
||||
input[type=radio] + label{
|
||||
display: inline-block;
|
||||
margin-left: -2em;
|
||||
line-height: 2em;
|
||||
display: inline-block;
|
||||
margin-left: -2em;
|
||||
line-height: 2em;
|
||||
font-family: Raleway-SemiBold;
|
||||
font-size: 14px;
|
||||
}
|
||||
input[type=radio] + label > span{
|
||||
display: inline-block;
|
||||
|
@ -157,7 +159,6 @@ input[type=radio]:active + label > span > span{
|
|||
border-width: 0px;
|
||||
background-image: linear-gradient(#00B4EF, #1080B8);
|
||||
min-height: 30px;
|
||||
|
||||
}
|
||||
.blueButton:hover {
|
||||
background-image: linear-gradient(#00B4EF, #00B4EF);
|
||||
|
|
|
@ -52,7 +52,7 @@ function clearImages() {
|
|||
imageCount = 0;
|
||||
idCounter = 0;
|
||||
}
|
||||
function addImage(image_data, isGifLoading, isShowingPreviousImages, canSharePreviousImages, hifiShareButtonsDisabled) {
|
||||
function addImage(image_data, isGifLoading, canShare, isShowingPreviousImages, blastButtonDisabled, hifiButtonDisabled) {
|
||||
if (!image_data.localPath) {
|
||||
return;
|
||||
}
|
||||
|
@ -60,8 +60,9 @@ function addImage(image_data, isGifLoading, isShowingPreviousImages, canSharePre
|
|||
// imageContainer setup
|
||||
var imageContainer = document.createElement("DIV");
|
||||
imageContainer.id = id;
|
||||
imageContainer.style.width = "100%";
|
||||
imageContainer.style.height = "251px";
|
||||
imageContainer.style.width = "95%";
|
||||
imageContainer.style.height = "240px";
|
||||
imageContainer.style.margin = "5px auto";
|
||||
imageContainer.style.display = "flex";
|
||||
imageContainer.style.justifyContent = "center";
|
||||
imageContainer.style.alignItems = "center";
|
||||
|
@ -80,22 +81,22 @@ function addImage(image_data, isGifLoading, isShowingPreviousImages, canSharePre
|
|||
if (isGif) {
|
||||
imageContainer.innerHTML += '<span class="gifLabel">GIF</span>';
|
||||
}
|
||||
if (!isGifLoading && !isShowingPreviousImages) {
|
||||
if (!isGifLoading && !isShowingPreviousImages && canShare) {
|
||||
shareForUrl(id);
|
||||
} else if (isShowingPreviousImages && canSharePreviousImages) {
|
||||
appendShareBar(id, image_data.story_id, isGif, hifiShareButtonsDisabled)
|
||||
} else if (isShowingPreviousImages && canShare && image_data.story_id) {
|
||||
appendShareBar(id, image_data.story_id, isGif, blastButtonDisabled, hifiButtonDisabled)
|
||||
}
|
||||
}
|
||||
function appendShareBar(divID, story_id, isGif, hifiShareButtonsDisabled) {
|
||||
function appendShareBar(divID, story_id, isGif, blastButtonDisabled, hifiButtonDisabled) {
|
||||
var story_url = "https://highfidelity.com/user_stories/" + story_id;
|
||||
var parentDiv = document.getElementById(divID);
|
||||
parentDiv.setAttribute('data-story-id', story_id);
|
||||
document.getElementById(divID).appendChild(createShareBar(divID, isGif, story_url, hifiShareButtonsDisabled));
|
||||
document.getElementById(divID).appendChild(createShareBar(divID, isGif, story_url, blastButtonDisabled, hifiButtonDisabled));
|
||||
if (divID === "p0") {
|
||||
selectImageToShare(divID, true);
|
||||
}
|
||||
}
|
||||
function createShareBar(parentID, isGif, shareURL, hifiShareButtonsDisabled) {
|
||||
function createShareBar(parentID, isGif, shareURL, blastButtonDisabled, hifiButtonDisabled) {
|
||||
var shareBar = document.createElement("div");
|
||||
shareBar.id = parentID + "shareBar";
|
||||
shareBar.className = "shareControls";
|
||||
|
@ -109,8 +110,8 @@ function createShareBar(parentID, isGif, shareURL, hifiShareButtonsDisabled) {
|
|||
var twitterButtonID = parentID + "twitterButton";
|
||||
shareBar.innerHTML += '' +
|
||||
'<div class="shareButtons" id="' + shareButtonsDivID + '" style="visibility:hidden">' +
|
||||
'<input type="button"' + (hifiShareButtonsDisabled ? ' disabled' : '') + ' class="blastToConnections blueButton" id="' + blastToConnectionsButtonID + '" value="BLAST TO MY CONNECTIONS" onclick="blastToConnections(' + parentID + ', ' + isGif + ')" />' +
|
||||
'<input type="button"' + (hifiShareButtonsDisabled ? ' disabled' : '') + ' class="shareWithEveryone" id="' + shareWithEveryoneButtonID + '" onclick="shareWithEveryone(' + parentID + ', ' + isGif + ')" />' +
|
||||
'<input type="button"' + (blastButtonDisabled ? ' disabled' : '') + ' class="blastToConnections blueButton" id="' + blastToConnectionsButtonID + '" value="BLAST TO MY CONNECTIONS" onclick="blastToConnections(' + parentID + ', ' + isGif + ')" />' +
|
||||
'<input type="button"' + (hifiButtonDisabled ? ' disabled' : '') + ' class="shareWithEveryone" id="' + shareWithEveryoneButtonID + '" onclick="shareWithEveryone(' + parentID + ', ' + isGif + ')" />' +
|
||||
'<a class="facebookButton" id="' + facebookButtonID + '" onclick="shareButtonClicked(' + parentID + ')" target="_blank" href="https://www.facebook.com/dialog/feed?app_id=1585088821786423&link=' + shareURL + '"></a>' +
|
||||
'<a class="twitterButton" id="' + twitterButtonID + '" onclick="shareButtonClicked(' + parentID + ')" target="_blank" href="https://twitter.com/intent/tweet?text=I%20just%20took%20a%20snapshot!&url=' + shareURL + '&via=highfidelity&hashtags=VR,HiFi"></a>' +
|
||||
'</div>' +
|
||||
|
@ -118,7 +119,7 @@ function createShareBar(parentID, isGif, shareURL, hifiShareButtonsDisabled) {
|
|||
'<label id="' + showShareButtonsLabelID + '" for="' + showShareButtonsButtonID + '">SHARE</label>' +
|
||||
'<input type="button" class="showShareButton inactive" id="' + showShareButtonsButtonID + '" onclick="selectImageToShare(' + parentID + ', true)" />' +
|
||||
'<div class="showShareButtonDots">' +
|
||||
'<span></span><span></span><span></span>' +
|
||||
'' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
|
@ -149,6 +150,15 @@ function selectImageToShare(selectedID, isSelected) {
|
|||
shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
|
||||
|
||||
shareButtonsDiv.style.visibility = "visible";
|
||||
|
||||
var containers = document.getElementsByClassName("shareControls");
|
||||
var parentID;
|
||||
for (var i = 0; i < containers.length; ++i) {
|
||||
parentID = containers[i].id.slice(0, 2);
|
||||
if (parentID !== selectedID) {
|
||||
selectImageToShare(parentID, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
showShareButtonsButton.onclick = function () { selectImageToShare(selectedID, true) };
|
||||
showShareButtonsButton.classList.remove("active");
|
||||
|
@ -173,7 +183,6 @@ function blastToConnections(selectedID, isGif) {
|
|||
selectedID = selectedID.id; // `selectedID` is passed as an HTML object to these functions; we just want the ID
|
||||
|
||||
document.getElementById(selectedID + "blastToConnectionsButton").disabled = true;
|
||||
document.getElementById(selectedID + "shareWithEveryoneButton").disabled = true;
|
||||
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
|
@ -185,7 +194,6 @@ function blastToConnections(selectedID, isGif) {
|
|||
function shareWithEveryone(selectedID, isGif) {
|
||||
selectedID = selectedID.id; // `selectedID` is passed as an HTML object to these functions; we just want the ID
|
||||
|
||||
document.getElementById(selectedID + "blastToConnectionsButton").disabled = true;
|
||||
document.getElementById(selectedID + "shareWithEveryoneButton").disabled = true;
|
||||
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
|
@ -233,7 +241,7 @@ function handleCaptureSetting(setting) {
|
|||
window.onload = function () {
|
||||
// Uncomment the line below to test functionality in a browser.
|
||||
// See definition of "testInBrowser()" to modify tests.
|
||||
//testInBrowser(true);
|
||||
//testInBrowser(false);
|
||||
openEventBridge(function () {
|
||||
// Set up a handler for receiving the data, and tell the .js we are ready to receive it.
|
||||
EventBridge.scriptEventReceived.connect(function (message) {
|
||||
|
@ -260,7 +268,7 @@ window.onload = function () {
|
|||
var messageOptions = message.options;
|
||||
imageCount = message.image_data.length;
|
||||
message.image_data.forEach(function (element, idx, array) {
|
||||
addImage(element, true, true, message.canShare, message.image_data[idx].buttonDisabled);
|
||||
addImage(element, true, message.canShare, true, message.image_data[idx].blastButtonDisabled, message.image_data[idx].hifiButtonDisabled);
|
||||
});
|
||||
break;
|
||||
case 'addImages':
|
||||
|
@ -272,22 +280,24 @@ window.onload = function () {
|
|||
if (messageOptions.containsGif) {
|
||||
if (messageOptions.processingGif) {
|
||||
imageCount = message.image_data.length + 1; // "+1" for the GIF that'll finish processing soon
|
||||
message.image_data.unshift({ localPath: messageOptions.loadingGifPath });
|
||||
message.image_data.push({ localPath: messageOptions.loadingGifPath });
|
||||
message.image_data.forEach(function (element, idx, array) {
|
||||
addImage(element, idx === 0, false, false);
|
||||
addImage(element, idx === 1, idx === 0 && messageOptions.canShare, false);
|
||||
});
|
||||
} else {
|
||||
var gifPath = message.image_data[0].localPath;
|
||||
var p0img = document.getElementById('p0img');
|
||||
p0img.src = gifPath;
|
||||
var p1img = document.getElementById('p1img');
|
||||
p1img.src = gifPath;
|
||||
|
||||
paths[0] = gifPath;
|
||||
shareForUrl("p0");
|
||||
paths[1] = gifPath;
|
||||
if (messageOptions.canShare) {
|
||||
shareForUrl("p1");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
imageCount = message.image_data.length;
|
||||
message.image_data.forEach(function (element, idx, array) {
|
||||
addImage(element, false, false, false);
|
||||
addImage(element, false, messageOptions.canShare, false);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
@ -296,7 +306,7 @@ window.onload = function () {
|
|||
break;
|
||||
case 'snapshotUploadComplete':
|
||||
var isGif = message.image_url.split('.').pop().toLowerCase() === "gif";
|
||||
appendShareBar(isGif || imageCount === 1 ? "p0" : "p1", message.story_id, isGif);
|
||||
appendShareBar(isGif ? "p1" : "p0", message.story_id, isGif);
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown message action received in SnapshotReview.js.");
|
||||
|
@ -329,6 +339,7 @@ function testInBrowser(isTestingSetupInstructions) {
|
|||
} else {
|
||||
imageCount = 1;
|
||||
//addImage({ localPath: 'http://lorempixel.com/553/255' });
|
||||
addImage({ localPath: 'C:/Users/valef/Desktop/hifi-snap-by-zfox-on-2017-04-26_10-26-53.gif' }, false, true, true, false);
|
||||
addImage({ localPath: 'C:/Users/valef/Desktop/hifi-snap-by-zfox-on-2017-05-01_15-48-15.gif' }, false, true, true, false, false);
|
||||
addImage({ localPath: 'C:/Users/valef/Desktop/hifi-snap-by-zfox-on-2017-05-01_15-48-15.jpg' }, false, true, true, false, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -519,11 +519,9 @@
|
|||
|
||||
function updateTriggers(value, fromKeyboard, hand) {
|
||||
if (currentHand && hand !== currentHand) {
|
||||
debug("currentHand", currentHand, "ignoring messages from", hand);
|
||||
debug("currentHand", currentHand, "ignoring messages from", hand); // this can be a lot of spam on Touch. Should guard that someday.
|
||||
return;
|
||||
}
|
||||
currentHand = hand;
|
||||
currentHandJointIndex = getIdealHandJointIndex(MyAvatar, handToString(currentHand)); // Always, in case of changed skeleton.
|
||||
// ok now, we are either initiating or quitting...
|
||||
var isGripping = value > GRIP_MIN;
|
||||
if (isGripping) {
|
||||
|
@ -531,6 +529,8 @@
|
|||
if (state !== STATES.INACTIVE) {
|
||||
return;
|
||||
}
|
||||
currentHand = hand;
|
||||
currentHandJointIndex = getIdealHandJointIndex(MyAvatar, handToString(currentHand)); // Always, in case of changed skeleton.
|
||||
startHandshake(fromKeyboard);
|
||||
} else {
|
||||
// TODO: should we end handshake even when inactive? Ponder
|
||||
|
|
|
@ -117,13 +117,15 @@ function onMessage(message) {
|
|||
setting: Settings.getValue("alsoTakeAnimatedSnapshot", true)
|
||||
}));
|
||||
if (Snapshot.getSnapshotsLocation() !== "") {
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
action: "showPreviousImages",
|
||||
options: snapshotOptions,
|
||||
image_data: imageData,
|
||||
canShare: !isDomainOpen(Settings.getValue("previousSnapshotDomainID"))
|
||||
}));
|
||||
isDomainOpen(Settings.getValue("previousSnapshotDomainID"), function (canShare) {
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
action: "showPreviousImages",
|
||||
options: snapshotOptions,
|
||||
image_data: imageData,
|
||||
canShare: canShare
|
||||
}));
|
||||
});
|
||||
} else {
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
|
@ -131,10 +133,12 @@ function onMessage(message) {
|
|||
}));
|
||||
Settings.setValue("previousStillSnapPath", "");
|
||||
Settings.setValue("previousStillSnapStoryID", "");
|
||||
Settings.setValue("previousStillSnapSharingDisabled", false);
|
||||
Settings.setValue("previousStillSnapBlastingDisabled", false);
|
||||
Settings.setValue("previousStillSnapHifiSharingDisabled", false);
|
||||
Settings.setValue("previousAnimatedSnapPath", "");
|
||||
Settings.setValue("previousAnimatedSnapStoryID", "");
|
||||
Settings.setValue("previousAnimatedSnapSharingDisabled", false);
|
||||
Settings.setValue("previousAnimatedSnapBlastingDisabled", false);
|
||||
Settings.setValue("previousAnimatedSnapHifiSharingDisabled", false);
|
||||
}
|
||||
break;
|
||||
case 'chooseSnapshotLocation':
|
||||
|
@ -180,9 +184,9 @@ function onMessage(message) {
|
|||
isLoggedIn = Account.isLoggedIn();
|
||||
storyIDsToMaybeDelete.splice(storyIDsToMaybeDelete.indexOf(message.story_id), 1);
|
||||
if (message.isGif) {
|
||||
Settings.setValue("previousAnimatedSnapSharingDisabled", true);
|
||||
Settings.setValue("previousAnimatedSnapBlastingDisabled", true);
|
||||
} else {
|
||||
Settings.setValue("previousStillSnapSharingDisabled", true);
|
||||
Settings.setValue("previousStillSnapBlastingDisabled", true);
|
||||
}
|
||||
|
||||
if (isLoggedIn) {
|
||||
|
@ -220,9 +224,9 @@ function onMessage(message) {
|
|||
if (error || (response.status !== 'success')) {
|
||||
print("ERROR uploading announcement story: ", error || response.status);
|
||||
if (message.isGif) {
|
||||
Settings.setValue("previousAnimatedSnapSharingDisabled", false);
|
||||
Settings.setValue("previousAnimatedSnapBlastingDisabled", false);
|
||||
} else {
|
||||
Settings.setValue("previousStillSnapSharingDisabled", false);
|
||||
Settings.setValue("previousStillSnapBlastingDisabled", false);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
|
@ -240,9 +244,9 @@ function onMessage(message) {
|
|||
isLoggedIn = Account.isLoggedIn();
|
||||
storyIDsToMaybeDelete.splice(storyIDsToMaybeDelete.indexOf(message.story_id), 1);
|
||||
if (message.isGif) {
|
||||
Settings.setValue("previousAnimatedSnapSharingDisabled", true);
|
||||
Settings.setValue("previousAnimatedSnapHifiSharingDisabled", true);
|
||||
} else {
|
||||
Settings.setValue("previousStillSnapSharingDisabled", true);
|
||||
Settings.setValue("previousStillSnapHifiSharingDisabled", true);
|
||||
}
|
||||
|
||||
if (isLoggedIn) {
|
||||
|
@ -264,9 +268,9 @@ function onMessage(message) {
|
|||
if (error || (response.status !== 'success')) {
|
||||
print("ERROR changing audience: ", error || response.status);
|
||||
if (message.isGif) {
|
||||
Settings.setValue("previousAnimatedSnapSharingDisabled", false);
|
||||
Settings.setValue("previousAnimatedSnapHifiSharingDisabled", false);
|
||||
} else {
|
||||
Settings.setValue("previousStillSnapSharingDisabled", false);
|
||||
Settings.setValue("previousStillSnapHifiSharingDisabled", false);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
|
@ -301,21 +305,33 @@ function onButtonClicked() {
|
|||
shouldActivateButton = true;
|
||||
var previousStillSnapPath = Settings.getValue("previousStillSnapPath");
|
||||
var previousStillSnapStoryID = Settings.getValue("previousStillSnapStoryID");
|
||||
var previousStillSnapSharingDisabled = Settings.getValue("previousStillSnapSharingDisabled");
|
||||
var previousStillSnapBlastingDisabled = Settings.getValue("previousStillSnapBlastingDisabled");
|
||||
var previousStillSnapHifiSharingDisabled = Settings.getValue("previousStillSnapHifiSharingDisabled");
|
||||
var previousAnimatedSnapPath = Settings.getValue("previousAnimatedSnapPath");
|
||||
var previousAnimatedSnapStoryID = Settings.getValue("previousAnimatedSnapStoryID");
|
||||
var previousAnimatedSnapSharingDisabled = Settings.getValue("previousAnimatedSnapSharingDisabled");
|
||||
var previousAnimatedSnapBlastingDisabled = Settings.getValue("previousAnimatedSnapBlastingDisabled");
|
||||
var previousAnimatedSnapHifiSharingDisabled = Settings.getValue("previousAnimatedSnapHifiSharingDisabled");
|
||||
snapshotOptions = {
|
||||
containsGif: previousAnimatedSnapPath !== "",
|
||||
processingGif: false,
|
||||
shouldUpload: false
|
||||
}
|
||||
imageData = [];
|
||||
if (previousAnimatedSnapPath !== "") {
|
||||
imageData.push({ localPath: previousAnimatedSnapPath, story_id: previousAnimatedSnapStoryID, buttonDisabled: previousAnimatedSnapSharingDisabled });
|
||||
}
|
||||
if (previousStillSnapPath !== "") {
|
||||
imageData.push({ localPath: previousStillSnapPath, story_id: previousStillSnapStoryID, buttonDisabled: previousStillSnapSharingDisabled });
|
||||
imageData.push({
|
||||
localPath: previousStillSnapPath,
|
||||
story_id: previousStillSnapStoryID,
|
||||
blastButtonDisabled: previousStillSnapBlastingDisabled,
|
||||
hifiButtonDisabled: previousStillSnapHifiSharingDisabled
|
||||
});
|
||||
}
|
||||
if (previousAnimatedSnapPath !== "") {
|
||||
imageData.push({
|
||||
localPath: previousAnimatedSnapPath,
|
||||
story_id: previousAnimatedSnapStoryID,
|
||||
blastButtonDisabled: previousAnimatedSnapBlastingDisabled,
|
||||
hifiButtonDisabled: previousAnimatedSnapHifiSharingDisabled
|
||||
});
|
||||
}
|
||||
tablet.gotoWebScreen(SNAPSHOT_REVIEW_URL);
|
||||
tablet.webEventReceived.connect(onMessage);
|
||||
|
@ -355,10 +371,12 @@ function takeSnapshot() {
|
|||
}));
|
||||
Settings.setValue("previousStillSnapPath", "");
|
||||
Settings.setValue("previousStillSnapStoryID", "");
|
||||
Settings.setValue("previousStillSnapSharingDisabled", false);
|
||||
Settings.setValue("previousStillSnapBlastingDisabled", false);
|
||||
Settings.setValue("previousStillSnapHifiSharingDisabled", false);
|
||||
Settings.setValue("previousAnimatedSnapPath", "");
|
||||
Settings.setValue("previousAnimatedSnapStoryID", "");
|
||||
Settings.setValue("previousAnimatedSnapSharingDisabled", false);
|
||||
Settings.setValue("previousAnimatedSnapBlastingDisabled", false);
|
||||
Settings.setValue("previousAnimatedSnapHifiSharingDisabled", false);
|
||||
|
||||
// Raising the desktop for the share dialog at end will interact badly with clearOverlayWhenMoving.
|
||||
// Turn it off now, before we start futzing with things (and possibly moving).
|
||||
|
@ -377,6 +395,7 @@ function takeSnapshot() {
|
|||
resetOverlays = Menu.isOptionChecked("Overlays"); // For completeness. Certainly true if the button is visible to be clicked.
|
||||
reticleVisible = Reticle.visible;
|
||||
Reticle.visible = false;
|
||||
Reticle.allowMouseCapture = false;
|
||||
|
||||
var includeAnimated = Settings.getValue("alsoTakeAnimatedSnapshot", true);
|
||||
if (includeAnimated) {
|
||||
|
@ -403,37 +422,40 @@ function takeSnapshot() {
|
|||
}, FINISH_SOUND_DELAY);
|
||||
}
|
||||
|
||||
function isDomainOpen(id) {
|
||||
function isDomainOpen(id, callback) {
|
||||
print("Checking open status of domain with ID:", id);
|
||||
if (!id) {
|
||||
return false;
|
||||
var status = false;
|
||||
if (id) {
|
||||
var options = [
|
||||
'now=' + new Date().toISOString(),
|
||||
'include_actions=concurrency',
|
||||
'domain_id=' + id.slice(1, -1),
|
||||
'restriction=open,hifi' // If we're sharing, we're logged in
|
||||
// If we're here, protocol matches, and it is online
|
||||
];
|
||||
var url = METAVERSE_BASE + "/api/v1/user_stories?" + options.join('&');
|
||||
|
||||
request({
|
||||
uri: url,
|
||||
method: 'GET'
|
||||
}, function (error, response) {
|
||||
if (error || (response.status !== 'success')) {
|
||||
print("ERROR getting open status of domain: ", error || response.status);
|
||||
} else {
|
||||
status = response.total_entries ? true : false;
|
||||
}
|
||||
print("Domain open status:", status);
|
||||
callback(status);
|
||||
});
|
||||
} else {
|
||||
callback(status);
|
||||
}
|
||||
|
||||
var options = [
|
||||
'now=' + new Date().toISOString(),
|
||||
'include_actions=concurrency',
|
||||
'domain_id=' + id.slice(1, -1),
|
||||
'restriction=open,hifi' // If we're sharing, we're logged in
|
||||
// If we're here, protocol matches, and it is online
|
||||
];
|
||||
var url = METAVERSE_BASE + "/api/v1/user_stories?" + options.join('&');
|
||||
|
||||
return request({
|
||||
uri: url,
|
||||
method: 'GET'
|
||||
}, function (error, response) {
|
||||
if (error || (response.status !== 'success')) {
|
||||
print("ERROR getting open status of domain: ", error || response.status);
|
||||
return false;
|
||||
} else {
|
||||
return response.total_entries;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function stillSnapshotTaken(pathStillSnapshot, notify) {
|
||||
// show hud
|
||||
Reticle.visible = reticleVisible;
|
||||
Reticle.allowMouseCapture = true;
|
||||
// show overlays if they were on
|
||||
if (resetOverlays) {
|
||||
Menu.setIsOptionChecked("Overlays", true);
|
||||
|
@ -448,25 +470,27 @@ function stillSnapshotTaken(pathStillSnapshot, notify) {
|
|||
// during which time the user may have moved. So stash that info in the dialog so that
|
||||
// it records the correct href. (We can also stash in .jpegs, but not .gifs.)
|
||||
// last element in data array tells dialog whether we can share or not
|
||||
snapshotOptions = {
|
||||
containsGif: false,
|
||||
processingGif: false,
|
||||
canShare: !isDomainOpen(domainId)
|
||||
};
|
||||
imageData = [{ localPath: pathStillSnapshot, href: href }];
|
||||
Settings.setValue("previousStillSnapPath", pathStillSnapshot);
|
||||
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
action: "addImages",
|
||||
options: snapshotOptions,
|
||||
image_data: imageData
|
||||
}));
|
||||
|
||||
if (clearOverlayWhenMoving) {
|
||||
MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog
|
||||
}
|
||||
HMD.openTablet();
|
||||
|
||||
isDomainOpen(domainId, function (canShare) {
|
||||
snapshotOptions = {
|
||||
containsGif: false,
|
||||
processingGif: false,
|
||||
canShare: canShare
|
||||
};
|
||||
imageData = [{ localPath: pathStillSnapshot, href: href }];
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
action: "addImages",
|
||||
options: snapshotOptions,
|
||||
image_data: imageData
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function processingGifStarted(pathStillSnapshot) {
|
||||
|
@ -474,31 +498,33 @@ function processingGifStarted(pathStillSnapshot) {
|
|||
Window.processingGifCompleted.connect(processingGifCompleted);
|
||||
// show hud
|
||||
Reticle.visible = reticleVisible;
|
||||
Reticle.allowMouseCapture = true;
|
||||
// show overlays if they were on
|
||||
if (resetOverlays) {
|
||||
Menu.setIsOptionChecked("Overlays", true);
|
||||
}
|
||||
|
||||
snapshotOptions = {
|
||||
containsGif: true,
|
||||
processingGif: true,
|
||||
loadingGifPath: Script.resolvePath(Script.resourcesPath() + 'icons/loadingDark.gif'),
|
||||
canShare: !isDomainOpen(domainId)
|
||||
};
|
||||
imageData = [{ localPath: pathStillSnapshot, href: href }];
|
||||
Settings.setValue("previousStillSnapPath", pathStillSnapshot);
|
||||
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
action: "addImages",
|
||||
options: snapshotOptions,
|
||||
image_data: imageData
|
||||
}));
|
||||
|
||||
if (clearOverlayWhenMoving) {
|
||||
MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog
|
||||
}
|
||||
HMD.openTablet();
|
||||
|
||||
isDomainOpen(domainId, function (canShare) {
|
||||
snapshotOptions = {
|
||||
containsGif: true,
|
||||
processingGif: true,
|
||||
loadingGifPath: Script.resolvePath(Script.resourcesPath() + 'icons/loadingDark.gif'),
|
||||
canShare: canShare
|
||||
};
|
||||
imageData = [{ localPath: pathStillSnapshot, href: href }];
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
action: "addImages",
|
||||
options: snapshotOptions,
|
||||
image_data: imageData
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function processingGifCompleted(pathAnimatedSnapshot) {
|
||||
|
@ -508,20 +534,22 @@ function processingGifCompleted(pathAnimatedSnapshot) {
|
|||
buttonConnected = true;
|
||||
}
|
||||
|
||||
snapshotOptions = {
|
||||
containsGif: true,
|
||||
processingGif: false,
|
||||
canShare: !isDomainOpen(domainId)
|
||||
}
|
||||
imageData = [{ localPath: pathAnimatedSnapshot, href: href }];
|
||||
Settings.setValue("previousAnimatedSnapPath", pathAnimatedSnapshot);
|
||||
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
action: "addImages",
|
||||
options: snapshotOptions,
|
||||
image_data: imageData
|
||||
}));
|
||||
isDomainOpen(domainId, function (canShare) {
|
||||
snapshotOptions = {
|
||||
containsGif: true,
|
||||
processingGif: false,
|
||||
canShare: canShare
|
||||
};
|
||||
imageData = [{ localPath: pathAnimatedSnapshot, href: href }];
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
action: "addImages",
|
||||
options: snapshotOptions,
|
||||
image_data: imageData
|
||||
}));
|
||||
});
|
||||
}
|
||||
function maybeDeleteSnapshotStories() {
|
||||
storyIDsToMaybeDelete.forEach(function (element, idx, array) {
|
||||
|
@ -554,12 +582,21 @@ function onUsernameChanged() {
|
|||
shareAfterLogin = false;
|
||||
}
|
||||
}
|
||||
function snapshotLocationSet(location) {
|
||||
if (location !== "") {
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
action: "snapshotLocationChosen"
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
button.clicked.connect(onButtonClicked);
|
||||
buttonConnected = true;
|
||||
Window.snapshotShared.connect(snapshotUploaded);
|
||||
tablet.screenChanged.connect(onTabletScreenChanged);
|
||||
Account.usernameChanged.connect(onUsernameChanged);
|
||||
Snapshot.snapshotLocationSet.connect(snapshotLocationSet);
|
||||
Script.scriptEnding.connect(function () {
|
||||
if (buttonConnected) {
|
||||
button.clicked.disconnect(onButtonClicked);
|
||||
|
@ -570,6 +607,7 @@ Script.scriptEnding.connect(function () {
|
|||
}
|
||||
Window.snapshotShared.disconnect(snapshotUploaded);
|
||||
tablet.screenChanged.disconnect(onTabletScreenChanged);
|
||||
Snapshot.snapshotLocationSet.disconnect(snapshotLocationSet);
|
||||
});
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <render/ShapePipeline.h>
|
||||
#include <render/Context.h>
|
||||
#include <render/Engine.h>
|
||||
|
||||
#define DEFERRED_LIGHTING
|
||||
|
||||
|
|
Loading…
Reference in a new issue