Merge branch 'master' of https://github.com/highfidelity/hifi into notification-circumstances

This commit is contained in:
howard-stearns 2017-05-02 16:16:27 -07:00
commit 6f52bb4b37
23 changed files with 1040 additions and 934 deletions

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -20,7 +20,6 @@
#include "model/Light.h"
#include "model/Geometry.h"
#include "render/Context.h"
#include <render/CullTask.h>
#include "DeferredFrameTransform.h"

View file

@ -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;
}

View file

@ -15,7 +15,6 @@
#include <ViewFrustum.h>
#include <render/Context.h>
#include <render/CullTask.h>
#include <render/SortTask.h>
#include <render/DrawTask.h>

View file

@ -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();

View file

@ -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

View file

@ -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>;

View file

@ -13,8 +13,6 @@
#define hifi_RenderFetchCullSortTask_h
#include <gpu/Pipeline.h>
#include "Task.h"
#include "CullTask.h"
class RenderFetchCullSortTask {

View file

@ -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

View file

@ -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);

View 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

View 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

View 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

View file

@ -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
*/

View file

@ -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);

View file

@ -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>' +
'&#xe019;' +
'</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);
}
}

View file

@ -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

View file

@ -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

View file

@ -17,7 +17,7 @@
#include <DeferredLightingEffect.h>
#include <render/ShapePipeline.h>
#include <render/Context.h>
#include <render/Engine.h>
#define DEFERRED_LIGHTING