diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 8066223318..39628ebb11 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -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')) { diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 250015bab9..bbb42e61ac 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -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 diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 2f812724c5..0bc72ae689 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -184,6 +184,8 @@ AudioClient::AudioClient() : checkDevices(); }); }); + const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000; + _checkDevicesTimer->start(DEVICE_CHECK_INTERVAL_MSECS); configureReverb(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index eab0e3011e..e89646d838 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -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() { diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index f7881b0333..55a46a526f 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -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()->getFrameBufferSize().width(); - int height = DependencyManager::get()->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()->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(); - 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; diff --git a/libraries/render-utils/src/AntialiasingEffect.h b/libraries/render-utils/src/AntialiasingEffect.h index e403032b4e..cec2554a3b 100644 --- a/libraries/render-utils/src/AntialiasingEffect.h +++ b/libraries/render-utils/src/AntialiasingEffect.h @@ -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: diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index a67d20c6b0..3359b3a12d 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -19,7 +19,6 @@ #include #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(); - const auto framebufferCache = DependencyManager::get(); const auto textureCache = DependencyManager::get(); glm::mat4 projMat; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 4b3ee9fec7..0b4eee125b 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -418,10 +418,7 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { } void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer) { - - auto framebufferCache = DependencyManager::get(); - 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 diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index af65f3dbf7..6a95ef6d76 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -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() diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 8105de7a13..15fb7d72c9 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -7,6 +7,9 @@ // #include "OpenVrDisplayPlugin.h" +// Odd ordering of header is required to avoid 'macro redinition warnings' +#include + #include #include #include @@ -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 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 deviceW; + deviceW.assign(size, INIT); + device.toWCharArray(deviceW.data()); + device = AudioClient::friendlyNameForAudioDevice(deviceW.data()); + } + return device; +} + diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h index 01e02c9892..a1bbed8754 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.h +++ b/plugins/openvr/src/OpenVrDisplayPlugin.h @@ -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; diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index d9db757b2f..7e287a16c3 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -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 diff --git a/plugins/openvr/src/OpenVrHelpers.h b/plugins/openvr/src/OpenVrHelpers.h index f00cd9e117..f4253899a2 100644 --- a/plugins/openvr/src/OpenVrHelpers.h +++ b/plugins/openvr/src/OpenVrHelpers.h @@ -25,6 +25,7 @@ bool openVrQuitRequested(); void enableOpenVrKeyboard(PluginContainer* container); void disableOpenVrKeyboard(); bool isOpenVrKeyboardShown(); +QString getVrSettingString(const char* section, const char* setting); template diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 2c3cc496dc..a3583e7808 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -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 - diff --git a/scripts/system/html/css/hifi-style.css b/scripts/system/html/css/hifi-style.css index ec6cd1a402..e1e4f67723 100644 --- a/scripts/system/html/css/hifi-style.css +++ b/scripts/system/html/css/hifi-style.css @@ -172,4 +172,4 @@ input[type=radio]:active + label > span > span{ } .blueButton:disabled { background-image: linear-gradient(#FFFFFF, #AFAFAF); -} \ No newline at end of file +} diff --git a/scripts/system/particle_explorer/dat.gui.min.js b/scripts/system/particle_explorer/dat.gui.min.js deleted file mode 100644 index 8ea141a966..0000000000 --- a/scripts/system/particle_explorer/dat.gui.min.js +++ /dev/null @@ -1,95 +0,0 @@ -/** - * dat-gui JavaScript Controller Library - * http://code.google.com/p/dat-gui - * - * Copyright 2011 Data Arts Team, Google Creative Lab - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -var dat=dat||{};dat.gui=dat.gui||{};dat.utils=dat.utils||{};dat.controllers=dat.controllers||{};dat.dom=dat.dom||{};dat.color=dat.color||{};dat.utils.css=function(){return{load:function(f,a){a=a||document;var d=a.createElement("link");d.type="text/css";d.rel="stylesheet";d.href=f;a.getElementsByTagName("head")[0].appendChild(d)},inject:function(f,a){a=a||document;var d=document.createElement("style");d.type="text/css";d.innerHTML=f;a.getElementsByTagName("head")[0].appendChild(d)}}}(); -dat.utils.common=function(){var f=Array.prototype.forEach,a=Array.prototype.slice;return{BREAK:{},extend:function(d){this.each(a.call(arguments,1),function(a){for(var c in a)this.isUndefined(a[c])||(d[c]=a[c])},this);return d},defaults:function(d){this.each(a.call(arguments,1),function(a){for(var c in a)this.isUndefined(d[c])&&(d[c]=a[c])},this);return d},compose:function(){var d=a.call(arguments);return function(){for(var e=a.call(arguments),c=d.length-1;0<=c;c--)e=[d[c].apply(this,e)];return e[0]}}, -each:function(a,e,c){if(a)if(f&&a.forEach&&a.forEach===f)a.forEach(e,c);else if(a.length===a.length+0)for(var b=0,p=a.length;bthis.__max&&(a=this.__max);void 0!==this.__step&&0!=a%this.__step&&(a=Math.round(a/this.__step)*this.__step);return e.superclass.prototype.setValue.call(this,a)},min:function(a){this.__min=a;return this},max:function(a){this.__max=a;return this},step:function(a){this.__impliedStep=this.__step=a;this.__precision=d(a);return this}});return e}(dat.controllers.Controller,dat.utils.common); -dat.controllers.NumberControllerBox=function(f,a,d){var e=function(c,b,f){function q(){var a=parseFloat(n.__input.value);d.isNaN(a)||n.setValue(a)}function l(a){var b=u-a.clientY;n.setValue(n.getValue()+b*n.__impliedStep);u=a.clientY}function r(){a.unbind(window,"mousemove",l);a.unbind(window,"mouseup",r)}this.__truncationSuspended=!1;e.superclass.call(this,c,b,f);var n=this,u;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"change",q);a.bind(this.__input, -"blur",function(){q();n.__onFinishChange&&n.__onFinishChange.call(n,n.getValue())});a.bind(this.__input,"mousedown",function(b){a.bind(window,"mousemove",l);a.bind(window,"mouseup",r);u=b.clientY});a.bind(this.__input,"keydown",function(a){13===a.keyCode&&(n.__truncationSuspended=!0,this.blur(),n.__truncationSuspended=!1)});this.updateDisplay();this.domElement.appendChild(this.__input)};e.superclass=f;d.extend(e.prototype,f.prototype,{updateDisplay:function(){var a=this.__input,b;if(this.__truncationSuspended)b= -this.getValue();else{b=this.getValue();var d=Math.pow(10,this.__precision);b=Math.round(b*d)/d}a.value=b;return e.superclass.prototype.updateDisplay.call(this)}});return e}(dat.controllers.NumberController,dat.dom.dom,dat.utils.common); -dat.controllers.NumberControllerSlider=function(f,a,d,e,c){function b(a,b,c,e,d){return e+(a-b)/(c-b)*(d-e)}var p=function(c,e,d,f,u){function A(c){c.preventDefault();var e=a.getOffset(k.__background),d=a.getWidth(k.__background);k.setValue(b(c.clientX,e.left,e.left+d,k.__min,k.__max));return!1}function g(){a.unbind(window,"mousemove",A);a.unbind(window,"mouseup",g);k.__onFinishChange&&k.__onFinishChange.call(k,k.getValue())}p.superclass.call(this,c,e,{min:d,max:f,step:u});var k=this;this.__background= -document.createElement("div");this.__foreground=document.createElement("div");a.bind(this.__background,"mousedown",function(b){a.bind(window,"mousemove",A);a.bind(window,"mouseup",g);A(b)});a.addClass(this.__background,"slider");a.addClass(this.__foreground,"slider-fg");this.updateDisplay();this.__background.appendChild(this.__foreground);this.domElement.appendChild(this.__background)};p.superclass=f;p.useDefaultStyles=function(){d.inject(c)};e.extend(p.prototype,f.prototype,{updateDisplay:function(){var a= -(this.getValue()-this.__min)/(this.__max-this.__min);this.__foreground.style.width=100*a+"%";return p.superclass.prototype.updateDisplay.call(this)}});return p}(dat.controllers.NumberController,dat.dom.dom,dat.utils.css,dat.utils.common,"/**\n * dat-gui JavaScript Controller Library\n * http://code.google.com/p/dat-gui\n *\n * Copyright 2011 Data Arts Team, Google Creative Lab\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n\n.slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}"); -dat.controllers.FunctionController=function(f,a,d){var e=function(c,b,d){e.superclass.call(this,c,b);var f=this;this.__button=document.createElement("div");this.__button.innerHTML=void 0===d?"Fire":d;a.bind(this.__button,"click",function(a){a.preventDefault();f.fire();return!1});a.addClass(this.__button,"button");this.domElement.appendChild(this.__button)};e.superclass=f;d.extend(e.prototype,f.prototype,{fire:function(){this.__onChange&&this.__onChange.call(this);this.getValue().call(this.object); -this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())}});return e}(dat.controllers.Controller,dat.dom.dom,dat.utils.common); -dat.controllers.BooleanController=function(f,a,d){var e=function(c,b){e.superclass.call(this,c,b);var d=this;this.__prev=this.getValue();this.__checkbox=document.createElement("input");this.__checkbox.setAttribute("type","checkbox");a.bind(this.__checkbox,"change",function(){d.setValue(!d.__prev)},!1);this.domElement.appendChild(this.__checkbox);this.updateDisplay()};e.superclass=f;d.extend(e.prototype,f.prototype,{setValue:function(a){a=e.superclass.prototype.setValue.call(this,a);this.__onFinishChange&& -this.__onFinishChange.call(this,this.getValue());this.__prev=this.getValue();return a},updateDisplay:function(){!0===this.getValue()?(this.__checkbox.setAttribute("checked","checked"),this.__checkbox.checked=!0):this.__checkbox.checked=!1;return e.superclass.prototype.updateDisplay.call(this)}});return e}(dat.controllers.Controller,dat.dom.dom,dat.utils.common); -dat.color.toString=function(f){return function(a){if(1==a.a||f.isUndefined(a.a)){for(a=a.hex.toString(16);6>a.length;)a="0"+a;return"#"+a}return"rgba("+Math.round(a.r)+","+Math.round(a.g)+","+Math.round(a.b)+","+a.a+")"}}(dat.utils.common); -dat.color.interpret=function(f,a){var d,e,c=[{litmus:a.isString,conversions:{THREE_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null===a?!1:{space:"HEX",hex:parseInt("0x"+a[1].toString()+a[1].toString()+a[2].toString()+a[2].toString()+a[3].toString()+a[3].toString())}},write:f},SIX_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9]{6})$/i);return null===a?!1:{space:"HEX",hex:parseInt("0x"+a[1].toString())}},write:f},CSS_RGB:{read:function(a){a=a.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/); -return null===a?!1:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3])}},write:f},CSS_RGBA:{read:function(a){a=a.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);return null===a?!1:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3]),a:parseFloat(a[4])}},write:f}}},{litmus:a.isNumber,conversions:{HEX:{read:function(a){return{space:"HEX",hex:a,conversionName:"HEX"}},write:function(a){return a.hex}}}},{litmus:a.isArray,conversions:{RGB_ARRAY:{read:function(a){return 3!= -a.length?!1:{space:"RGB",r:a[0],g:a[1],b:a[2]}},write:function(a){return[a.r,a.g,a.b]}},RGBA_ARRAY:{read:function(a){return 4!=a.length?!1:{space:"RGB",r:a[0],g:a[1],b:a[2],a:a[3]}},write:function(a){return[a.r,a.g,a.b,a.a]}}}},{litmus:a.isObject,conversions:{RGBA_OBJ:{read:function(b){return a.isNumber(b.r)&&a.isNumber(b.g)&&a.isNumber(b.b)&&a.isNumber(b.a)?{space:"RGB",r:b.r,g:b.g,b:b.b,a:b.a}:!1},write:function(a){return{r:a.r,g:a.g,b:a.b,a:a.a}}},RGB_OBJ:{read:function(b){return a.isNumber(b.r)&& -a.isNumber(b.g)&&a.isNumber(b.b)?{space:"RGB",r:b.r,g:b.g,b:b.b}:!1},write:function(a){return{r:a.r,g:a.g,b:a.b}}},HSVA_OBJ:{read:function(b){return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)&&a.isNumber(b.a)?{space:"HSV",h:b.h,s:b.s,v:b.v,a:b.a}:!1},write:function(a){return{h:a.h,s:a.s,v:a.v,a:a.a}}},HSV_OBJ:{read:function(b){return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)?{space:"HSV",h:b.h,s:b.s,v:b.v}:!1},write:function(a){return{h:a.h,s:a.s,v:a.v}}}}}];return function(){e=!1; -var b=1\n\n Here\'s the new load parameter for your GUI\'s constructor:\n\n \n\n
\n\n Automatically save\n values to localStorage on exit.\n\n
The values saved to localStorage will\n override those passed to dat.GUI\'s constructor. This makes it\n easier to work incrementally, but localStorage is fragile,\n and your friends may not see the same values you do.\n \n
\n \n
\n\n', -".dg {\n /** Clear list styles */\n /* Auto-place container */\n /* Auto-placed GUI's */\n /* Line items that don't contain folders. */\n /** Folder names */\n /** Hides closed items */\n /** Controller row */\n /** Name-half (left) */\n /** Controller-half (right) */\n /** Controller placement */\n /** Shorter number boxes when slider is present. */\n /** Ensure the entire boolean and function row shows a hand */ }\n .dg ul {\n list-style: none;\n margin: 0;\n padding: 0;\n width: 100%;\n clear: both; }\n .dg.ac {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 0;\n z-index: 0; }\n .dg:not(.ac) .main {\n /** Exclude mains in ac so that we don't hide close button */\n overflow: hidden; }\n .dg.main {\n -webkit-transition: opacity 0.1s linear;\n -o-transition: opacity 0.1s linear;\n -moz-transition: opacity 0.1s linear;\n transition: opacity 0.1s linear; }\n .dg.main.taller-than-window {\n overflow-y: auto; }\n .dg.main.taller-than-window .close-button {\n opacity: 1;\n /* TODO, these are style notes */\n margin-top: -1px;\n border-top: 1px solid #2c2c2c; }\n .dg.main ul.closed .close-button {\n opacity: 1 !important; }\n .dg.main:hover .close-button,\n .dg.main .close-button.drag {\n opacity: 1; }\n .dg.main .close-button {\n /*opacity: 0;*/\n -webkit-transition: opacity 0.1s linear;\n -o-transition: opacity 0.1s linear;\n -moz-transition: opacity 0.1s linear;\n transition: opacity 0.1s linear;\n border: 0;\n position: absolute;\n line-height: 19px;\n height: 20px;\n /* TODO, these are style notes */\n cursor: pointer;\n text-align: center;\n background-color: #000; }\n .dg.main .close-button:hover {\n background-color: #111; }\n .dg.a {\n float: right;\n margin-right: 15px;\n overflow-x: hidden; }\n .dg.a.has-save > ul {\n margin-top: 27px; }\n .dg.a.has-save > ul.closed {\n margin-top: 0; }\n .dg.a .save-row {\n position: fixed;\n top: 0;\n z-index: 1002; }\n .dg li {\n -webkit-transition: height 0.1s ease-out;\n -o-transition: height 0.1s ease-out;\n -moz-transition: height 0.1s ease-out;\n transition: height 0.1s ease-out; }\n .dg li:not(.folder) {\n cursor: auto;\n height: 27px;\n line-height: 27px;\n overflow: hidden;\n padding: 0 4px 0 5px; }\n .dg li.folder {\n padding: 0;\n border-left: 4px solid rgba(0, 0, 0, 0); }\n .dg li.title {\n cursor: pointer;\n margin-left: -4px; }\n .dg .closed li:not(.title),\n .dg .closed ul li,\n .dg .closed ul li > * {\n height: 0;\n overflow: hidden;\n border: 0; }\n .dg .cr {\n clear: both;\n padding-left: 3px;\n height: 27px; }\n .dg .property-name {\n cursor: default;\n float: left;\n clear: left;\n width: 40%;\n overflow: hidden;\n text-overflow: ellipsis; }\n .dg .c {\n float: left;\n width: 60%; }\n .dg .c input[type=text] {\n border: 0;\n margin-top: 4px;\n padding: 3px;\n width: 100%;\n float: right; }\n .dg .has-slider input[type=text] {\n width: 30%;\n /*display: none;*/\n margin-left: 0; }\n .dg .slider {\n float: left;\n width: 66%;\n margin-left: -5px;\n margin-right: 0;\n height: 19px;\n margin-top: 4px; }\n .dg .slider-fg {\n height: 100%; }\n .dg .c input[type=checkbox] {\n margin-top: 9px; }\n .dg .c select {\n margin-top: 5px; }\n .dg .cr.function,\n .dg .cr.function .property-name,\n .dg .cr.function *,\n .dg .cr.boolean,\n .dg .cr.boolean * {\n cursor: pointer; }\n .dg .selector {\n display: none;\n position: absolute;\n margin-left: -9px;\n margin-top: 23px;\n z-index: 10; }\n .dg .c:hover .selector,\n .dg .selector.drag {\n display: block; }\n .dg li.save-row {\n padding: 0; }\n .dg li.save-row .button {\n display: inline-block;\n padding: 0px 6px; }\n .dg.dialogue {\n background-color: #222;\n width: 460px;\n padding: 15px;\n font-size: 13px;\n line-height: 15px; }\n\n/* TODO Separate style and structure */\n#dg-new-constructor {\n padding: 10px;\n color: #222;\n font-family: Monaco, monospace;\n font-size: 10px;\n border: 0;\n resize: none;\n box-shadow: inset 1px 1px 1px #888;\n word-wrap: break-word;\n margin: 12px 0;\n display: block;\n width: 440px;\n overflow-y: scroll;\n height: 100px;\n position: relative; }\n\n#dg-local-explain {\n display: none;\n font-size: 11px;\n line-height: 17px;\n border-radius: 3px;\n background-color: #333;\n padding: 8px;\n margin-top: 10px; }\n #dg-local-explain code {\n font-size: 10px; }\n\n#dat-gui-save-locally {\n display: none; }\n\n/** Main type */\n.dg {\n color: #eee;\n font: 11px 'Lucida Grande', sans-serif;\n text-shadow: 0 -1px 0 #111;\n /** Auto place */\n /* Controller row,
  • */\n /** Controllers */ }\n .dg.main {\n /** Scrollbar */ }\n .dg.main::-webkit-scrollbar {\n width: 5px;\n background: #1a1a1a; }\n .dg.main::-webkit-scrollbar-corner {\n height: 0;\n display: none; }\n .dg.main::-webkit-scrollbar-thumb {\n border-radius: 5px;\n background: #676767; }\n .dg li:not(.folder) {\n background: #1a1a1a;\n border-bottom: 1px solid #2c2c2c; }\n .dg li.save-row {\n line-height: 25px;\n background: #dad5cb;\n border: 0; }\n .dg li.save-row select {\n margin-left: 5px;\n width: 108px; }\n .dg li.save-row .button {\n margin-left: 5px;\n margin-top: 1px;\n border-radius: 2px;\n font-size: 9px;\n line-height: 7px;\n padding: 4px 4px 5px 4px;\n background: #c5bdad;\n color: #fff;\n text-shadow: 0 1px 0 #b0a58f;\n box-shadow: 0 -1px 0 #b0a58f;\n cursor: pointer; }\n .dg li.save-row .button.gears {\n background: #c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;\n height: 7px;\n width: 8px; }\n .dg li.save-row .button:hover {\n background-color: #bab19e;\n box-shadow: 0 -1px 0 #b0a58f; }\n .dg li.folder {\n border-bottom: 0; }\n .dg li.title {\n padding-left: 16px;\n background: black url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;\n cursor: pointer;\n border-bottom: 1px solid rgba(255, 255, 255, 0.2); }\n .dg .closed li.title {\n background-image: url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==); }\n .dg .cr.boolean {\n border-left: 3px solid #806787; }\n .dg .cr.function {\n border-left: 3px solid #e61d5f; }\n .dg .cr.number {\n border-left: 3px solid #2fa1d6; }\n .dg .cr.number input[type=text] {\n color: #2fa1d6; }\n .dg .cr.string {\n border-left: 3px solid #1ed36f; }\n .dg .cr.string input[type=text] {\n color: #1ed36f; }\n .dg .cr.function:hover, .dg .cr.boolean:hover {\n background: #111; }\n .dg .c input[type=text] {\n background: #303030;\n outline: none; }\n .dg .c input[type=text]:hover {\n background: #3c3c3c; }\n .dg .c input[type=text]:focus {\n background: #494949;\n color: #fff; }\n .dg .c .slider {\n background: #303030;\n cursor: ew-resize; }\n .dg .c .slider-fg {\n background: #2fa1d6; }\n .dg .c .slider:hover {\n background: #3c3c3c; }\n .dg .c .slider:hover .slider-fg {\n background: #44abda; }\n", -dat.controllers.factory=function(f,a,d,e,c,b,p){return function(q,l,r,n){var u=q[l];if(p.isArray(r)||p.isObject(r))return new f(q,l,r);if(p.isNumber(u))return p.isNumber(r)&&p.isNumber(n)?new d(q,l,r,n):new a(q,l,{min:r,max:n});if(p.isString(u))return new e(q,l);if(p.isFunction(u))return new c(q,l,"");if(p.isBoolean(u))return new b(q,l)}}(dat.controllers.OptionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.StringController=function(f,a,d){var e= -function(c,b){function d(){f.setValue(f.__input.value)}e.superclass.call(this,c,b);var f=this;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"keyup",d);a.bind(this.__input,"change",d);a.bind(this.__input,"blur",function(){f.__onFinishChange&&f.__onFinishChange.call(f,f.getValue())});a.bind(this.__input,"keydown",function(a){13===a.keyCode&&this.blur()});this.updateDisplay();this.domElement.appendChild(this.__input)};e.superclass=f;d.extend(e.prototype, -f.prototype,{updateDisplay:function(){a.isActive(this.__input)||(this.__input.value=this.getValue());return e.superclass.prototype.updateDisplay.call(this)}});return e}(dat.controllers.Controller,dat.dom.dom,dat.utils.common),dat.controllers.FunctionController,dat.controllers.BooleanController,dat.utils.common),dat.controllers.Controller,dat.controllers.BooleanController,dat.controllers.FunctionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.OptionController, -dat.controllers.ColorController=function(f,a,d,e,c){function b(a,b,d,e){a.style.background="";c.each(l,function(c){a.style.cssText+="background: "+c+"linear-gradient("+b+", "+d+" 0%, "+e+" 100%); "})}function p(a){a.style.background="";a.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);";a.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"; -a.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";a.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";a.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}var q=function(f,n){function u(b){v(b);a.bind(window,"mousemove",v);a.bind(window, -"mouseup",l)}function l(){a.unbind(window,"mousemove",v);a.unbind(window,"mouseup",l)}function g(){var a=e(this.value);!1!==a?(t.__color.__state=a,t.setValue(t.__color.toOriginal())):this.value=t.__color.toString()}function k(){a.unbind(window,"mousemove",w);a.unbind(window,"mouseup",k)}function v(b){b.preventDefault();var c=a.getWidth(t.__saturation_field),d=a.getOffset(t.__saturation_field),e=(b.clientX-d.left+document.body.scrollLeft)/c;b=1-(b.clientY-d.top+document.body.scrollTop)/c;1 -b&&(b=0);1e&&(e=0);t.__color.v=b;t.__color.s=e;t.setValue(t.__color.toOriginal());return!1}function w(b){b.preventDefault();var c=a.getHeight(t.__hue_field),d=a.getOffset(t.__hue_field);b=1-(b.clientY-d.top+document.body.scrollTop)/c;1b&&(b=0);t.__color.h=360*b;t.setValue(t.__color.toOriginal());return!1}q.superclass.call(this,f,n);this.__color=new d(this.getValue());this.__temp=new d(0);var t=this;this.domElement=document.createElement("div");a.makeSelectable(this.domElement,!1); -this.__selector=document.createElement("div");this.__selector.className="selector";this.__saturation_field=document.createElement("div");this.__saturation_field.className="saturation-field";this.__field_knob=document.createElement("div");this.__field_knob.className="field-knob";this.__field_knob_border="2px solid ";this.__hue_knob=document.createElement("div");this.__hue_knob.className="hue-knob";this.__hue_field=document.createElement("div");this.__hue_field.className="hue-field";this.__input=document.createElement("input"); -this.__input.type="text";this.__input_textShadow="0 1px 1px ";a.bind(this.__input,"keydown",function(a){13===a.keyCode&&g.call(this)});a.bind(this.__input,"blur",g);a.bind(this.__selector,"mousedown",function(b){a.addClass(this,"drag").bind(window,"mouseup",function(b){a.removeClass(t.__selector,"drag")})});var y=document.createElement("div");c.extend(this.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"});c.extend(this.__field_knob.style, -{position:"absolute",width:"12px",height:"12px",border:this.__field_knob_border+(.5>this.__color.v?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1});c.extend(this.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1});c.extend(this.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"});c.extend(y.style,{width:"100%",height:"100%", -background:"none"});b(y,"top","rgba(0,0,0,0)","#000");c.extend(this.__hue_field.style,{width:"15px",height:"100px",display:"inline-block",border:"1px solid #555",cursor:"ns-resize"});p(this.__hue_field);c.extend(this.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:this.__input_textShadow+"rgba(0,0,0,0.7)"});a.bind(this.__saturation_field,"mousedown",u);a.bind(this.__field_knob,"mousedown",u);a.bind(this.__hue_field,"mousedown",function(b){w(b);a.bind(window, -"mousemove",w);a.bind(window,"mouseup",k)});this.__saturation_field.appendChild(y);this.__selector.appendChild(this.__field_knob);this.__selector.appendChild(this.__saturation_field);this.__selector.appendChild(this.__hue_field);this.__hue_field.appendChild(this.__hue_knob);this.domElement.appendChild(this.__input);this.domElement.appendChild(this.__selector);this.updateDisplay()};q.superclass=f;c.extend(q.prototype,f.prototype,{updateDisplay:function(){var a=e(this.getValue());if(!1!==a){var f=!1; -c.each(d.COMPONENTS,function(b){if(!c.isUndefined(a[b])&&!c.isUndefined(this.__color.__state[b])&&a[b]!==this.__color.__state[b])return f=!0,{}},this);f&&c.extend(this.__color.__state,a)}c.extend(this.__temp.__state,this.__color.__state);this.__temp.a=1;var l=.5>this.__color.v||.5a&&(a+=1);return{h:360*a,s:c/b,v:b/255}},rgb_to_hex:function(a,d,e){a=this.hex_with_component(0,2,a);a=this.hex_with_component(a,1,d);return a=this.hex_with_component(a,0,e)},component_from_hex:function(a,d){return a>>8*d&255},hex_with_component:function(a,d,e){return e<<(f=8*d)|a&~(255< 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 = $('
    ', { + 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; + } +}; diff --git a/scripts/system/particle_explorer/particle-style.css b/scripts/system/particle_explorer/particle-style.css new file mode 100644 index 0000000000..e8b71fdba0 --- /dev/null +++ b/scripts/system/particle_explorer/particle-style.css @@ -0,0 +1,124 @@ +/* +// particle-style.css +// +// Created by Matti 'Menithal' Lahtinen on 21 May 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 +*/ + + +.property-group { + max-height: 0; + -webkit-transition: max-height 0.15s ease-out; + transition: max-height 0.15s ease-out; + overflow: hidden; +} +.property-group.visible { + transition: max-height 0.25s ease-in; +} +.section-wrap { + width: 100%; +} +.property { + padding: 0.4rem 0; + margin: 0; +} +.property.checkbox { + margin: 0; +} +.property.range label{ + display: block; +} + +input[type="button"] { + margin: 0.4rem; + min-width: 6rem; +} +input[type="text"] { + margin: 0; +} +.property.range input[type=number]{ + margin-left: 0.8rem; + width: 5.4rem; + height: 1.8rem; +} +input[type=range] { + -webkit-appearance: none; + background: #2e2e2e; + height: 1.8rem; + border-radius: 1rem; +} +input[type=range]::-webkit-slider-thumb { + -webkit-appearance:none; + width: 0.6rem; + height: 1.8rem; + padding:0; + margin: 0; + background-color: #696969; + border-radius: 1rem; +} +input[type=range]::-webkit-slider-thumb:hover { + background-color: white; +} +input[type=range]:focus { /*#252525*/ + outline: none; +} +.tuple label { + text-transform: capitalize; +} +.slider-wrapper { + display: table; + padding: 0.4rem 0; +} +hr.splitter{ + width: 100%; + padding: 0.2rem 0 0 0; + margin: 0; + position: relative; + clear: both; +} +hr.splitter:last-of-type{ + padding:0; +} +#rem { + height: 1rem; + width: 1rem; +} +.property { + min-height: 2rem; +} +.property.vector-section{ + + width: 24rem; +} + +.property.texture { + display: block; +} +.property.texture input{ + margin: 0.4rem 0; +} +.texture-image img{ + padding: 0; + margin: 0; + width: 100%; + height: 100%; + display: none; +} +.texture-image { + display: block; + position: relative; + background-repeat: no-repeat; + background-position: center; + background-size: 100% 100%; + margin-top: 0.4rem; + height:128px; + width: 128px; + background-image: url('data:image/png;base64,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'); +} + +.texture-image.no-texture{ + background-image: url('data:image/png;base64,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'); +} diff --git a/scripts/system/particle_explorer/particleExplorer.html b/scripts/system/particle_explorer/particleExplorer.html index d0d86d79da..0f014e9fa8 100644 --- a/scripts/system/particle_explorer/particleExplorer.html +++ b/scripts/system/particle_explorer/particleExplorer.html @@ -1,95 +1,42 @@ +// + --> - - - - - - - - - - + + + - -
    - -
    -
    -
    -
    -
    - + +
    +
    + +
    + +
    +
    + diff --git a/scripts/system/particle_explorer/particleExplorer.js b/scripts/system/particle_explorer/particleExplorer.js index 5f66fe7ae6..ca6a873b73 100644 --- a/scripts/system/particle_explorer/particleExplorer.js +++ b/scripts/system/particle_explorer/particleExplorer.js @@ -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 = $('
    ', { - id: key.toString(), - class: "color-box" - }); - $colPickContainer.css('background-color', "rgb(" + colorObject.red + "," + colorObject.green + "," + colorObject.blue + ")"); - container.appendChild($colPickContainer[0]); - - var $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); - }); - }); - }); -} +})(); diff --git a/scripts/system/particle_explorer/particleExplorerTool.js b/scripts/system/particle_explorer/particleExplorerTool.js index b3db475ab0..d85fc169b1 100644 --- a/scripts/system/particle_explorer/particleExplorerTool.js +++ b/scripts/system/particle_explorer/particleExplorerTool.js @@ -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); } }