mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 04:13:11 +02:00
Merge branch 'master' into 21369
This commit is contained in:
commit
a6b1b17d45
35 changed files with 1462 additions and 783 deletions
|
@ -47,7 +47,7 @@ void OctreeInboundPacketProcessor::resetStats() {
|
|||
_singleSenderStats.clear();
|
||||
}
|
||||
|
||||
unsigned long OctreeInboundPacketProcessor::getMaxWait() const {
|
||||
uint32_t OctreeInboundPacketProcessor::getMaxWait() const {
|
||||
// calculate time until next sendNackPackets()
|
||||
quint64 nextNackTime = _lastNackTime + TOO_LONG_SINCE_LAST_NACK;
|
||||
quint64 now = usecTimestampNow();
|
||||
|
|
|
@ -80,7 +80,7 @@ protected:
|
|||
|
||||
virtual void processPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) override;
|
||||
|
||||
virtual unsigned long getMaxWait() const override;
|
||||
virtual uint32_t getMaxWait() const override;
|
||||
virtual void preProcess() override;
|
||||
virtual void midProcess() override;
|
||||
|
||||
|
|
|
@ -223,6 +223,14 @@ $(document).ready(function(){
|
|||
// set focus to the first input in the new row
|
||||
$target.closest('table').find('tr.inputs input:first').focus();
|
||||
}
|
||||
|
||||
var tableRows = sibling.parent();
|
||||
var tableBody = tableRows.parent();
|
||||
|
||||
// if theres no more siblings, we should jump to a new row
|
||||
if (sibling.next().length == 0 && tableRows.nextAll().length == 1) {
|
||||
tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click();
|
||||
}
|
||||
}
|
||||
|
||||
} else if ($target.is('input')) {
|
||||
|
|
|
@ -128,7 +128,7 @@ Rectangle {
|
|||
pal.sendToScript({method: 'refreshNearby', params: params});
|
||||
}
|
||||
|
||||
Item {
|
||||
Rectangle {
|
||||
id: palTabContainer;
|
||||
// Anchors
|
||||
anchors {
|
||||
|
@ -137,6 +137,7 @@ Rectangle {
|
|||
left: parent.left;
|
||||
right: parent.right;
|
||||
}
|
||||
color: "white";
|
||||
Rectangle {
|
||||
id: tabSelectorContainer;
|
||||
// Anchors
|
||||
|
|
|
@ -1961,6 +1961,32 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
totalBodyYaw += (speedFactor * deltaAngle * (180.0f / PI));
|
||||
}
|
||||
|
||||
// Use head/HMD roll to turn while walking or flying.
|
||||
if (qApp->isHMDMode() && _hmdRollControlEnabled) {
|
||||
// Turn with head roll.
|
||||
const float MIN_CONTROL_SPEED = 0.01f;
|
||||
float speed = glm::length(getVelocity());
|
||||
if (speed >= MIN_CONTROL_SPEED) {
|
||||
// Feather turn when stopping moving.
|
||||
float speedFactor;
|
||||
if (getDriveKey(TRANSLATE_Z) != 0.0f || _lastDrivenSpeed == 0.0f) {
|
||||
_lastDrivenSpeed = speed;
|
||||
speedFactor = 1.0f;
|
||||
} else {
|
||||
speedFactor = glm::min(speed / _lastDrivenSpeed, 1.0f);
|
||||
}
|
||||
|
||||
float direction = glm::dot(getVelocity(), getRotation() * Vectors::UNIT_NEG_Z) > 0.0f ? 1.0f : -1.0f;
|
||||
|
||||
float rollAngle = glm::degrees(asinf(glm::dot(IDENTITY_UP, _hmdSensorOrientation * IDENTITY_RIGHT)));
|
||||
float rollSign = rollAngle < 0.0f ? -1.0f : 1.0f;
|
||||
rollAngle = fabsf(rollAngle);
|
||||
rollAngle = rollAngle > _hmdRollControlDeadZone ? rollSign * (rollAngle - _hmdRollControlDeadZone) : 0.0f;
|
||||
|
||||
totalBodyYaw += speedFactor * direction * rollAngle * deltaTime * _hmdRollControlRate;
|
||||
}
|
||||
}
|
||||
|
||||
// update body orientation by movement inputs
|
||||
glm::quat initialOrientation = getOrientationOutbound();
|
||||
setOrientation(getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f))));
|
||||
|
|
|
@ -132,6 +132,10 @@ class MyAvatar : public Avatar {
|
|||
Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled)
|
||||
Q_PROPERTY(bool useAdvancedMovementControls READ useAdvancedMovementControls WRITE setUseAdvancedMovementControls)
|
||||
|
||||
Q_PROPERTY(bool hmdRollControlEnabled READ getHMDRollControlEnabled WRITE setHMDRollControlEnabled)
|
||||
Q_PROPERTY(float hmdRollControlDeadZone READ getHMDRollControlDeadZone WRITE setHMDRollControlDeadZone)
|
||||
Q_PROPERTY(float hmdRollControlRate READ getHMDRollControlRate WRITE setHMDRollControlRate)
|
||||
|
||||
public:
|
||||
enum DriveKeys {
|
||||
TRANSLATE_X = 0,
|
||||
|
@ -337,6 +341,13 @@ public:
|
|||
void setUseAdvancedMovementControls(bool useAdvancedMovementControls)
|
||||
{ _useAdvancedMovementControls.set(useAdvancedMovementControls); }
|
||||
|
||||
void setHMDRollControlEnabled(bool value) { _hmdRollControlEnabled = value; }
|
||||
bool getHMDRollControlEnabled() const { return _hmdRollControlEnabled; }
|
||||
void setHMDRollControlDeadZone(float value) { _hmdRollControlDeadZone = value; }
|
||||
float getHMDRollControlDeadZone() const { return _hmdRollControlDeadZone; }
|
||||
void setHMDRollControlRate(float value) { _hmdRollControlRate = value; }
|
||||
float getHMDRollControlRate() const { return _hmdRollControlRate; }
|
||||
|
||||
// get/set avatar data
|
||||
void saveData();
|
||||
void loadData();
|
||||
|
@ -687,6 +698,13 @@ private:
|
|||
bool _useSnapTurn { true };
|
||||
bool _clearOverlayWhenMoving { true };
|
||||
|
||||
const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // deg
|
||||
const float ROLL_CONTROL_RATE_DEFAULT = 2.5f; // deg/sec/deg
|
||||
bool _hmdRollControlEnabled { true };
|
||||
float _hmdRollControlDeadZone { ROLL_CONTROL_DEAD_ZONE_DEFAULT };
|
||||
float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT };
|
||||
float _lastDrivenSpeed { 0.0f };
|
||||
|
||||
// working copies -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
|
||||
glm::mat4 _sensorToWorldMatrix { glm::mat4() };
|
||||
|
||||
|
|
|
@ -184,6 +184,8 @@ AudioClient::AudioClient() :
|
|||
checkDevices();
|
||||
});
|
||||
});
|
||||
const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
|
||||
_checkDevicesTimer->start(DEVICE_CHECK_INTERVAL_MSECS);
|
||||
|
||||
|
||||
configureReverb();
|
||||
|
|
|
@ -605,7 +605,7 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
|
|||
|
||||
QString extraInfo;
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
||||
face, surfaceNormal, extraInfo, precisionPicking, precisionPicking);
|
||||
face, surfaceNormal, extraInfo, precisionPicking, false);
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::getCollisionGeometryResource() {
|
||||
|
|
|
@ -63,11 +63,17 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
|||
int useScissor = batch._params[paramOffset + 0]._int;
|
||||
|
||||
GLuint glmask = 0;
|
||||
bool restoreStencilMask = false;
|
||||
uint8_t cacheStencilMask = 0xFF;
|
||||
if (masks & Framebuffer::BUFFER_STENCIL) {
|
||||
glClearStencil(stencil);
|
||||
glmask |= GL_STENCIL_BUFFER_BIT;
|
||||
// TODO: we will probably need to also check the write mask of stencil like we do
|
||||
// for depth buffer, but as would say a famous Fez owner "We'll cross that bridge when we come to it"
|
||||
|
||||
cacheStencilMask = _pipeline._stateCache.stencilActivation.getWriteMaskFront();
|
||||
if (cacheStencilMask != 0xFF) {
|
||||
restoreStencilMask = true;
|
||||
glStencilMask( 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
bool restoreDepthMask = false;
|
||||
|
@ -121,6 +127,11 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
|||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
// Restore Stencil write mask
|
||||
if (restoreStencilMask) {
|
||||
glStencilMask(cacheStencilMask);
|
||||
}
|
||||
|
||||
// Restore write mask meaning turn back off
|
||||
if (restoreDepthMask) {
|
||||
glDepthMask(GL_FALSE);
|
||||
|
|
|
@ -584,7 +584,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
|||
return matchingNode;
|
||||
} else {
|
||||
// we didn't have this node, so add them
|
||||
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, connectionSecret, this);
|
||||
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, connectionSecret);
|
||||
|
||||
if (nodeType == NodeType::AudioMixer) {
|
||||
LimitedNodeList::flagTimeForConnectionStep(LimitedNodeList::AddedAudioMixer);
|
||||
|
@ -617,24 +617,28 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
|||
}
|
||||
|
||||
// insert the new node and release our read lock
|
||||
_nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer));
|
||||
_nodeHash.emplace(newNode->getUUID(), newNodePointer);
|
||||
readLocker.unlock();
|
||||
|
||||
qCDebug(networking) << "Added" << *newNode;
|
||||
|
||||
auto weakPtr = newNodePointer.toWeakRef(); // We don't want the lambdas to hold a strong ref
|
||||
|
||||
emit nodeAdded(newNodePointer);
|
||||
if (newNodePointer->getActiveSocket()) {
|
||||
emit nodeActivated(newNodePointer);
|
||||
} else {
|
||||
connect(newNodePointer.data(), &NetworkPeer::socketActivated, this, [=] {
|
||||
emit nodeActivated(newNodePointer);
|
||||
disconnect(newNodePointer.data(), &NetworkPeer::socketActivated, this, 0);
|
||||
connect(newNodePointer.data(), &NetworkPeer::socketActivated, this, [this, weakPtr] {
|
||||
auto sharedPtr = weakPtr.lock();
|
||||
if (sharedPtr) {
|
||||
emit nodeActivated(sharedPtr);
|
||||
disconnect(sharedPtr.data(), &NetworkPeer::socketActivated, this, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Signal when a socket changes, so we can start the hole punch over.
|
||||
auto weakPtr = newNodePointer.toWeakRef(); // We don't want the lambda to hold a strong ref
|
||||
connect(newNodePointer.data(), &NetworkPeer::socketUpdated, this, [=] {
|
||||
connect(newNodePointer.data(), &NetworkPeer::socketUpdated, this, [this, weakPtr] {
|
||||
emit nodeSocketUpdated(weakPtr);
|
||||
});
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
Node(const QUuid& uuid, NodeType_t type,
|
||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
||||
const NodePermissions& permissions, const QUuid& connectionSecret = QUuid(),
|
||||
QObject* parent = 0);
|
||||
QObject* parent = nullptr);
|
||||
|
||||
bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; }
|
||||
bool operator!=(const Node& otherNode) const { return !(*this == otherNode); }
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
class ReceivedPacketProcessor : public GenericThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const uint64_t MAX_WAIT_TIME { 100 }; // Max wait time in ms
|
||||
|
||||
ReceivedPacketProcessor();
|
||||
|
||||
/// Add packet from network receive thread to the processing queue.
|
||||
|
@ -63,8 +65,8 @@ protected:
|
|||
/// Implements generic processing behavior for this thread.
|
||||
virtual bool process() override;
|
||||
|
||||
/// Determines the timeout of the wait when there are no packets to process. Default value means no timeout
|
||||
virtual unsigned long getMaxWait() const { return ULONG_MAX; }
|
||||
/// Determines the timeout of the wait when there are no packets to process. Default value is 100ms to allow for regular event processing.
|
||||
virtual uint32_t getMaxWait() const { return MAX_WAIT_TIME; }
|
||||
|
||||
/// Override to do work before the packets processing loop. Default does nothing.
|
||||
virtual void preProcess() { }
|
||||
|
|
|
@ -35,14 +35,13 @@ void JurisdictionListener::nodeKilled(SharedNodePointer node) {
|
|||
}
|
||||
|
||||
bool JurisdictionListener::queueJurisdictionRequest() {
|
||||
auto packet = NLPacket::create(PacketType::JurisdictionRequest, 0);
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
int nodeCount = 0;
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
if (node->getType() == getNodeType() && node->getActiveSocket()) {
|
||||
auto packet = NLPacket::create(PacketType::JurisdictionRequest, 0);
|
||||
_packetSender.queuePacketForSending(node, std::move(packet));
|
||||
nodeCount++;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,6 @@ bool JurisdictionSender::process() {
|
|||
|
||||
// call our ReceivedPacketProcessor base class process so we'll get any pending packets
|
||||
if (continueProcessing && (continueProcessing = ReceivedPacketProcessor::process())) {
|
||||
auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket()
|
||||
: JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType());
|
||||
int nodeCount = 0;
|
||||
|
||||
lockRequestingNodes();
|
||||
|
@ -53,6 +51,8 @@ bool JurisdictionSender::process() {
|
|||
SharedNodePointer node = DependencyManager::get<NodeList>()->nodeWithUUID(nodeUUID);
|
||||
|
||||
if (node && node->getActiveSocket()) {
|
||||
auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket()
|
||||
: JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType());
|
||||
_packetSender.queuePacketForSending(node, std::move(packet));
|
||||
nodeCount++;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "AntialiasingEffect.h"
|
||||
#include "StencilMaskPass.h"
|
||||
#include "TextureCache.h"
|
||||
#include "FramebufferCache.h"
|
||||
#include "DependencyManager.h"
|
||||
#include "ViewFrustum.h"
|
||||
#include "GeometryCache.h"
|
||||
|
@ -40,9 +39,9 @@ Antialiasing::~Antialiasing() {
|
|||
}
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
|
||||
int width = DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width();
|
||||
int height = DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height();
|
||||
const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline(RenderArgs* args) {
|
||||
int width = args->_viewport.z;
|
||||
int height = args->_viewport.w;
|
||||
|
||||
if (_antialiasingBuffer && _antialiasingBuffer->getSize() != uvec2(width, height)) {
|
||||
_antialiasingBuffer.reset();
|
||||
|
@ -51,7 +50,7 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
|
|||
if (!_antialiasingBuffer) {
|
||||
// Link the antialiasing FBO to texture
|
||||
_antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("antialiasing"));
|
||||
auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get<FramebufferCache>()->getLightingTexture()->getTexelFormat();
|
||||
auto format = gpu::Element::COLOR_SRGBA_32;
|
||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||
_antialiasingTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, defaultSampler);
|
||||
_antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture);
|
||||
|
@ -115,10 +114,8 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const
|
|||
batch.setViewportTransform(args->_viewport);
|
||||
|
||||
// FIXME: NEED to simplify that code to avoid all the GeometryCahce call, this is purely pixel manipulation
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
||||
float fbWidth = framebufferSize.width();
|
||||
float fbHeight = framebufferSize.height();
|
||||
float fbWidth = renderContext->args->_viewport.z;
|
||||
float fbHeight = renderContext->args->_viewport.w;
|
||||
// float sMin = args->_viewport.x / fbWidth;
|
||||
// float sWidth = args->_viewport.z / fbWidth;
|
||||
// float tMin = args->_viewport.y / fbHeight;
|
||||
|
@ -133,10 +130,10 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const
|
|||
batch.setModelTransform(Transform());
|
||||
|
||||
// FXAA step
|
||||
getAntialiasingPipeline();
|
||||
auto pipeline = getAntialiasingPipeline(renderContext->args);
|
||||
batch.setResourceTexture(0, sourceBuffer->getRenderBuffer(0));
|
||||
batch.setFramebuffer(_antialiasingBuffer);
|
||||
batch.setPipeline(getAntialiasingPipeline());
|
||||
batch.setPipeline(pipeline);
|
||||
|
||||
// initialize the view-space unpacking uniforms using frustum data
|
||||
float left, right, bottom, top, nearVal, farVal;
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
void configure(const Config& config) {}
|
||||
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceBuffer);
|
||||
|
||||
const gpu::PipelinePointer& getAntialiasingPipeline();
|
||||
const gpu::PipelinePointer& getAntialiasingPipeline(RenderArgs* args);
|
||||
const gpu::PipelinePointer& getBlendPipeline();
|
||||
|
||||
private:
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <ViewFrustum.h>
|
||||
|
||||
#include "GeometryCache.h"
|
||||
#include "FramebufferCache.h"
|
||||
#include "TextureCache.h"
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
|
@ -410,7 +409,6 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I
|
|||
batch.setViewportTransform(args->_viewport);
|
||||
|
||||
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
|
||||
const auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
const auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
glm::mat4 projMat;
|
||||
|
|
|
@ -418,10 +418,7 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() {
|
|||
}
|
||||
|
||||
void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer) {
|
||||
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
auto framebufferSize = framebufferCache->getFrameBufferSize();
|
||||
glm::uvec2 frameSize(framebufferSize.width(), framebufferSize.height());
|
||||
glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w);
|
||||
|
||||
// Resizing framebuffers instead of re-building them seems to cause issues with threaded
|
||||
// rendering
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include "GenericThread.h"
|
||||
|
||||
|
@ -73,6 +74,7 @@ void GenericThread::threadRoutine() {
|
|||
}
|
||||
|
||||
while (!_stopThread) {
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
// override this function to do whatever your class actually does, return false to exit thread early
|
||||
if (!process()) {
|
||||
|
|
|
@ -10,10 +10,10 @@ if (WIN32)
|
|||
# we're using static GLEW, so define GLEW_STATIC
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
set(TARGET_NAME openvr)
|
||||
setup_hifi_plugin(OpenGL Script Qml Widgets)
|
||||
setup_hifi_plugin(OpenGL Script Qml Widgets Multimedia)
|
||||
link_hifi_libraries(shared gl networking controllers ui
|
||||
plugins display-plugins ui-plugins input-plugins script-engine
|
||||
render-utils model gpu gpu-gl render model-networking fbx ktx image procedural)
|
||||
audio-client render-utils model gpu gpu-gl render model-networking fbx ktx image procedural)
|
||||
|
||||
include_hifi_library_headers(octree)
|
||||
|
||||
|
@ -21,4 +21,5 @@ if (WIN32)
|
|||
find_package(OpenVR REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
|
||||
target_link_libraries(${TARGET_NAME} Winmm.lib)
|
||||
endif()
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
//
|
||||
#include "OpenVrDisplayPlugin.h"
|
||||
|
||||
// Odd ordering of header is required to avoid 'macro redinition warnings'
|
||||
#include <AudioClient.h>
|
||||
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
@ -713,3 +716,30 @@ bool OpenVrDisplayPlugin::isKeyboardVisible() {
|
|||
int OpenVrDisplayPlugin::getRequiredThreadCount() const {
|
||||
return Parent::getRequiredThreadCount() + (_threadedSubmit ? 1 : 0);
|
||||
}
|
||||
|
||||
QString OpenVrDisplayPlugin::getPreferredAudioInDevice() const {
|
||||
QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_OnPlaybackDevice_String);
|
||||
if (!device.isEmpty()) {
|
||||
static const WCHAR INIT = 0;
|
||||
size_t size = device.size() + 1;
|
||||
std::vector<WCHAR> deviceW;
|
||||
deviceW.assign(size, INIT);
|
||||
device.toWCharArray(deviceW.data());
|
||||
device = AudioClient::friendlyNameForAudioDevice(deviceW.data());
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
QString OpenVrDisplayPlugin::getPreferredAudioOutDevice() const {
|
||||
QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_OnRecordDevice_String);
|
||||
if (!device.isEmpty()) {
|
||||
static const WCHAR INIT = 0;
|
||||
size_t size = device.size() + 1;
|
||||
std::vector<WCHAR> deviceW;
|
||||
deviceW.assign(size, INIT);
|
||||
device.toWCharArray(deviceW.data());
|
||||
device = AudioClient::friendlyNameForAudioDevice(deviceW.data());
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,9 @@ public:
|
|||
// Possibly needs an additional thread for VR submission
|
||||
int getRequiredThreadCount() const override;
|
||||
|
||||
QString getPreferredAudioInDevice() const override;
|
||||
QString getPreferredAudioOutDevice() const override;
|
||||
|
||||
protected:
|
||||
bool internalActivate() override;
|
||||
void internalDeactivate() override;
|
||||
|
|
|
@ -72,6 +72,21 @@ bool openVrSupported() {
|
|||
return (enableDebugOpenVR || !isOculusPresent()) && vr::VR_IsHmdPresent();
|
||||
}
|
||||
|
||||
QString getVrSettingString(const char* section, const char* setting) {
|
||||
QString result;
|
||||
static const uint32_t BUFFER_SIZE = 1024;
|
||||
static char BUFFER[BUFFER_SIZE];
|
||||
vr::IVRSettings * vrSettings = vr::VRSettings();
|
||||
if (vrSettings) {
|
||||
vr::EVRSettingsError error = vr::VRSettingsError_None;
|
||||
vrSettings->GetString(vr::k_pch_audio_Section, vr::k_pch_audio_OnPlaybackDevice_String, BUFFER, BUFFER_SIZE, &error);
|
||||
if (error == vr::VRSettingsError_None) {
|
||||
result = BUFFER;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vr::IVRSystem* acquireOpenVrSystem() {
|
||||
bool hmdPresent = vr::VR_IsHmdPresent();
|
||||
if (hmdPresent) {
|
||||
|
@ -82,6 +97,7 @@ vr::IVRSystem* acquireOpenVrSystem() {
|
|||
#endif
|
||||
vr::EVRInitError eError = vr::VRInitError_None;
|
||||
activeHmd = vr::VR_Init(&eError, vr::VRApplication_Scene);
|
||||
|
||||
#if DEV_BUILD
|
||||
qCDebug(displayplugins) << "OpenVR display: HMD is " << activeHmd << " error is " << eError;
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,7 @@ bool openVrQuitRequested();
|
|||
void enableOpenVrKeyboard(PluginContainer* container);
|
||||
void disableOpenVrKeyboard();
|
||||
bool isOpenVrKeyboardShown();
|
||||
QString getVrSettingString(const char* section, const char* setting);
|
||||
|
||||
|
||||
template<typename F>
|
||||
|
|
17
scripts/developer/hmdRollControlDisable.js
Normal file
17
scripts/developer/hmdRollControlDisable.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// hmdRollControlDisable.js
|
||||
//
|
||||
// Created by David Rowe on 4 Jun 2017.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var hmdRollControlEnabled = false;
|
||||
|
||||
//print("HMD roll control: " + hmdRollControlEnabled);
|
||||
|
||||
MyAvatar.hmdRollControlEnabled = hmdRollControlEnabled;
|
||||
|
||||
Script.stop();
|
21
scripts/developer/hmdRollControlEnable.js
Normal file
21
scripts/developer/hmdRollControlEnable.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// hmdRollControlEnable.js
|
||||
//
|
||||
// Created by David Rowe on 4 Jun 2017.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var hmdRollControlEnabled = true;
|
||||
var hmdRollControlDeadZone = 8.0; // deg
|
||||
var hmdRollControlRate = 2.5; // deg/sec/deg
|
||||
|
||||
//print("HMD roll control: " + hmdRollControlEnabled + ", " + hmdRollControlDeadZone + ", " + hmdRollControlRate);
|
||||
|
||||
MyAvatar.hmdRollControlEnabled = hmdRollControlEnabled;
|
||||
MyAvatar.hmdRollControlDeadZone = hmdRollControlDeadZone;
|
||||
MyAvatar.hmdRollControlRate = hmdRollControlRate;
|
||||
|
||||
Script.stop();
|
|
@ -12,7 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager, Overlays, OverlayWebWindow, UserActivityLogger,
|
||||
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager, Overlays, OverlayWebWindow, UserActivityLogger,
|
||||
Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
@ -80,27 +80,7 @@ selectionManager.addEventListener(function () {
|
|||
}
|
||||
var type = Entities.getEntityProperties(selectedEntityID, "type").type;
|
||||
if (type === "ParticleEffect") {
|
||||
// Destroy the old particles web view first
|
||||
particleExplorerTool.destroyWebView();
|
||||
particleExplorerTool.createWebView();
|
||||
var properties = Entities.getEntityProperties(selectedEntityID);
|
||||
var particleData = {
|
||||
messageType: "particle_settings",
|
||||
currentProperties: properties
|
||||
};
|
||||
selectedParticleEntityID = selectedEntityID;
|
||||
particleExplorerTool.setActiveParticleEntity(selectedParticleEntityID);
|
||||
|
||||
particleExplorerTool.webView.webEventReceived.connect(function (data) {
|
||||
data = JSON.parse(data);
|
||||
if (data.messageType === "page_loaded") {
|
||||
particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
|
||||
}
|
||||
});
|
||||
|
||||
// Switch to particle explorer
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
tablet.sendToQml({method: 'selectTab', params: {id: 'particle'}});
|
||||
selectParticleEntity(selectedEntityID);
|
||||
} else {
|
||||
needToDestroyParticleExplorer = true;
|
||||
}
|
||||
|
@ -218,7 +198,7 @@ function hideMarketplace() {
|
|||
// }
|
||||
|
||||
function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) {
|
||||
// Adjust the position such that the bounding box (registration, dimenions, and orientation) lies behind the original
|
||||
// Adjust the position such that the bounding box (registration, dimenions, and orientation) lies behind the original
|
||||
// position in the given direction.
|
||||
var CORNERS = [
|
||||
{ x: 0, y: 0, z: 0 },
|
||||
|
@ -1373,7 +1353,7 @@ function parentSelectedEntities() {
|
|||
}
|
||||
});
|
||||
|
||||
if(parentCheck) {
|
||||
if (parentCheck) {
|
||||
Window.notify("Entities parented");
|
||||
}else {
|
||||
Window.notify("Entities are already parented to last");
|
||||
|
@ -1575,7 +1555,7 @@ function importSVO(importURL) {
|
|||
var properties = Entities.getEntityProperties(pastedEntityIDs[0], ["position", "dimensions",
|
||||
"registrationPoint"]);
|
||||
var position = Vec3.sum(deltaPosition, properties.position);
|
||||
position = grid.snapToSurface(grid.snapToGrid(position, false, properties.dimensions,
|
||||
position = grid.snapToSurface(grid.snapToGrid(position, false, properties.dimensions,
|
||||
properties.registrationPoint), properties.dimensions, properties.registrationPoint);
|
||||
deltaPosition = Vec3.subtract(position, properties.position);
|
||||
}
|
||||
|
@ -1907,11 +1887,11 @@ var PropertiesTool = function (opts) {
|
|||
}
|
||||
pushCommandForSelections();
|
||||
selectionManager._update();
|
||||
} else if(data.type === 'parent') {
|
||||
} else if (data.type === 'parent') {
|
||||
parentSelectedEntities();
|
||||
} else if(data.type === 'unparent') {
|
||||
} else if (data.type === 'unparent') {
|
||||
unparentSelectedEntities();
|
||||
} else if(data.type === 'saveUserData'){
|
||||
} else if (data.type === 'saveUserData'){
|
||||
//the event bridge and json parsing handle our avatar id string differently.
|
||||
var actualID = data.id.split('"')[1];
|
||||
Entities.editEntity(actualID, data.properties);
|
||||
|
@ -2203,6 +2183,10 @@ var selectedParticleEntityID = null;
|
|||
|
||||
function selectParticleEntity(entityID) {
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
|
||||
if (properties.emitOrientation) {
|
||||
properties.emitOrientation = Quat.safeEulerAngles(properties.emitOrientation);
|
||||
}
|
||||
var particleData = {
|
||||
messageType: "particle_settings",
|
||||
currentProperties: properties
|
||||
|
@ -2212,6 +2196,7 @@ function selectParticleEntity(entityID) {
|
|||
|
||||
selectedParticleEntity = entityID;
|
||||
particleExplorerTool.setActiveParticleEntity(entityID);
|
||||
|
||||
particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
|
||||
|
||||
// Switch to particle explorer
|
||||
|
@ -2229,7 +2214,7 @@ entityListTool.webView.webEventReceived.connect(function (data) {
|
|||
|
||||
if (data.type === 'parent') {
|
||||
parentSelectedEntities();
|
||||
} else if(data.type === 'unparent') {
|
||||
} else if (data.type === 'unparent') {
|
||||
unparentSelectedEntities();
|
||||
} else if (data.type === "selectionUpdate") {
|
||||
var ids = data.entityIds;
|
||||
|
@ -2250,4 +2235,3 @@ entityListTool.webView.webEventReceived.connect(function (data) {
|
|||
});
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
||||
|
|
|
@ -172,4 +172,4 @@ input[type=radio]:active + label > span > span{
|
|||
}
|
||||
.blueButton:disabled {
|
||||
background-image: linear-gradient(#FFFFFF, #AFAFAF);
|
||||
}
|
||||
}
|
||||
|
|
95
scripts/system/particle_explorer/dat.gui.min.js
vendored
95
scripts/system/particle_explorer/dat.gui.min.js
vendored
File diff suppressed because one or more lines are too long
680
scripts/system/particle_explorer/hifi-entity-ui.js
Normal file
680
scripts/system/particle_explorer/hifi-entity-ui.js
Normal file
|
@ -0,0 +1,680 @@
|
|||
/* global window, document, print, alert, console,setTimeout, clearTimeout, _ $ */
|
||||
/* eslint no-console: 0 */
|
||||
|
||||
/**
|
||||
UI Builder V1.0
|
||||
|
||||
Created by Matti 'Menithal' Lahtinen
|
||||
24/5/2017
|
||||
Copyright 2017 High Fidelity, Inc.
|
||||
|
||||
This can eventually be expanded to all of Edit, for now, starting
|
||||
with Particles Only.
|
||||
|
||||
This is created for the sole purpose of streamliming the bridge, and to simplify
|
||||
the logic between an inputfield in WebView and Entities in High Fidelity.
|
||||
|
||||
We also do not need anything as heavy as jquery or any other platform,
|
||||
as we are mostly only building for QT (while, all the other JS frameworks usually do alot of polyfilling)
|
||||
|
||||
Available Types:
|
||||
|
||||
JSONInputField - Accepts JSON input, once one presses Save, it will be propegated.
|
||||
Button- A Button that listens for a custom event as defined by callback
|
||||
Boolean - Creates a checkbox that the user can either check or uncheck
|
||||
SliderFloat - Creates a slider (with input) that has Float values from min to max.
|
||||
Default is min 0, max 1
|
||||
SliderInteger - Creates a slider (with input) that has a Integer value from min to max.
|
||||
Default is min 1, max 10000
|
||||
SliderRadian - Creates a slider (with input) that has Float values in degrees,
|
||||
that are converted to radians. default is min 0, max Math.PI.
|
||||
Texture - Creates a Image with an url input field that points to texture.
|
||||
If image cannot form, show "cannot find image"
|
||||
VecQuaternion - Creates a 3D Vector field that converts to quaternions.
|
||||
Checkbox exists to show quaternions instead.
|
||||
Color - Create field color button, that when pressed, opens the color picker.
|
||||
Vector - Create a 3D Vector field that has one to one correspondence.
|
||||
|
||||
The script will use this structure to build a UI that is connected The
|
||||
id fields within High Fidelity
|
||||
|
||||
This should make editing, and everything related much more simpler to maintain,
|
||||
and If there is any changes to either the Entities or properties of
|
||||
|
||||
**/
|
||||
|
||||
var RADIANS_PER_DEGREE = Math.PI / 180;
|
||||
|
||||
var roundFloat = function (input, round) {
|
||||
round = round ? round : 1000;
|
||||
var sanitizedInput;
|
||||
if (typeof input === "string") {
|
||||
sanitizedInput = parseFloat(input);
|
||||
} else {
|
||||
sanitizedInput = input;
|
||||
}
|
||||
return Math.round(sanitizedInput * round) / round;
|
||||
};
|
||||
|
||||
function HifiEntityUI(parent) {
|
||||
this.parent = parent;
|
||||
|
||||
var self = this;
|
||||
this.webBridgeSync = _.debounce(function (id, val) {
|
||||
if (self.EventBridge) {
|
||||
var sendPackage = {};
|
||||
sendPackage[id] = val;
|
||||
self.submitChanges(sendPackage);
|
||||
}
|
||||
}, 125);
|
||||
}
|
||||
|
||||
HifiEntityUI.prototype = {
|
||||
setOnSelect: function (callback) {
|
||||
this.onSelect = callback;
|
||||
},
|
||||
submitChanges: function (structure) {
|
||||
var message = {
|
||||
messageType: "settings_update",
|
||||
updatedSettings: structure
|
||||
};
|
||||
this.EventBridge.emitWebEvent(JSON.stringify(message));
|
||||
},
|
||||
setUI: function (structure) {
|
||||
this.structure = structure;
|
||||
},
|
||||
disableFields: function () {
|
||||
var fields = document.getElementsByTagName("input");
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
if (fields[i].getAttribute("type") !== "button") {
|
||||
fields[i].value = "";
|
||||
}
|
||||
|
||||
fields[i].setAttribute("disabled", true);
|
||||
}
|
||||
var textures = document.getElementsByTagName("img");
|
||||
for (i = 0; i < textures.length; i++) {
|
||||
textures[i].src = "";
|
||||
}
|
||||
|
||||
textures = document.getElementsByClassName("with-texture");
|
||||
for (i = 0; i < textures.length; i++) {
|
||||
textures[i].classList.remove("with-textures");
|
||||
textures[i].classList.add("no-texture");
|
||||
}
|
||||
|
||||
var textareas = document.getElementsByTagName("textarea");
|
||||
for (var x = 0; x < textareas.length; x++) {
|
||||
textareas[x].remove();
|
||||
}
|
||||
},
|
||||
getSettings: function () {
|
||||
var self = this;
|
||||
var json = {};
|
||||
var keys = Object.keys(self.builtRows);
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
var el = self.builtRows[key];
|
||||
if (el.className.indexOf("checkbox") !== -1) {
|
||||
json[key] = document.getElementById(key)
|
||||
.checked ? true : false;
|
||||
} else if (el.className.indexOf("vector-section") !== -1) {
|
||||
var vector = {};
|
||||
if (el.className.indexOf("rgb") !== -1) {
|
||||
var red = document.getElementById(key + "-red");
|
||||
var blue = document.getElementById(key + "-blue");
|
||||
var green = document.getElementById(key + "-green");
|
||||
vector.red = red.value;
|
||||
vector.blue = blue.value;
|
||||
vector.green = green.value;
|
||||
} else if (el.className.indexOf("pyr") !== -1) {
|
||||
var p = document.getElementById(key + "-Pitch");
|
||||
var y = document.getElementById(key + "-Yaw");
|
||||
var r = document.getElementById(key + "-Roll");
|
||||
vector.x = p.value;
|
||||
vector.y = y.value;
|
||||
vector.z = r.value;
|
||||
} else {
|
||||
var x = document.getElementById(key + "-x");
|
||||
var ey = document.getElementById(key + "-y");
|
||||
var z = document.getElementById(key + "-z");
|
||||
vector.x = x.value;
|
||||
vector.y = ey.value;
|
||||
vector.z = z.value;
|
||||
}
|
||||
json[key] = vector;
|
||||
} else if (el.className.length > 0) {
|
||||
json[key] = document.getElementById(key)
|
||||
.value;
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
},
|
||||
fillFields: function (currentProperties) {
|
||||
var self = this;
|
||||
var fields = document.getElementsByTagName("input");
|
||||
|
||||
if (!currentProperties.locked) {
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
fields[i].removeAttribute("disabled");
|
||||
}
|
||||
}
|
||||
if (self.onSelect) {
|
||||
self.onSelect();
|
||||
}
|
||||
var keys = Object.keys(currentProperties);
|
||||
|
||||
|
||||
for (var e in keys) {
|
||||
if (keys.hasOwnProperty(e)) {
|
||||
var value = keys[e];
|
||||
|
||||
var property = currentProperties[value];
|
||||
var field = self.builtRows[value];
|
||||
if (field) {
|
||||
var el = document.getElementById(value);
|
||||
|
||||
if (field.className.indexOf("radian") !== -1) {
|
||||
el.value = property / RADIANS_PER_DEGREE;
|
||||
el.onchange({
|
||||
target: el
|
||||
});
|
||||
} else if (field.className.indexOf("range") !== -1 || field.className.indexOf("texture") !== -1) {
|
||||
el.value = property;
|
||||
el.onchange({
|
||||
target: el
|
||||
});
|
||||
} else if (field.className.indexOf("checkbox") !== -1) {
|
||||
if (property) {
|
||||
el.setAttribute("checked", property);
|
||||
} else {
|
||||
el.removeAttribute("checked");
|
||||
}
|
||||
} else if (field.className.indexOf("vector-section") !== -1) {
|
||||
if (field.className.indexOf("rgb") !== -1) {
|
||||
var red = document.getElementById(value + "-red");
|
||||
var blue = document.getElementById(value + "-blue");
|
||||
var green = document.getElementById(value + "-green");
|
||||
red.value = parseInt(property.red);
|
||||
blue.value = parseInt(property.blue);
|
||||
green.value = parseInt(property.green);
|
||||
|
||||
red.oninput({
|
||||
target: red
|
||||
});
|
||||
} else if (field.className.indexOf("xyz") !== -1) {
|
||||
var x = document.getElementById(value + "-x");
|
||||
var y = document.getElementById(value + "-y");
|
||||
var z = document.getElementById(value + "-z");
|
||||
|
||||
x.value = roundFloat(property.x, 100);
|
||||
y.value = roundFloat(property.y, 100);
|
||||
z.value = roundFloat(property.z, 100);
|
||||
} else if (field.className.indexOf("pyr") !== -1) {
|
||||
var pitch = document.getElementById(value + "-Pitch");
|
||||
var yaw = document.getElementById(value + "-Yaw");
|
||||
var roll = document.getElementById(value + "-Roll");
|
||||
|
||||
pitch.value = roundFloat(property.x, 100);
|
||||
yaw.value = roundFloat(property.y, 100);
|
||||
roll.value = roundFloat(property.z, 100);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
connect: function (EventBridge) {
|
||||
this.EventBridge = EventBridge;
|
||||
|
||||
var self = this;
|
||||
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
messageType: 'page_loaded'
|
||||
}));
|
||||
|
||||
EventBridge.scriptEventReceived.connect(function (data) {
|
||||
data = JSON.parse(data);
|
||||
|
||||
if (data.messageType === 'particle_settings') {
|
||||
// Update settings
|
||||
var currentProperties = data.currentProperties;
|
||||
self.fillFields(currentProperties);
|
||||
// Do expected property match with structure;
|
||||
} else if (data.messageType === 'particle_close') {
|
||||
self.disableFields();
|
||||
}
|
||||
});
|
||||
},
|
||||
build: function () {
|
||||
var self = this;
|
||||
var sections = Object.keys(this.structure);
|
||||
this.builtRows = {};
|
||||
sections.forEach(function (section, index) {
|
||||
var properties = self.structure[section];
|
||||
self.addSection(self.parent, section, properties, index);
|
||||
});
|
||||
},
|
||||
addSection: function (parent, section, properties, index) {
|
||||
var self = this;
|
||||
|
||||
var sectionDivHeader = document.createElement("div");
|
||||
var title = document.createElement("label");
|
||||
var dropDown = document.createElement("span");
|
||||
|
||||
dropDown.className = "arrow";
|
||||
sectionDivHeader.className = "section-header";
|
||||
title.innerHTML = section;
|
||||
sectionDivHeader.appendChild(title);
|
||||
sectionDivHeader.appendChild(dropDown);
|
||||
var collapsed = index !== 0;
|
||||
|
||||
dropDown.innerHTML = collapsed ? "L" : "M";
|
||||
sectionDivHeader.setAttribute("collapsed", collapsed);
|
||||
parent.appendChild(sectionDivHeader);
|
||||
|
||||
var sectionDivBody = document.createElement("div");
|
||||
sectionDivBody.className = "property-group";
|
||||
|
||||
var animationWrapper = document.createElement("div");
|
||||
animationWrapper.className = "section-wrap";
|
||||
|
||||
for (var property in properties) {
|
||||
if (properties.hasOwnProperty(property)) {
|
||||
var builtRow = self.addElement(animationWrapper, properties[property]);
|
||||
var id = properties[property].id;
|
||||
if (id) {
|
||||
self.builtRows[id] = builtRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
sectionDivBody.appendChild(animationWrapper);
|
||||
parent.appendChild(sectionDivBody);
|
||||
_.defer(function () {
|
||||
var height = (animationWrapper.clientHeight) + "px";
|
||||
if (collapsed) {
|
||||
sectionDivBody.classList.remove("visible");
|
||||
sectionDivBody.style.maxHeight = "0px";
|
||||
} else {
|
||||
sectionDivBody.classList.add("visible");
|
||||
sectionDivBody.style.maxHeight = height;
|
||||
}
|
||||
|
||||
sectionDivHeader.onclick = function () {
|
||||
collapsed = !collapsed;
|
||||
if (collapsed) {
|
||||
sectionDivBody.classList.remove("visible");
|
||||
sectionDivBody.style.maxHeight = "0px";
|
||||
} else {
|
||||
sectionDivBody.classList.add("visible");
|
||||
sectionDivBody.style.maxHeight = (animationWrapper.clientHeight) + "px";
|
||||
}
|
||||
// sectionDivBody.style.display = collapsed ? "none": "block";
|
||||
dropDown.innerHTML = collapsed ? "L" : "M";
|
||||
sectionDivHeader.setAttribute("collapsed", collapsed);
|
||||
};
|
||||
});
|
||||
},
|
||||
addLabel: function (parent, group) {
|
||||
var label = document.createElement("label");
|
||||
label.innerHTML = group.name;
|
||||
parent.appendChild(label);
|
||||
if (group.unit) {
|
||||
var span = document.createElement("span");
|
||||
span.innerHTML = group.unit;
|
||||
span.className = "unit";
|
||||
label.appendChild(span);
|
||||
}
|
||||
return label;
|
||||
},
|
||||
addVector: function (parent, group, labels, domArray) {
|
||||
var self = this;
|
||||
var inputs = labels ? labels : ["x", "y", "z"];
|
||||
domArray = domArray ? domArray : [];
|
||||
parent.id = group.id;
|
||||
for (var index in inputs) {
|
||||
var element = document.createElement("input");
|
||||
|
||||
element.setAttribute("type", "number");
|
||||
element.className = inputs[index];
|
||||
element.id = group.id + "-" + inputs[index];
|
||||
|
||||
if (group.defaultRange) {
|
||||
if (group.defaultRange.min) {
|
||||
element.setAttribute("min", group.defaultRange.min);
|
||||
}
|
||||
if (group.defaultRange.max) {
|
||||
element.setAttribute("max", group.defaultRange.max);
|
||||
}
|
||||
if (group.defaultRange.step) {
|
||||
element.setAttribute("step", group.defaultRange.step);
|
||||
}
|
||||
}
|
||||
if (group.oninput) {
|
||||
element.oninput = group.oninput;
|
||||
} else {
|
||||
element.oninput = function (event) {
|
||||
self.webBridgeSync(group.id, {
|
||||
x: domArray[0].value,
|
||||
y: domArray[1].value,
|
||||
z: domArray[2].value
|
||||
});
|
||||
};
|
||||
}
|
||||
element.onchange = element.oninput;
|
||||
domArray.push(element);
|
||||
}
|
||||
|
||||
this.addLabel(parent, group);
|
||||
var className = "";
|
||||
for (var i = 0; i < inputs.length; i++) {
|
||||
className += inputs[i].charAt(0)
|
||||
.toLowerCase();
|
||||
}
|
||||
parent.className += " property vector-section " + className;
|
||||
|
||||
// Add Tuple and the rest
|
||||
var tupleContainer = document.createElement("div");
|
||||
tupleContainer.className = "tuple";
|
||||
for (var domIndex in domArray) {
|
||||
var container = domArray[domIndex];
|
||||
var div = document.createElement("div");
|
||||
var label = document.createElement("label");
|
||||
label.innerHTML = inputs[domIndex] + ":";
|
||||
label.setAttribute("for", container.id);
|
||||
div.appendChild(container);
|
||||
div.appendChild(label);
|
||||
tupleContainer.appendChild(div);
|
||||
}
|
||||
parent.appendChild(tupleContainer);
|
||||
},
|
||||
addVectorQuaternion: function (parent, group) {
|
||||
this.addVector(parent, group, ["Pitch", "Yaw", "Roll"]);
|
||||
},
|
||||
addColorPicker: function (parent, group) {
|
||||
var self = this;
|
||||
var $colPickContainer = $('<div>', {
|
||||
id: group.id,
|
||||
class: "color-picker"
|
||||
});
|
||||
var updateColors = function (red, green, blue) {
|
||||
$colPickContainer.css('background-color', "rgb(" +
|
||||
red + "," +
|
||||
green + "," +
|
||||
blue + ")");
|
||||
};
|
||||
|
||||
var inputs = ["red", "green", "blue"];
|
||||
var domArray = [];
|
||||
group.oninput = function (event) {
|
||||
$colPickContainer.colpickSetColor(
|
||||
{
|
||||
r: domArray[0].value,
|
||||
g: domArray[1].value,
|
||||
b: domArray[2].value
|
||||
},
|
||||
true);
|
||||
};
|
||||
group.defaultRange = {
|
||||
min: 0,
|
||||
max: 255,
|
||||
step: 1
|
||||
};
|
||||
|
||||
parent.appendChild($colPickContainer[0]);
|
||||
self.addVector(parent, group, inputs, domArray);
|
||||
|
||||
updateColors(domArray[0].value, domArray[1].value, domArray[2].value);
|
||||
|
||||
// Could probably write a custom one for this to completely write out jquery,
|
||||
// but for now, using the same as earlier.
|
||||
|
||||
/* Color Picker Logic Here */
|
||||
|
||||
|
||||
$colPickContainer.colpick({
|
||||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: {
|
||||
r: domArray[0].value,
|
||||
g: domArray[1].value,
|
||||
b: domArray[2].value
|
||||
},
|
||||
onChange: function (hsb, hex, rgb, el) {
|
||||
updateColors(rgb.r, rgb.g, rgb.b);
|
||||
|
||||
domArray[0].value = rgb.r;
|
||||
domArray[1].value = rgb.g;
|
||||
domArray[2].value = rgb.b;
|
||||
self.webBridgeSync(group.id, {
|
||||
red: rgb.r,
|
||||
green: rgb.g,
|
||||
blue: rgb.b
|
||||
});
|
||||
},
|
||||
onSubmit: function (hsb, hex, rgb, el) {
|
||||
$(el)
|
||||
.css('background-color', '#' + hex);
|
||||
$(el)
|
||||
.colpickHide();
|
||||
domArray[0].value = rgb.r;
|
||||
domArray[1].value = rgb.g;
|
||||
domArray[2].value = rgb.b;
|
||||
self.webBridgeSync(group.id, {
|
||||
red: rgb.r,
|
||||
green: rgb.g,
|
||||
blue: rgb.b
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
addTextureField: function (parent, group) {
|
||||
var self = this;
|
||||
this.addLabel(parent, group);
|
||||
parent.className += " property texture";
|
||||
var textureImage = document.createElement("div");
|
||||
var textureUrl = document.createElement("input");
|
||||
textureUrl.setAttribute("type", "text");
|
||||
textureUrl.id = group.id;
|
||||
textureImage.className = "texture-image no-texture";
|
||||
var image = document.createElement("img");
|
||||
var imageLoad = _.debounce(function (url) {
|
||||
if (url.length > 0) {
|
||||
textureImage.classList.remove("no-texture");
|
||||
textureImage.classList.add("with-texture");
|
||||
image.src = url;
|
||||
image.style.display = "block";
|
||||
} else {
|
||||
image.src = "";
|
||||
image.style.display = "none";
|
||||
textureImage.classList.add("no-texture");
|
||||
}
|
||||
self.webBridgeSync(group.id, url);
|
||||
}, 250);
|
||||
|
||||
textureUrl.oninput = function (event) {
|
||||
// Add throttle
|
||||
var url = event.target.value;
|
||||
imageLoad(url);
|
||||
};
|
||||
textureUrl.onchange = textureUrl.oninput;
|
||||
textureImage.appendChild(image);
|
||||
parent.appendChild(textureImage);
|
||||
parent.appendChild(textureUrl);
|
||||
},
|
||||
addSlider: function (parent, group) {
|
||||
var self = this;
|
||||
this.addLabel(parent, group);
|
||||
parent.className += " property range";
|
||||
var container = document.createElement("div");
|
||||
container.className = "slider-wrapper";
|
||||
var slider = document.createElement("input");
|
||||
slider.setAttribute("type", "range");
|
||||
|
||||
var inputField = document.createElement("input");
|
||||
inputField.setAttribute("type", "number");
|
||||
|
||||
container.appendChild(slider);
|
||||
container.appendChild(inputField);
|
||||
parent.appendChild(container);
|
||||
|
||||
if (group.type === "SliderInteger") {
|
||||
inputField.setAttribute("min", group.min !== undefined ? group.min : 0);
|
||||
inputField.setAttribute("step", 1);
|
||||
|
||||
slider.setAttribute("min", group.min !== undefined ? group.min : 0);
|
||||
slider.setAttribute("max", group.max !== undefined ? group.max : 10000);
|
||||
slider.setAttribute("step", 1);
|
||||
|
||||
inputField.oninput = function (event) {
|
||||
|
||||
if (parseInt(event.target.value) > parseInt(slider.getAttribute("max")) && group.max !== 1) {
|
||||
slider.setAttribute("max", event.target.value);
|
||||
}
|
||||
slider.value = event.target.value;
|
||||
|
||||
self.webBridgeSync(group.id, slider.value);
|
||||
};
|
||||
inputField.onchange = inputField.oninput;
|
||||
slider.oninput = function (event) {
|
||||
inputField.value = event.target.value;
|
||||
self.webBridgeSync(group.id, slider.value);
|
||||
};
|
||||
|
||||
inputField.id = group.id;
|
||||
} else if (group.type === "SliderRadian") {
|
||||
slider.setAttribute("min", group.min !== undefined ? group.min : 0);
|
||||
slider.setAttribute("max", group.max !== undefined ? group.max : 180);
|
||||
slider.setAttribute("step", 1);
|
||||
parent.className += " radian";
|
||||
inputField.setAttribute("min", (group.min !== undefined ? group.min : 0));
|
||||
inputField.setAttribute("max", (group.max !== undefined ? group.max : 180));
|
||||
|
||||
inputField.oninput = function (event) {
|
||||
slider.value = event.target.value;
|
||||
self.webBridgeSync(group.id, slider.value * RADIANS_PER_DEGREE);
|
||||
};
|
||||
inputField.onchange = inputField.oninput;
|
||||
|
||||
inputField.id = group.id;
|
||||
slider.oninput = function (event) {
|
||||
if (event.target.value > 0) {
|
||||
inputField.value = Math.floor(event.target.value);
|
||||
} else {
|
||||
inputField.value = Math.ceil(event.target.value);
|
||||
}
|
||||
self.webBridgeSync(group.id, slider.value * RADIANS_PER_DEGREE);
|
||||
};
|
||||
var degrees = document.createElement("label");
|
||||
degrees.innerHTML = "°";
|
||||
degrees.style.fontSize = "1.4rem";
|
||||
degrees.style.display = "inline";
|
||||
degrees.style.verticalAlign = "top";
|
||||
degrees.style.paddingLeft = "0.4rem";
|
||||
container.appendChild(degrees);
|
||||
|
||||
} else {
|
||||
// Must then be Float
|
||||
inputField.setAttribute("min", group.min !== undefined ? group.min : 0);
|
||||
slider.setAttribute("step", 0.01);
|
||||
|
||||
slider.setAttribute("min", group.min !== undefined ? group.min : 0);
|
||||
slider.setAttribute("max", group.max !== undefined ? group.max : 1);
|
||||
slider.setAttribute("step", 0.01);
|
||||
|
||||
inputField.oninput = function (event) {
|
||||
if (parseFloat(event.target.value) > parseFloat(slider.getAttribute("max")) && group.max !== 1) {
|
||||
slider.setAttribute("max", event.target.value);
|
||||
}
|
||||
|
||||
slider.value = event.target.value;
|
||||
self.webBridgeSync(group.id, slider.value);
|
||||
// bind web sock update here.
|
||||
};
|
||||
inputField.onchange = inputField.oninput;
|
||||
slider.oninput = function (event) {
|
||||
inputField.value = event.target.value;
|
||||
self.webBridgeSync(group.id, inputField.value);
|
||||
};
|
||||
|
||||
inputField.id = group.id;
|
||||
}
|
||||
|
||||
// UpdateBinding
|
||||
},
|
||||
addCheckBox: function (parent, group) {
|
||||
var checkBox = document.createElement("input");
|
||||
checkBox.setAttribute("type", "checkbox");
|
||||
var self = this;
|
||||
checkBox.onchange = function (event) {
|
||||
self.webBridgeSync(group.id, event.target.checked);
|
||||
};
|
||||
checkBox.id = group.id;
|
||||
parent.appendChild(checkBox);
|
||||
var label = this.addLabel(parent, group);
|
||||
label.setAttribute("for", checkBox.id);
|
||||
parent.className += " property checkbox";
|
||||
},
|
||||
addElement: function (parent, group) {
|
||||
var self = this;
|
||||
var property = document.createElement("div");
|
||||
property.id = group.id;
|
||||
|
||||
var row = document.createElement("div");
|
||||
switch (group.type) {
|
||||
case "Button":
|
||||
var button = document.createElement("input");
|
||||
button.setAttribute("type", "button");
|
||||
button.id = group.id;
|
||||
if (group.disabled) {
|
||||
button.disabled = group.disabled;
|
||||
}
|
||||
button.className = group.class;
|
||||
button.value = group.name;
|
||||
|
||||
button.onclick = group.callback;
|
||||
parent.appendChild(button);
|
||||
break;
|
||||
case "Row":
|
||||
var hr = document.createElement("hr");
|
||||
hr.className = "splitter";
|
||||
if (group.id) {
|
||||
hr.id = group.id;
|
||||
}
|
||||
parent.appendChild(hr);
|
||||
break;
|
||||
case "Boolean":
|
||||
self.addCheckBox(row, group);
|
||||
parent.appendChild(row);
|
||||
break;
|
||||
case "SliderFloat":
|
||||
case "SliderInteger":
|
||||
case "SliderRadian":
|
||||
self.addSlider(row, group);
|
||||
parent.appendChild(row);
|
||||
break;
|
||||
case "Texture":
|
||||
self.addTextureField(row, group);
|
||||
parent.appendChild(row);
|
||||
break;
|
||||
case "Color":
|
||||
self.addColorPicker(row, group);
|
||||
parent.appendChild(row);
|
||||
break;
|
||||
case "Vector":
|
||||
self.addVector(row, group);
|
||||
parent.appendChild(row);
|
||||
break;
|
||||
case "VectorQuaternion":
|
||||
self.addVectorQuaternion(row, group);
|
||||
parent.appendChild(row);
|
||||
break;
|
||||
default:
|
||||
console.log("not defined");
|
||||
}
|
||||
return row;
|
||||
}
|
||||
};
|
124
scripts/system/particle_explorer/particle-style.css
Normal file
124
scripts/system/particle_explorer/particle-style.css
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,95 +1,42 @@
|
|||
<!--
|
||||
// particleExplorer.hml
|
||||
//
|
||||
//
|
||||
//
|
||||
// Created by James B. Pollack @imgntn on 9/26/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Loads dat.gui, underscore, and the app
|
||||
// Quickly edit the aesthetics of a particle system.
|
||||
|
||||
// Reworked by Menithal on 20/5/2017
|
||||
// Using a custom built system for High Fidelity
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
-->
|
||||
//
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="../html/css/colpick.css">
|
||||
<script type="text/javascript" src="dat.gui.min.js"></script>
|
||||
<script type="text/javascript" src="underscore-min.js"></script>
|
||||
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
<script type="text/javascript" src="../html/js/eventBridgeLoader.js"></script>
|
||||
<script type="text/javascript" src="../html/js/jquery-2.1.4.min.js"></script>
|
||||
<script type="text/javascript" src="../html/js/colpick.js"></script>
|
||||
<script type="text/javascript" src="particleExplorer.js"></script>
|
||||
<script>
|
||||
function loaded() {
|
||||
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
|
||||
document.addEventListener("contextmenu", function (event) {
|
||||
event.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
<link rel="stylesheet" type="text/css" href="../html/css/colpick.css">
|
||||
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
<script type="text/javascript" src="../html/js/eventBridgeLoader.js"></script>
|
||||
<!---->
|
||||
<script type="text/javascript" src="../html/js/jquery-2.1.4.min.js"></script>
|
||||
<script type="text/javascript" src="../html/js/colpick.js"></script>
|
||||
|
||||
body{
|
||||
background-color:black;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
<script type="text/javascript" src="underscore-min.js"></script>
|
||||
<script type="text/javascript" src="hifi-entity-ui.js?v1"></script>
|
||||
|
||||
#my-gui-container{
|
||||
|
||||
}
|
||||
|
||||
.importer{
|
||||
margin-bottom:4px;
|
||||
}
|
||||
.exported-props-section {
|
||||
width: 50%;
|
||||
margin: 0 auto;
|
||||
|
||||
}
|
||||
#exported-props {
|
||||
/* Set the margin-left and margin-right automatically set */
|
||||
color: white;
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
}
|
||||
|
||||
.color-box {
|
||||
display: block;
|
||||
width: 60%;
|
||||
height: 21px;
|
||||
margin-top: 4px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.color-box.highlight {
|
||||
width: 13.5pt;
|
||||
height: 13.5pt;
|
||||
border: 1.5pt solid black;
|
||||
}
|
||||
|
||||
::-webkit-input-placeholder {
|
||||
text-align: center;
|
||||
font-family: Helvetica
|
||||
}
|
||||
|
||||
#importer-input{
|
||||
width:90%;
|
||||
line-height: 2;
|
||||
margin-left:5%;
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="../html/css/hifi-style.css">
|
||||
<link rel="stylesheet" type="text/css" href="../html/css/edit-style.css">
|
||||
<link rel="stylesheet" type="text/css" href="particle-style.css">
|
||||
</head>
|
||||
<body onload="loaded();">
|
||||
<div class="importer">
|
||||
<input type='text' id="importer-input" placeholder="Import: Paste JSON here." onkeypress="handleInputKeyPress(event)">
|
||||
<div class = "exported-props-section">
|
||||
<div id = "exported-props"></div>
|
||||
</div>
|
||||
<div id="my-gui-container">
|
||||
</div>
|
||||
|
||||
<body>
|
||||
<div id="particle-explorer">
|
||||
<div class="section-header">
|
||||
<label> Particle Explorer </label>
|
||||
</div>
|
||||
<!-- This will be filled by the script! -->
|
||||
</div>
|
||||
<div id="rem"></div>
|
||||
<script type="text/javascript" src="particleExplorer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,550 +2,410 @@
|
|||
// particleExplorer.js
|
||||
//
|
||||
// Created by James B. Pollack @imgntn on 9/26/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Reworked by Menithal on 20/5/2017
|
||||
//
|
||||
// Web app side of the App - contains GUI.
|
||||
// This is an example of a new, easy way to do two way bindings between dynamically created GUI and in-world entities.
|
||||
// This is an example of a new, easy way to do two way bindings between dynamically created GUI and in-world entities.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
/* global window, alert, EventBridge, dat, listenForSettingsUpdates, createVec3Folder, createQuatFolder, writeVec3ToInterface, writeDataToInterface,
|
||||
$, document, _, openEventBridge */
|
||||
/* global HifiEntityUI, openEventBridge, console, EventBridge, document, window */
|
||||
/* eslint no-console: 0, no-global-assign: 0 */
|
||||
|
||||
var Settings = function () {
|
||||
this.exportSettings = function () {
|
||||
// copyExportSettingsToClipboard();
|
||||
showPreselectedPrompt();
|
||||
};
|
||||
this.importSettings = function () {
|
||||
importSettings();
|
||||
};
|
||||
};
|
||||
(function () {
|
||||
|
||||
// 2-way bindings-aren't quite ready yet. see bottom of file.
|
||||
var AUTO_UPDATE = false;
|
||||
var UPDATE_ALL_FREQUENCY = 100;
|
||||
var root = document.getElementById("particle-explorer");
|
||||
|
||||
var controllers = [];
|
||||
var colpickKeys = [];
|
||||
var folders = [];
|
||||
var gui = null;
|
||||
var settings = new Settings();
|
||||
var updateInterval;
|
||||
|
||||
var active = false;
|
||||
|
||||
var currentInputField;
|
||||
var storedController;
|
||||
// CHANGE TO WHITELIST
|
||||
var keysToAllow = [
|
||||
'isEmitting',
|
||||
'maxParticles',
|
||||
'lifespan',
|
||||
'emitRate',
|
||||
'emitSpeed',
|
||||
'speedSpread',
|
||||
'emitOrientation',
|
||||
'emitDimensions',
|
||||
'polarStart',
|
||||
'polarFinish',
|
||||
'azimuthStart',
|
||||
'azimuthFinish',
|
||||
'emitAcceleration',
|
||||
'accelerationSpread',
|
||||
'particleRadius',
|
||||
'radiusSpread',
|
||||
'radiusStart',
|
||||
'radiusFinish',
|
||||
'color',
|
||||
'colorSpread',
|
||||
'colorStart',
|
||||
'colorFinish',
|
||||
'alpha',
|
||||
'alphaSpread',
|
||||
'alphaStart',
|
||||
'alphaFinish',
|
||||
'emitterShouldTrail',
|
||||
'textures'
|
||||
];
|
||||
|
||||
var individualKeys = [];
|
||||
var vec3Keys = [];
|
||||
var quatKeys = [];
|
||||
var colorKeys = [];
|
||||
|
||||
window.onload = function () {
|
||||
openEventBridge(function () {
|
||||
var stringifiedData = JSON.stringify({
|
||||
messageType: 'page_loaded'
|
||||
window.onload = function () {
|
||||
var ui = new HifiEntityUI(root);
|
||||
var textarea = document.createElement("textarea");
|
||||
var properties = "";
|
||||
var menuStructure = {
|
||||
General: [
|
||||
{
|
||||
type: "Row",
|
||||
id: "export-import-field"
|
||||
},
|
||||
{
|
||||
id: "show-properties-button",
|
||||
name: "Show Properties",
|
||||
type: "Button",
|
||||
class: "blue",
|
||||
disabled: true,
|
||||
callback: function (event) {
|
||||
var insertZone = document.getElementById("export-import-field");
|
||||
var json = ui.getSettings();
|
||||
properties = JSON.stringify(json);
|
||||
textarea.value = properties;
|
||||
if (!insertZone.contains(textarea)) {
|
||||
insertZone.appendChild(textarea);
|
||||
insertZone.parentNode.parentNode.style.maxHeight =
|
||||
insertZone.parentNode.clientHeight + "px";
|
||||
document.getElementById("export-properties-button").removeAttribute("disabled");
|
||||
textarea.onchange = function (e) {
|
||||
if (e.target.value !== properties) {
|
||||
document.getElementById("import-properties-button").removeAttribute("disabled");
|
||||
}
|
||||
};
|
||||
textarea.oninput = textarea.onchange;
|
||||
} else {
|
||||
textarea.onchange = function () {};
|
||||
textarea.oninput = textarea.onchange;
|
||||
textarea.value = "";
|
||||
textarea.remove();
|
||||
insertZone.parentNode.parentNode.style.maxHeight =
|
||||
insertZone.parentNode.clientHeight + "px";
|
||||
document.getElementById("export-properties-button").setAttribute("disabled", true);
|
||||
document.getElementById("import-properties-button").setAttribute("disabled", true);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "import-properties-button",
|
||||
name: "Import",
|
||||
type: "Button",
|
||||
class: "blue",
|
||||
disabled: true,
|
||||
callback: function (event) {
|
||||
ui.fillFields(JSON.parse(textarea.value));
|
||||
ui.submitChanges(JSON.parse(textarea.value));
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "export-properties-button",
|
||||
name: "Export",
|
||||
type: "Button",
|
||||
class: "red",
|
||||
disabled: true,
|
||||
callback: function (event) {
|
||||
textarea.select();
|
||||
try {
|
||||
var success = document.execCommand('copy');
|
||||
if (!success) {
|
||||
throw "Not success :(";
|
||||
}
|
||||
} catch (e) {
|
||||
print("couldnt copy field");
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "isEmitting",
|
||||
name: "Is Emitting",
|
||||
type: "Boolean"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "lifespan",
|
||||
name: "Lifespan",
|
||||
type: "SliderFloat",
|
||||
min: 0.01,
|
||||
max: 10
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "maxParticles",
|
||||
name: "Max Particles",
|
||||
type: "SliderInteger",
|
||||
min: 1,
|
||||
max: 10000
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "textures",
|
||||
name: "Textures",
|
||||
type: "Texture"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
}
|
||||
],
|
||||
Emit: [
|
||||
{
|
||||
id: "emitRate",
|
||||
name: "Emit Rate",
|
||||
type: "SliderInteger",
|
||||
max: 1000,
|
||||
min: 1
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "emitSpeed",
|
||||
name: "Emit Speed",
|
||||
type: "SliderFloat",
|
||||
max: 5
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "emitDimensions",
|
||||
name: "Emit Dimension",
|
||||
type: "Vector",
|
||||
defaultRange: {
|
||||
min: 0,
|
||||
step: 0.01
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "emitOrientation",
|
||||
unit: "deg",
|
||||
name: "Emit Orientation",
|
||||
type: "VectorQuaternion",
|
||||
defaultRange: {
|
||||
min: 0,
|
||||
step: 0.01
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "emitShouldTrail",
|
||||
name: "Emit Should Trail",
|
||||
type: "Boolean"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
}
|
||||
],
|
||||
Radius: [
|
||||
{
|
||||
id: "particleRadius",
|
||||
name: "Particle Radius",
|
||||
type: "SliderFloat",
|
||||
max: 4.0
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "radiusSpread",
|
||||
name: "Radius Spread",
|
||||
type: "SliderFloat",
|
||||
max: 4.0
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "radiusStart",
|
||||
name: "Radius Start",
|
||||
type: "SliderFloat",
|
||||
max: 4.0
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "radiusFinish",
|
||||
name: "Radius Finish",
|
||||
type: "SliderFloat",
|
||||
max: 4.0
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
}
|
||||
],
|
||||
Color: [
|
||||
{
|
||||
id: "color",
|
||||
name: "Color",
|
||||
type: "Color",
|
||||
defaultColor: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "colorSpread",
|
||||
name: "Color Spread",
|
||||
type: "Color",
|
||||
defaultColor: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "colorStart",
|
||||
name: "Color Start",
|
||||
type: "Color",
|
||||
defaultColor: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "colorFinish",
|
||||
name: "Color Finish",
|
||||
type: "Color",
|
||||
defaultColor: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
}
|
||||
],
|
||||
Acceleration: [
|
||||
{
|
||||
id: "emitAcceleration",
|
||||
name: "Emit Acceleration",
|
||||
type: "Vector",
|
||||
defaultRange: {
|
||||
step: 0.01
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "accelerationSpread",
|
||||
name: "Acceleration Spread",
|
||||
type: "Vector",
|
||||
defaultRange: {
|
||||
step: 0.01
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
}
|
||||
],
|
||||
Alpha: [
|
||||
{
|
||||
id: "alpha",
|
||||
name: "Alpha",
|
||||
type: "SliderFloat"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "alphaSpread",
|
||||
name: "Alpha Spread",
|
||||
type: "SliderFloat"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "alphaStart",
|
||||
name: "Alpha Start",
|
||||
type: "SliderFloat"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "alphaFinish",
|
||||
name: "Alpha Finish",
|
||||
type: "SliderFloat"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
}
|
||||
],
|
||||
Polar: [
|
||||
{
|
||||
id: "polarStart",
|
||||
name: "Polar Start",
|
||||
unit: "deg",
|
||||
type: "SliderRadian"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "polarFinish",
|
||||
name: "Polar Finish",
|
||||
unit: "deg",
|
||||
type: "SliderRadian"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
}
|
||||
],
|
||||
Azimuth: [
|
||||
{
|
||||
id: "azimuthStart",
|
||||
name: "Azimuth Start",
|
||||
unit: "deg",
|
||||
type: "SliderRadian",
|
||||
min: -180,
|
||||
max: 0
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "azimuthFinish",
|
||||
name: "Azimuth Finish",
|
||||
unit: "deg",
|
||||
type: "SliderRadian"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
}
|
||||
]
|
||||
};
|
||||
ui.setUI(menuStructure);
|
||||
ui.setOnSelect(function () {
|
||||
document.getElementById("show-properties-button").removeAttribute("disabled");
|
||||
document.getElementById("export-properties-button").setAttribute("disabled", true);
|
||||
document.getElementById("import-properties-button").setAttribute("disabled", true);
|
||||
});
|
||||
ui.build();
|
||||
var overrideLoad = false;
|
||||
if (openEventBridge === undefined) {
|
||||
overrideLoad = true,
|
||||
openEventBridge = function (callback) {
|
||||
callback({
|
||||
emitWebEvent: function () {},
|
||||
submitChanges: function () {},
|
||||
scriptEventReceived: {
|
||||
connect: function () {
|
||||
|
||||
EventBridge.emitWebEvent(
|
||||
stringifiedData
|
||||
);
|
||||
|
||||
listenForSettingsUpdates();
|
||||
window.onresize = setGUIWidthToWindowWidth;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
function loadGUI() {
|
||||
// whether or not to autoplace
|
||||
gui = new dat.GUI({
|
||||
autoPlace: false
|
||||
});
|
||||
|
||||
// if not autoplacing, put gui in a custom container
|
||||
if (gui.autoPlace === false) {
|
||||
var customContainer = document.getElementById('my-gui-container');
|
||||
customContainer.appendChild(gui.domElement);
|
||||
}
|
||||
|
||||
// presets for the GUI itself. a little confusing and import/export is mostly what we want to do at the moment.
|
||||
// gui.remember(settings);
|
||||
|
||||
colpickKeys = [];
|
||||
var keys = _.keys(settings);
|
||||
|
||||
_.each(keys, function(key) {
|
||||
var shouldAllow = _.contains(keysToAllow, key);
|
||||
|
||||
if (shouldAllow) {
|
||||
var subKeys = _.keys(settings[key]);
|
||||
var hasX = _.contains(subKeys, 'x');
|
||||
var hasY = _.contains(subKeys, 'y');
|
||||
var hasZ = _.contains(subKeys, 'z');
|
||||
var hasW = _.contains(subKeys, 'w');
|
||||
var hasRed = _.contains(subKeys, 'red');
|
||||
var hasGreen = _.contains(subKeys, 'green');
|
||||
var hasBlue = _.contains(subKeys, 'blue');
|
||||
|
||||
if ((hasX && hasY && hasZ) && hasW === false) {
|
||||
vec3Keys.push(key);
|
||||
} else if (hasX && hasY && hasZ && hasW) {
|
||||
quatKeys.push(key);
|
||||
} else if (hasRed || hasGreen || hasBlue) {
|
||||
colorKeys.push(key);
|
||||
|
||||
} else {
|
||||
individualKeys.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// alphabetize our keys
|
||||
individualKeys.sort();
|
||||
vec3Keys.sort();
|
||||
quatKeys.sort();
|
||||
colorKeys.sort();
|
||||
|
||||
// add to gui in the order they should appear
|
||||
gui.add(settings, 'importSettings');
|
||||
gui.add(settings, 'exportSettings');
|
||||
addIndividualKeys();
|
||||
addFolders();
|
||||
|
||||
// set the gui width to match the web window width
|
||||
gui.width = window.innerWidth;
|
||||
|
||||
// 2-way binding stuff
|
||||
// if (AUTO_UPDATE) {
|
||||
// setInterval(manuallyUpdateDisplay, UPDATE_ALL_FREQUENCY);
|
||||
// registerDOMElementsForListenerBlocking();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
function addIndividualKeys() {
|
||||
_.each(individualKeys, function(key) {
|
||||
// temporary patch for not crashing when this goes below 0
|
||||
var controller;
|
||||
|
||||
if (key.indexOf('emitRate') > -1) {
|
||||
controller = gui.add(settings, key).min(0);
|
||||
} else {
|
||||
controller = gui.add(settings, key);
|
||||
}
|
||||
|
||||
// 2-way - need to fix not being able to input exact values if constantly listening
|
||||
// controller.listen();
|
||||
|
||||
// keep track of our controller
|
||||
controllers.push(controller);
|
||||
|
||||
// hook into change events for this gui controller
|
||||
controller.onChange(function(value) {
|
||||
// Fires on every change, drag, keypress, etc.
|
||||
writeDataToInterface(this.property, value);
|
||||
openEventBridge(function (EventBridge) {
|
||||
ui.connect(EventBridge);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function addFolders() {
|
||||
_.each(colorKeys, function(key) {
|
||||
createColorPicker(key);
|
||||
});
|
||||
_.each(vec3Keys, function(key) {
|
||||
createVec3Folder(key);
|
||||
});
|
||||
_.each(quatKeys, function(key) {
|
||||
createQuatFolder(key);
|
||||
});
|
||||
}
|
||||
|
||||
function createColorPicker(key) {
|
||||
var colorObject = settings[key];
|
||||
|
||||
// Embed colpick's color picker into dat.GUI
|
||||
var name = document.createElement('span');
|
||||
name.className = 'property-name';
|
||||
name.innerHTML = key;
|
||||
|
||||
var container = document.createElement('div');
|
||||
container.appendChild(name);
|
||||
|
||||
var $colPickContainer = $('<div>', {
|
||||
id: key.toString(),
|
||||
class: "color-box"
|
||||
});
|
||||
$colPickContainer.css('background-color', "rgb(" + colorObject.red + "," + colorObject.green + "," + colorObject.blue + ")");
|
||||
container.appendChild($colPickContainer[0]);
|
||||
|
||||
var $li = $('<li>', { class: 'cr object color' });
|
||||
$li.append(container);
|
||||
gui.__ul.appendChild($li[0]);
|
||||
gui.onResize();
|
||||
|
||||
$colPickContainer.colpick({
|
||||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: { r: colorObject.red, g: colorObject.green, b: colorObject.blue },
|
||||
onSubmit: function (hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
$(el).colpickHide();
|
||||
|
||||
var obj = {};
|
||||
obj[key] = { red: rgb.r, green: rgb.g, blue: rgb.b };
|
||||
writeVec3ToInterface(obj);
|
||||
if (overrideLoad) {
|
||||
openEventBridge();
|
||||
}
|
||||
});
|
||||
|
||||
colpickKeys.push(key);
|
||||
}
|
||||
|
||||
function createVec3Folder(category) {
|
||||
var folder = gui.addFolder(category);
|
||||
|
||||
folder.add(settings[category], 'x').step(0.1).onChange(function(value) {
|
||||
// Fires when a controller loses focus.
|
||||
var obj = {};
|
||||
obj[category] = {};
|
||||
obj[category][this.property] = value;
|
||||
obj[category].y = settings[category].y;
|
||||
obj[category].z = settings[category].z;
|
||||
writeVec3ToInterface(obj);
|
||||
});
|
||||
|
||||
folder.add(settings[category], 'y').step(0.1).onChange(function(value) {
|
||||
// Fires when a controller loses focus.
|
||||
var obj = {};
|
||||
obj[category] = {};
|
||||
obj[category].x = settings[category].x;
|
||||
obj[category][this.property] = value;
|
||||
obj[category].z = settings[category].z;
|
||||
writeVec3ToInterface(obj);
|
||||
});
|
||||
|
||||
folder.add(settings[category], 'z').step(0.1).onChange(function(value) {
|
||||
// Fires when a controller loses focus.
|
||||
var obj = {};
|
||||
obj[category] = {};
|
||||
obj[category].y = settings[category].y;
|
||||
obj[category].x = settings[category].x;
|
||||
obj[category][this.property] = value;
|
||||
writeVec3ToInterface(obj);
|
||||
});
|
||||
|
||||
folders.push(folder);
|
||||
folder.open();
|
||||
}
|
||||
|
||||
function createQuatFolder(category) {
|
||||
var folder = gui.addFolder(category);
|
||||
|
||||
folder.add(settings[category], 'x').step(0.1).onChange(function(value) {
|
||||
// Fires when a controller loses focus.
|
||||
var obj = {};
|
||||
obj[category] = {};
|
||||
obj[category][this.property] = value;
|
||||
obj[category].y = settings[category].y;
|
||||
obj[category].z = settings[category].z;
|
||||
obj[category].w = settings[category].w;
|
||||
writeVec3ToInterface(obj);
|
||||
});
|
||||
|
||||
folder.add(settings[category], 'y').step(0.1).onChange(function(value) {
|
||||
// Fires when a controller loses focus.
|
||||
var obj = {};
|
||||
obj[category] = {};
|
||||
obj[category].x = settings[category].x;
|
||||
obj[category][this.property] = value;
|
||||
obj[category].z = settings[category].z;
|
||||
obj[category].w = settings[category].w;
|
||||
writeVec3ToInterface(obj);
|
||||
});
|
||||
|
||||
folder.add(settings[category], 'z').step(0.1).onChange(function(value) {
|
||||
// Fires when a controller loses focus.
|
||||
var obj = {};
|
||||
obj[category] = {};
|
||||
obj[category].x = settings[category].x;
|
||||
obj[category].y = settings[category].y;
|
||||
obj[category][this.property] = value;
|
||||
obj[category].w = settings[category].w;
|
||||
writeVec3ToInterface(obj);
|
||||
});
|
||||
|
||||
folder.add(settings[category], 'w').step(0.1).onChange(function(value) {
|
||||
// Fires when a controller loses focus.
|
||||
var obj = {};
|
||||
obj[category] = {};
|
||||
obj[category].x = settings[category].x;
|
||||
obj[category].y = settings[category].y;
|
||||
obj[category].z = settings[category].z;
|
||||
obj[category][this.property] = value;
|
||||
writeVec3ToInterface(obj);
|
||||
});
|
||||
|
||||
folders.push(folder);
|
||||
folder.open();
|
||||
}
|
||||
|
||||
function convertColorObjectToArray(colorObject) {
|
||||
var colorArray = [];
|
||||
|
||||
_.each(colorObject, function(singleColor) {
|
||||
colorArray.push(singleColor);
|
||||
});
|
||||
|
||||
return colorArray;
|
||||
}
|
||||
|
||||
function convertColorArrayToObject(colorArray) {
|
||||
var colorObject = {
|
||||
red: colorArray[0],
|
||||
green: colorArray[1],
|
||||
blue: colorArray[2]
|
||||
};
|
||||
|
||||
return colorObject;
|
||||
}
|
||||
|
||||
function writeDataToInterface(property, value) {
|
||||
var data = {};
|
||||
data[property] = value;
|
||||
|
||||
var sendData = {
|
||||
messageType: "settings_update",
|
||||
updatedSettings: data
|
||||
};
|
||||
|
||||
var stringifiedData = JSON.stringify(sendData);
|
||||
|
||||
EventBridge.emitWebEvent(stringifiedData);
|
||||
}
|
||||
|
||||
function writeVec3ToInterface(obj) {
|
||||
var sendData = {
|
||||
messageType: "settings_update",
|
||||
updatedSettings: obj
|
||||
};
|
||||
|
||||
var stringifiedData = JSON.stringify(sendData);
|
||||
|
||||
EventBridge.emitWebEvent(stringifiedData);
|
||||
}
|
||||
|
||||
function listenForSettingsUpdates() {
|
||||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
if (data.messageType === 'particle_settings') {
|
||||
_.each(data.currentProperties, function(value, key) {
|
||||
settings[key] = {};
|
||||
settings[key] = value;
|
||||
});
|
||||
|
||||
if (gui) {
|
||||
manuallyUpdateDisplay();
|
||||
} else {
|
||||
loadGUI();
|
||||
}
|
||||
if (!active) {
|
||||
// gui.toggleHide();
|
||||
gui.closed = false;
|
||||
}
|
||||
active = true;
|
||||
|
||||
} else if (data.messageType === "particle_close") {
|
||||
// none of this seems to work.
|
||||
// if (active) {
|
||||
// gui.toggleHide();
|
||||
// }
|
||||
active = false;
|
||||
gui.closed = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function manuallyUpdateDisplay() {
|
||||
// Iterate over all controllers
|
||||
// this is expensive, write a method for indiviudal controllers and use it when the value is different than a cached value, perhaps.
|
||||
var i;
|
||||
for (i in gui.__controllers) {
|
||||
gui.__controllers[i].updateDisplay();
|
||||
}
|
||||
|
||||
// Update color pickers
|
||||
for (i in colpickKeys) {
|
||||
var color = settings[colpickKeys[i]];
|
||||
var $object = $('#' + colpickKeys[i]);
|
||||
$object.css('background-color', "rgb(" + color.red + "," + color.green + "," + color.blue + ")");
|
||||
$object.colpickSetColor({ r: color.red, g: color.green, b: color.blue }, true);
|
||||
}
|
||||
}
|
||||
|
||||
function setGUIWidthToWindowWidth() {
|
||||
if (gui !== null) {
|
||||
gui.width = window.innerWidth;
|
||||
}
|
||||
}
|
||||
|
||||
function handleInputKeyPress(e) {
|
||||
if (e.keyCode === 13) {
|
||||
importSettings();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function importSettings() {
|
||||
var importInput = document.getElementById('importer-input');
|
||||
|
||||
try {
|
||||
var importedSettings = JSON.parse(importInput.value);
|
||||
|
||||
var keys = _.keys(importedSettings);
|
||||
|
||||
_.each(keys, function(key) {
|
||||
var shouldAllow = _.contains(keysToAllow, key);
|
||||
|
||||
if (!shouldAllow) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings[key] = importedSettings[key];
|
||||
});
|
||||
|
||||
writeVec3ToInterface(settings);
|
||||
|
||||
manuallyUpdateDisplay();
|
||||
} catch (e) {
|
||||
alert('Not properly formatted JSON');
|
||||
}
|
||||
}
|
||||
|
||||
function prepareSettingsForExport() {
|
||||
var keys = _.keys(settings);
|
||||
|
||||
var exportSettings = {};
|
||||
|
||||
_.each(keys, function(key) {
|
||||
var shouldAllow = _.contains(keysToAllow, key);
|
||||
|
||||
if (!shouldAllow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key.indexOf('color') > -1) {
|
||||
var colorObject = convertColorArrayToObject(settings[key]);
|
||||
settings[key] = colorObject;
|
||||
}
|
||||
|
||||
exportSettings[key] = settings[key];
|
||||
});
|
||||
|
||||
return JSON.stringify(exportSettings, null, 4);
|
||||
}
|
||||
|
||||
function showPreselectedPrompt() {
|
||||
var elem = document.getElementById("exported-props");
|
||||
var exportSettings = prepareSettingsForExport();
|
||||
elem.innerHTML = "";
|
||||
var buttonnode = document.createElement('input');
|
||||
buttonnode.setAttribute('type', 'button');
|
||||
buttonnode.setAttribute('value', 'close');
|
||||
elem.appendChild(document.createTextNode("COPY THE BELOW FIELD TO CLIPBOARD:"));
|
||||
elem.appendChild(document.createElement("br"));
|
||||
var textAreaNode = document.createElement("textarea");
|
||||
textAreaNode.value = exportSettings;
|
||||
elem.appendChild(textAreaNode);
|
||||
elem.appendChild(document.createElement("br"));
|
||||
elem.appendChild(buttonnode);
|
||||
|
||||
buttonnode.onclick = function() {
|
||||
console.log("click");
|
||||
elem.innerHTML = "";
|
||||
};
|
||||
|
||||
// window.alert("Ctrl-C to copy, then Enter.", prepareSettingsForExport());
|
||||
}
|
||||
|
||||
function removeContainerDomElement() {
|
||||
var elem = document.getElementById("my-gui-container");
|
||||
elem.parentNode.removeChild(elem);
|
||||
}
|
||||
|
||||
function removeListenerFromGUI(key) {
|
||||
_.each(gui.__listening, function(controller, index) {
|
||||
if (controller.property === key) {
|
||||
storedController = controller;
|
||||
gui.__listening.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// the section below is to try to work at achieving two way bindings;
|
||||
|
||||
function addListenersBackToGUI() {
|
||||
gui.__listening.push(storedController);
|
||||
storedController = null;
|
||||
}
|
||||
|
||||
function registerDOMElementsForListenerBlocking() {
|
||||
_.each(gui.__controllers, function(controller) {
|
||||
var input = controller.domElement.childNodes[0];
|
||||
input.addEventListener('focus', function() {
|
||||
console.log('INPUT ELEMENT GOT FOCUS!' + controller.property);
|
||||
removeListenerFromGUI(controller.property);
|
||||
});
|
||||
});
|
||||
|
||||
_.each(gui.__controllers, function(controller) {
|
||||
var input = controller.domElement.childNodes[0];
|
||||
input.addEventListener('blur', function() {
|
||||
console.log('INPUT ELEMENT GOT BLUR!' + controller.property);
|
||||
addListenersBackToGUI();
|
||||
});
|
||||
});
|
||||
|
||||
// also listen to inputs inside of folders
|
||||
_.each(gui.__folders, function(folder) {
|
||||
_.each(folder.__controllers, function(controller) {
|
||||
var input = controller.__input;
|
||||
input.addEventListener('focus', function() {
|
||||
console.log('FOLDER ELEMENT GOT FOCUS!' + controller.property);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -4,23 +4,22 @@
|
|||
// Created by Eric Levin on 2/15/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
// Adds particleExplorer tool to the edit panel when a user selects a particle entity from the edit tool window
|
||||
// This is an example of a new, easy way to do two way bindings between dynamically created GUI and in-world entities.
|
||||
// This is an example of a new, easy way to do two way bindings between dynamically created GUI and in-world entities.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
/*global window, alert, EventBridge, dat, listenForSettingsUpdates,createVec3Folder,createQuatFolder,writeVec3ToInterface,writeDataToInterface*/
|
||||
/* global window, alert, ParticleExplorerTool, EventBridge, dat, listenForSettingsUpdates,createVec3Folder,createQuatFolder,writeVec3ToInterface,writeDataToInterface*/
|
||||
|
||||
|
||||
var PARTICLE_EXPLORER_HTML_URL = Script.resolvePath('particleExplorer.html');
|
||||
|
||||
ParticleExplorerTool = function() {
|
||||
var that = {};
|
||||
|
||||
that.createWebView = function() {
|
||||
that.webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
that.webView.setVisible = function(value) {};
|
||||
that.webView.webEventReceived.connect(that.webEventReceived);
|
||||
that.webView.webEventReceived.connect(that.webEventReceived);
|
||||
}
|
||||
|
||||
that.destroyWebView = function() {
|
||||
|
@ -38,6 +37,9 @@ ParticleExplorerTool = function() {
|
|||
that.webEventReceived = function(data) {
|
||||
var data = JSON.parse(data);
|
||||
if (data.messageType === "settings_update") {
|
||||
if (data.updatedSettings.emitOrientation) {
|
||||
data.updatedSettings.emitOrientation = Quat.fromVec3Degrees(data.updatedSettings.emitOrientation);
|
||||
}
|
||||
Entities.editEntity(that.activeParticleEntity, data.updatedSettings);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,6 +101,10 @@ function getApplicationDataDirectory() {
|
|||
return path.join(getRootHifiDataDirectory(), '/Server Console');
|
||||
}
|
||||
|
||||
// Update lock filepath
|
||||
const UPDATER_LOCK_FILENAME = ".updating";
|
||||
const UPDATER_LOCK_FULL_PATH = getRootHifiDataDirectory() + "/" + UPDATER_LOCK_FILENAME;
|
||||
|
||||
// Configure log
|
||||
global.log = require('electron-log');
|
||||
const logFile = getApplicationDataDirectory() + '/log.txt';
|
||||
|
@ -630,11 +634,22 @@ function checkNewContent() {
|
|||
userConfig.save(configPath);
|
||||
}
|
||||
});
|
||||
} else if (fs.existsSync(UPDATER_LOCK_FULL_PATH)) {
|
||||
backupResourceDirectoriesAndRestart();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function removeIncompleteUpdate(acResourceDirectory, dsResourceDirectory) {
|
||||
if (fs.existsSync(UPDATER_LOCK_FULL_PATH)) {
|
||||
log.debug('Removing incomplete content update files before copying new update');
|
||||
fs.emptyDirSync(dsResourceDirectory);
|
||||
fs.emptyDirSync(acResourceDirectory);
|
||||
} else {
|
||||
fs.ensureFileSync(UPDATER_LOCK_FULL_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
function maybeInstallDefaultContentSet(onComplete) {
|
||||
// Check for existing data
|
||||
|
@ -673,7 +688,11 @@ function maybeInstallDefaultContentSet(onComplete) {
|
|||
}
|
||||
|
||||
log.debug("Found contentPath:" + argv.contentPath);
|
||||
|
||||
if (argv.contentPath) {
|
||||
// check if we're updating a data folder whose update is incomplete
|
||||
removeIncompleteUpdate(acResourceDirectory, dsResourceDirectory);
|
||||
|
||||
fs.copy(argv.contentPath, getRootHifiDataDirectory(), function (err) {
|
||||
if (err) {
|
||||
log.debug('Could not copy home content: ' + err);
|
||||
|
@ -682,12 +701,12 @@ function maybeInstallDefaultContentSet(onComplete) {
|
|||
log.debug('Copied home content over to: ' + getRootHifiDataDirectory());
|
||||
userConfig.set('homeContentLastModified', new Date());
|
||||
userConfig.save(configPath);
|
||||
fs.removeSync(UPDATER_LOCK_FULL_PATH);
|
||||
onComplete();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Show popup
|
||||
var window = new BrowserWindow({
|
||||
icon: appIcon,
|
||||
|
@ -718,6 +737,9 @@ function maybeInstallDefaultContentSet(onComplete) {
|
|||
|
||||
var aborted = false;
|
||||
|
||||
// check if we're updating a data folder whose update is incomplete
|
||||
removeIncompleteUpdate(acResourceDirectory, dsResourceDirectory);
|
||||
|
||||
// Start downloading content set
|
||||
var req = progress(request.get({
|
||||
url: HOME_CONTENT_URL
|
||||
|
@ -763,6 +785,7 @@ function maybeInstallDefaultContentSet(onComplete) {
|
|||
log.debug("Finished unarchiving home content set");
|
||||
userConfig.set('homeContentLastModified', new Date());
|
||||
userConfig.save(configPath);
|
||||
fs.removeSync(UPDATER_LOCK_FULL_PATH);
|
||||
sendStateUpdate('complete');
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue