From 340096d45735da353de600f082ba8cd906eb08cb Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Sun, 1 Nov 2015 15:16:00 -0800 Subject: [PATCH 001/209] Initial version of AnimExpression class with minimal tokenizer --- libraries/animation/src/AnimExpression.cpp | 228 +++++++++++++++++++++ libraries/animation/src/AnimExpression.h | 78 +++++++ tests/animation/src/AnimTests.cpp | 53 ++++- tests/animation/src/AnimTests.h | 1 + 4 files changed, 354 insertions(+), 6 deletions(-) create mode 100644 libraries/animation/src/AnimExpression.cpp create mode 100644 libraries/animation/src/AnimExpression.h diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp new file mode 100644 index 0000000000..f2ec0426be --- /dev/null +++ b/libraries/animation/src/AnimExpression.cpp @@ -0,0 +1,228 @@ +// +// AnimExpression.cpp +// +// Created by Anthony J. Thibault on 11/1/15. +// Copyright (c) 2015 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include + +#include "AnimExpression.h" +#include "AnimationLogging.h" + + +#ifndef NDEBUG +void AnimExpression::Token::dump() { + switch (type) { + case End: + qCDebug(animation) << " End"; + break; + case Identifier: + qCDebug(animation) << " Identifer =" << strVal; + break; + case LiteralInt: + qCDebug(animation) << " LiteralInt =" << intVal; + break; + case LiteralFloat: + qCDebug(animation) << " LiteralFloat" << floatVal; + break; + case LiteralVec3: + qCDebug(animation) << " LiteralVec3" << vec3Val; + break; + case LiteralVec4: + qCDebug(animation) << " LiteralVec4" << vec4Val; + break; + case LiteralQuat: + qCDebug(animation) << " LiteralQuat" << quatVal; + break; + case And: + qCDebug(animation) << " And"; + break; + case Or: + qCDebug(animation) << " Or"; + break; + case GreaterThan: + qCDebug(animation) << " GreaterThan"; + break; + case GreaterThanEqual: + qCDebug(animation) << " GreaterThanEqual"; + break; + case LessThan: + qCDebug(animation) << " LessThan"; + break; + case LessThanEqual: + qCDebug(animation) << " LessThanEqual"; + break; + case Equal: + qCDebug(animation) << " Equal"; + break; + case NotEqual: + qCDebug(animation) << " NotEqual"; + break; + case LeftParen: + qCDebug(animation) << " LeftParen"; + break; + case RightParen: + qCDebug(animation) << " RightParen"; + break; + case Not: + qCDebug(animation) << " Not"; + break; + case Minus: + qCDebug(animation) << " Minus"; + break; + case Plus: + qCDebug(animation) << " Plus"; + break; + case Multiply: + qCDebug(animation) << " Multiply"; + break; + case Modulus: + qCDebug(animation) << " Modulus"; + break; + case Error: + qCDebug(animation) << " Error"; + break; + } +} +#endif + +AnimExpression::AnimExpression(const QString& str) : + _expression(str) { + parseExpression(_expression); +} + +bool AnimExpression::parseExpression(const QString& str) { + Token token(Token::End); + auto iter = str.begin(); + do { + token = consumeToken(str, iter); + switch(token.type) { + case Token::Error: + case Token::End: + return false; + } + } while(iter != str.end()); +} + +AnimExpression::Token AnimExpression::consumeToken(const QString& str, QString::const_iterator& iter) const { + while (iter != str.end()) { + if (iter->isSpace()) { + ++iter; + } else if (iter->isLetter()) { + return consumeIdentifier(str, iter); + } else if (iter->isDigit()) { + return consumeNumber(str, iter); + } else { + switch (iter->unicode()) { + case '&': return consumeAnd(str, iter); + case '|': return consumeOr(str, iter); + case '>': return consumeGreaterThan(str, iter); + case '<': return consumeLessThan(str, iter); + case '(': ++iter; return Token(Token::LeftParen); + case ')': ++iter; return Token(Token::RightParen); + case '!': return consumeNot(str, iter); + case '-': ++iter; return Token(Token::Minus); + case '+': ++iter; return Token(Token::Plus); + case '*': ++iter; return Token(Token::Multiply); + case '%': ++iter; return Token(Token::Modulus); + default: + qCCritical(animation) << "AnimExpression: unexpected char" << *iter << "at index " << (int)(iter - str.begin()); + return Token(Token::Error); + } + } + } + return Token(Token::End); +} + +AnimExpression::Token AnimExpression::consumeIdentifier(const QString& str, QString::const_iterator& iter) const { + assert(iter != str.end()); + assert(iter->isLetter()); + auto begin = iter; + while (iter->isLetter() && iter != str.end()) { + ++iter; + } + int pos = (int)(begin - str.begin()); + int len = (int)(iter - begin); + return Token(QStringRef(const_cast(&str), pos, len)); +} + +AnimExpression::Token AnimExpression::consumeNumber(const QString& str, QString::const_iterator& iter) const { + assert(iter != str.end()); + assert(iter->isDigit()); + auto begin = iter; + while (iter->isDigit() && iter != str.end()) { + ++iter; + } + int pos = (int)(begin - str.begin()); + int len = (int)(iter - begin); + QString sub = QStringRef(const_cast(&str), pos, len).toString(); + return Token(sub.toInt()); +} + +AnimExpression::Token AnimExpression::consumeAnd(const QString& str, QString::const_iterator& iter) const { + assert(iter != str.end()); + assert(iter->unicode() == '&'); + iter++; + if (iter->unicode() == '&') { + iter++; + return Token(Token::And); + } else { + qCCritical(animation) << "AnimExpression: unexpected char" << *iter << "at index " << (int)(iter - str.begin()); + return Token(Token::Error); + } +} + +AnimExpression::Token AnimExpression::consumeOr(const QString& str, QString::const_iterator& iter) const { + assert(iter != str.end()); + assert(iter->unicode() == '|'); + iter++; + if (iter->unicode() == '|') { + iter++; + return Token(Token::Or); + } else { + qCCritical(animation) << "AnimExpression: unexpected char" << *iter << "at index " << (int)(iter - str.begin()); + return Token(Token::Error); + } +} + +AnimExpression::Token AnimExpression::consumeGreaterThan(const QString& str, QString::const_iterator& iter) const { + assert(iter != str.end()); + assert(iter->unicode() == '>'); + iter++; + if (iter->unicode() == '=') { + iter++; + return Token(Token::GreaterThanEqual); + } else { + return Token(Token::GreaterThan); + } +} + +AnimExpression::Token AnimExpression::consumeLessThan(const QString& str, QString::const_iterator& iter) const { + assert(iter != str.end()); + assert(iter->unicode() == '<'); + iter++; + if (iter->unicode() == '=') { + iter++; + return Token(Token::LessThanEqual); + } else { + return Token(Token::LessThan); + } +} + +AnimExpression::Token AnimExpression::consumeNot(const QString& str, QString::const_iterator& iter) const { + assert(iter != str.end()); + assert(iter->unicode() == '!'); + iter++; + if (iter->unicode() == '=') { + iter++; + return Token(Token::NotEqual); + } else { + return Token(Token::Not); + } +} + diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h new file mode 100644 index 0000000000..a69b13c286 --- /dev/null +++ b/libraries/animation/src/AnimExpression.h @@ -0,0 +1,78 @@ +// +// AnimExpression.h +// +// Created by Anthony J. Thibault on 11/1/15. +// Copyright (c) 2015 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AnimExpression +#define hifi_AnimExpression + +#include +#include +#include +#include + +class AnimExpression { +public: + friend class AnimTests; + AnimExpression(const QString& str); +protected: + struct Token { + enum Type { + End = 0, + Identifier, + LiteralInt, + LiteralFloat, + LiteralVec3, + LiteralVec4, + LiteralQuat, + And, + Or, + GreaterThan, + GreaterThanEqual, + LessThan, + LessThanEqual, + Equal, + NotEqual, + LeftParen, + RightParen, + Not, + Minus, + Plus, + Multiply, + Modulus, + Error + }; + Token(Type type) : type(type) {} + Token(const QStringRef& strRef) : type(Type::Identifier), strVal(strRef.toString()) {} + Token(int val) : type(Type::LiteralInt), intVal(val) {} + Type type = End; + QString strVal; + int intVal; + float floatVal; + glm::vec3 vec3Val; + glm::vec4 vec4Val; + glm::quat quatVal; +#ifndef NDEBUG + void dump(); +#endif + }; + bool parseExpression(const QString& str); + Token consumeToken(const QString& str, QString::const_iterator& iter) const; + Token consumeIdentifier(const QString& str, QString::const_iterator& iter) const; + Token consumeNumber(const QString& str, QString::const_iterator& iter) const; + Token consumeAnd(const QString& str, QString::const_iterator& iter) const; + Token consumeOr(const QString& str, QString::const_iterator& iter) const; + Token consumeGreaterThan(const QString& str, QString::const_iterator& iter) const; + Token consumeLessThan(const QString& str, QString::const_iterator& iter) const; + Token consumeNot(const QString& str, QString::const_iterator& iter) const; + + QString _expression; +}; + +#endif + diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 1b5bb4739a..08f13b7ec7 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -8,12 +8,13 @@ // #include "AnimTests.h" -#include "AnimNodeLoader.h" -#include "AnimClip.h" -#include "AnimBlendLinear.h" -#include "AnimationLogging.h" -#include "AnimVariant.h" -#include "AnimUtil.h" +#include +#include +#include +#include +#include +#include +#include #include <../QTestExtensions.h> @@ -322,4 +323,44 @@ void AnimTests::testAccumulateTimeWithParameters(float startFrame, float endFram QVERIFY(resultFrame == startFrame + 0.5f); QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnLoop"); triggers.clear(); + +void AnimTests::testTokenizer() { + QString str = "(10 + x) >= 20 && (y != !z)"; + AnimExpression e(""); + auto iter = str.cbegin(); + AnimExpression::Token token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::LeftParen); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::LiteralInt); + QVERIFY(token.intVal == 10); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::Plus); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::Identifier); + QVERIFY(token.strVal == "x"); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::RightParen); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::GreaterThanEqual); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::LiteralInt); + QVERIFY(token.intVal == 20); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::And); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::LeftParen); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::Identifier); + QVERIFY(token.strVal == "y"); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::NotEqual); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::Not); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::Identifier); + QVERIFY(token.strVal == "z"); + token = e.consumeToken(str, iter); + QVERIFY(token.type == AnimExpression::Token::RightParen); + token = e.consumeToken(str, iter); } + diff --git a/tests/animation/src/AnimTests.h b/tests/animation/src/AnimTests.h index 7bd05369c7..bfea4eb086 100644 --- a/tests/animation/src/AnimTests.h +++ b/tests/animation/src/AnimTests.h @@ -26,6 +26,7 @@ private slots: void testLoader(); void testVariant(); void testAccumulateTime(); + void testTokenizer(); }; #endif // hifi_AnimTests_h From 7f0fc4f6eb5bc9a4f28f55c6641c516e32cddd81 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Sun, 1 Nov 2015 15:51:57 -0800 Subject: [PATCH 002/209] Added limited floating point support --- libraries/animation/src/AnimExpression.cpp | 38 +++++++++++++++++++++- libraries/animation/src/AnimExpression.h | 1 + tests/animation/src/AnimTests.cpp | 6 ++-- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index f2ec0426be..14b3e9da87 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -151,6 +151,21 @@ AnimExpression::Token AnimExpression::consumeIdentifier(const QString& str, QStr return Token(QStringRef(const_cast(&str), pos, len)); } +// TODO: not very efficient or accruate, but it's close enough for now. +static float computeFractionalPart(int fractionalPart) +{ + float frac = (float)fractionalPart; + while (fractionalPart) { + fractionalPart /= 10; + frac /= 10.0f; + } + return frac; +} + +static float computeFloat(int whole, int fraction) { + return (float)whole + computeFractionalPart(fraction); +} + AnimExpression::Token AnimExpression::consumeNumber(const QString& str, QString::const_iterator& iter) const { assert(iter != str.end()); assert(iter->isDigit()); @@ -158,10 +173,31 @@ AnimExpression::Token AnimExpression::consumeNumber(const QString& str, QString: while (iter->isDigit() && iter != str.end()) { ++iter; } + + // parse whole integer part int pos = (int)(begin - str.begin()); int len = (int)(iter - begin); QString sub = QStringRef(const_cast(&str), pos, len).toString(); - return Token(sub.toInt()); + int whole = sub.toInt(); + + // parse optional fractional part + if (iter->unicode() == '.') { + iter++; + auto begin = iter; + while (iter->isDigit() && iter != str.end()) { + ++iter; + } + + int pos = (int)(begin - str.begin()); + int len = (int)(iter - begin); + QString sub = QStringRef(const_cast(&str), pos, len).toString(); + int fraction = sub.toInt(); + + return Token(computeFloat(whole, fraction)); + + } else { + return Token(whole); + } } AnimExpression::Token AnimExpression::consumeAnd(const QString& str, QString::const_iterator& iter) const { diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index a69b13c286..25e1803721 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -50,6 +50,7 @@ protected: Token(Type type) : type(type) {} Token(const QStringRef& strRef) : type(Type::Identifier), strVal(strRef.toString()) {} Token(int val) : type(Type::LiteralInt), intVal(val) {} + Token(float val) : type(Type::LiteralFloat), floatVal(val) {} Type type = End; QString strVal; int intVal; diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 08f13b7ec7..5b6806ec09 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -325,7 +325,7 @@ void AnimTests::testAccumulateTimeWithParameters(float startFrame, float endFram triggers.clear(); void AnimTests::testTokenizer() { - QString str = "(10 + x) >= 20 && (y != !z)"; + QString str = "(10 + x) >= 20.1 && (y != !z)"; AnimExpression e(""); auto iter = str.cbegin(); AnimExpression::Token token = e.consumeToken(str, iter); @@ -343,8 +343,8 @@ void AnimTests::testTokenizer() { token = e.consumeToken(str, iter); QVERIFY(token.type == AnimExpression::Token::GreaterThanEqual); token = e.consumeToken(str, iter); - QVERIFY(token.type == AnimExpression::Token::LiteralInt); - QVERIFY(token.intVal == 20); + QVERIFY(token.type == AnimExpression::Token::LiteralFloat); + QVERIFY(fabsf(token.floatVal - 20.1f) < 0.0001f); token = e.consumeToken(str, iter); QVERIFY(token.type == AnimExpression::Token::And); token = e.consumeToken(str, iter); From 4394083138744a47fd8f2a14c46e1fd008b38772 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Sun, 1 Nov 2015 15:57:20 -0800 Subject: [PATCH 003/209] Added comma token --- libraries/animation/src/AnimExpression.cpp | 79 +--------------------- libraries/animation/src/AnimExpression.h | 4 +- 2 files changed, 2 insertions(+), 81 deletions(-) diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index 14b3e9da87..fe056be81d 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -14,83 +14,6 @@ #include "AnimExpression.h" #include "AnimationLogging.h" - -#ifndef NDEBUG -void AnimExpression::Token::dump() { - switch (type) { - case End: - qCDebug(animation) << " End"; - break; - case Identifier: - qCDebug(animation) << " Identifer =" << strVal; - break; - case LiteralInt: - qCDebug(animation) << " LiteralInt =" << intVal; - break; - case LiteralFloat: - qCDebug(animation) << " LiteralFloat" << floatVal; - break; - case LiteralVec3: - qCDebug(animation) << " LiteralVec3" << vec3Val; - break; - case LiteralVec4: - qCDebug(animation) << " LiteralVec4" << vec4Val; - break; - case LiteralQuat: - qCDebug(animation) << " LiteralQuat" << quatVal; - break; - case And: - qCDebug(animation) << " And"; - break; - case Or: - qCDebug(animation) << " Or"; - break; - case GreaterThan: - qCDebug(animation) << " GreaterThan"; - break; - case GreaterThanEqual: - qCDebug(animation) << " GreaterThanEqual"; - break; - case LessThan: - qCDebug(animation) << " LessThan"; - break; - case LessThanEqual: - qCDebug(animation) << " LessThanEqual"; - break; - case Equal: - qCDebug(animation) << " Equal"; - break; - case NotEqual: - qCDebug(animation) << " NotEqual"; - break; - case LeftParen: - qCDebug(animation) << " LeftParen"; - break; - case RightParen: - qCDebug(animation) << " RightParen"; - break; - case Not: - qCDebug(animation) << " Not"; - break; - case Minus: - qCDebug(animation) << " Minus"; - break; - case Plus: - qCDebug(animation) << " Plus"; - break; - case Multiply: - qCDebug(animation) << " Multiply"; - break; - case Modulus: - qCDebug(animation) << " Modulus"; - break; - case Error: - qCDebug(animation) << " Error"; - break; - } -} -#endif - AnimExpression::AnimExpression(const QString& str) : _expression(str) { parseExpression(_expression); @@ -130,6 +53,7 @@ AnimExpression::Token AnimExpression::consumeToken(const QString& str, QString:: case '+': ++iter; return Token(Token::Plus); case '*': ++iter; return Token(Token::Multiply); case '%': ++iter; return Token(Token::Modulus); + case ',': ++iter; return Token(Token::Comma); default: qCCritical(animation) << "AnimExpression: unexpected char" << *iter << "at index " << (int)(iter - str.begin()); return Token(Token::Error); @@ -261,4 +185,3 @@ AnimExpression::Token AnimExpression::consumeNot(const QString& str, QString::co return Token(Token::Not); } } - diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 25e1803721..7e6c42f08a 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -45,6 +45,7 @@ protected: Plus, Multiply, Modulus, + Comma, Error }; Token(Type type) : type(type) {} @@ -58,9 +59,6 @@ protected: glm::vec3 vec3Val; glm::vec4 vec4Val; glm::quat quatVal; -#ifndef NDEBUG - void dump(); -#endif }; bool parseExpression(const QString& str); Token consumeToken(const QString& str, QString::const_iterator& iter) const; From 32c40d37c02694326abfd784010fc4c328764251 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Sun, 1 Nov 2015 16:01:29 -0800 Subject: [PATCH 004/209] Removed vec literals tokens and renamed int and float token types --- libraries/animation/src/AnimExpression.h | 11 ++++------- tests/animation/src/AnimTests.cpp | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 7e6c42f08a..7ba099ce2e 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -25,11 +25,8 @@ protected: enum Type { End = 0, Identifier, - LiteralInt, - LiteralFloat, - LiteralVec3, - LiteralVec4, - LiteralQuat, + Int, + Float, And, Or, GreaterThan, @@ -50,8 +47,8 @@ protected: }; Token(Type type) : type(type) {} Token(const QStringRef& strRef) : type(Type::Identifier), strVal(strRef.toString()) {} - Token(int val) : type(Type::LiteralInt), intVal(val) {} - Token(float val) : type(Type::LiteralFloat), floatVal(val) {} + Token(int val) : type(Type::Int), intVal(val) {} + Token(float val) : type(Type::Float), floatVal(val) {} Type type = End; QString strVal; int intVal; diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 5b6806ec09..44f9c05c22 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -331,7 +331,7 @@ void AnimTests::testTokenizer() { AnimExpression::Token token = e.consumeToken(str, iter); QVERIFY(token.type == AnimExpression::Token::LeftParen); token = e.consumeToken(str, iter); - QVERIFY(token.type == AnimExpression::Token::LiteralInt); + QVERIFY(token.type == AnimExpression::Token::Int); QVERIFY(token.intVal == 10); token = e.consumeToken(str, iter); QVERIFY(token.type == AnimExpression::Token::Plus); @@ -343,7 +343,7 @@ void AnimTests::testTokenizer() { token = e.consumeToken(str, iter); QVERIFY(token.type == AnimExpression::Token::GreaterThanEqual); token = e.consumeToken(str, iter); - QVERIFY(token.type == AnimExpression::Token::LiteralFloat); + QVERIFY(token.type == AnimExpression::Token::Float); QVERIFY(fabsf(token.floatVal - 20.1f) < 0.0001f); token = e.consumeToken(str, iter); QVERIFY(token.type == AnimExpression::Token::And); From a80ab0003c424e3c85ef36424a58e14f08f9b4c1 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 2 Nov 2015 20:46:29 -0800 Subject: [PATCH 005/209] Removed vec literal values --- libraries/animation/src/AnimExpression.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 7ba099ce2e..145350547b 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -12,7 +12,6 @@ #define hifi_AnimExpression #include -#include #include #include @@ -53,11 +52,7 @@ protected: QString strVal; int intVal; float floatVal; - glm::vec3 vec3Val; - glm::vec4 vec4Val; - glm::quat quatVal; }; - bool parseExpression(const QString& str); Token consumeToken(const QString& str, QString::const_iterator& iter) const; Token consumeIdentifier(const QString& str, QString::const_iterator& iter) const; Token consumeNumber(const QString& str, QString::const_iterator& iter) const; @@ -67,6 +62,8 @@ protected: Token consumeLessThan(const QString& str, QString::const_iterator& iter) const; Token consumeNot(const QString& str, QString::const_iterator& iter) const; + bool parseExpression(const QString& str); + QString _expression; }; From 61d1dd00d1d1d949887f230a84ea1d31518ad334 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 4 Nov 2015 12:04:34 -0800 Subject: [PATCH 006/209] Fixes for Mac build and crash on startup For some reason the qt code gen is getting confused by the #if 0 in 3DConnextionClient.h, so I added a stub implementation. In Application.cpp the change of moving idle into paintGL had a sideeffect of calling OffscreenGlCanvas before it was initialized. To work around this I added a guard to prevent calling idle before all the gl windows/widgets have been initialized. (cherry picked from commit 69f1cfbcb9125aa9d449a5d01b3734bcd51309e8) --- interface/src/Application.cpp | 12 ++++++------ interface/src/Application.h | 3 ++- interface/src/devices/3DConnexionClient.h | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d31d9de4a0..556664ec10 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -940,14 +940,12 @@ void Application::initializeGL() { qCDebug(interfaceapp) << "Created Display Window."; // initialize glut for shape drawing; Qt apparently initializes it on OS X - #ifndef __APPLE__ - static bool isInitialized = false; - if (isInitialized) { + if (_isGLInitialized) { return; } else { - isInitialized = true; + _isGLInitialized = true; } - #endif + // Where the gpuContext is initialized and where the TRUE Backend is created and assigned gpu::Context::init(); _gpuContext = std::make_shared(); @@ -1059,7 +1057,9 @@ void Application::paintGL() { _lastFramesPerSecondUpdate = now; } - idle(now); + if (_isGLInitialized) { + idle(now); + } PROFILE_RANGE(__FUNCTION__); PerformanceTimer perfTimer("paintGL"); diff --git a/interface/src/Application.h b/interface/src/Application.h index 212687c11e..5a5d5a015c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -414,7 +414,7 @@ private: bool _dependencyManagerIsSetup; - OffscreenGlCanvas* _offscreenContext; + OffscreenGlCanvas* _offscreenContext {nullptr}; DisplayPluginPointer _displayPlugin; InputPluginList _activeInputPlugins; @@ -548,6 +548,7 @@ private: quint64 _lastSimsPerSecondUpdate = 0; bool _isForeground = true; // starts out assumed to be in foreground bool _inPaint = false; + bool _isGLInitialized {false}; }; #endif // hifi_Application_h diff --git a/interface/src/devices/3DConnexionClient.h b/interface/src/devices/3DConnexionClient.h index 03a43d4c64..b6fa6a37c3 100755 --- a/interface/src/devices/3DConnexionClient.h +++ b/interface/src/devices/3DConnexionClient.h @@ -220,4 +220,19 @@ public: #endif +#include +#include + +// stub +class ConnexionClient : public QObject { + Q_OBJECT +public: + static ConnexionClient& getInstance(); + void init() {}; + void destroy() {}; + bool Is3dmouseAttached() { return false; }; +public slots: + void toggleConnexion(bool shouldEnable) {}; +}; + #endif // defined(hifi_3DConnexionClient_h) From 04d8a598da5d8f2ee684619cfb7492349853fdcc Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 4 Nov 2015 16:56:34 -0800 Subject: [PATCH 007/209] First step toward evaluation * added OpCodes * added first parser rules * removed mat4 support from AnimVariantMap --- libraries/animation/src/AnimExpression.cpp | 164 ++++++++++++++++----- libraries/animation/src/AnimExpression.h | 75 +++++++++- libraries/animation/src/AnimVariant.h | 74 ++++++---- libraries/shared/src/GLMHelpers.h | 1 + tests/animation/src/AnimTests.cpp | 34 +++-- tests/animation/src/AnimTests.h | 3 +- 6 files changed, 265 insertions(+), 86 deletions(-) diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index fe056be81d..8807262028 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -16,58 +16,56 @@ AnimExpression::AnimExpression(const QString& str) : _expression(str) { - parseExpression(_expression); + auto iter = str.begin(); + parseExpression(_expression, iter); } -bool AnimExpression::parseExpression(const QString& str) { - Token token(Token::End); - auto iter = str.begin(); - do { - token = consumeToken(str, iter); - switch(token.type) { - case Token::Error: - case Token::End: - return false; - } - } while(iter != str.end()); +void AnimExpression::unconsumeToken(const Token& token) { + _tokenStack.push(token); } AnimExpression::Token AnimExpression::consumeToken(const QString& str, QString::const_iterator& iter) const { - while (iter != str.end()) { - if (iter->isSpace()) { - ++iter; - } else if (iter->isLetter()) { - return consumeIdentifier(str, iter); - } else if (iter->isDigit()) { - return consumeNumber(str, iter); - } else { - switch (iter->unicode()) { - case '&': return consumeAnd(str, iter); - case '|': return consumeOr(str, iter); - case '>': return consumeGreaterThan(str, iter); - case '<': return consumeLessThan(str, iter); - case '(': ++iter; return Token(Token::LeftParen); - case ')': ++iter; return Token(Token::RightParen); - case '!': return consumeNot(str, iter); - case '-': ++iter; return Token(Token::Minus); - case '+': ++iter; return Token(Token::Plus); - case '*': ++iter; return Token(Token::Multiply); - case '%': ++iter; return Token(Token::Modulus); - case ',': ++iter; return Token(Token::Comma); - default: - qCCritical(animation) << "AnimExpression: unexpected char" << *iter << "at index " << (int)(iter - str.begin()); - return Token(Token::Error); + if (!_tokenStack.empty()) { + Token top = _tokenStack.top(); + _tokenStack.pop(); + return top; + } else { + while (iter != str.end()) { + if (iter->isSpace()) { + ++iter; + } else if (iter->isLetter()) { + return consumeIdentifier(str, iter); + } else if (iter->isDigit()) { + return consumeNumber(str, iter); + } else { + switch (iter->unicode()) { + case '&': return consumeAnd(str, iter); + case '|': return consumeOr(str, iter); + case '>': return consumeGreaterThan(str, iter); + case '<': return consumeLessThan(str, iter); + case '(': ++iter; return Token(Token::LeftParen); + case ')': ++iter; return Token(Token::RightParen); + case '!': return consumeNot(str, iter); + case '-': ++iter; return Token(Token::Minus); + case '+': ++iter; return Token(Token::Plus); + case '*': ++iter; return Token(Token::Multiply); + case '%': ++iter; return Token(Token::Modulus); + case ',': ++iter; return Token(Token::Comma); + default: + qCCritical(animation) << "AnimExpression: unexpected char" << *iter << "at index " << (int)(iter - str.begin()); + return Token(Token::Error); + } } } + return Token(Token::End); } - return Token(Token::End); } AnimExpression::Token AnimExpression::consumeIdentifier(const QString& str, QString::const_iterator& iter) const { assert(iter != str.end()); assert(iter->isLetter()); auto begin = iter; - while (iter->isLetter() && iter != str.end()) { + while ((iter->isLetter() || iter->isDigit()) && iter != str.end()) { ++iter; } int pos = (int)(begin - str.begin()); @@ -185,3 +183,93 @@ AnimExpression::Token AnimExpression::consumeNot(const QString& str, QString::co return Token(Token::Not); } } + +bool AnimExpression::parseExpression(const QString& str, QString::const_iterator& iter) { + auto token = consumeToken(str, iter); + if (token.type == Token::Identifier) { + if (token.strVal == "true") { + _opCodes.push_back(OpCode {true}); + } else if (token.strVal == "false") { + _opCodes.push_back(OpCode {false}); + } else { + _opCodes.push_back(OpCode {token.strVal}); + } + return true; + } else if (token.type == Token::Int) { + _opCodes.push_back(OpCode {token.intVal}); + return true; + } else if (token.type == Token::Float) { + _opCodes.push_back(OpCode {token.floatVal}); + return true; + } else if (token.type == Token::LeftParen) { + if (parseUnaryExpression(str, iter)) { + token = consumeToken(str, iter); + if (token.type != Token::RightParen) { + qCCritical(animation) << "Error parsing expression, expected ')'"; + return false; + } else { + return true; + } + } else { + return false; + } + } else { + qCCritical(animation) << "Error parsing expression, unexpected symbol"; + return false; + } +} + +bool AnimExpression::parseUnaryExpression(const QString& str, QString::const_iterator& iter) { + auto token = consumeToken(str, iter); + if (token.type == Token::Plus) { + if (parseExpression(str, iter)) { + _opCodes.push_back(OpCode {OpCode::UnaryPlus}); + return true; + } else { + return false; + } + } else if (token.type == Token::Minus) { + if (parseExpression(str, iter)) { + _opCodes.push_back(OpCode {OpCode::UnaryMinus}); + return true; + } else { + return false; + } + } else if (token.type == Token::Not) { + if (parseExpression(str, iter)) { + _opCodes.push_back(OpCode {OpCode::Not}); + return true; + } else { + return false; + } + } else { + unconsumeToken(token); + return parseExpression(str, iter); + } +} + +AnimExpression::OpCode AnimExpression::evaluate(const AnimVariantMap& map) const { + std::stack stack; + for (auto& opCode : _opCodes) { + switch (opCode.type) { + case OpCode::Identifier: + case OpCode::Int: + case OpCode::Float: + stack.push(opCode); + break; + default: + switch (opCode.type) { + case OpCode::Not: + evalNot(map, stack); + break; + } + } + } + return stack.top(); +} + +void AnimExpression::evalNot(const AnimVariantMap& map, std::stack& stack) const { + bool lhs = stack.top().coerceBool(map); + stack.pop(); + stack.push(OpCode {!lhs}); +} diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 145350547b..8d216ca412 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include "AnimVariant.h" class AnimExpression { public: @@ -44,15 +47,64 @@ protected: Comma, Error }; - Token(Type type) : type(type) {} - Token(const QStringRef& strRef) : type(Type::Identifier), strVal(strRef.toString()) {} - Token(int val) : type(Type::Int), intVal(val) {} - Token(float val) : type(Type::Float), floatVal(val) {} - Type type = End; + Token(Type type) : type {type} {} + Token(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} + Token(int val) : type {Type::Int}, intVal {val} {} + Token(float val) : type {Type::Float}, floatVal {val} {} + Type type {End}; QString strVal; - int intVal; - float floatVal; + int intVal {0}; + float floatVal {0.0f}; }; + + struct OpCode { + enum Type { + Identifier, + Bool, + Int, + Float, + And, + Or, + GreaterThan, + GreaterThanEqual, + LessThan, + LessThanEqual, + Equal, + NotEqual, + LeftParen, + RightParen, + Not, + Minus, + Plus, + Multiply, + Modulus, + UnaryPlus, + UnaryMinus + }; + OpCode(Type type) : type {type} {} + OpCode(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} + OpCode(const QString& str) : type {Type::Identifier}, strVal {str} {} + OpCode(int val) : type {Type::Int}, intVal {val} {} + OpCode(bool val) : type {Type::Bool}, intVal {(int)val} {} + OpCode(float val) : type {Type::Float}, floatVal {val} {} + + bool coerceBool(const AnimVariantMap& map) const { + if (type == Int || type == Bool) { + return intVal != 0; + } else if (type == Identifier) { + return map.lookup(strVal, false); + } else { + return true; + } + } + + Type type {Int}; + QString strVal; + int intVal {0}; + float floatVal {0.0f}; + }; + + void unconsumeToken(const Token& token); Token consumeToken(const QString& str, QString::const_iterator& iter) const; Token consumeIdentifier(const QString& str, QString::const_iterator& iter) const; Token consumeNumber(const QString& str, QString::const_iterator& iter) const; @@ -62,9 +114,16 @@ protected: Token consumeLessThan(const QString& str, QString::const_iterator& iter) const; Token consumeNot(const QString& str, QString::const_iterator& iter) const; - bool parseExpression(const QString& str); + bool parseExpression(const QString& str, QString::const_iterator& iter); + bool parseUnaryExpression(const QString& str, QString::const_iterator& iter); + + OpCode evaluate(const AnimVariantMap& map) const; + void evalNot(const AnimVariantMap& map, std::stack& stack) const; QString _expression; + mutable std::stack _tokenStack; + std::vector _opCodes; + }; #endif diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index 0d7c657058..ff7794a16a 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -18,8 +18,9 @@ #include #include #include +#include +#include #include "AnimationLogging.h" -#include "StreamUtils.h" class AnimVariant { public: @@ -29,7 +30,6 @@ public: Float, Vec3, Quat, - Mat4, String, NumTypes }; @@ -40,7 +40,6 @@ public: AnimVariant(float value) : _type(Type::Float) { _val.floats[0] = value; } AnimVariant(const glm::vec3& value) : _type(Type::Vec3) { *reinterpret_cast(&_val) = value; } AnimVariant(const glm::quat& value) : _type(Type::Quat) { *reinterpret_cast(&_val) = value; } - AnimVariant(const glm::mat4& value) : _type(Type::Mat4) { *reinterpret_cast(&_val) = value; } AnimVariant(const QString& value) : _type(Type::String) { _stringVal = value; } bool isBool() const { return _type == Type::Bool; } @@ -48,7 +47,6 @@ public: bool isFloat() const { return _type == Type::Float; } bool isVec3() const { return _type == Type::Vec3; } bool isQuat() const { return _type == Type::Quat; } - bool isMat4() const { return _type == Type::Mat4; } bool isString() const { return _type == Type::String; } Type getType() const { return _type; } @@ -57,17 +55,52 @@ public: void setFloat(float value) { assert(_type == Type::Float); _val.floats[0] = value; } void setVec3(const glm::vec3& value) { assert(_type == Type::Vec3); *reinterpret_cast(&_val) = value; } void setQuat(const glm::quat& value) { assert(_type == Type::Quat); *reinterpret_cast(&_val) = value; } - void setMat4(const glm::mat4& value) { assert(_type == Type::Mat4); *reinterpret_cast(&_val) = value; } void setString(const QString& value) { assert(_type == Type::String); _stringVal = value; } - bool getBool() const { assert(_type == Type::Bool); return _val.boolVal; } - int getInt() const { assert(_type == Type::Int || _type == Type::Float); return _type == Type::Float ? (int)_val.floats[0] : _val.intVal; } - float getFloat() const { assert(_type == Type::Float || _type == Type::Int); return _type == Type::Int ? (float)_val.intVal : _val.floats[0]; } - - const glm::vec3& getVec3() const { assert(_type == Type::Vec3); return *reinterpret_cast(&_val); } - const glm::quat& getQuat() const { assert(_type == Type::Quat); return *reinterpret_cast(&_val); } - const glm::mat4& getMat4() const { assert(_type == Type::Mat4); return *reinterpret_cast(&_val); } - const QString& getString() const { assert(_type == Type::String); return _stringVal; } + bool getBool() const { + if (_type == Type::Bool) { + return _val.boolVal; + } else if (_type == Type::Int) { + return _val.intVal != 0; + } else { + return false; + } + } + int getInt() const { + if (_type == Type::Int) { + return _val.intVal; + } else if (_type == Type::Float) { + return (int)_val.floats[0]; + } else { + return 0; + } + } + float getFloat() const { + if (_type == Type::Float) { + return _val.floats[0]; + } else if (_type == Type::Int) { + return (float)_val.intVal; + } else { + return 0.0f; + } + } + const glm::vec3& getVec3() const { + if (_type == Type::Vec3) { + return *reinterpret_cast(&_val); + } else { + return Vectors::ZERO; + } + } + const glm::quat& getQuat() const { + if (_type == Type::Quat) { + return *reinterpret_cast(&_val); + } else { + return Quaternions::IDENTITY; + } + } + const QString& getString() const { + return _stringVal; + } protected: Type _type; @@ -75,7 +108,7 @@ protected: union { bool boolVal; int intVal; - float floats[16]; + float floats[4]; } _val; }; @@ -130,15 +163,6 @@ public: } } - const glm::mat4& lookup(const QString& key, const glm::mat4& defaultValue) const { - if (key.isEmpty()) { - return defaultValue; - } else { - auto iter = _map.find(key); - return iter != _map.end() ? iter->second.getMat4() : defaultValue; - } - } - const QString& lookup(const QString& key, const QString& defaultValue) const { if (key.isEmpty()) { return defaultValue; @@ -153,7 +177,6 @@ public: void set(const QString& key, float value) { _map[key] = AnimVariant(value); } void set(const QString& key, const glm::vec3& value) { _map[key] = AnimVariant(value); } void set(const QString& key, const glm::quat& value) { _map[key] = AnimVariant(value); } - void set(const QString& key, const glm::mat4& value) { _map[key] = AnimVariant(value); } void set(const QString& key, const QString& value) { _map[key] = AnimVariant(value); } void unset(const QString& key) { _map.erase(key); } @@ -189,9 +212,6 @@ public: case AnimVariant::Type::Quat: qCDebug(animation) << " " << pair.first << "=" << pair.second.getQuat(); break; - case AnimVariant::Type::Mat4: - qCDebug(animation) << " " << pair.first << "=" << pair.second.getMat4(); - break; case AnimVariant::Type::String: qCDebug(animation) << " " << pair.first << "=" << pair.second.getString(); break; diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 9c1bbe23a4..e69d11629e 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -80,6 +80,7 @@ public: static const vec3& RIGHT; static const vec3& UP; static const vec3& FRONT; + static const vec3 ZERO4; }; // These pack/unpack functions are designed to start specific known types in as efficient a manner diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 44f9c05c22..94caed66f5 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -195,10 +195,7 @@ void AnimTests::testVariant() { auto floatVarNegative = AnimVariant(-1.0f); auto vec3Var = AnimVariant(glm::vec3(1.0f, -2.0f, 3.0f)); auto quatVar = AnimVariant(glm::quat(1.0f, 2.0f, -3.0f, 4.0f)); - auto mat4Var = AnimVariant(glm::mat4(glm::vec4(1.0f, 2.0f, 3.0f, 4.0f), - glm::vec4(5.0f, 6.0f, -7.0f, 8.0f), - glm::vec4(9.0f, 10.0f, 11.0f, 12.0f), - glm::vec4(13.0f, 14.0f, 15.0f, 16.0f))); + QVERIFY(defaultVar.isBool()); QVERIFY(defaultVar.getBool() == false); @@ -233,12 +230,6 @@ void AnimTests::testVariant() { QVERIFY(q.x == 2.0f); QVERIFY(q.y == -3.0f); QVERIFY(q.z == 4.0f); - - QVERIFY(mat4Var.isMat4()); - auto m = mat4Var.getMat4(); - QVERIFY(m[0].x == 1.0f); - QVERIFY(m[1].z == -7.0f); - QVERIFY(m[3].w == 16.0f); } void AnimTests::testAccumulateTime() { @@ -323,10 +314,11 @@ void AnimTests::testAccumulateTimeWithParameters(float startFrame, float endFram QVERIFY(resultFrame == startFrame + 0.5f); QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnLoop"); triggers.clear(); +} -void AnimTests::testTokenizer() { +void AnimTests::testExpressionTokenizer() { QString str = "(10 + x) >= 20.1 && (y != !z)"; - AnimExpression e(""); + AnimExpression e("x"); auto iter = str.cbegin(); AnimExpression::Token token = e.consumeToken(str, iter); QVERIFY(token.type == AnimExpression::Token::LeftParen); @@ -364,3 +356,21 @@ void AnimTests::testTokenizer() { token = e.consumeToken(str, iter); } +void AnimTests::testExpressionParser() { + QString str = "(!x)"; + AnimExpression e(str); + QVERIFY(e._opCodes.size() == 2); + if (e._opCodes.size() == 2) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); + QVERIFY(e._opCodes[0].strVal == "x"); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Not); + } + + auto vars = AnimVariantMap(); + vars.set("x", false); + + auto opCode = e.evaluate(vars); + QVERIFY(opCode.type == AnimExpression::OpCode::Bool); + QVERIFY(opCode.coerceBool(vars) == true); +} + diff --git a/tests/animation/src/AnimTests.h b/tests/animation/src/AnimTests.h index bfea4eb086..94b3eddd25 100644 --- a/tests/animation/src/AnimTests.h +++ b/tests/animation/src/AnimTests.h @@ -26,7 +26,8 @@ private slots: void testLoader(); void testVariant(); void testAccumulateTime(); - void testTokenizer(); + void testExpressionTokenizer(); + void testExpressionParser(); }; #endif // hifi_AnimTests_h From 431a108c351431345d9aab4144ef55f80de84ed3 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 4 Nov 2015 20:13:17 -0800 Subject: [PATCH 008/209] Bugfixes to expression for !!x expressions Added stub eval methods. only boolean not, boolean and, boolean or and unary minus are implemented. --- libraries/animation/src/AnimExpression.cpp | 186 +++++++++++++++++++-- libraries/animation/src/AnimExpression.h | 25 ++- libraries/animation/src/AnimVariant.cpp | 2 + libraries/animation/src/AnimVariant.h | 11 ++ tests/animation/src/AnimTests.cpp | 87 +++++++++- 5 files changed, 280 insertions(+), 31 deletions(-) diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index 8807262028..a03925f8f9 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -214,23 +214,27 @@ bool AnimExpression::parseExpression(const QString& str, QString::const_iterator return false; } } else { - qCCritical(animation) << "Error parsing expression, unexpected symbol"; - return false; + unconsumeToken(token); + if (parseUnaryExpression(str, iter)) { + return true; + } else { + qCCritical(animation) << "Error parsing expression"; + return false; + } } } bool AnimExpression::parseUnaryExpression(const QString& str, QString::const_iterator& iter) { auto token = consumeToken(str, iter); - if (token.type == Token::Plus) { + if (token.type == Token::Plus) { // unary plus is a no op. if (parseExpression(str, iter)) { - _opCodes.push_back(OpCode {OpCode::UnaryPlus}); return true; } else { return false; } } else if (token.type == Token::Minus) { if (parseExpression(str, iter)) { - _opCodes.push_back(OpCode {OpCode::UnaryMinus}); + _opCodes.push_back(OpCode {OpCode::Minus}); return true; } else { return false; @@ -255,21 +259,173 @@ AnimExpression::OpCode AnimExpression::evaluate(const AnimVariantMap& map) const case OpCode::Identifier: case OpCode::Int: case OpCode::Float: + case OpCode::Bool: stack.push(opCode); break; - default: - switch (opCode.type) { - case OpCode::Not: - evalNot(map, stack); - break; - } + case OpCode::And: evalAnd(map, stack); break; + case OpCode::Or: evalOr(map, stack); break; + case OpCode::GreaterThan: evalGreaterThan(map, stack); break; + case OpCode::GreaterThanEqual: evalGreaterThanEqual(map, stack); break; + case OpCode::LessThan: evalLessThan(map, stack); break; + case OpCode::LessThanEqual: evalLessThanEqual(map, stack); break; + case OpCode::Equal: evalEqual(map, stack); break; + case OpCode::NotEqual: evalNotEqual(map, stack); break; + case OpCode::Not: evalNot(map, stack); break; + case OpCode::Subtract: evalSubtract(map, stack); break; + case OpCode::Add: evalAdd(map, stack); break; + case OpCode::Multiply: evalMultiply(map, stack); break; + case OpCode::Modulus: evalModulus(map, stack); break; + case OpCode::Minus: evalMinus(map, stack); break; } } return stack.top(); } -void AnimExpression::evalNot(const AnimVariantMap& map, std::stack& stack) const { - bool lhs = stack.top().coerceBool(map); - stack.pop(); - stack.push(OpCode {!lhs}); +#define POP_BOOL(NAME) \ + const OpCode& NAME##_temp = stack.top(); \ + bool NAME = NAME##_temp.coerceBool(map); \ + stack.pop() + +#define PUSH(EXPR) \ + stack.push(OpCode {(EXPR)}) + +void AnimExpression::evalAnd(const AnimVariantMap& map, std::stack& stack) const { + POP_BOOL(lhs); + POP_BOOL(rhs); + PUSH(lhs && rhs); +} + +void AnimExpression::evalOr(const AnimVariantMap& map, std::stack& stack) const { + POP_BOOL(lhs); + POP_BOOL(rhs); + PUSH(lhs || rhs); +} + +void AnimExpression::evalGreaterThan(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = stack.top(); stack.pop(); + OpCode rhs = stack.top(); stack.pop(); + + // TODO: + PUSH(false); +} + +void AnimExpression::evalGreaterThanEqual(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = stack.top(); stack.pop(); + OpCode rhs = stack.top(); stack.pop(); + + // TODO: + PUSH(false); +} + +void AnimExpression::evalLessThan(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = stack.top(); stack.pop(); + OpCode rhs = stack.top(); stack.pop(); + + // TODO: + PUSH(false); +} + +void AnimExpression::evalLessThanEqual(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = stack.top(); stack.pop(); + OpCode rhs = stack.top(); stack.pop(); + + // TODO: + PUSH(false); +} + +void AnimExpression::evalEqual(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = stack.top(); stack.pop(); + OpCode rhs = stack.top(); stack.pop(); + + // TODO: + PUSH(false); +} + +void AnimExpression::evalNotEqual(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = stack.top(); stack.pop(); + OpCode rhs = stack.top(); stack.pop(); + + // TODO: + PUSH(false); +} + +void AnimExpression::evalNot(const AnimVariantMap& map, std::stack& stack) const { + POP_BOOL(rhs); + PUSH(!rhs); +} + +void AnimExpression::evalSubtract(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = stack.top(); stack.pop(); + OpCode rhs = stack.top(); stack.pop(); + + // TODO: + PUSH(0.0f); +} + +void AnimExpression::evalAdd(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = stack.top(); stack.pop(); + OpCode rhs = stack.top(); stack.pop(); + + // TODO: + PUSH(0.0f); +} + +void AnimExpression::evalMultiply(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = stack.top(); stack.pop(); + OpCode rhs = stack.top(); stack.pop(); + + // TODO: + PUSH(0.0f); +} + +void AnimExpression::evalModulus(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = stack.top(); stack.pop(); + OpCode rhs = stack.top(); stack.pop(); + + // TODO: + PUSH((int)0); +} + +void AnimExpression::evalMinus(const AnimVariantMap& map, std::stack& stack) const { + OpCode rhs = stack.top(); stack.pop(); + + switch (rhs.type) { + case OpCode::Identifier: { + const AnimVariant& var = map.get(rhs.strVal); + switch (var.getType()) { + case AnimVariant::Type::Bool: + qCWarning(animation) << "AnimExpression: type missmatch for unary minus, expected a number not a bool"; + // interpret this as boolean not. + PUSH(!var.getBool()); + break; + case AnimVariant::Type::Int: + PUSH(-var.getInt()); + break; + case AnimVariant::Type::Float: + PUSH(-var.getFloat()); + break; + default: + // TODO: Vec3, Quat are unsupported + assert(false); + PUSH(false); + break; + } + } + case OpCode::Int: + PUSH(-rhs.intVal); + break; + case OpCode::Float: + PUSH(-rhs.floatVal); + break; + case OpCode::Bool: + qCWarning(animation) << "AnimExpression: type missmatch for unary minus, expected a number not a bool"; + // interpret this as boolean not. + PUSH(!rhs.coerceBool(map)); + break; + default: + qCCritical(animation) << "AnimExpression: ERRROR for unary minus, expected a number, type = " << rhs.type; + assert(false); + PUSH(false); + break; + } } diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 8d216ca412..afada44e86 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -71,15 +71,12 @@ protected: LessThanEqual, Equal, NotEqual, - LeftParen, - RightParen, Not, - Minus, - Plus, + Subtract, + Add, Multiply, Modulus, - UnaryPlus, - UnaryMinus + Minus }; OpCode(Type type) : type {type} {} OpCode(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} @@ -118,12 +115,24 @@ protected: bool parseUnaryExpression(const QString& str, QString::const_iterator& iter); OpCode evaluate(const AnimVariantMap& map) const; + void evalAnd(const AnimVariantMap& map, std::stack& stack) const; + void evalOr(const AnimVariantMap& map, std::stack& stack) const; + void evalGreaterThan(const AnimVariantMap& map, std::stack& stack) const; + void evalGreaterThanEqual(const AnimVariantMap& map, std::stack& stack) const; + void evalLessThan(const AnimVariantMap& map, std::stack& stack) const; + void evalLessThanEqual(const AnimVariantMap& map, std::stack& stack) const; + void evalEqual(const AnimVariantMap& map, std::stack& stack) const; + void evalNotEqual(const AnimVariantMap& map, std::stack& stack) const; void evalNot(const AnimVariantMap& map, std::stack& stack) const; + void evalSubtract(const AnimVariantMap& map, std::stack& stack) const; + void evalAdd(const AnimVariantMap& map, std::stack& stack) const; + void evalMultiply(const AnimVariantMap& map, std::stack& stack) const; + void evalModulus(const AnimVariantMap& map, std::stack& stack) const; + void evalMinus(const AnimVariantMap& map, std::stack& stack) const; QString _expression; - mutable std::stack _tokenStack; + mutable std::stack _tokenStack; // TODO: remove, only needed during parsing std::vector _opCodes; - }; #endif diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index 234e9cef09..cae6dce23d 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -15,6 +15,8 @@ #include #include "AnimVariant.h" // which has AnimVariant/AnimVariantMap +const AnimVariant AnimVariant::FALSE = AnimVariant(); + QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine, const QStringList& names, bool useNames) const { if (QThread::currentThread() != engine->thread()) { qCWarning(animation) << "Cannot create Javacript object from non-script thread" << QThread::currentThread(); diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index ff7794a16a..b15b25f4e0 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -34,6 +34,8 @@ public: NumTypes }; + static const AnimVariant FALSE; + AnimVariant() : _type(Type::Bool) { memset(&_val, 0, sizeof(_val)); } AnimVariant(bool value) : _type(Type::Bool) { _val.boolVal = value; } AnimVariant(int value) : _type(Type::Int) { _val.intVal = value; } @@ -186,6 +188,15 @@ public: void clearMap() { _map.clear(); } bool hasKey(const QString& key) const { return _map.find(key) != _map.end(); } + const AnimVariant& get(const QString& key) const { + auto iter = _map.find(key); + if (iter != _map.end()) { + return iter->second; + } else { + return AnimVariant::FALSE; + } + } + // Answer a Plain Old Javascript Object (for the given engine) all of our values set as properties. QScriptValue animVariantMapToScriptValue(QScriptEngine* engine, const QStringList& names, bool useNames) const; // Side-effect us with the value of object's own properties. (No inherited properties.) diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 94caed66f5..58fd3a1d35 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -357,20 +357,91 @@ void AnimTests::testExpressionTokenizer() { } void AnimTests::testExpressionParser() { - QString str = "(!x)"; - AnimExpression e(str); + + auto vars = AnimVariantMap(); + vars.set("f", false); + vars.set("t", true); + vars.set("ten", (int)10); + vars.set("twenty", (int)20); + vars.set("five", (float)5.0f); + vars.set("forty", (float)40.0f); + + AnimExpression e("(!f)"); QVERIFY(e._opCodes.size() == 2); if (e._opCodes.size() == 2) { QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); - QVERIFY(e._opCodes[0].strVal == "x"); + QVERIFY(e._opCodes[0].strVal == "f"); QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Not); + + auto opCode = e.evaluate(vars); + QVERIFY(opCode.type == AnimExpression::OpCode::Bool); + QVERIFY((opCode.intVal != 0) == true); } - auto vars = AnimVariantMap(); - vars.set("x", false); + e = AnimExpression("!!f"); + QVERIFY(e._opCodes.size() == 3); + if (e._opCodes.size() == 3) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); + QVERIFY(e._opCodes[0].strVal == "f"); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Not); + QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Not); - auto opCode = e.evaluate(vars); - QVERIFY(opCode.type == AnimExpression::OpCode::Bool); - QVERIFY(opCode.coerceBool(vars) == true); + auto opCode = e.evaluate(vars); + QVERIFY(opCode.type == AnimExpression::OpCode::Bool); + QVERIFY((opCode.intVal != 0) == false); + } + + e = AnimExpression("!!(!f)"); + QVERIFY(e._opCodes.size() == 4); + if (e._opCodes.size() == 4) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); + QVERIFY(e._opCodes[0].strVal == "f"); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Not); + QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Not); + QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Not); + + auto opCode = e.evaluate(vars); + QVERIFY(opCode.type == AnimExpression::OpCode::Bool); + QVERIFY((opCode.intVal != 0) == true); + } +/* + e = AnimExpression("f || !f"); + QVERIFY(e._opCodes.size() == 4); + if (e._opCodes.size() == 4) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); + QVERIFY(e._opCodes[0].strVal == "f"); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Identifier); + QVERIFY(e._opCodes[1].strVal == "f"); + QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Not); + QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Or); + + auto opCode = e.evaluate(vars); + QVERIFY(opCode.type == AnimExpression::OpCode::Bool); + QVERIFY((opCode.intVal != 0) == true); + } +*/ + e = AnimExpression("-10"); + QVERIFY(e._opCodes.size() == 2); + if (e._opCodes.size() == 1) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[0].intVal == 10); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Minus); + + auto opCode = e.evaluate(vars); + QVERIFY(opCode.type == AnimExpression::OpCode::Int); + QVERIFY(opCode.intVal == 10); + } + + e = AnimExpression("-ten"); + QVERIFY(e._opCodes.size() == 2); + if (e._opCodes.size() == 1) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); + QVERIFY(e._opCodes[0].strVal == "ten"); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Minus); + + auto opCode = e.evaluate(vars); + QVERIFY(opCode.type == AnimExpression::OpCode::Int); + QVERIFY(opCode.intVal == 10); + } } From 71d361ed3bc7f31cec1d2d09d2cf674a90432877 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 30 Nov 2015 17:06:35 -0800 Subject: [PATCH 009/209] fixed hydra paint, adding more interactive brushes --- examples/example/painting/hydraPaint.js | 12 +++---- .../src/RenderablePolyLineEntityItem.cpp | 32 ++++++++++++++----- .../src/RenderablePolyLineEntityItem.h | 4 +++ .../entities-renderer/src/paintStroke.slf | 14 +++++--- .../entities-renderer/src/paintStroke.slv | 2 ++ libraries/entities/src/PolyLineEntityItem.cpp | 2 ++ libraries/entities/src/PolyLineEntityItem.h | 4 ++- 7 files changed, 51 insertions(+), 19 deletions(-) diff --git a/examples/example/painting/hydraPaint.js b/examples/example/painting/hydraPaint.js index 36137945cc..14ea256369 100644 --- a/examples/example/painting/hydraPaint.js +++ b/examples/example/painting/hydraPaint.js @@ -67,12 +67,12 @@ var colorPalette = [{ var MIN_STROKE_WIDTH = 0.002; var MAX_STROKE_WIDTH = 0.05; -function controller(side, cycleColorButton) { +function controller(side, triggerAction) { this.triggerHeld = false; this.triggerThreshold = 0.9; this.side = side; - this.trigger = side == LEFT ? Controller.Stantard.LT : Controller.Standard.RT; - this.cycleColorButton = side == LEFT ? Controller.Stantard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; + this.triggerAction = triggerAction; + this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; this.points = []; this.normals = []; @@ -174,7 +174,7 @@ function controller(side, cycleColorButton) { this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; - this.triggerValue = Controller.getValue(this.trigger); + this.triggerValue = Controller.getActionValue(this.triggerAction); if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { @@ -212,8 +212,8 @@ function vectorIsZero(v) { } -var rightController = new controller(RIGHT); -var leftController = new controller(LEFT); +var rightController = new controller(RIGHT, Controller.findAction("RIGHT_HAND_CLICK")); +var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK")); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 036d37a95b..63a03bb8e7 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -24,14 +24,22 @@ +struct PolyLineUniforms { + float time; +}; + EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return EntityItemPointer(new RenderablePolyLineEntityItem(entityID, properties)); } RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : -PolyLineEntityItem(entityItemID, properties) { - _numVertices = 0; +PolyLineEntityItem(entityItemID, properties), +_counter(0.0f), +_numVertices(0) +{ _vertices = QVector(0.0f); + PolyLineUniforms uniforms; + _uniformBuffer = std::make_shared(sizeof(PolyLineUniforms), (const gpu::Byte*) &uniforms); } @@ -161,6 +169,18 @@ void RenderablePolyLineEntityItem::updateVertices() { } +void RenderablePolyLineEntityItem::update(const quint64& now) { + PolyLineUniforms uniforms; + _counter += 0.01; + uniforms.time = _counter; + memcpy(&_uniformBuffer.edit(), &uniforms, sizeof(PolyLineUniforms)); + + if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) { + updateVertices(); + updateGeometry(); + } + +} void RenderablePolyLineEntityItem::render(RenderArgs* args) { QWriteLocker lock(&_quadReadWriteLock); @@ -181,17 +201,13 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderablePolyLineEntityItem::render"); Q_ASSERT(getType() == EntityTypes::PolyLine); - Q_ASSERT(args->_batch); - if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) { - updateVertices(); - updateGeometry(); - } gpu::Batch& batch = *args->_batch; Transform transform = Transform(); transform.setTranslation(getPosition()); transform.setRotation(getRotation()); + batch.setUniformBuffer(0, _uniformBuffer); batch.setModelTransform(transform); batch.setPipeline(_pipeline); @@ -200,7 +216,7 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) { } else { batch.setResourceTexture(PAINTSTROKE_GPU_SLOT, args->_whiteTexture); } - + batch.setInputFormat(_format); batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index c49777cfa3..658614e72e 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -29,6 +29,8 @@ public: RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); virtual void render(RenderArgs* args); + virtual void update(const quint64& now) override; + virtual bool needsToCallUpdate() const { return true; }; SIMPLE_RENDERABLE(); @@ -42,8 +44,10 @@ protected: void updateGeometry(); void updateVertices(); gpu::BufferPointer _verticesBuffer; + gpu::BufferView _uniformBuffer; unsigned int _numVertices; QVector _vertices; + float _counter; }; diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index 4e2bc8d097..48de1274f4 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -23,11 +23,15 @@ in vec3 interpolatedNormal; in vec2 varTexcoord; in vec4 varColor; -float rand(vec2 point){ - return fract(sin(dot(point.xy ,vec2(12.9898,78.233))) * 43758.5453); -} +flat in int varVertexId; +struct PolyLineUniforms { + float time; +}; +uniform polyLineBuffer { + PolyLineUniforms polyline; +}; void main(void) { @@ -35,11 +39,13 @@ void main(void) { vec4 texel = texture(originalTexture, varTexcoord); int frontCondition = 1 -int(gl_FrontFacing) * 2; vec3 color = varColor.rgb; + color.g = 1.0 + sin(polyline.time) * 0.5; + //texel.a = varVertexId / 20.0; //vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess packDeferredFragmentTranslucent( interpolatedNormal * frontCondition, texel.a, - color *texel.rgb, + color * texel.rgb, vec3(0.01, 0.01, 0.01), 10.0); } diff --git a/libraries/entities-renderer/src/paintStroke.slv b/libraries/entities-renderer/src/paintStroke.slv index 7d7523deb9..25f046456a 100644 --- a/libraries/entities-renderer/src/paintStroke.slv +++ b/libraries/entities-renderer/src/paintStroke.slv @@ -24,6 +24,7 @@ out vec3 interpolatedNormal; out vec2 varTexcoord; out vec4 varColor; +flat out int varVertexId; void main(void) { @@ -31,6 +32,7 @@ void main(void) { // pass along the diffuse color varColor = inColor; + varVertexId = gl_VertexID; // standard transform TransformCamera cam = getTransformCamera(); diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 012ec3ca4a..f2cdd6c1c1 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -90,6 +90,7 @@ bool PolyLineEntityItem::setProperties(const EntityItemProperties& properties) { return somethingChanged; } + bool PolyLineEntityItem::appendPoint(const glm::vec3& point) { if (_points.size() > MAX_POINTS_PER_LINE - 1) { qDebug() << "MAX POINTS REACHED!"; @@ -105,6 +106,7 @@ bool PolyLineEntityItem::appendPoint(const glm::vec3& point) { return true; } + bool PolyLineEntityItem::setStrokeWidths(const QVector& strokeWidths) { _strokeWidths = strokeWidths; _strokeWidthsChanged = true; diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 4da52f3f21..1610bf87b5 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -75,7 +75,9 @@ class PolyLineEntityItem : public EntityItem { _texturesChangedFlag = true; } } - + + virtual bool needsToCallUpdate() const { return true; } + virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; } // never have a ray intersection pick a PolyLineEntityItem. From 191cab2e5f5fd60f40c5310cb8c35d564b1a4157 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Dec 2015 10:15:47 -0800 Subject: [PATCH 010/209] adding light trail app --- examples/flowArts/lightTrails.js | 223 ++++++++++++++++++++++++++++++ examples/lightTrails.js | 224 +++++++++++++++++++++++++++++++ 2 files changed, 447 insertions(+) create mode 100644 examples/flowArts/lightTrails.js create mode 100644 examples/lightTrails.js diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js new file mode 100644 index 0000000000..60754f42a8 --- /dev/null +++ b/examples/flowArts/lightTrails.js @@ -0,0 +1,223 @@ +// +// hydraPaint.js +// examples +// +// Created by Eric Levin on 5/14/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script allows you to paint with the hydra! +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +var LEFT = 0; +var RIGHT = 1; +var LASER_WIDTH = 3; +var LASER_COLOR = { + red: 50, + green: 150, + blue: 200 +}; +var TRIGGER_THRESHOLD = .1; + +var MAX_POINTS_PER_LINE = 40; + +var LIFETIME = 6000; +var DRAWING_DEPTH = 1; +var LINE_DIMENSIONS = 20; + + +var MIN_POINT_DISTANCE = 0.01; + +var MIN_BRUSH_RADIUS = 0.08; +var MAX_BRUSH_RADIUS = 0.1; + +var RIGHT_BUTTON_1 = 7 +var RIGHT_BUTTON_2 = 8 +var RIGHT_BUTTON_3 = 9; +var RIGHT_BUTTON_4 = 10 +var LEFT_BUTTON_1 = 1; +var LEFT_BUTTON_2 = 2; +var LEFT_BUTTON_3 = 3; +var LEFT_BUTTON_4 = 4; + +var colorPalette = [{ + red: 250, + green: 0, + blue: 0 +}, { + red: 214, + green: 91, + blue: 67 +}, { + red: 192, + green: 41, + blue: 66 +}, { + red: 84, + green: 36, + blue: 55 +}, { + red: 83, + green: 119, + blue: 122 +}]; + +var MIN_STROKE_WIDTH = 0.002; +var MAX_STROKE_WIDTH = 0.05; + +function controller(side, triggerAction) { + this.triggerHeld = false; + this.triggerThreshold = 0.9; + this.side = side; + this.triggerAction = triggerAction; + this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; + + this.points = []; + this.normals = []; + this.strokeWidths = []; + + this.currentColorIndex = 0; + this.currentColor = colorPalette[this.currentColorIndex]; + + var self = this; + + + this.brush = Entities.addEntity({ + type: 'Sphere', + position: { + x: 0, + y: 0, + z: 0 + }, + color: this.currentColor, + dimensions: { + x: MIN_BRUSH_RADIUS, + y: MIN_BRUSH_RADIUS, + z: MIN_BRUSH_RADIUS + } + }); + + this.cycleColor = function() { + this.currentColor = colorPalette[++this.currentColorIndex]; + if (this.currentColorIndex === colorPalette.length - 1) { + this.currentColorIndex = -1; + } + } + this.newLine = function(position) { + this.linePosition = position; + this.line = Entities.addEntity({ + position: position, + type: "PolyLine", + color: this.currentColor, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + textures: "http://localhost:8080/trails.png", + lifetime: LIFETIME + }); + this.points = []; + this.normals = [] + this.strokeWidths = []; + } + + this.update = function(deltaTime) { + this.updateControllerState(); + var newBrushPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); + var newBrushPos = Vec3.sum(this.palmPosition, newBrushPosOffset); + var brushRadius = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_BRUSH_RADIUS, MAX_BRUSH_RADIUS) + Entities.editEntity(this.brush, { + position: newBrushPos, + color: this.currentColor, + dimensions: { + x: brushRadius, + y: brushRadius, + z: brushRadius + } + }); + + + if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { + this.newLine(newBrushPos); + this.drawing = true; + } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { + this.drawing = false; + } + + if (this.drawing && this.points.length < MAX_POINTS_PER_LINE) { + var localPoint = Vec3.subtract(newBrushPos, this.linePosition); + if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { + //Need a minimum distance to avoid binormal NANs + return; + } + + this.points.push(localPoint); + var normal = computeNormal(newBrushPos, Camera.getPosition()); + + this.normals.push(normal); + var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); + this.strokeWidths.push(strokeWidth); + Entities.editEntity(this.line, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + color: this.currentColor + }); + + } + } + + + this.updateControllerState = function() { + this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); + this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; + this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; + this.triggerValue = Controller.getActionValue(this.triggerAction); + + + if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { + this.cycleColor(); + Entities.editEntity(this.brush, { + // color: this.currentColor + }); + } + + this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; + + } + + this.cleanup = function() { + Entities.deleteEntity(self.brush); + } +} + +function computeNormal(p1, p2) { + return Vec3.normalize(Vec3.subtract(p2, p1)); +} + +function update(deltaTime) { + leftController.update(deltaTime); + rightController.update(deltaTime); +} + +function scriptEnding() { + leftController.cleanup(); + rightController.cleanup(); +} + +function vectorIsZero(v) { + return v.x === 0 && v.y === 0 && v.z === 0; +} + + +var rightController = new controller(RIGHT, Controller.findAction("RIGHT_HAND_CLICK")); +var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK")); +Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); + +function map(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} \ No newline at end of file diff --git a/examples/lightTrails.js b/examples/lightTrails.js new file mode 100644 index 0000000000..fc8d7082e4 --- /dev/null +++ b/examples/lightTrails.js @@ -0,0 +1,224 @@ +// +// hydraPaint.js +// examples +// +// Created by Eric Levin on 5/14/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script allows you to paint with the hydra! +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +var LEFT = 0; +var RIGHT = 1; +var LASER_WIDTH = 3; +var LASER_COLOR = { + red: 50, + green: 150, + blue: 200 +}; +var TRIGGER_THRESHOLD = .1; + +var MAX_POINTS_PER_LINE = 40; + +var LIFETIME = 6000; +var DRAWING_DEPTH = 1; +var LINE_DIMENSIONS = 20; + + +var MIN_POINT_DISTANCE = 0.01; + +var MIN_BRUSH_RADIUS = 0.08; +var MAX_BRUSH_RADIUS = 0.1; + +var RIGHT_BUTTON_1 = 7 +var RIGHT_BUTTON_2 = 8 +var RIGHT_BUTTON_3 = 9; +var RIGHT_BUTTON_4 = 10 +var LEFT_BUTTON_1 = 1; +var LEFT_BUTTON_2 = 2; +var LEFT_BUTTON_3 = 3; +var LEFT_BUTTON_4 = 4; + +var colorPalette = [{ + red: 250, + green: 0, + blue: 0 +}, { + red: 214, + green: 91, + blue: 67 +}, { + red: 192, + green: 41, + blue: 66 +}, { + red: 84, + green: 36, + blue: 55 +}, { + red: 83, + green: 119, + blue: 122 +}]; + +var MIN_STROKE_WIDTH = 0.002; +var MAX_STROKE_WIDTH = 0.05; + +function controller(side, triggerAction) { + this.triggerHeld = false; + this.triggerThreshold = 0.9; + this.side = side; + this.triggerAction = triggerAction; + this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; + + this.points = []; + this.normals = []; + this.strokeWidths = []; + + this.currentColorIndex = 0; + this.currentColor = colorPalette[this.currentColorIndex]; + + var self = this; + + + this.brush = Entities.addEntity({ + type: 'Sphere', + position: { + x: 0, + y: 0, + z: 0 + }, + color: this.currentColor, + dimensions: { + x: MIN_BRUSH_RADIUS, + y: MIN_BRUSH_RADIUS, + z: MIN_BRUSH_RADIUS + } + }); + + this.cycleColor = function() { + this.currentColor = colorPalette[++this.currentColorIndex]; + if (this.currentColorIndex === colorPalette.length - 1) { + this.currentColorIndex = -1; + } + } + this.newLine = function(position) { + this.linePosition = position; + this.line = Entities.addEntity({ + position: position, + type: "PolyLine", + color: this.currentColor, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + textures: "http://localhost:8080/trails.png", + lifetime: LIFETIME + }); + this.points = []; + this.normals = [] + this.strokeWidths = []; + } + + this.update = function(deltaTime) { + this.updateControllerState(); + var newBrushPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); + var newBrushPos = Vec3.sum(this.palmPosition, newBrushPosOffset); + var brushRadius = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_BRUSH_RADIUS, MAX_BRUSH_RADIUS) + Entities.editEntity(this.brush, { + position: newBrushPos, + color: this.currentColor, + dimensions: { + x: brushRadius, + y: brushRadius, + z: brushRadius + } + }); + + + if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { + this.newLine(newBrushPos); + this.drawing = true; + } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { + this.drawing = false; + } + + if (this.drawing && this.points.length < MAX_POINTS_PER_LINE) { + var localPoint = Vec3.subtract(newBrushPos, this.linePosition); + if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { + //Need a minimum distance to avoid binormal NANs + return; + } + + this.points.push(localPoint); + var normal = computeNormal(newBrushPos, Camera.getPosition()); + + this.normals.push(normal); + var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); + this.strokeWidths.push(strokeWidth); + Entities.editEntity(this.line, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + color: this.currentColor + }); + } + + // Once we get to max points + } + + + this.updateControllerState = function() { + this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); + this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; + this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; + this.triggerValue = Controller.getActionValue(this.triggerAction); + + + if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { + this.cycleColor(); + Entities.editEntity(this.brush, { + // color: this.currentColor + }); + } + + this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; + + } + + this.cleanup = function() { + Entities.deleteEntity(self.brush); + } +} + +function computeNormal(p1, p2) { + return Vec3.normalize(Vec3.subtract(p2, p1)); +} + +function update(deltaTime) { + leftController.update(deltaTime); + rightController.update(deltaTime); +} + +function scriptEnding() { + leftController.cleanup(); + rightController.cleanup(); +} + +function vectorIsZero(v) { + return v.x === 0 && v.y === 0 && v.z === 0; +} + + +var rightController = new controller(RIGHT, Controller.findAction("RIGHT_HAND_CLICK")); +var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK")); +Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); + +function map(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} \ No newline at end of file From a83f374036727eab11afe3616f5f8299814c1e97 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Dec 2015 10:50:25 -0800 Subject: [PATCH 011/209] tweaking light trail --- examples/flowArts/lightTrails.js | 103 +++++++++++-------------------- 1 file changed, 36 insertions(+), 67 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 60754f42a8..c01fc1c4d3 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -33,14 +33,6 @@ var MIN_POINT_DISTANCE = 0.01; var MIN_BRUSH_RADIUS = 0.08; var MAX_BRUSH_RADIUS = 0.1; -var RIGHT_BUTTON_1 = 7 -var RIGHT_BUTTON_2 = 8 -var RIGHT_BUTTON_3 = 9; -var RIGHT_BUTTON_4 = 10 -var LEFT_BUTTON_1 = 1; -var LEFT_BUTTON_2 = 2; -var LEFT_BUTTON_3 = 3; -var LEFT_BUTTON_4 = 4; var colorPalette = [{ red: 250, @@ -73,94 +65,73 @@ function controller(side, triggerAction) { this.side = side; this.triggerAction = triggerAction; this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; - + this.currentColorIndex = 0; + this.currentColor = colorPalette[this.currentColorIndex]; + this.trail = Entities.addEntity({ + type: "PolyLine", + color: this.currentColor, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + textures: "http://localhost:8080/trails.png", + lifetime: LIFETIME + }); this.points = []; this.normals = []; this.strokeWidths = []; - - this.currentColorIndex = 0; - this.currentColor = colorPalette[this.currentColorIndex]; - var self = this; - this.brush = Entities.addEntity({ - type: 'Sphere', - position: { - x: 0, - y: 0, - z: 0 - }, - color: this.currentColor, - dimensions: { - x: MIN_BRUSH_RADIUS, - y: MIN_BRUSH_RADIUS, - z: MIN_BRUSH_RADIUS - } - }); - this.cycleColor = function() { this.currentColor = colorPalette[++this.currentColorIndex]; if (this.currentColorIndex === colorPalette.length - 1) { this.currentColorIndex = -1; } } - this.newLine = function(position) { - this.linePosition = position; - this.line = Entities.addEntity({ - position: position, - type: "PolyLine", - color: this.currentColor, - dimensions: { - x: LINE_DIMENSIONS, - y: LINE_DIMENSIONS, - z: LINE_DIMENSIONS - }, - textures: "http://localhost:8080/trails.png", - lifetime: LIFETIME + + this.setTrailPosition = function(position) { + this.trailPosition = position; + Entities.editEntity(this.trail, { + position: this.trailPosition }); - this.points = []; - this.normals = [] - this.strokeWidths = []; } + this.update = function(deltaTime) { this.updateControllerState(); - var newBrushPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); - var newBrushPos = Vec3.sum(this.palmPosition, newBrushPosOffset); - var brushRadius = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_BRUSH_RADIUS, MAX_BRUSH_RADIUS) - Entities.editEntity(this.brush, { - position: newBrushPos, - color: this.currentColor, - dimensions: { - x: brushRadius, - y: brushRadius, - z: brushRadius - } - }); + var newTrailPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); + var newTrailPos = Vec3.sum(this.palmPosition, newTrailPosOffset); if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { - this.newLine(newBrushPos); + this.setTrailPosition(newTrailPos); this.drawing = true; } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { this.drawing = false; } - if (this.drawing && this.points.length < MAX_POINTS_PER_LINE) { - var localPoint = Vec3.subtract(newBrushPos, this.linePosition); + if (this.drawing) { + var localPoint = Vec3.subtract(newTrailPos, this.trailPosition); if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { //Need a minimum distance to avoid binormal NANs return; } + if (this.points.length === MAX_POINTS_PER_LINE) { + this.points.shift(); + this.normals.shift(); + this.strokeWidths.shift(); + } + this.points.push(localPoint); - var normal = computeNormal(newBrushPos, Camera.getPosition()); + var normal = computeNormal(newTrailPos, Camera.getPosition()); this.normals.push(normal); var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); this.strokeWidths.push(strokeWidth); - Entities.editEntity(this.line, { + Entities.editEntity(this.trail, { linePoints: this.points, normals: this.normals, strokeWidths: this.strokeWidths, @@ -175,9 +146,9 @@ function controller(side, triggerAction) { this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; - this.triggerValue = Controller.getActionValue(this.triggerAction); + this.triggerValue = Controller.getActionValue(this.triggerAction); + - if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { this.cycleColor(); Entities.editEntity(this.brush, { @@ -189,9 +160,7 @@ function controller(side, triggerAction) { } - this.cleanup = function() { - Entities.deleteEntity(self.brush); - } + this.cleanup = function() {} } function computeNormal(p1, p2) { @@ -204,7 +173,7 @@ function update(deltaTime) { } function scriptEnding() { - leftController.cleanup(); + leftController.cleanup(); rightController.cleanup(); } From 191f7f2c228771d55c544d2fb497ae34e2d0527e Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Dec 2015 16:22:11 -0800 Subject: [PATCH 012/209] no audio for now --- examples/flowArts/lightTrails.js | 22 ++++++++-------- .../src/RenderablePolyLineEntityItem.cpp | 25 +++---------------- .../entities-renderer/src/paintStroke.slf | 7 ++---- 3 files changed, 16 insertions(+), 38 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index c01fc1c4d3..8251803a5f 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -19,19 +19,17 @@ var LASER_COLOR = { green: 150, blue: 200 }; -var TRIGGER_THRESHOLD = .1; -var MAX_POINTS_PER_LINE = 40; +var MAX_POINTS_PER_LINE = 50; var LIFETIME = 6000; -var DRAWING_DEPTH = 1; +var DRAWING_DEPTH = 0.3; var LINE_DIMENSIONS = 20; -var MIN_POINT_DISTANCE = 0.01; +var MIN_POINT_DISTANCE = 0.03; + -var MIN_BRUSH_RADIUS = 0.08; -var MAX_BRUSH_RADIUS = 0.1; var colorPalette = [{ @@ -75,7 +73,7 @@ function controller(side, triggerAction) { y: LINE_DIMENSIONS, z: LINE_DIMENSIONS }, - textures: "http://localhost:8080/trails.png", + textures: "http://localhost:8080/trails.png?v1" + Math.random(), lifetime: LIFETIME }); this.points = []; @@ -105,11 +103,9 @@ function controller(side, triggerAction) { var newTrailPos = Vec3.sum(this.palmPosition, newTrailPosOffset); - if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { + if (!this.drawing) { this.setTrailPosition(newTrailPos); this.drawing = true; - } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { - this.drawing = false; } if (this.drawing) { @@ -129,7 +125,7 @@ function controller(side, triggerAction) { var normal = computeNormal(newTrailPos, Camera.getPosition()); this.normals.push(normal); - var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); + var strokeWidth = MAX_STROKE_WIDTH; this.strokeWidths.push(strokeWidth); Entities.editEntity(this.trail, { linePoints: this.points, @@ -160,7 +156,9 @@ function controller(side, triggerAction) { } - this.cleanup = function() {} + this.cleanup = function() { + Entities.deleteEntity(this.trail); + } } function computeNormal(p1, p2) { diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 63a03bb8e7..bfb27a93b9 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -80,30 +80,12 @@ void RenderablePolyLineEntityItem::updateGeometry() { _verticesBuffer.reset(new gpu::Buffer()); int vertexIndex = 0; vec2 uv; - float tailStart = 0.0f; - float tailEnd = 0.25f; - float tailLength = tailEnd - tailStart; - - float headStart = 0.76f; - float headEnd = 1.0f; - float headLength = headEnd - headStart; float uCoord, vCoord; - - int numTailStrips = 5; - int numHeadStrips = 10; - int startHeadIndex = _vertices.size() / 2 - numHeadStrips; + uCoord = 0.0f; + float uCoordInc = 1.0 / (_vertices.size() / 2); for (int i = 0; i < _vertices.size() / 2; i++) { - uCoord = 0.26f; vCoord = 0.0f; - //tail - if (i < numTailStrips) { - uCoord = float(i) / numTailStrips * tailLength + tailStart; - } - - //head - if (i > startHeadIndex) { - uCoord = float((i + 1) - startHeadIndex) / numHeadStrips * headLength + headStart; - } + uv = vec2(uCoord, vCoord); @@ -121,6 +103,7 @@ void RenderablePolyLineEntityItem::updateGeometry() { vertexIndex++; _numVertices += 2; + uCoord += uCoordInc; } _pointsChanged = false; _normalsChanged = false; diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index 48de1274f4..6c51b4c979 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -38,14 +38,11 @@ void main(void) { vec4 texel = texture(originalTexture, varTexcoord); int frontCondition = 1 -int(gl_FrontFacing) * 2; - vec3 color = varColor.rgb; - color.g = 1.0 + sin(polyline.time) * 0.5; - //texel.a = varVertexId / 20.0; - //vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess + vec3 color = varColor.rgb; packDeferredFragmentTranslucent( interpolatedNormal * frontCondition, texel.a, - color * texel.rgb, + texel.rgb, vec3(0.01, 0.01, 0.01), 10.0); } From 8aeb5598488905b7b47bca4db686874ec1ad51fa Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 15:58:30 -0800 Subject: [PATCH 013/209] flowy --- examples/flowArts/lightTrails.js | 45 +++++-- examples/lightTrails.js | 224 ------------------------------- 2 files changed, 36 insertions(+), 233 deletions(-) delete mode 100644 examples/lightTrails.js diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 8251803a5f..8d88957f03 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -11,6 +11,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +var eraseTrail = true; +var ugLSD = 25; +// var eraseTrail = false; var LEFT = 0; var RIGHT = 1; var LASER_WIDTH = 3; @@ -23,13 +27,11 @@ var LASER_COLOR = { var MAX_POINTS_PER_LINE = 50; var LIFETIME = 6000; -var DRAWING_DEPTH = 0.3; +var DRAWING_DEPTH = 0.2; var LINE_DIMENSIONS = 20; -var MIN_POINT_DISTANCE = 0.03; - - +var MIN_POINT_DISTANCE = 0.02; var colorPalette = [{ @@ -54,8 +56,7 @@ var colorPalette = [{ blue: 122 }]; -var MIN_STROKE_WIDTH = 0.002; -var MAX_STROKE_WIDTH = 0.05; +var STROKE_WIDTH = 0.05; function controller(side, triggerAction) { this.triggerHeld = false; @@ -65,6 +66,16 @@ function controller(side, triggerAction) { this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; this.currentColorIndex = 0; this.currentColor = colorPalette[this.currentColorIndex]; + var textures = "http://localhost:8080/trails.png?v2" + Math.random(); + + // this.light = Entities.addEntity({ + // type: 'Light', + // position: MyAvatar.position, + // dimensions: {x: 20, y: 20, z: 20}, + // color: {red: 60, green: 10, blue: 100}, + // intensity: 10 + // }); + this.trail = Entities.addEntity({ type: "PolyLine", color: this.currentColor, @@ -73,7 +84,7 @@ function controller(side, triggerAction) { y: LINE_DIMENSIONS, z: LINE_DIMENSIONS }, - textures: "http://localhost:8080/trails.png?v1" + Math.random(), + textures: textures, lifetime: LIFETIME }); this.points = []; @@ -81,6 +92,18 @@ function controller(side, triggerAction) { this.strokeWidths = []; var self = this; + this.trailEraseInterval = Script.setInterval(function() { + if (self.points.length > 0 && eraseTrail) { + self.points.shift(); + self.normals.shift(); + self.strokeWidths.shift(); + Entities.editEntity(self.trail, { + linePoints: self.points, + strokeWidths: self.strokeWidths, + normals: self.normals + }); + } + }, ugLSD); this.cycleColor = function() { this.currentColor = colorPalette[++this.currentColorIndex]; @@ -101,6 +124,9 @@ function controller(side, triggerAction) { this.updateControllerState(); var newTrailPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); var newTrailPos = Vec3.sum(this.palmPosition, newTrailPosOffset); + // Entities.editEntity(this.light, { + // position: newTrailPos + // }); if (!this.drawing) { @@ -125,8 +151,7 @@ function controller(side, triggerAction) { var normal = computeNormal(newTrailPos, Camera.getPosition()); this.normals.push(normal); - var strokeWidth = MAX_STROKE_WIDTH; - this.strokeWidths.push(strokeWidth); + this.strokeWidths.push(STROKE_WIDTH); Entities.editEntity(this.trail, { linePoints: this.points, normals: this.normals, @@ -158,6 +183,8 @@ function controller(side, triggerAction) { this.cleanup = function() { Entities.deleteEntity(this.trail); + // Entities.deleteEntity(this.light); + Script.clearInterval(this.trailEraseInterval); } } diff --git a/examples/lightTrails.js b/examples/lightTrails.js deleted file mode 100644 index fc8d7082e4..0000000000 --- a/examples/lightTrails.js +++ /dev/null @@ -1,224 +0,0 @@ -// -// hydraPaint.js -// examples -// -// Created by Eric Levin on 5/14/15. -// Copyright 2014 High Fidelity, Inc. -// -// This script allows you to paint with the hydra! -// -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -var LEFT = 0; -var RIGHT = 1; -var LASER_WIDTH = 3; -var LASER_COLOR = { - red: 50, - green: 150, - blue: 200 -}; -var TRIGGER_THRESHOLD = .1; - -var MAX_POINTS_PER_LINE = 40; - -var LIFETIME = 6000; -var DRAWING_DEPTH = 1; -var LINE_DIMENSIONS = 20; - - -var MIN_POINT_DISTANCE = 0.01; - -var MIN_BRUSH_RADIUS = 0.08; -var MAX_BRUSH_RADIUS = 0.1; - -var RIGHT_BUTTON_1 = 7 -var RIGHT_BUTTON_2 = 8 -var RIGHT_BUTTON_3 = 9; -var RIGHT_BUTTON_4 = 10 -var LEFT_BUTTON_1 = 1; -var LEFT_BUTTON_2 = 2; -var LEFT_BUTTON_3 = 3; -var LEFT_BUTTON_4 = 4; - -var colorPalette = [{ - red: 250, - green: 0, - blue: 0 -}, { - red: 214, - green: 91, - blue: 67 -}, { - red: 192, - green: 41, - blue: 66 -}, { - red: 84, - green: 36, - blue: 55 -}, { - red: 83, - green: 119, - blue: 122 -}]; - -var MIN_STROKE_WIDTH = 0.002; -var MAX_STROKE_WIDTH = 0.05; - -function controller(side, triggerAction) { - this.triggerHeld = false; - this.triggerThreshold = 0.9; - this.side = side; - this.triggerAction = triggerAction; - this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; - - this.points = []; - this.normals = []; - this.strokeWidths = []; - - this.currentColorIndex = 0; - this.currentColor = colorPalette[this.currentColorIndex]; - - var self = this; - - - this.brush = Entities.addEntity({ - type: 'Sphere', - position: { - x: 0, - y: 0, - z: 0 - }, - color: this.currentColor, - dimensions: { - x: MIN_BRUSH_RADIUS, - y: MIN_BRUSH_RADIUS, - z: MIN_BRUSH_RADIUS - } - }); - - this.cycleColor = function() { - this.currentColor = colorPalette[++this.currentColorIndex]; - if (this.currentColorIndex === colorPalette.length - 1) { - this.currentColorIndex = -1; - } - } - this.newLine = function(position) { - this.linePosition = position; - this.line = Entities.addEntity({ - position: position, - type: "PolyLine", - color: this.currentColor, - dimensions: { - x: LINE_DIMENSIONS, - y: LINE_DIMENSIONS, - z: LINE_DIMENSIONS - }, - textures: "http://localhost:8080/trails.png", - lifetime: LIFETIME - }); - this.points = []; - this.normals = [] - this.strokeWidths = []; - } - - this.update = function(deltaTime) { - this.updateControllerState(); - var newBrushPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); - var newBrushPos = Vec3.sum(this.palmPosition, newBrushPosOffset); - var brushRadius = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_BRUSH_RADIUS, MAX_BRUSH_RADIUS) - Entities.editEntity(this.brush, { - position: newBrushPos, - color: this.currentColor, - dimensions: { - x: brushRadius, - y: brushRadius, - z: brushRadius - } - }); - - - if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { - this.newLine(newBrushPos); - this.drawing = true; - } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { - this.drawing = false; - } - - if (this.drawing && this.points.length < MAX_POINTS_PER_LINE) { - var localPoint = Vec3.subtract(newBrushPos, this.linePosition); - if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { - //Need a minimum distance to avoid binormal NANs - return; - } - - this.points.push(localPoint); - var normal = computeNormal(newBrushPos, Camera.getPosition()); - - this.normals.push(normal); - var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); - this.strokeWidths.push(strokeWidth); - Entities.editEntity(this.line, { - linePoints: this.points, - normals: this.normals, - strokeWidths: this.strokeWidths, - color: this.currentColor - }); - } - - // Once we get to max points - } - - - this.updateControllerState = function() { - this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); - this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; - this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; - this.triggerValue = Controller.getActionValue(this.triggerAction); - - - if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { - this.cycleColor(); - Entities.editEntity(this.brush, { - // color: this.currentColor - }); - } - - this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; - - } - - this.cleanup = function() { - Entities.deleteEntity(self.brush); - } -} - -function computeNormal(p1, p2) { - return Vec3.normalize(Vec3.subtract(p2, p1)); -} - -function update(deltaTime) { - leftController.update(deltaTime); - rightController.update(deltaTime); -} - -function scriptEnding() { - leftController.cleanup(); - rightController.cleanup(); -} - -function vectorIsZero(v) { - return v.x === 0 && v.y === 0 && v.z === 0; -} - - -var rightController = new controller(RIGHT, Controller.findAction("RIGHT_HAND_CLICK")); -var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK")); -Script.update.connect(update); -Script.scriptEnding.connect(scriptEnding); - -function map(value, min1, max1, min2, max2) { - return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); -} \ No newline at end of file From d2d0326c02268b4cf8cd496de12d5e23888910b9 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 16:44:47 -0800 Subject: [PATCH 014/209] using deployed texture --- examples/flowArts/lightTrails.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 8d88957f03..a494f9a810 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -66,7 +66,7 @@ function controller(side, triggerAction) { this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; this.currentColorIndex = 0; this.currentColor = colorPalette[this.currentColorIndex]; - var textures = "http://localhost:8080/trails.png?v2" + Math.random(); + var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png"; // this.light = Entities.addEntity({ // type: 'Light', @@ -84,7 +84,7 @@ function controller(side, triggerAction) { y: LINE_DIMENSIONS, z: LINE_DIMENSIONS }, - textures: textures, + textures: texture, lifetime: LIFETIME }); this.points = []; From 2336dd96dd934f5efc1832db5815bf2dc87f3c21 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 18:10:45 -0800 Subject: [PATCH 015/209] lights --- examples/flowArts/lightTrails.js | 108 ++++++++++++++----------------- 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index a494f9a810..4a7f9de277 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -12,73 +12,82 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Script.include("../libraries/utils.js"); + var eraseTrail = true; var ugLSD = 25; // var eraseTrail = false; var LEFT = 0; var RIGHT = 1; -var LASER_WIDTH = 3; -var LASER_COLOR = { - red: 50, - green: 150, - blue: 200 -}; - var MAX_POINTS_PER_LINE = 50; var LIFETIME = 6000; -var DRAWING_DEPTH = 0.2; +var DRAWING_DEPTH = 0.6; var LINE_DIMENSIONS = 20; +var lightZone = Entities.addEntity({ + type: "Zone", + shapeType: 'box', + keyLightIntensity: 0.02, + keyLightColor: { + red: 5, + green: 0, + blue: 5 + }, + keyLightAmbientIntensity: .05, + position: MyAvatar.position, + dimensions: { + x: 100, + y: 100, + z: 100 + } +}); + var MIN_POINT_DISTANCE = 0.02; var colorPalette = [{ red: 250, - green: 0, - blue: 0 + green: 137, + blue: 162 }, { - red: 214, - green: 91, - blue: 67 + red: 204, + green: 244, + blue: 249 }, { - red: 192, - green: 41, - blue: 66 + red: 146, + green: 206, + blue: 116 }, { - red: 84, - green: 36, - blue: 55 -}, { - red: 83, - green: 119, - blue: 122 + red: 240, + green: 87, + blue: 129 }]; -var STROKE_WIDTH = 0.05; +var STROKE_WIDTH = 0.03; function controller(side, triggerAction) { this.triggerHeld = false; this.triggerThreshold = 0.9; this.side = side; this.triggerAction = triggerAction; - this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; - this.currentColorIndex = 0; - this.currentColor = colorPalette[this.currentColorIndex]; var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png"; - // this.light = Entities.addEntity({ - // type: 'Light', - // position: MyAvatar.position, - // dimensions: {x: 20, y: 20, z: 20}, - // color: {red: 60, green: 10, blue: 100}, - // intensity: 10 - // }); + this.light = Entities.addEntity({ + type: 'Light', + position: MyAvatar.position, + dimensions: { + x: 20, + y: 20, + z: 20 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 20 + }); this.trail = Entities.addEntity({ type: "PolyLine", - color: this.currentColor, dimensions: { x: LINE_DIMENSIONS, y: LINE_DIMENSIONS, @@ -105,12 +114,6 @@ function controller(side, triggerAction) { } }, ugLSD); - this.cycleColor = function() { - this.currentColor = colorPalette[++this.currentColorIndex]; - if (this.currentColorIndex === colorPalette.length - 1) { - this.currentColorIndex = -1; - } - } this.setTrailPosition = function(position) { this.trailPosition = position; @@ -124,9 +127,9 @@ function controller(side, triggerAction) { this.updateControllerState(); var newTrailPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); var newTrailPos = Vec3.sum(this.palmPosition, newTrailPosOffset); - // Entities.editEntity(this.light, { - // position: newTrailPos - // }); + Entities.editEntity(this.light, { + position: newTrailPos + }); if (!this.drawing) { @@ -151,12 +154,11 @@ function controller(side, triggerAction) { var normal = computeNormal(newTrailPos, Camera.getPosition()); this.normals.push(normal); - this.strokeWidths.push(STROKE_WIDTH); + this.strokeWidths.push(STROKE_WIDTH + Math.random() * 0.01); Entities.editEntity(this.trail, { linePoints: this.points, normals: this.normals, strokeWidths: this.strokeWidths, - color: this.currentColor }); } @@ -164,26 +166,15 @@ function controller(side, triggerAction) { this.updateControllerState = function() { - this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; this.triggerValue = Controller.getActionValue(this.triggerAction); - - if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { - this.cycleColor(); - Entities.editEntity(this.brush, { - // color: this.currentColor - }); - } - - this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; - } this.cleanup = function() { Entities.deleteEntity(this.trail); - // Entities.deleteEntity(this.light); + Entities.deleteEntity(this.light); Script.clearInterval(this.trailEraseInterval); } } @@ -200,6 +191,7 @@ function update(deltaTime) { function scriptEnding() { leftController.cleanup(); rightController.cleanup(); + Entities.deleteEntity(lightZone); } function vectorIsZero(v) { From 5f881e765093d62d9ecc0031b3883ff31acb5505 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 3 Dec 2015 13:46:29 -0800 Subject: [PATCH 016/209] polylines now take color as a uniform --- examples/flowArts/lightTrails.js | 7 ++++--- examples/painting/closePaint.js | 5 ++++- .../painting/whiteboard/whiteboardEntityScript.js | 3 +++ .../src/RenderablePolyLineEntityItem.cpp | 13 +++---------- .../src/RenderablePolyLineEntityItem.h | 1 - libraries/entities-renderer/src/paintStroke.slf | 6 ++---- libraries/entities-renderer/src/paintStroke.slv | 3 --- libraries/entities/src/PolyLineEntityItem.h | 2 +- 8 files changed, 17 insertions(+), 23 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 4a7f9de277..e063897eb8 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -22,7 +22,7 @@ var RIGHT = 1; var MAX_POINTS_PER_LINE = 50; var LIFETIME = 6000; -var DRAWING_DEPTH = 0.6; +var DRAWING_DEPTH = 0.8; var LINE_DIMENSIONS = 20; var lightZone = Entities.addEntity({ @@ -65,7 +65,7 @@ var colorPalette = [{ blue: 129 }]; -var STROKE_WIDTH = 0.03; +var STROKE_WIDTH = 0.04; function controller(side, triggerAction) { this.triggerHeld = false; @@ -83,7 +83,7 @@ function controller(side, triggerAction) { z: 20 }, color: colorPalette[randInt(0, colorPalette.length)], - intensity: 20 + intensity: 5 }); this.trail = Entities.addEntity({ @@ -93,6 +93,7 @@ function controller(side, triggerAction) { y: LINE_DIMENSIONS, z: LINE_DIMENSIONS }, + color: {red: 255, green: 255, blue: 255}, textures: texture, lifetime: LIFETIME }); diff --git a/examples/painting/closePaint.js b/examples/painting/closePaint.js index 60b4ac2e25..bea4d9c9aa 100644 --- a/examples/painting/closePaint.js +++ b/examples/painting/closePaint.js @@ -43,6 +43,8 @@ var MAX_STROKE_WIDTH = 0.04; var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(Camera.getOrientation()))); +var textureURL = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png"; + function MyController(hand, triggerAction) { @@ -148,7 +150,8 @@ function MyController(hand, triggerAction) { y: 50, z: 50 }, - lifetime: 200 + lifetime: 200, + textures: textureURL }); this.strokePoints = []; this.strokeNormals = []; diff --git a/examples/painting/whiteboard/whiteboardEntityScript.js b/examples/painting/whiteboard/whiteboardEntityScript.js index 61d7291e11..374ec8b873 100644 --- a/examples/painting/whiteboard/whiteboardEntityScript.js +++ b/examples/painting/whiteboard/whiteboardEntityScript.js @@ -29,6 +29,8 @@ var MIN_STROKE_WIDTH = 0.0005; var MAX_STROKE_WIDTH = 0.03; + var textureURL = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png"; + var TRIGGER_CONTROLS = [ Controller.Standard.LT, Controller.Standard.RT, @@ -168,6 +170,7 @@ type: "PolyLine", name: "paintStroke", color: this.strokeColor, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png", dimensions: { x: 50, y: 50, diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index bfb27a93b9..d38da0d3f7 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -25,7 +25,7 @@ struct PolyLineUniforms { - float time; + glm::vec3 color; }; EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -34,7 +34,6 @@ EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& enti RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : PolyLineEntityItem(entityItemID, properties), -_counter(0.0f), _numVertices(0) { _vertices = QVector(0.0f); @@ -49,13 +48,11 @@ int32_t RenderablePolyLineEntityItem::PAINTSTROKE_GPU_SLOT; void RenderablePolyLineEntityItem::createPipeline() { static const int NORMAL_OFFSET = 12; - static const int COLOR_OFFSET = 24; - static const int TEXTURE_OFFSET = 28; + static const int TEXTURE_OFFSET = 24; _format.reset(new gpu::Stream::Format()); _format->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); _format->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), NORMAL_OFFSET); - _format->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, COLOR_OFFSET); _format->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), TEXTURE_OFFSET); auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(paintStroke_vert))); @@ -91,14 +88,12 @@ void RenderablePolyLineEntityItem::updateGeometry() { _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_vertices.at(vertexIndex)); _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_normals.at(i)); - _verticesBuffer->append(sizeof(int), (gpu::Byte*)&_color); _verticesBuffer->append(sizeof(glm::vec2), (gpu::Byte*)&uv); vertexIndex++; uv.y = 1.0f; _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_vertices.at(vertexIndex)); _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_normals.at(i)); - _verticesBuffer->append(sizeof(int), (gpu::Byte*)_color); _verticesBuffer->append(sizeof(glm::vec2), (const gpu::Byte*)&uv); vertexIndex++; @@ -154,10 +149,8 @@ void RenderablePolyLineEntityItem::updateVertices() { void RenderablePolyLineEntityItem::update(const quint64& now) { PolyLineUniforms uniforms; - _counter += 0.01; - uniforms.time = _counter; + uniforms.color = toGlm(getXColor()); memcpy(&_uniformBuffer.edit(), &uniforms, sizeof(PolyLineUniforms)); - if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) { updateVertices(); updateGeometry(); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 658614e72e..411b856d91 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -47,7 +47,6 @@ protected: gpu::BufferView _uniformBuffer; unsigned int _numVertices; QVector _vertices; - float _counter; }; diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index 6c51b4c979..1a87f84bfd 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -21,12 +21,11 @@ uniform sampler2D originalTexture; // the interpolated normal in vec3 interpolatedNormal; in vec2 varTexcoord; -in vec4 varColor; flat in int varVertexId; struct PolyLineUniforms { - float time; + vec3 color; }; uniform polyLineBuffer { @@ -38,11 +37,10 @@ void main(void) { vec4 texel = texture(originalTexture, varTexcoord); int frontCondition = 1 -int(gl_FrontFacing) * 2; - vec3 color = varColor.rgb; packDeferredFragmentTranslucent( interpolatedNormal * frontCondition, texel.a, - texel.rgb, + polyline.color * texel.rgb, vec3(0.01, 0.01, 0.01), 10.0); } diff --git a/libraries/entities-renderer/src/paintStroke.slv b/libraries/entities-renderer/src/paintStroke.slv index 25f046456a..5c368f9c0f 100644 --- a/libraries/entities-renderer/src/paintStroke.slv +++ b/libraries/entities-renderer/src/paintStroke.slv @@ -23,15 +23,12 @@ out vec3 interpolatedNormal; //the diffuse texture out vec2 varTexcoord; -out vec4 varColor; flat out int varVertexId; void main(void) { varTexcoord = inTexCoord0.st; - // pass along the diffuse color - varColor = inColor; varVertexId = gl_VertexID; // standard transform diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 1610bf87b5..20549d1bbd 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -49,7 +49,7 @@ class PolyLineEntityItem : public EntityItem { memcpy(_color, value, sizeof(_color)); } void setColor(const xColor& value) { - + _color[RED_INDEX] = value.red; _color[GREEN_INDEX] = value.green; _color[BLUE_INDEX] = value.blue; From 99223d0a3c8848fbef5d8ce16f834747c8efe2e5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 3 Dec 2015 15:02:00 -0800 Subject: [PATCH 017/209] AnimExpression: support for parsing simple expressions supports parens, binary +, -, / and *. / and * have higher precedence then + and - --- libraries/animation/src/AnimExpression.cpp | 349 +++++++++++++++++---- libraries/animation/src/AnimExpression.h | 24 +- tests/animation/src/AnimTests.cpp | 174 ++++++---- tests/animation/src/AnimTests.h | 1 + 4 files changed, 417 insertions(+), 131 deletions(-) diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index a03925f8f9..b76aaff3f9 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -17,9 +17,16 @@ AnimExpression::AnimExpression(const QString& str) : _expression(str) { auto iter = str.begin(); - parseExpression(_expression, iter); + parseExpr(_expression, iter); + while(!_tokenStack.empty()) { + _tokenStack.pop(); + } } +// +// Tokenizer +// + void AnimExpression::unconsumeToken(const Token& token) { _tokenStack.push(token); } @@ -49,6 +56,7 @@ AnimExpression::Token AnimExpression::consumeToken(const QString& str, QString:: case '-': ++iter; return Token(Token::Minus); case '+': ++iter; return Token(Token::Plus); case '*': ++iter; return Token(Token::Multiply); + case '/': ++iter; return Token(Token::Divide); case '%': ++iter; return Token(Token::Modulus); case ',': ++iter; return Token(Token::Comma); default: @@ -184,73 +192,137 @@ AnimExpression::Token AnimExpression::consumeNot(const QString& str, QString::co } } -bool AnimExpression::parseExpression(const QString& str, QString::const_iterator& iter) { +// +// Parser +// + +/* +Expr → Term Expr' +Expr' → + Term Expr' + | – Term Expr' + | ε +Term → Factor Term' +Term' → * Term' + | / Term' + | ε +Factor → INT + | FLOAT + | IDENTIFIER + | (Expr) +*/ + +bool AnimExpression::parseExpr(const QString& str, QString::const_iterator& iter) { + if (!parseTerm(str, iter)) { + return false; + } + if (!parseExprPrime(str, iter)) { + return false; + } + return true; +} + +bool AnimExpression::parseExprPrime(const QString& str, QString::const_iterator& iter) { auto token = consumeToken(str, iter); - if (token.type == Token::Identifier) { - if (token.strVal == "true") { - _opCodes.push_back(OpCode {true}); - } else if (token.strVal == "false") { - _opCodes.push_back(OpCode {false}); - } else { - _opCodes.push_back(OpCode {token.strVal}); + if (token.type == Token::Plus) { + if (!parseTerm(str, iter)) { + unconsumeToken(token); + return false; } + if (!parseExprPrime(str, iter)) { + unconsumeToken(token); + return false; + } + _opCodes.push_back(OpCode {OpCode::Add}); return true; - } else if (token.type == Token::Int) { + } else if (token.type == Token::Minus) { + if (!parseTerm(str, iter)) { + unconsumeToken(token); + return false; + } + if (!parseExprPrime(str, iter)) { + unconsumeToken(token); + return false; + } + _opCodes.push_back(OpCode {OpCode::Subtract}); + return true; + } else { + unconsumeToken(token); + return true; + } +} + +bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter) { + if (!parseFactor(str, iter)) { + return false; + } + if (!parseTermPrime(str, iter)) { + return false; + } + return true; +} + +bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& iter) { + auto token = consumeToken(str, iter); + if (token.type == Token::Multiply) { + if (!parseTerm(str, iter)) { + unconsumeToken(token); + return false; + } + if (!parseTermPrime(str, iter)) { + unconsumeToken(token); + return false; + } + _opCodes.push_back(OpCode {OpCode::Multiply}); + return true; + } else if (token.type == Token::Divide) { + if (!parseTerm(str, iter)) { + unconsumeToken(token); + return false; + } + if (!parseTermPrime(str, iter)) { + unconsumeToken(token); + return false; + } + _opCodes.push_back(OpCode {OpCode::Divide}); + return true; + } else { + unconsumeToken(token); + return true; + } +} + +bool AnimExpression::parseFactor(const QString& str, QString::const_iterator& iter) { + auto token = consumeToken(str, iter); + if (token.type == Token::Int) { _opCodes.push_back(OpCode {token.intVal}); return true; } else if (token.type == Token::Float) { _opCodes.push_back(OpCode {token.floatVal}); return true; + } else if (token.type == Token::Identifier) { + _opCodes.push_back(OpCode {token.strVal}); + return true; } else if (token.type == Token::LeftParen) { - if (parseUnaryExpression(str, iter)) { - token = consumeToken(str, iter); - if (token.type != Token::RightParen) { - qCCritical(animation) << "Error parsing expression, expected ')'"; - return false; - } else { - return true; - } - } else { + if (!parseExpr(str, iter)) { + unconsumeToken(token); return false; } + auto nextToken = consumeToken(str, iter); + if (nextToken.type != Token::RightParen) { + unconsumeToken(nextToken); + unconsumeToken(token); + return false; + } + return true; } else { unconsumeToken(token); - if (parseUnaryExpression(str, iter)) { - return true; - } else { - qCCritical(animation) << "Error parsing expression"; - return false; - } + return false; } } -bool AnimExpression::parseUnaryExpression(const QString& str, QString::const_iterator& iter) { - auto token = consumeToken(str, iter); - if (token.type == Token::Plus) { // unary plus is a no op. - if (parseExpression(str, iter)) { - return true; - } else { - return false; - } - } else if (token.type == Token::Minus) { - if (parseExpression(str, iter)) { - _opCodes.push_back(OpCode {OpCode::Minus}); - return true; - } else { - return false; - } - } else if (token.type == Token::Not) { - if (parseExpression(str, iter)) { - _opCodes.push_back(OpCode {OpCode::Not}); - return true; - } else { - return false; - } - } else { - unconsumeToken(token); - return parseExpression(str, iter); - } -} +// +// Evaluator +// AnimExpression::OpCode AnimExpression::evaluate(const AnimVariantMap& map) const { std::stack stack; @@ -274,8 +346,9 @@ AnimExpression::OpCode AnimExpression::evaluate(const AnimVariantMap& map) const case OpCode::Subtract: evalSubtract(map, stack); break; case OpCode::Add: evalAdd(map, stack); break; case OpCode::Multiply: evalMultiply(map, stack); break; + case OpCode::Divide: evalDivide(map, stack); break; case OpCode::Modulus: evalModulus(map, stack); break; - case OpCode::Minus: evalMinus(map, stack); break; + case OpCode::UnaryMinus: evalUnaryMinus(map, stack); break; } } return stack.top(); @@ -362,15 +435,107 @@ void AnimExpression::evalSubtract(const AnimVariantMap& map, std::stack& PUSH(0.0f); } -void AnimExpression::evalAdd(const AnimVariantMap& map, std::stack& stack) const { - OpCode lhs = stack.top(); stack.pop(); - OpCode rhs = stack.top(); stack.pop(); +void AnimExpression::add(int lhs, const OpCode& rhs, std::stack& stack) const { + switch (rhs.type) { + case OpCode::Bool: + case OpCode::Int: + PUSH(lhs + rhs.intVal); + break; + case OpCode::Float: + PUSH((float)lhs + rhs.floatVal); + break; + default: + PUSH(lhs); + } +} - // TODO: - PUSH(0.0f); +void AnimExpression::add(float lhs, const OpCode& rhs, std::stack& stack) const { + switch (rhs.type) { + case OpCode::Bool: + case OpCode::Int: + PUSH(lhs + (float)rhs.intVal); + break; + case OpCode::Float: + PUSH(lhs + rhs.floatVal); + break; + default: + PUSH(lhs); + } +} + +void AnimExpression::evalAdd(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = coerseToValue(map, stack.top()); + stack.pop(); + OpCode rhs = coerseToValue(map, stack.top()); + stack.pop(); + + switch (lhs.type) { + case OpCode::Bool: + add(lhs.intVal, rhs, stack); + break; + case OpCode::Int: + add(lhs.intVal, rhs, stack); + break; + case OpCode::Float: + add(lhs.floatVal, rhs, stack); + break; + default: + add(0, rhs, stack); + break; + } } void AnimExpression::evalMultiply(const AnimVariantMap& map, std::stack& stack) const { + OpCode lhs = coerseToValue(map, stack.top()); + stack.pop(); + OpCode rhs = coerseToValue(map, stack.top()); + stack.pop(); + + switch(lhs.type) { + case OpCode::Bool: + mul(lhs.intVal, rhs, stack); + break; + case OpCode::Int: + mul(lhs.intVal, rhs, stack); + break; + case OpCode::Float: + mul(lhs.floatVal, rhs, stack); + break; + default: + mul(0, rhs, stack); + break; + } +} + +void AnimExpression::mul(int lhs, const OpCode& rhs, std::stack& stack) const { + switch (rhs.type) { + case OpCode::Bool: + case OpCode::Int: + PUSH(lhs * rhs.intVal); + break; + case OpCode::Float: + PUSH((float)lhs * rhs.floatVal); + break; + default: + PUSH(lhs); + } +} + +void AnimExpression::mul(float lhs, const OpCode& rhs, std::stack& stack) const { + switch (rhs.type) { + case OpCode::Bool: + case OpCode::Int: + PUSH(lhs * (float)rhs.intVal); + break; + case OpCode::Float: + PUSH(lhs * rhs.floatVal); + break; + default: + PUSH(lhs); + } +} + +void AnimExpression::evalDivide(const AnimVariantMap& map, std::stack& stack) const { OpCode lhs = stack.top(); stack.pop(); OpCode rhs = stack.top(); stack.pop(); @@ -386,7 +551,7 @@ void AnimExpression::evalModulus(const AnimVariantMap& map, std::stack& PUSH((int)0); } -void AnimExpression::evalMinus(const AnimVariantMap& map, std::stack& stack) const { +void AnimExpression::evalUnaryMinus(const AnimVariantMap& map, std::stack& stack) const { OpCode rhs = stack.top(); stack.pop(); switch (rhs.type) { @@ -429,3 +594,69 @@ void AnimExpression::evalMinus(const AnimVariantMap& map, std::stack& st break; } } + +AnimExpression::OpCode AnimExpression::coerseToValue(const AnimVariantMap& map, const OpCode& opCode) const { + switch (opCode.type) { + case OpCode::Identifier: + { + const AnimVariant& var = map.get(opCode.strVal); + switch (var.getType()) { + case AnimVariant::Type::Bool: + qCWarning(animation) << "AnimExpression: type missmatch, expected a number not a bool"; + return OpCode(0); + break; + case AnimVariant::Type::Int: + return OpCode(var.getInt()); + break; + case AnimVariant::Type::Float: + return OpCode(var.getFloat()); + break; + default: + // TODO: Vec3, Quat are unsupported + assert(false); + return OpCode(0); + break; + } + } + break; + case OpCode::Bool: + case OpCode::Int: + case OpCode::Float: + return opCode; + default: + qCCritical(animation) << "AnimExpression: ERROR expected a number, type = " << opCode.type; + assert(false); + return OpCode(0); + break; + } +} + +void AnimExpression::dumpOpCodes() const { + QString tmp; + for (auto& op : _opCodes) { + switch (op.type) { + case OpCode::Identifier: tmp += QString(" %1").arg(op.strVal); break; + case OpCode::Bool: tmp += QString(" %1").arg(op.intVal ? "true" : "false"); break; + case OpCode::Int: tmp += QString(" %1").arg(op.intVal); break; + case OpCode::Float: tmp += QString(" %1").arg(op.floatVal); break; + case OpCode::And: tmp += " &&"; break; + case OpCode::Or: tmp += " ||"; break; + case OpCode::GreaterThan: tmp += " >"; break; + case OpCode::GreaterThanEqual: tmp += " >="; break; + case OpCode::LessThan: tmp += " <"; break; + case OpCode::LessThanEqual: tmp += " <="; break; + case OpCode::Equal: tmp += " =="; break; + case OpCode::NotEqual: tmp += " !="; break; + case OpCode::Not: tmp += " !"; break; + case OpCode::Subtract: tmp += " -"; break; + case OpCode::Add: tmp += " +"; break; + case OpCode::Multiply: tmp += " *"; break; + case OpCode::Divide: tmp += " /"; break; + case OpCode::Modulus: tmp += " %"; break; + case OpCode::UnaryMinus: tmp += " unary-"; break; + default: tmp += " ???"; break; + } + } + qCDebug(animation).nospace().noquote() << "opCodes =" << tmp; + qCDebug(animation).resetFormat(); +} diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index afada44e86..6e204483d5 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -43,6 +43,7 @@ protected: Minus, Plus, Multiply, + Divide, Modulus, Comma, Error @@ -75,8 +76,9 @@ protected: Subtract, Add, Multiply, + Divide, Modulus, - Minus + UnaryMinus }; OpCode(Type type) : type {type} {} OpCode(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} @@ -111,8 +113,11 @@ protected: Token consumeLessThan(const QString& str, QString::const_iterator& iter) const; Token consumeNot(const QString& str, QString::const_iterator& iter) const; - bool parseExpression(const QString& str, QString::const_iterator& iter); - bool parseUnaryExpression(const QString& str, QString::const_iterator& iter); + bool parseExpr(const QString& str, QString::const_iterator& iter); + bool parseExprPrime(const QString& str, QString::const_iterator& iter); + bool parseTerm(const QString& str, QString::const_iterator& iter); + bool parseTermPrime(const QString& str, QString::const_iterator& iter); + bool parseFactor(const QString& str, QString::const_iterator& iter); OpCode evaluate(const AnimVariantMap& map) const; void evalAnd(const AnimVariantMap& map, std::stack& stack) const; @@ -126,13 +131,24 @@ protected: void evalNot(const AnimVariantMap& map, std::stack& stack) const; void evalSubtract(const AnimVariantMap& map, std::stack& stack) const; void evalAdd(const AnimVariantMap& map, std::stack& stack) const; + void add(int lhs, const OpCode& rhs, std::stack& stack) const; + void add(float lhs, const OpCode& rhs, std::stack& stack) const; void evalMultiply(const AnimVariantMap& map, std::stack& stack) const; + void mul(int lhs, const OpCode& rhs, std::stack& stack) const; + void mul(float lhs, const OpCode& rhs, std::stack& stack) const; + void evalDivide(const AnimVariantMap& map, std::stack& stack) const; void evalModulus(const AnimVariantMap& map, std::stack& stack) const; - void evalMinus(const AnimVariantMap& map, std::stack& stack) const; + void evalUnaryMinus(const AnimVariantMap& map, std::stack& stack) const; + + OpCode coerseToValue(const AnimVariantMap& map, const OpCode& opCode) const; QString _expression; mutable std::stack _tokenStack; // TODO: remove, only needed during parsing std::vector _opCodes; + +#ifndef NDEBUG + void dumpOpCodes() const; +#endif }; #endif diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 58fd3a1d35..6765553a25 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -366,82 +366,120 @@ void AnimTests::testExpressionParser() { vars.set("five", (float)5.0f); vars.set("forty", (float)40.0f); - AnimExpression e("(!f)"); - QVERIFY(e._opCodes.size() == 2); - if (e._opCodes.size() == 2) { - QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); - QVERIFY(e._opCodes[0].strVal == "f"); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Not); - - auto opCode = e.evaluate(vars); - QVERIFY(opCode.type == AnimExpression::OpCode::Bool); - QVERIFY((opCode.intVal != 0) == true); - } - - e = AnimExpression("!!f"); - QVERIFY(e._opCodes.size() == 3); - if (e._opCodes.size() == 3) { - QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); - QVERIFY(e._opCodes[0].strVal == "f"); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Not); - QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Not); - - auto opCode = e.evaluate(vars); - QVERIFY(opCode.type == AnimExpression::OpCode::Bool); - QVERIFY((opCode.intVal != 0) == false); - } - - e = AnimExpression("!!(!f)"); - QVERIFY(e._opCodes.size() == 4); - if (e._opCodes.size() == 4) { - QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); - QVERIFY(e._opCodes[0].strVal == "f"); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Not); - QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Not); - QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Not); - - auto opCode = e.evaluate(vars); - QVERIFY(opCode.type == AnimExpression::OpCode::Bool); - QVERIFY((opCode.intVal != 0) == true); - } -/* - e = AnimExpression("f || !f"); - QVERIFY(e._opCodes.size() == 4); - if (e._opCodes.size() == 4) { - QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); - QVERIFY(e._opCodes[0].strVal == "f"); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Identifier); - QVERIFY(e._opCodes[1].strVal == "f"); - QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Not); - QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Or); - - auto opCode = e.evaluate(vars); - QVERIFY(opCode.type == AnimExpression::OpCode::Bool); - QVERIFY((opCode.intVal != 0) == true); - } -*/ - e = AnimExpression("-10"); - QVERIFY(e._opCodes.size() == 2); + AnimExpression e("10"); + QVERIFY(e._opCodes.size() == 1); if (e._opCodes.size() == 1) { QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); QVERIFY(e._opCodes[0].intVal == 10); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Minus); - - auto opCode = e.evaluate(vars); - QVERIFY(opCode.type == AnimExpression::OpCode::Int); - QVERIFY(opCode.intVal == 10); } - e = AnimExpression("-ten"); - QVERIFY(e._opCodes.size() == 2); + e = AnimExpression("(10)"); + QVERIFY(e._opCodes.size() == 1); + if (e._opCodes.size() == 1) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[0].intVal == 10); + } + + e = AnimExpression("((10))"); + QVERIFY(e._opCodes.size() == 1); + if (e._opCodes.size() == 1) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[0].intVal == 10); + } + + e = AnimExpression("12.5"); + QVERIFY(e._opCodes.size() == 1); + if (e._opCodes.size() == 1) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Float); + QVERIFY(e._opCodes[0].floatVal == 12.5f); + } + + e = AnimExpression("twenty"); + QVERIFY(e._opCodes.size() == 1); if (e._opCodes.size() == 1) { QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier); - QVERIFY(e._opCodes[0].strVal == "ten"); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Minus); + QVERIFY(e._opCodes[0].strVal == "twenty"); + } - auto opCode = e.evaluate(vars); - QVERIFY(opCode.type == AnimExpression::OpCode::Int); - QVERIFY(opCode.intVal == 10); + e = AnimExpression("2 + 3"); + QVERIFY(e._opCodes.size() == 3); + if (e._opCodes.size() == 3) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[0].intVal == 2); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[1].intVal == 3); + QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Add); + } + + e = AnimExpression("2 + 3 * 10"); + QVERIFY(e._opCodes.size() == 5); + if (e._opCodes.size() == 5) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[0].intVal == 2); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[1].intVal == 3); + QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[2].intVal == 10); + QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Multiply); + QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Add); + } + + e = AnimExpression("(2 + 3) * 10"); + QVERIFY(e._opCodes.size() == 5); + if (e._opCodes.size() == 5) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[0].intVal == 2); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[1].intVal == 3); + QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Add); + QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Int); + QVERIFY(e._opCodes[3].intVal == 10); + QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Multiply); } } +void AnimTests::testExpressionEvaluator() { + auto vars = AnimVariantMap(); + vars.set("f", false); + vars.set("t", true); + vars.set("ten", (int)10); + vars.set("twenty", (int)20); + vars.set("five", (float)5.0f); + vars.set("forty", (float)40.0f); + + AnimExpression::OpCode result = AnimExpression("10").evaluate(vars); + QVERIFY(result.type == AnimExpression::OpCode::Int); + QVERIFY(result.intVal == 10); + + result = AnimExpression("(10)").evaluate(vars); + QVERIFY(result.type == AnimExpression::OpCode::Int); + QVERIFY(result.intVal == 10); + + result = AnimExpression("2 + 3").evaluate(vars); + QVERIFY(result.type == AnimExpression::OpCode::Int); + QVERIFY(result.intVal == 2 + 3); + + result = AnimExpression("2 + 3 * 5").evaluate(vars); + QVERIFY(result.type == AnimExpression::OpCode::Int); + QVERIFY(result.intVal == 2 + 3 * 5); + + result = AnimExpression("(2 + 3) * 5").evaluate(vars); + QVERIFY(result.type == AnimExpression::OpCode::Int); + QVERIFY(result.intVal == (2 + 3) * 5); + + result = AnimExpression("(2 + 3) * (5 + 3)").evaluate(vars); + QVERIFY(result.type == AnimExpression::OpCode::Int); + QVERIFY(result.intVal == (2 + 3) * (5 + 3)); + + result = AnimExpression("(ten + twenty) * 5").evaluate(vars); + QVERIFY(result.type == AnimExpression::OpCode::Int); + QVERIFY(result.intVal == (10 + 20) * 5); + + result = AnimExpression("(ten + twenty) * 5.0").evaluate(vars); + QVERIFY(result.type == AnimExpression::OpCode::Float); + QVERIFY(result.floatVal == (10 + 20) * 5.0f); + + result = AnimExpression("five * forty").evaluate(vars); + QVERIFY(result.type == AnimExpression::OpCode::Float); + QVERIFY(result.floatVal == 5.0f * 40.0f); +} diff --git a/tests/animation/src/AnimTests.h b/tests/animation/src/AnimTests.h index 94b3eddd25..a70acc21f7 100644 --- a/tests/animation/src/AnimTests.h +++ b/tests/animation/src/AnimTests.h @@ -28,6 +28,7 @@ private slots: void testAccumulateTime(); void testExpressionTokenizer(); void testExpressionParser(); + void testExpressionEvaluator(); }; #endif // hifi_AnimTests_h From 4a18b5ffe4f31d0a7671651f1ab620ed210cc406 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 8 Dec 2015 20:29:18 +0100 Subject: [PATCH 018/209] small update to have the bow shoot arrows with the creatorSessionUUID in the userData --- examples/toybox/bow/bow.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/toybox/bow/bow.js b/examples/toybox/bow/bow.js index 90199fb70f..1ea3e39b02 100644 --- a/examples/toybox/bow/bow.js +++ b/examples/toybox/bow/bow.js @@ -259,9 +259,9 @@ userData: JSON.stringify({ grabbableKey: { grabbable: false - } + }, + creatorSessionUUID: MyAvatar.sessionUUID }) - }); var makeArrowStick = function(entityA, entityB, collision) { From 2fb318cc5366afe54e8794f33094e5bca6d84969 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 8 Dec 2015 17:52:23 -0800 Subject: [PATCH 019/209] work with clements branch --- examples/controllers/handControllerGrab.js | 161 +++++++++++++++++++-- 1 file changed, 149 insertions(+), 12 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 138240f5d6..20ca3811c0 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -251,9 +251,10 @@ function MyController(hand) { this.triggerValue = 0; // rolling average of trigger value this.rawTriggerValue = 0; this.rawBumperValue = 0; - + this.overlayLine = null; - + this.particleBeam = null; + this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; @@ -398,6 +399,119 @@ function MyController(hand) { } }; + + //test particles instead of overlays + + + this.handleParticleBeam = function(position, orientation) { + + var rotation = Quat.angleAxis(0, { + x: 1, + y: 0, + z: 0 + }); + + var finalRotation = Quat.multiply(orientation, rotation); + + + if (this.particleBeam === null) { + print('create beam') + this.createParticleBeam(position, finalRotation) + } else { + print('update beam') + this.updateParticleBeam(position, finalRotation) + } + } + + this.createParticleBeam = function(position, orientation) { + var particleBeamProperties = { + type: "ParticleEffect", + isEmitting: true, + position: position, + //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), + "name": "Particle Beam", + "color": { + "red": 110, + "green": 118.52941176470593, + "blue": 255 + }, + "maxParticles": 1000, + "lifespan": 3, + "emitRate": 20, + "emitSpeed": 10, + "speedSpread": 0, + "emitOrientation": { + "x": -0.7000000000000001, + "y": 0, + "z": 0, + "w": 0.7071068286895752 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitRadiusStart": 0.5, + "polarStart": 0, + "polarFinish": 0, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + x: 0, + y: 0, + z: 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.02, + "radiusSpread": 0, + "radiusStart": 0.01, + "radiusFinish": 0.01, + "colorSpread": { + "red": 0, + "green": 0, + "blue": 0 + }, + "colorStart": { + "red": 110, + "green": 118.52941176470593, + "blue": 255 + }, + "colorFinish": { + "red": 110, + "green": 118.52941176470593, + "blue": 255 + }, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 1, + "alphaFinish": 1, + "additiveBlending": 0, + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" + } + + this.particleBeam = Entities.addEntity(particleBeamProperties); + } + + this.updateParticleBeam = function(position, orientation, acceleration) { + print('O IN UPDATE:::' + JSON.stringify(orientation)) + + // var beamProps = Entities.getEntityProperties(this.particleBeam); + + Entities.editEntity(this.particleBeam, { + //rotation:rotation, + rotation: orientation, + position: position, + + }) + + // var emitO = Entities.getEntityProperties(this.particleBeam, "emitOrientation").emitOrientation; + // print('EMIT o :::' + JSON.stringify(emitO)); + } + this.lineOff = function() { if (this.pointer !== null) { Entities.deleteEntity(this.pointer); @@ -412,6 +526,14 @@ function MyController(hand) { this.overlayLine = null; }; + this.particleBeamOff = function() { + if (this.particleBeam !== null) { + Entities.deleteEntity(this.particleBeam) + } + + this.particleBeam = null; + } + this.triggerPress = function(value) { _this.rawTriggerValue = value; }; @@ -662,6 +784,9 @@ function MyController(hand) { //this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation()); + + }; this.distanceHolding = function() { @@ -715,6 +840,7 @@ function MyController(hand) { this.currentAvatarOrientation = MyAvatar.orientation; this.overlayLineOff(); + this.particleBeamOff(); }; this.continueDistanceHolding = function() { @@ -808,8 +934,16 @@ function MyController(hand) { // mix in head motion if (MOVE_WITH_HEAD) { var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { x: 0.0, y: 0.0, z: objDistance }); - var after = Vec3.multiplyQbyV(Camera.orientation, { x: 0.0, y: 0.0, z: objDistance }); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); var change = Vec3.subtract(before, after); this.currentCameraOrientation = Camera.orientation; this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); @@ -837,6 +971,7 @@ function MyController(hand) { this.lineOff(); this.overlayLineOff(); + this.particleBeamOff(); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); this.activateEntity(this.grabbedEntity, grabbedProperties); @@ -975,6 +1110,7 @@ function MyController(hand) { this.pullTowardEquipPosition = function() { this.lineOff(); this.overlayLineOff(); + this.particleBeamOff(); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); @@ -1164,6 +1300,7 @@ function MyController(hand) { this.lineOff(); this.overlayLineOff(); + this.particleBeamOff(); if (this.grabbedEntity !== null) { if (this.actionID !== null) { Entities.deleteAction(this.grabbedEntity, this.actionID); @@ -1285,10 +1422,10 @@ Controller.enableMapping(MAPPING_NAME); var handToDisable = 'none'; function update() { - if (handToDisable !== LEFT_HAND && handToDisable!=='both') { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { leftController.update(); } - if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { rightController.update(); } } @@ -1296,7 +1433,7 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { - + if (sender === MyAvatar.sessionUUID) { if (message === 'left') { handToDisable = LEFT_HAND; @@ -1304,11 +1441,11 @@ handleHandDisablerMessages = function(channel, message, sender) { if (message === 'right') { handToDisable = RIGHT_HAND; } - if(message==='both'){ - handToDisable='both'; + if (message === 'both') { + handToDisable = 'both'; } - if(message==='none'){ - handToDisable='none'; + if (message === 'none') { + handToDisable = 'none'; } } @@ -1323,4 +1460,4 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -Script.update.connect(update); +Script.update.connect(update); \ No newline at end of file From 1134d12ea0e9f92de38646e6d45c45e91f86bac3 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 9 Dec 2015 16:08:32 -0800 Subject: [PATCH 020/209] particles --- examples/controllers/handControllerGrab.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 20ca3811c0..b2af86c479 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -399,10 +399,7 @@ function MyController(hand) { } }; - //test particles instead of overlays - - this.handleParticleBeam = function(position, orientation) { var rotation = Quat.angleAxis(0, { @@ -435,11 +432,11 @@ function MyController(hand) { "green": 118.52941176470593, "blue": 255 }, - "maxParticles": 1000, + "maxParticles": 2000, "lifespan": 3, - "emitRate": 20, - "emitSpeed": 10, - "speedSpread": 0, + "emitRate": 50, + "emitSpeed": 2, + "speedSpread": 0.1, "emitOrientation": { "x": -0.7000000000000001, "y": 0, From 31526091d323a5ed8ad5038fa533697a6ac257bf Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 11:13:35 -0800 Subject: [PATCH 021/209] create beams at start --- examples/controllers/handControllerGrab.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index b2af86c479..4348722df0 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -425,6 +425,7 @@ function MyController(hand) { type: "ParticleEffect", isEmitting: true, position: position, + visible: false, //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": { @@ -436,12 +437,12 @@ function MyController(hand) { "lifespan": 3, "emitRate": 50, "emitSpeed": 2, - "speedSpread": 0.1, + "speedSpread": 0, "emitOrientation": { - "x": -0.7000000000000001, + "x": -1, "y": 0, "z": 0, - "w": 0.7071068286895752 + "w": 1 }, "emitDimensions": { "x": 0, @@ -486,7 +487,7 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 0, + "additiveBlending": 1, "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" } @@ -502,6 +503,7 @@ function MyController(hand) { //rotation:rotation, rotation: orientation, position: position, + visible: true }) @@ -525,10 +527,12 @@ function MyController(hand) { this.particleBeamOff = function() { if (this.particleBeam !== null) { - Entities.deleteEntity(this.particleBeam) + Entities.editEntity(this.particleBeam, { + visible: false + }) } - this.particleBeam = null; + //this.particleBeam = null; } this.triggerPress = function(value) { @@ -1314,6 +1318,7 @@ function MyController(hand) { this.cleanup = function() { this.release(); this.endHandGrasp(); + Entities.deleteEntity(this.particleBeam); }; this.activateEntity = function(entityID, grabbedProperties) { @@ -1404,6 +1409,8 @@ function MyController(hand) { var rightController = new MyController(RIGHT_HAND); var leftController = new MyController(LEFT_HAND); +rightController.createParticleBeam(); +leftController.createParticleBeam(); var MAPPING_NAME = "com.highfidelity.handControllerGrab"; From 1000b602808f4a487012be55df9ec685824a8f29 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 12:21:50 -0800 Subject: [PATCH 022/209] far beams --- examples/controllers/handControllerGrab.js | 65 ++++++++++++---------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 4348722df0..812eef07f8 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -400,7 +400,7 @@ function MyController(hand) { }; //test particles instead of overlays - this.handleParticleBeam = function(position, orientation) { + this.handleParticleBeam = function(position, orientation, color) { var rotation = Quat.angleAxis(0, { x: 1, @@ -409,18 +409,36 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); + // var finalRotation = orientation + + if (this.particleBeam === null) { + print('create beam') + this.createParticleBeam(position, finalRotation, color) + } else { + print('update beam') + this.updateParticleBeam(position, finalRotation, color) + } + } + + this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + + + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1,Vec3.UP), handToObject); + + if (this.particleBeam === null) { print('create beam') - this.createParticleBeam(position, finalRotation) + this.createParticleBeam(objectPosition, finalRotation, color) } else { print('update beam') - this.updateParticleBeam(position, finalRotation) + this.updateParticleBeam(objectPosition, finalRotation, color) } } - this.createParticleBeam = function(position, orientation) { + this.createParticleBeam = function(position, orientation, color) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, @@ -428,15 +446,11 @@ function MyController(hand) { visible: false, //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", - "color": { - "red": 110, - "green": 118.52941176470593, - "blue": 255 - }, + "color": color, "maxParticles": 2000, "lifespan": 3, "emitRate": 50, - "emitSpeed": 2, + "emitSpeed": 20, "speedSpread": 0, "emitOrientation": { "x": -1, @@ -473,16 +487,8 @@ function MyController(hand) { "green": 0, "blue": 0 }, - "colorStart": { - "red": 110, - "green": 118.52941176470593, - "blue": 255 - }, - "colorFinish": { - "red": 110, - "green": 118.52941176470593, - "blue": 255 - }, + "colorStart": color, + "colorFinish": color, "alpha": 1, "alphaSpread": 0, "alphaStart": 1, @@ -494,21 +500,19 @@ function MyController(hand) { this.particleBeam = Entities.addEntity(particleBeamProperties); } - this.updateParticleBeam = function(position, orientation, acceleration) { + this.updateParticleBeam = function(position, orientation, color) { print('O IN UPDATE:::' + JSON.stringify(orientation)) // var beamProps = Entities.getEntityProperties(this.particleBeam); Entities.editEntity(this.particleBeam, { - //rotation:rotation, rotation: orientation, position: position, - visible: true + visible: true, + color: color }) - // var emitO = Entities.getEntityProperties(this.particleBeam, "emitOrientation").emitOrientation; - // print('EMIT o :::' + JSON.stringify(emitO)); } this.lineOff = function() { @@ -784,8 +788,8 @@ function MyController(hand) { } //this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); - this.handleParticleBeam(distantPickRay.origin, this.getHandRotation()); + //this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); }; @@ -867,9 +871,8 @@ function MyController(hand) { return; } - this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); - - // the action was set up on a previous call. update the targets. + // this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + // the action was set up on a previous call. update the targets. var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; if (radius < 1.0) { @@ -950,6 +953,8 @@ function MyController(hand) { this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } + this.handleDistantParticleBeam(handPosition, grabbedProperties.position,this.currentObjectRotation, INTERSECT_COLOR) + Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, From c3e9cde7fbc59ce8dafb0f8c7c443212bd08662c Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 13:44:53 -0800 Subject: [PATCH 023/209] beamz --- examples/controllers/handControllerGrab.js | 31 +++++++++++++--------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 812eef07f8..1106295cde 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -423,22 +423,25 @@ function MyController(hand) { this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { - var handToObject = Vec3.subtract(objectPosition, handPosition); - var finalRotation = Quat.rotationBetween(Vec3.multiply(-1,Vec3.UP), handToObject); - + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); + var distance = Vec3.distance(handPosition, objectPosition); + var speed = distance * 1; + var lifepsan = distance / speed; + var lifespan = 1; if (this.particleBeam === null) { print('create beam') - this.createParticleBeam(objectPosition, finalRotation, color) + this.createParticleBeam(objectPosition, finalRotation, color, speed) } else { print('update beam') - this.updateParticleBeam(objectPosition, finalRotation, color) + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan) } } - this.createParticleBeam = function(position, orientation, color) { + this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, @@ -448,9 +451,9 @@ function MyController(hand) { "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": 3, + "lifespan": 1, "emitRate": 50, - "emitSpeed": 20, + "emitSpeed": 1, "speedSpread": 0, "emitOrientation": { "x": -1, @@ -500,7 +503,7 @@ function MyController(hand) { this.particleBeam = Entities.addEntity(particleBeamProperties); } - this.updateParticleBeam = function(position, orientation, color) { + this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { print('O IN UPDATE:::' + JSON.stringify(orientation)) // var beamProps = Entities.getEntityProperties(this.particleBeam); @@ -509,7 +512,9 @@ function MyController(hand) { rotation: orientation, position: position, visible: true, - color: color + color: color, + emitSpeed: speed, + lifepsan: lifepsan }) @@ -871,8 +876,8 @@ function MyController(hand) { return; } - // this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); - // the action was set up on a previous call. update the targets. + // this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + // the action was set up on a previous call. update the targets. var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; if (radius < 1.0) { @@ -953,7 +958,7 @@ function MyController(hand) { this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } - this.handleDistantParticleBeam(handPosition, grabbedProperties.position,this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, From efaa30a509148a6f0da8921d88c0c4c732aa04ca Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 16:18:40 -0800 Subject: [PATCH 024/209] rotatable light --- examples/controllers/handControllerGrab.js | 91 ++++++++++++++++++---- 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index d92cb35b43..4e612799f7 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -116,6 +116,17 @@ var DEFAULT_GRABBABLE_DATA = { invertSolidWhileHeld: false }; +var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 +}; +var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 +}); + // states for the state machine var STATE_OFF = 0; @@ -137,6 +148,7 @@ var STATE_WAITING_FOR_BUMPER_RELEASE = 15; var STATE_EQUIP_SPRING = 16; + function stateToName(state) { switch (state) { case STATE_OFF: @@ -218,6 +230,7 @@ function getSpatialOffsetPosition(hand, spatialKey) { } var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + function getSpatialOffsetRotation(hand, spatialKey) { var rotation = Quat.IDENTITY; @@ -264,7 +277,8 @@ function MyController(hand) { this.overlayLine = null; this.particleBeam = null; - + this.spotlight = null; + this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; @@ -420,7 +434,6 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - // var finalRotation = orientation if (this.particleBeam === null) { print('create beam') @@ -433,7 +446,6 @@ function MyController(hand) { this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { - var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); @@ -453,6 +465,7 @@ function MyController(hand) { } this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, @@ -463,7 +476,7 @@ function MyController(hand) { "color": color, "maxParticles": 2000, "lifespan": 1, - "emitRate": 50, + "emitRate": 15, "emitSpeed": 1, "speedSpread": 0, "emitOrientation": { @@ -494,21 +507,21 @@ function MyController(hand) { }, "particleRadius": 0.02, "radiusSpread": 0, - "radiusStart": 0.01, - "radiusFinish": 0.01, - "colorSpread": { - "red": 0, - "green": 0, - "blue": 0 - }, - "colorStart": color, - "colorFinish": color, + // "radiusStart": 0.01, + // "radiusFinish": 0.01, + // "colorSpread": { + // "red": 0, + // "green": 0, + // "blue": 0 + // }, + // "colorStart": color, + // "colorFinish": color, "alpha": 1, "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, "additiveBlending": 1, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" + "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); @@ -531,6 +544,49 @@ function MyController(hand) { } + + this.evalLightWorldTransform = function(modelPos, modelRot) { + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + } + + this.createSpotlight = function(parentID, position) { + var LIFETIME = 100; + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + //this light casts the beam + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + rotation: lightTransform.q, + }; + + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + + } + } + this.lineOff = function() { if (this.pointer !== null) { Entities.deleteEntity(this.pointer); @@ -555,6 +611,11 @@ function MyController(hand) { //this.particleBeam = null; } + this.spotlightOff = function() { + // Entities.deleteEntity(this.spotlight); + // this.spotlight = null; + } + this.triggerPress = function(value) { _this.rawTriggerValue = value; }; @@ -970,6 +1031,7 @@ function MyController(hand) { } this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.createSpotlight(this.grabbedEntity); Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, @@ -1331,6 +1393,7 @@ function MyController(hand) { this.lineOff(); this.overlayLineOff(); this.particleBeamOff(); + this.spotlightOff(); if (this.grabbedEntity !== null) { if (this.actionID !== null) { Entities.deleteAction(this.grabbedEntity, this.actionID); From 16ab7e74de0c12813694e4f006c21f8c89e6f739 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 16:53:13 -0800 Subject: [PATCH 025/209] cleanup spotlights --- examples/controllers/handControllerGrab.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 4e612799f7..b787d8f0df 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -476,7 +476,7 @@ function MyController(hand) { "color": color, "maxParticles": 2000, "lifespan": 1, - "emitRate": 15, + "emitRate": 300, "emitSpeed": 1, "speedSpread": 0, "emitOrientation": { @@ -505,7 +505,7 @@ function MyController(hand) { "y": 0, "z": 0 }, - "particleRadius": 0.02, + "particleRadius": 0.01, "radiusSpread": 0, // "radiusStart": 0.01, // "radiusFinish": 0.01, @@ -583,7 +583,10 @@ function MyController(hand) { if (this.spotlight === null) { this.spotlight = Entities.addEntity(lightProperties); } else { - + // var rotationBetween = Quat.rotationBetween(Vec3.UP, ) + // Entities.editEntity(this.spotlight, { + // rotation: lightTransform.q + // }) } } @@ -612,8 +615,10 @@ function MyController(hand) { } this.spotlightOff = function() { - // Entities.deleteEntity(this.spotlight); - // this.spotlight = null; + if (this.spotlight !== null) { + Overlays.deleteOverlay(this.spotlight); + } + this.spotlight = null; } this.triggerPress = function(value) { From 2acc0df1f0bf29315d146b63d4e0f46342f63f37 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 17:39:29 -0800 Subject: [PATCH 026/209] beams with spotlights --- examples/controllers/handControllerGrab.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index b787d8f0df..58eeb83b0e 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -559,7 +559,7 @@ function MyController(hand) { //this light casts the beam var lightProperties = { type: "Light", - isSpotlight: true, + isSpotlight: false, dimensions: { x: 2, y: 2, @@ -576,17 +576,18 @@ function MyController(hand) { cutoff: 20, lifetime: LIFETIME, position: lightTransform.p, - rotation: lightTransform.q, + // rotation: lightTransform.q, }; if (this.spotlight === null) { this.spotlight = Entities.addEntity(lightProperties); } else { - // var rotationBetween = Quat.rotationBetween(Vec3.UP, ) - // Entities.editEntity(this.spotlight, { - // rotation: lightTransform.q - // }) + Entities.editEntity(this.spotlight, { + parentID:parentID, + position:lightTransform.p, + visible:true + }) } } @@ -616,9 +617,13 @@ function MyController(hand) { this.spotlightOff = function() { if (this.spotlight !== null) { - Overlays.deleteOverlay(this.spotlight); + print('SHOULD DELETE SPOTLIGHT' + this.spotlight) + Entities.editEntity(this.spotlight,{ + visible:false + }) + //Entities.deleteEntity(this.spotlight); } - this.spotlight = null; + //this.spotlight = null; } this.triggerPress = function(value) { @@ -1416,6 +1421,7 @@ function MyController(hand) { this.release(); this.endHandGrasp(); Entities.deleteEntity(this.particleBeam); + Entities.deleteEntity(this.spotLight); }; this.activateEntity = function(entityID, grabbedProperties) { From 4e9d81f18737203e4bbdd60343aab98d65a210a1 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Dec 2015 11:38:16 -0800 Subject: [PATCH 027/209] add support for various beam visualizations --- examples/controllers/handControllerGrab.js | 269 ++++++++++++++------- 1 file changed, 178 insertions(+), 91 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 58eeb83b0e..9e2f55b238 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -116,17 +116,14 @@ var DEFAULT_GRABBABLE_DATA = { invertSolidWhileHeld: false }; -var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 -}; -var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 -}); - +//we've created various ways of visualizing looking for and moving distant objects +var USE_ENTITY_LASERS_FOR_SEARCHING = false; +var USE_ENTITY_LASERS_FOR_MOVING = true; +var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_PARTICLE_BEAM_FOR_SEARCHING = false; +var USE_PARTICLE_BEAM_FOR_MOVING = false; +var USE_SPOTLIGHT = false; +var USE_POINTLIGHT = false; // states for the state machine var STATE_OFF = 0; @@ -275,9 +272,13 @@ function MyController(hand) { this.rawTriggerValue = 0; this.rawBumperValue = 0; + //for visualizations this.overlayLine = null; this.particleBeam = null; + + //for lights this.spotlight = null; + this.pointlight = null; this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; @@ -366,33 +367,6 @@ function MyController(hand) { }); } - this.overlayLineOn = function(closePoint, farPoint, color) { - if (this.overlayLine === null) { - var lineProperties = { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - ignoreRayIntersection: true, // always ignore this - visible: true, - alpha: 1 - }; - - this.overlayLine = Overlays.addOverlay("line3d", lineProperties); - - } else { - var success = Overlays.editOverlay(this.overlayLine, { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - visible: true, - ignoreRayIntersection: true, // always ignore this - alpha: 1 - }); - } - } - this.lineOn = function(closePoint, farPoint, color) { // draw a line if (this.pointer === null) { @@ -424,7 +398,33 @@ function MyController(hand) { } }; - //test particles instead of overlays + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine === null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, // always ignore this + visible: true, + alpha: 1 + }; + + this.overlayLine = Overlays.addOverlay("line3d", lineProperties); + + } else { + var success = Overlays.editOverlay(this.overlayLine, { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + visible: true, + ignoreRayIntersection: true, // always ignore this + alpha: 1 + }); + } + } + this.handleParticleBeam = function(position, orientation, color) { var rotation = Quat.angleAxis(0, { @@ -437,10 +437,10 @@ function MyController(hand) { if (this.particleBeam === null) { print('create beam') - this.createParticleBeam(position, finalRotation, color) + this.createParticleBeam(position, finalRotation, color); } else { print('update beam') - this.updateParticleBeam(position, finalRotation, color) + this.updateParticleBeam(position, finalRotation, color); } } @@ -456,11 +456,9 @@ function MyController(hand) { var lifespan = 1; if (this.particleBeam === null) { - print('create beam') - this.createParticleBeam(objectPosition, finalRotation, color, speed) + this.createParticleBeam(objectPosition, finalRotation, color, speed); } else { - print('update beam') - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan) + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); } } @@ -475,10 +473,10 @@ function MyController(hand) { "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": 1, - "emitRate": 300, - "emitSpeed": 1, - "speedSpread": 0, + "lifespan": LINE_LENGTH / 10, + "emitRate": 50, + "emitSpeed": 5, + "speedSpread": 2, "emitOrientation": { "x": -1, "y": 0, @@ -528,9 +526,6 @@ function MyController(hand) { } this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - print('O IN UPDATE:::' + JSON.stringify(orientation)) - - // var beamProps = Entities.getEntityProperties(this.particleBeam); Entities.editEntity(this.particleBeam, { rotation: orientation, @@ -544,19 +539,72 @@ function MyController(hand) { } - this.evalLightWorldTransform = function(modelPos, modelRot) { + + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + return { p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) }; } - this.createSpotlight = function(parentID, position) { + this.handleSpotlight = function(parentID, position) { var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + Entities.editEntity(this.spotlight, { + parentID: parentID, + position: lightTransform.p, + //without this, this light would maintain rotation with its parent + rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + visible: true + }) + } + } + + this.handlePointLight = function(parentID, position) { + var LIFETIME = 100; + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - //this light casts the beam + var lightProperties = { type: "Light", isSpotlight: false, @@ -576,17 +624,18 @@ function MyController(hand) { cutoff: 20, lifetime: LIFETIME, position: lightTransform.p, - // rotation: lightTransform.q, }; + if (this.pointlight === null) { - if (this.spotlight === null) { - this.spotlight = Entities.addEntity(lightProperties); + print('create pointlight') + this.pointlight = Entities.addEntity(lightProperties); } else { - Entities.editEntity(this.spotlight, { - parentID:parentID, - position:lightTransform.p, - visible:true + print('update pointlight') + Entities.editEntity(this.pointlight, { + parentID: parentID, + position: lightTransform.p, + visible: true }) } } @@ -611,19 +660,25 @@ function MyController(hand) { visible: false }) } - - //this.particleBeam = null; } - this.spotlightOff = function() { + this.turnLightsOff = function() { + //use visibility for now instead of creating and deleting since deleting seems to crash if (this.spotlight !== null) { - print('SHOULD DELETE SPOTLIGHT' + this.spotlight) - Entities.editEntity(this.spotlight,{ - visible:false - }) - //Entities.deleteEntity(this.spotlight); + Entities.editEntity(this.spotlight, { + visible: false + }) + //Entities.deleteEntity(this.spotlight); + //this.spotLight=null; + } + + if (this.pointlight !== null) { + Entities.editEntity(this.pointlight, { + visible: false + }) + //Entities.deleteEntity(this.pointlight); + //this.pointlight = null; } - //this.spotlight = null; } this.triggerPress = function(value) { @@ -634,7 +689,6 @@ function MyController(hand) { _this.rawBumperValue = value; }; - this.updateSmoothedTrigger = function() { var triggerValue = this.rawTriggerValue; // smooth out trigger value @@ -663,7 +717,6 @@ function MyController(hand) { return _this.rawBumperValue < BUMPER_ON_VALUE; } - this.off = function() { if (this.triggerSmoothedSqueezed()) { this.lastPickTime = 0; @@ -874,10 +927,18 @@ function MyController(hand) { } } - //this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - //this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); - this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + //search line visualizations + if (USE_ENTITY_LASERS_FOR_SEARCHING === true) { + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + } }; @@ -931,10 +992,22 @@ function MyController(hand) { this.currentAvatarPosition = MyAvatar.position; this.currentAvatarOrientation = MyAvatar.orientation; - this.overlayLineOff(); - this.particleBeamOff(); + this.turnOffVisualizations(); }; + this.turnOffVisualizations = function() { + if (USE_ENTITY_LASERS_FOR_SEARCHING === true || USE_ENTITY_LASERS_FOR_MOVING === true) { + this.lineOff(); + } + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + } + this.continueDistanceHolding = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); @@ -958,7 +1031,7 @@ function MyController(hand) { return; } - // this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + // the action was set up on a previous call. update the targets. var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; @@ -1040,8 +1113,22 @@ function MyController(hand) { this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) - this.createSpotlight(this.grabbedEntity); + + //visualizations + if (USE_ENTITY_LASERS_FOR_MOVING === true) { + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } + if (USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + } + + if (USE_POINTLIGHT === true) { + this.handlePointLight(this.grabbedEntity); + } + + if (USE_SPOTLIGHT === true) { + this.handleSpotlight(this.grabbedEntity); + } Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, @@ -1050,6 +1137,7 @@ function MyController(hand) { angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, ttl: ACTION_TTL }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); }; @@ -1063,9 +1151,7 @@ function MyController(hand) { return; } - this.lineOff(); - this.overlayLineOff(); - this.particleBeamOff(); + this.turnOffVisualizations(); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); this.activateEntity(this.grabbedEntity, grabbedProperties); @@ -1207,9 +1293,8 @@ function MyController(hand) { }; this.pullTowardEquipPosition = function() { - this.lineOff(); - this.overlayLineOff(); - this.particleBeamOff(); + + this.turnOffVisualizations(); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); @@ -1400,10 +1485,9 @@ function MyController(hand) { this.release = function() { - this.lineOff(); - this.overlayLineOff(); - this.particleBeamOff(); - this.spotlightOff(); + this.turnLightsOff(); + this.turnOffVisualizations(); + if (this.grabbedEntity !== null) { if (this.actionID !== null) { Entities.deleteAction(this.grabbedEntity, this.actionID); @@ -1422,6 +1506,7 @@ function MyController(hand) { this.endHandGrasp(); Entities.deleteEntity(this.particleBeam); Entities.deleteEntity(this.spotLight); + Entities.deleteEntity(this.pointLight); }; this.activateEntity = function(entityID, grabbedProperties) { @@ -1512,6 +1597,8 @@ function MyController(hand) { var rightController = new MyController(RIGHT_HAND); var leftController = new MyController(LEFT_HAND); + +//reload the particle beams rightController.createParticleBeam(); leftController.createParticleBeam(); From 11aaeb1ec00a76273f639648d47a00e4f691e0aa Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Dec 2015 14:48:07 -0800 Subject: [PATCH 028/209] only create particle beams if set --- examples/controllers/handControllerGrab.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 9e2f55b238..217b5b6632 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1599,8 +1599,10 @@ var rightController = new MyController(RIGHT_HAND); var leftController = new MyController(LEFT_HAND); //reload the particle beams -rightController.createParticleBeam(); -leftController.createParticleBeam(); +if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + rightController.createParticleBeam(); + leftController.createParticleBeam(); +} var MAPPING_NAME = "com.highfidelity.handControllerGrab"; From 1b1edf6f7ab8a8e94e7d78df9eaf2b42d81c703b Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Dec 2015 17:23:35 -0800 Subject: [PATCH 029/209] actually delete lights now that it doesnt crash --- examples/controllers/handControllerGrab.js | 30 +++++----------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 217b5b6632..ae95ab47fd 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -122,7 +122,7 @@ var USE_ENTITY_LASERS_FOR_MOVING = true; var USE_OVERLAY_LINES_FOR_SEARCHING = true; var USE_PARTICLE_BEAM_FOR_SEARCHING = false; var USE_PARTICLE_BEAM_FOR_MOVING = false; -var USE_SPOTLIGHT = false; +var USE_SPOTLIGHT = true; var USE_POINTLIGHT = false; // states for the state machine @@ -436,10 +436,8 @@ function MyController(hand) { var finalRotation = Quat.multiply(orientation, rotation); if (this.particleBeam === null) { - print('create beam') this.createParticleBeam(position, finalRotation, color); } else { - print('update beam') this.updateParticleBeam(position, finalRotation, color); } } @@ -590,11 +588,8 @@ function MyController(hand) { this.spotlight = Entities.addEntity(lightProperties); } else { Entities.editEntity(this.spotlight, { - parentID: parentID, - position: lightTransform.p, //without this, this light would maintain rotation with its parent rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), - visible: true }) } } @@ -627,16 +622,9 @@ function MyController(hand) { }; if (this.pointlight === null) { - - print('create pointlight') this.pointlight = Entities.addEntity(lightProperties); } else { - print('update pointlight') - Entities.editEntity(this.pointlight, { - parentID: parentID, - position: lightTransform.p, - visible: true - }) + } } @@ -665,19 +653,13 @@ function MyController(hand) { this.turnLightsOff = function() { //use visibility for now instead of creating and deleting since deleting seems to crash if (this.spotlight !== null) { - Entities.editEntity(this.spotlight, { - visible: false - }) - //Entities.deleteEntity(this.spotlight); - //this.spotLight=null; + Entities.deleteEntity(this.spotlight); + this.spotlight = null; } if (this.pointlight !== null) { - Entities.editEntity(this.pointlight, { - visible: false - }) - //Entities.deleteEntity(this.pointlight); - //this.pointlight = null; + Entities.deleteEntity(this.pointlight); + this.pointlight = null; } } From 70a0e51cc9b5898dc49b1134f84a6f96d50b7aff Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Dec 2015 17:59:03 -0800 Subject: [PATCH 030/209] back to default state --- examples/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index ae95ab47fd..fc217de03a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -122,7 +122,7 @@ var USE_ENTITY_LASERS_FOR_MOVING = true; var USE_OVERLAY_LINES_FOR_SEARCHING = true; var USE_PARTICLE_BEAM_FOR_SEARCHING = false; var USE_PARTICLE_BEAM_FOR_MOVING = false; -var USE_SPOTLIGHT = true; +var USE_SPOTLIGHT = false; var USE_POINTLIGHT = false; // states for the state machine From cb948e0608502d38cafac927b682d9759818ee23 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sat, 12 Dec 2015 21:15:06 +0100 Subject: [PATCH 031/209] allow entity scripts to attach entities to a hand with handControllerGrab.js --- examples/controllers/handControllerGrab.js | 40 +++++++++++++--------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 138240f5d6..7976e5286f 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -968,7 +968,6 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); Entities.callEntityMethod(this.grabbedEntity, "unequip"); this.endHandGrasp(); - } }; @@ -1288,33 +1287,40 @@ function update() { if (handToDisable !== LEFT_HAND && handToDisable!=='both') { leftController.update(); } - if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { + if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { rightController.update(); } } Messages.subscribe('Hifi-Hand-Disabler'); +Messages.subscribe('Hifi-Hand-Grab'); -handleHandDisablerMessages = function(channel, message, sender) { - +handleHandMessages = function(channel, message, sender) { if (sender === MyAvatar.sessionUUID) { - if (message === 'left') { - handToDisable = LEFT_HAND; - } - if (message === 'right') { - handToDisable = RIGHT_HAND; - } - if(message==='both'){ - handToDisable='both'; - } - if(message==='none'){ - handToDisable='none'; + if (channel === 'Hifi-Hand-Disabler') { + if (message === 'left') { + handToDisable = LEFT_HAND; + } + if (message === 'right') { + handToDisable = RIGHT_HAND; + } + if (message === 'both' || message === 'none') { + handToDisable = handToDisable; + } + } else if (channel === 'Hifi-Hand-Grab') { + try { + var data = JSON.parse(message); + var selectedController = (data.hand === 'left') ? leftController : rightController; + selectedController.release(); + selectedController.setState(STATE_EQUIP); + selectedController.grabbedEntity = data.entityID; + + } catch (e) { } } } - } -Messages.messageReceived.connect(handleHandDisablerMessages); +Messages.messageReceived.connect(handleHandMessages); function cleanup() { rightController.cleanup(); From fe05542440f2c74668cbec2859c2c8227eb91e42 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 14:30:34 -0800 Subject: [PATCH 032/209] more vis --- examples/controllers/handControllerGrab.js | 80 ++++++++++++---------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index fc217de03a..afad62412e 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1,5 +1,4 @@ // handControllerGrab.js -// examples // // Created by Eric Levin on 9/2/15 // Additions by James B. Pollack @imgntn on 9/24/2015 @@ -7,6 +6,7 @@ // Copyright 2015 High Fidelity, Inc. // // Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// Also supports touch and equipping objects. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -14,7 +14,6 @@ Script.include("../libraries/utils.js"); - // // add lines where the hand ray picking is happening // @@ -54,6 +53,7 @@ var LINE_ENTITY_DIMENSIONS = { y: 1000, z: 1000 }; + var LINE_LENGTH = 500; var PICK_MAX_DISTANCE = 500; // max length of pick-ray @@ -120,6 +120,7 @@ var DEFAULT_GRABBABLE_DATA = { var USE_ENTITY_LASERS_FOR_SEARCHING = false; var USE_ENTITY_LASERS_FOR_MOVING = true; var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_OVERLAY_LINES_FOR_MOVING = false; var USE_PARTICLE_BEAM_FOR_SEARCHING = false; var USE_PARTICLE_BEAM_FOR_MOVING = false; var USE_SPOTLIGHT = false; @@ -345,7 +346,7 @@ function MyController(hand) { print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); } this.state = newState; - } + }; this.debugLine = function(closePoint, farPoint, color) { Entities.addEntity({ @@ -365,7 +366,7 @@ function MyController(hand) { } }) }); - } + }; this.lineOn = function(closePoint, farPoint, color) { // draw a line @@ -423,7 +424,7 @@ function MyController(hand) { alpha: 1 }); } - } + }; this.handleParticleBeam = function(position, orientation, color) { @@ -440,7 +441,7 @@ function MyController(hand) { } else { this.updateParticleBeam(position, finalRotation, color); } - } + }; this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { @@ -458,7 +459,7 @@ function MyController(hand) { } else { this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); } - } + }; this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { @@ -521,7 +522,7 @@ function MyController(hand) { } this.particleBeam = Entities.addEntity(particleBeamProperties); - } + }; this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { @@ -535,7 +536,7 @@ function MyController(hand) { }) - } + }; this.evalLightWorldTransform = function(modelPos, modelRot) { @@ -555,7 +556,7 @@ function MyController(hand) { p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) }; - } + }; this.handleSpotlight = function(parentID, position) { var LIFETIME = 100; @@ -592,7 +593,7 @@ function MyController(hand) { rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), }) } - } + }; this.handlePointLight = function(parentID, position) { var LIFETIME = 100; @@ -626,7 +627,7 @@ function MyController(hand) { } else { } - } + }; this.lineOff = function() { if (this.pointer !== null) { @@ -651,7 +652,6 @@ function MyController(hand) { } this.turnLightsOff = function() { - //use visibility for now instead of creating and deleting since deleting seems to crash if (this.spotlight !== null) { Entities.deleteEntity(this.spotlight); this.spotlight = null; @@ -661,7 +661,22 @@ function MyController(hand) { Entities.deleteEntity(this.pointlight); this.pointlight = null; } - } + }; + + + this.turnOffVisualizations = function() { + if (USE_ENTITY_LASERS_FOR_SEARCHING === true || USE_ENTITY_LASERS_FOR_MOVING === true) { + this.lineOff(); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + }; this.triggerPress = function(value) { _this.rawTriggerValue = value; @@ -693,11 +708,11 @@ function MyController(hand) { this.bumperSqueezed = function() { return _this.rawBumperValue > BUMPER_ON_VALUE; - } + }; this.bumperReleased = function() { return _this.rawBumperValue < BUMPER_ON_VALUE; - } + }; this.off = function() { if (this.triggerSmoothedSqueezed()) { @@ -710,7 +725,7 @@ function MyController(hand) { this.setState(STATE_EQUIP_SEARCHING); return; } - } + }; this.search = function() { this.grabbedEntity = null; @@ -977,19 +992,6 @@ function MyController(hand) { this.turnOffVisualizations(); }; - this.turnOffVisualizations = function() { - if (USE_ENTITY_LASERS_FOR_SEARCHING === true || USE_ENTITY_LASERS_FOR_MOVING === true) { - this.lineOff(); - } - if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOff(); - } - - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.particleBeamOff(); - } - } - this.continueDistanceHolding = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); @@ -1100,14 +1102,15 @@ function MyController(hand) { if (USE_ENTITY_LASERS_FOR_MOVING === true) { this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); } + if (USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) } - if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); } - if (USE_SPOTLIGHT === true) { this.handleSpotlight(this.grabbedEntity); } @@ -1399,6 +1402,7 @@ function MyController(hand) { }; _this.allTouchedIDs = {}; + this.touchTest = function() { var maxDistance = 0.05; var leftHandPosition = MyAvatar.getLeftPalmPosition(); @@ -1559,28 +1563,29 @@ function MyController(hand) { } //return an object with our updated settings return result; - } + }; this.graspHandler = null + this.startHandGrasp = function() { if (this.hand === RIGHT_HAND) { this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); } else if (this.hand === LEFT_HAND) { this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); } - } + }; this.endHandGrasp = function() { // Tell the animation system we don't need any more callbacks. MyAvatar.removeAnimationStateHandler(this.graspHandler); - } + }; -} +}; var rightController = new MyController(RIGHT_HAND); var leftController = new MyController(LEFT_HAND); -//reload the particle beams +//preload the particle beams so that they are full length when you start searching if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { rightController.createParticleBeam(); leftController.createParticleBeam(); @@ -1597,6 +1602,7 @@ mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); Controller.enableMapping(MAPPING_NAME); +//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items var handToDisable = 'none'; function update() { From 0fe4803b04dc9e2554d1ef5335ce98e498c05cde Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 16:17:00 -0800 Subject: [PATCH 033/209] start --- examples/lights/box.js | 31 +++++++++ examples/lights/light_modifier.js | 103 ++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 examples/lights/box.js create mode 100644 examples/lights/light_modifier.js diff --git a/examples/lights/box.js b/examples/lights/box.js new file mode 100644 index 0000000000..711f5487b2 --- /dev/null +++ b/examples/lights/box.js @@ -0,0 +1,31 @@ +(function() { + + function Box () { + this.oldColor = {}; + this.oldColorKnown = false; + } + + Box.prototype = { + preload: function(entityID) { + print("preload"); + + this.entityID = entityID; + this.storeOldColor(entityID); + }, + startDistantGrab:function(){ + + }, + continueDistantGrab:function(){ + + }, + releaseGrab:function(){ + + } + setHand:function(){ + + } + + }; + + return new Box(); +}); \ No newline at end of file diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js new file mode 100644 index 0000000000..fd49690088 --- /dev/null +++ b/examples/lights/light_modifier.js @@ -0,0 +1,103 @@ +// given a selected light, instantiate some entities that represent various values you can dynamically adjust +// + +var BOX_SCRIPT_URL = Script.resolvePath('box.js'); + +function entitySlider(color) { + this.color = color; + return this; +} + +var RED = { + r: 255, + g: 0, + b: 0 +}; + +var GREEN = { + r: 0, + g: 255, + b: 0 +}; + +var BLUE = { + r: 0, + g: 0, + b: 255 +}; + +var PURPLE = { + r: 255, + g: 0, + b: 255 +}; + +var WHITE = { + r: 255 + g: 255, + b: 255 +}; + +//what's the ux for adjusting values? start with simple entities, try image overlays etc +entitySlider.prototype = { + createAxis: function() { + var properties = { + type: 'Line', + color: this.color, + collisionsWillMove: false, + ignoreForCollisions: true, + }; + + this.axis = Entities.addEntity(properties); + }, + createBoxIndicator: function() { + var properties = { + type: 'Box', + dimensions: { + x: 0.04, + y: 0.04, + z: 0.04 + }, + color: this.color, + position: position, + script: BOX_SCRIPT_URL + }; + + + + this.boxIndicator = Entities.addEntity(properties); + }, + moveIndicatorAlongAxis: function(direction) { + + } +}; + +//create them for this light +function makeSliders(light) { + if (light.type === 'spotlight') { + var USE_COLOR_SLIDER = true; + var USE_INTENSITY_SLIDER = true; + var USE_CUTOFF_SLIDER = true; + var USE_EXPONENT_SLIDER = true; + } + if (light.type === 'pointlight') { + var USE_COLOR_SLIDER = true; + var USE_INTENSITY_SLIDER = true; + var USE_CUTOFF_SLIDER = false; + var USE_EXPONENT_SLIDER = false; + } + if (USE_COLOR_SLIDER === true) { + var r = new entitySlider(RED); + var g = new entitySlider(GREEN); + var b = new entitySlider(BLUE); + } + if (USE_INTENSITY_SLIDER === true) { + var intensity = new entitySlider(WHITE); + } + if (USE_CUTOFF_SLIDER === true) { + var cutoff = new entitySlider(PURPLE); + } + if (USE_EXPONENT_SLIDER === true) { + var exponent = new entitySlider(PURPLE); + } +}; \ No newline at end of file From 0ddc2ba76e22359f202cb2205efbf6da24ec08a1 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 16:18:15 -0800 Subject: [PATCH 034/209] rename lasers to lines --- examples/controllers/handControllerGrab.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index afad62412e..f8fe1b821c 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -117,8 +117,8 @@ var DEFAULT_GRABBABLE_DATA = { }; //we've created various ways of visualizing looking for and moving distant objects -var USE_ENTITY_LASERS_FOR_SEARCHING = false; -var USE_ENTITY_LASERS_FOR_MOVING = true; +var USE_ENTITY_LINES_FOR_SEARCHING = false; +var USE_ENTITY_LINES_FOR_MOVING = true; var USE_OVERLAY_LINES_FOR_SEARCHING = true; var USE_OVERLAY_LINES_FOR_MOVING = false; var USE_PARTICLE_BEAM_FOR_SEARCHING = false; @@ -665,7 +665,7 @@ function MyController(hand) { this.turnOffVisualizations = function() { - if (USE_ENTITY_LASERS_FOR_SEARCHING === true || USE_ENTITY_LASERS_FOR_MOVING === true) { + if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { this.lineOff(); } @@ -925,7 +925,7 @@ function MyController(hand) { } //search line visualizations - if (USE_ENTITY_LASERS_FOR_SEARCHING === true) { + if (USE_ENTITY_LINES_FOR_SEARCHING === true) { this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } @@ -1099,7 +1099,7 @@ function MyController(hand) { //visualizations - if (USE_ENTITY_LASERS_FOR_MOVING === true) { + if (USE_ENTITY_LINES_FOR_MOVING === true) { this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); } if (USE_OVERLAY_LINES_FOR_MOVING === true) { From 7cace240025b3f950a91cbf072e2dbd664fa3235 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 17:14:43 -0800 Subject: [PATCH 035/209] light editing framework --- examples/lights/box.js | 65 ++++++++++++----- examples/lights/light_modifier.js | 116 +++++++++++++++++++++++++----- 2 files changed, 148 insertions(+), 33 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index 711f5487b2..3a24ef1568 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -1,29 +1,62 @@ (function() { - function Box () { - this.oldColor = {}; - this.oldColorKnown = false; + function Box() { + return this; } Box.prototype = { preload: function(entityID) { - print("preload"); - this.entityID = entityID; - this.storeOldColor(entityID); }, - startDistantGrab:function(){ - + startNearGrab: function() { + this.setInitialProperties(); }, - continueDistantGrab:function(){ - + startDistantGrab: function() { + this.setInitialProperties(); }, - releaseGrab:function(){ - - } - setHand:function(){ - - } + setInitialProperties: function() { + this.initialProperties = Entities.getEntityProperties(this.entityID); + }, + getClampedPosition: function() { + return position; + }, + getClampedRotation: function() { + var rotation = initialProperties.rotation; + return rotation; + }, + continueDistantGrab: function() { + var currentPosition = this.getClampedPosition(); + var distance = Vec3.distance(this.initialProperties.position, currentPosition); + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance); + Entities.editEntity(this.entityID) { + position: currentPosition, + rotation: this.getClampedRotation() + } + }, + releaseGrab: function() { + Entities.editEntity(this.entityID, { + velocity: { + x: 0, + y: 0, + z: 0 + } + }) + this.sendValueToSlider(); + }, + scaleValueBasedOnDistanceFromStart: function(value, min1, max1, min2, max2) { + var min1 = 0; + var max1 = 1; + var min2 = 0; + var max2 = 255; + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); + }, + sendValueToSlider: function() { + var message = { + lightID: this.entityID, + sliderValue: this.sliderValue + } + Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); + }; }; diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index fd49690088..71d3d38c64 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -3,8 +3,10 @@ var BOX_SCRIPT_URL = Script.resolvePath('box.js'); -function entitySlider(color) { +function entitySlider(color, sliderType, verticalOffset) { this.color = color; + this.sliderType = sliderType; + this.verticalOffset = verticalOffset; return this; } @@ -38,6 +40,13 @@ var WHITE = { b: 255 }; +var AXIS_SCALE = 1; +var BOX_DIMENSIONS = { + x: 0.04, + y: 0.04, + z: 0.04 +} + //what's the ux for adjusting values? start with simple entities, try image overlays etc entitySlider.prototype = { createAxis: function() { @@ -53,27 +62,98 @@ entitySlider.prototype = { createBoxIndicator: function() { var properties = { type: 'Box', - dimensions: { - x: 0.04, - y: 0.04, - z: 0.04 - }, + dimensions: BOX_DIMENSIONS, color: this.color, position: position, script: BOX_SCRIPT_URL }; - - this.boxIndicator = Entities.addEntity(properties); }, - moveIndicatorAlongAxis: function(direction) { + handleValueMessages: function(channel, message, sender) { + //easily protect from other people editing your values, but group editing might be fun so lets try that first. + // if (sender !== MyAvatar.sessionUUID) { + // return; + // } + var parsedMessage = JSON.parse(message); + setValueFromMessage(parsedMessage); + }, + setValueFromMessage: function(message) { + var lightProperties = Entities.getEntitiyProperties(message.lightID); + if (this.sliderType === 'color_red') { + Entities.editEntity(message.lightID, { + color: { + red: message.sliderValue, + green: lightProperties.color.g, + blue: lightProperties.color.b + } + }) + } + + if (this.sliderType === 'color_green') { + Entities.editEntity(message.lightID, { + color: { + red: lightProperties.color.r + green: message.sliderValue, + blue: lightProperties.color.b + } + }) + } + + if (this.sliderType === 'color_blue') { + Entities.editEntity(message.lightID, { + color: { + red: lightProperties.color.r, + green: lightProperties.color.g, + blue: message.sliderValue, + } + }) + } + + if (this.sliderType === 'intensity') { + Entities.editEntity(message.lightID, { + intensity: message.sliderValue + }) + } + + if (this.sliderType === 'cutoff') { + Entities.editEntity(message.lightID, { + cutoff: message.sliderValue + }) + } + + if (this.sliderType === 'exponent') { + Entities.editEntity(message.lightID, { + exponent: message.sliderValue + }) + } + }, + subscribeToBoxMessages: function() { + Messages.subscribe('Hifi-Slider-Value-Reciever'); + Messages.messageReceived.connect(this.handleValueMessages); + }, + cleanup: function() { + Entities.deleteEntity(this.boxIndicator); + Entities.deleteEntity(this.axis); + Messages.messageReceived.disconnect(this.handleValueMessages); } }; -//create them for this light +//create them for a given light function makeSliders(light) { + var initialPosition = { + x: 0, + y: 0, + z: 0 + }; + + var perRowOffset = { + x: 0, + y: 0.2, + z: 0 + }; + if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -87,17 +167,19 @@ function makeSliders(light) { var USE_EXPONENT_SLIDER = false; } if (USE_COLOR_SLIDER === true) { - var r = new entitySlider(RED); - var g = new entitySlider(GREEN); - var b = new entitySlider(BLUE); + var r = new entitySlider(RED, 'color_red', Vec3.multiply(1, perRowOffset)); + var g = new entitySlider(GREEN, 'color_green', Vec3.multiply(2, perRowOffset)); + var b = new entitySlider(BLUE, 'color_blue', Vec3.multiply(3, perRowOffset)); } if (USE_INTENSITY_SLIDER === true) { - var intensity = new entitySlider(WHITE); + var intensity = new entitySlider(WHITE, 'intensity', Vec3.multiply(4, perRowOffset)); } if (USE_CUTOFF_SLIDER === true) { - var cutoff = new entitySlider(PURPLE); + var cutoff = new entitySlider(PURPLE, 'cutoff', Vec3.multiply(5, perRowOffset)); } if (USE_EXPONENT_SLIDER === true) { - var exponent = new entitySlider(PURPLE); + var exponent = new entitySlider(PURPLE, 'exponent', Vec3.multiply(6, perRowOffset)); } -}; \ No newline at end of file +}; + +makeSliders(light) \ No newline at end of file From 231bcdb8f0fbf0eb8b608f3f89e9f64ed6098f54 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 17:22:57 -0800 Subject: [PATCH 036/209] name some things better and cleanup --- examples/lights/box.js | 4 +- examples/lights/light_modifier.js | 74 +++++++++++++++---------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index 3a24ef1568..27bffe6e33 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -28,6 +28,7 @@ var currentPosition = this.getClampedPosition(); var distance = Vec3.distance(this.initialProperties.position, currentPosition); this.sliderValue = scaleValueBasedOnDistanceFromStart(distance); + Entities.editEntity(this.entityID) { position: currentPosition, rotation: this.getClampedRotation() @@ -41,6 +42,7 @@ z: 0 } }) + this.sendValueToSlider(); }, scaleValueBasedOnDistanceFromStart: function(value, min1, max1, min2, max2) { @@ -52,7 +54,7 @@ }, sendValueToSlider: function() { var message = { - lightID: this.entityID, + boxID: this.entityID, sliderValue: this.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index 71d3d38c64..9c841eeb24 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -3,10 +3,11 @@ var BOX_SCRIPT_URL = Script.resolvePath('box.js'); -function entitySlider(color, sliderType, verticalOffset) { +function entitySlider(light, color, sliderType, row) { + this.light = light; this.color = color; this.sliderType = sliderType; - this.verticalOffset = verticalOffset; + this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET);; return this; } @@ -42,20 +43,27 @@ var WHITE = { var AXIS_SCALE = 1; var BOX_DIMENSIONS = { - x: 0.04, - y: 0.04, - z: 0.04 -} + x: 0.05, + y: 0.05, + z: 0.05 +}; +var PER_ROW_OFFSET = { + x: 0, + y: 0.2, + z: 0 +}; //what's the ux for adjusting values? start with simple entities, try image overlays etc entitySlider.prototype = { createAxis: function() { - var properties = { - type: 'Line', - color: this.color, - collisionsWillMove: false, - ignoreForCollisions: true, - }; + var position = + var properties = { + type: 'Line', + color: this.color, + collisionsWillMove: false, + ignoreForCollisions: true, + position: position, + }; this.axis = Entities.addEntity(properties); }, @@ -79,54 +87,54 @@ entitySlider.prototype = { setValueFromMessage(parsedMessage); }, setValueFromMessage: function(message) { - var lightProperties = Entities.getEntitiyProperties(message.lightID); + var lightProperties = Entities.getEntityProperties(this.lightID); if (this.sliderType === 'color_red') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { color: { red: message.sliderValue, green: lightProperties.color.g, blue: lightProperties.color.b } - }) + }); } if (this.sliderType === 'color_green') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { color: { red: lightProperties.color.r green: message.sliderValue, blue: lightProperties.color.b } - }) + }); } if (this.sliderType === 'color_blue') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { color: { red: lightProperties.color.r, green: lightProperties.color.g, blue: message.sliderValue, } - }) + }); } if (this.sliderType === 'intensity') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { intensity: message.sliderValue - }) + }); } if (this.sliderType === 'cutoff') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { cutoff: message.sliderValue - }) + }); } if (this.sliderType === 'exponent') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { exponent: message.sliderValue - }) + }); } }, subscribeToBoxMessages: function() { @@ -142,17 +150,6 @@ entitySlider.prototype = { //create them for a given light function makeSliders(light) { - var initialPosition = { - x: 0, - y: 0, - z: 0 - }; - - var perRowOffset = { - x: 0, - y: 0.2, - z: 0 - }; if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; @@ -167,7 +164,7 @@ function makeSliders(light) { var USE_EXPONENT_SLIDER = false; } if (USE_COLOR_SLIDER === true) { - var r = new entitySlider(RED, 'color_red', Vec3.multiply(1, perRowOffset)); + var r = new entitySlider(RED, 'color_red', 1); var g = new entitySlider(GREEN, 'color_green', Vec3.multiply(2, perRowOffset)); var b = new entitySlider(BLUE, 'color_blue', Vec3.multiply(3, perRowOffset)); } @@ -182,4 +179,5 @@ function makeSliders(light) { } }; -makeSliders(light) \ No newline at end of file + +makeSliders(light); \ No newline at end of file From 77969e14810ab20d689dff5e65c3bcd6591b65d9 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 17:31:49 -0800 Subject: [PATCH 037/209] breaktime --- examples/lights/light_modifier.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index 9c841eeb24..d6c964bf55 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -179,5 +179,4 @@ function makeSliders(light) { } }; - makeSliders(light); \ No newline at end of file From a0b698c0283ce162720ad13465d04ccb8105439d Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 17:33:54 -0800 Subject: [PATCH 038/209] reorg props --- examples/controllers/handControllerGrab.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f8fe1b821c..382d5cac7a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -118,11 +118,13 @@ var DEFAULT_GRABBABLE_DATA = { //we've created various ways of visualizing looking for and moving distant objects var USE_ENTITY_LINES_FOR_SEARCHING = false; -var USE_ENTITY_LINES_FOR_MOVING = true; var USE_OVERLAY_LINES_FOR_SEARCHING = true; -var USE_OVERLAY_LINES_FOR_MOVING = false; var USE_PARTICLE_BEAM_FOR_SEARCHING = false; + +var USE_ENTITY_LINES_FOR_MOVING = true; +var USE_OVERLAY_LINES_FOR_MOVING = false; var USE_PARTICLE_BEAM_FOR_MOVING = false; + var USE_SPOTLIGHT = false; var USE_POINTLIGHT = false; From ab5b783cb7dbb3bf6f1878bf2f2e134ef331406e Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 14 Dec 2015 09:01:45 -0800 Subject: [PATCH 039/209] zone tweal --- examples/flowArts/lightTrails.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index e063897eb8..8e0dc98bbb 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -23,7 +23,7 @@ var MAX_POINTS_PER_LINE = 50; var LIFETIME = 6000; var DRAWING_DEPTH = 0.8; -var LINE_DIMENSIONS = 20; +var LINE_DIMENSIONS = 100; var lightZone = Entities.addEntity({ type: "Zone", @@ -78,9 +78,9 @@ function controller(side, triggerAction) { type: 'Light', position: MyAvatar.position, dimensions: { - x: 20, - y: 20, - z: 20 + x: 30, + y: 30, + z: 30 }, color: colorPalette[randInt(0, colorPalette.length)], intensity: 5 From 1698e903c94ef65de1366e30de692beafc3352c9 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 11:25:30 -0800 Subject: [PATCH 040/209] midday --- examples/lights/box.js | 6 +- examples/lights/light_modifier.js | 114 ++++++++++++++++++++++++------ 2 files changed, 96 insertions(+), 24 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index 27bffe6e33..ac3cac7ab3 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -18,7 +18,11 @@ this.initialProperties = Entities.getEntityProperties(this.entityID); }, getClampedPosition: function() { - return position; + dPosition = Vec3.subtract(MyAvatar.position, previousPosition); + //convert to localFrame + dPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), dPosition); + + return dPosition; }, getClampedRotation: function() { var rotation = initialProperties.rotation; diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index d6c964bf55..6ae702bf7f 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -3,14 +3,6 @@ var BOX_SCRIPT_URL = Script.resolvePath('box.js'); -function entitySlider(light, color, sliderType, row) { - this.light = light; - this.color = color; - this.sliderType = sliderType; - this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET);; - return this; -} - var RED = { r: 255, g: 0, @@ -42,6 +34,7 @@ var WHITE = { }; var AXIS_SCALE = 1; + var BOX_DIMENSIONS = { x: 0.05, y: 0.05, @@ -53,17 +46,54 @@ var PER_ROW_OFFSET = { z: 0 }; +function entitySlider(light, color, sliderType, row) { + this.light = light; + this.lightID = light.id; + this.initialProperties = light.initialProperties; + this.color = color; + this.sliderType = sliderType; + this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); + + var formattedMessage = { + 'color_red': this.initialProperties.color.r, + 'color_green': this.initialProperties.color.g, + 'color_blue': this.initialProperties.color.b, + 'intensity': this.initialProperties.intensity, + 'exponent': this.initialProperties.exponent, + 'cutoff': this.initialProperties.cutoff, + } + + this.setValueFromMessage(formattedMessage); + this.setInitialSliderPositions(); + + return this; +} + //what's the ux for adjusting values? start with simple entities, try image overlays etc entitySlider.prototype = { createAxis: function() { - var position = - var properties = { - type: 'Line', - color: this.color, - collisionsWillMove: false, - ignoreForCollisions: true, - position: position, - }; + //start of line + var position; + //1 meter along orientationAxis + var endOfAxis; + var properties = { + type: 'Line', + color: this.color, + collisionsWillMove: false, + ignoreForCollisions: true, + dimensions: { + x: 3, + y: 3, + z: 3 + }, + position: position, + linePoints: [{ + x: 0, + y: 0, + z: 0 + }, endOfAxis], + lineWidth: 5, + }; this.axis = Entities.addEntity(properties); }, @@ -79,6 +109,9 @@ entitySlider.prototype = { this.boxIndicator = Entities.addEntity(properties); }, handleValueMessages: function(channel, message, sender) { + if (channel !== 'Hifi-Slider-Value-Reciever') { + return; + } //easily protect from other people editing your values, but group editing might be fun so lets try that first. // if (sender !== MyAvatar.sessionUUID) { // return; @@ -141,6 +174,15 @@ entitySlider.prototype = { Messages.subscribe('Hifi-Slider-Value-Reciever'); Messages.messageReceived.connect(this.handleValueMessages); }, + setInitialSliderPositions:function(){ + + var distanceRed = (this.initialProperties.color.r / 255) * AXIS_SCALE; + var distanceGreen = (this.initialProperties.color.g / 255) * AXIS_SCALE; + var distanceBlue = (this.initialProperties.color.b / 255) * AXIS_SCALE; + var distanceIntensity = (this.initialProperties.intensity / 255) * AXIS_SCALE; + var distanceCutoff = (this.initialProperties.cutoff / 360) * AXIS_SCALE; + var distanceExponent = (this.initialProperties.exponent / 255) * AXIS_SCALE; + }, cleanup: function() { Entities.deleteEntity(this.boxIndicator); Entities.deleteEntity(this.axis); @@ -150,7 +192,6 @@ entitySlider.prototype = { //create them for a given light function makeSliders(light) { - if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -165,18 +206,45 @@ function makeSliders(light) { } if (USE_COLOR_SLIDER === true) { var r = new entitySlider(RED, 'color_red', 1); - var g = new entitySlider(GREEN, 'color_green', Vec3.multiply(2, perRowOffset)); - var b = new entitySlider(BLUE, 'color_blue', Vec3.multiply(3, perRowOffset)); + var g = new entitySlider(GREEN, 'color_green', 2); + var b = new entitySlider(BLUE, 'color_blue', 3); } if (USE_INTENSITY_SLIDER === true) { - var intensity = new entitySlider(WHITE, 'intensity', Vec3.multiply(4, perRowOffset)); + var intensity = new entitySlider(WHITE, 'intensity', 4); } if (USE_CUTOFF_SLIDER === true) { - var cutoff = new entitySlider(PURPLE, 'cutoff', Vec3.multiply(5, perRowOffset)); + var cutoff = new entitySlider(PURPLE, 'cutoff', 5); } if (USE_EXPONENT_SLIDER === true) { - var exponent = new entitySlider(PURPLE, 'exponent', Vec3.multiply(6, perRowOffset)); + var exponent = new entitySlider(PURPLE, 'exponent', 6); } }; -makeSliders(light); \ No newline at end of file +function subScribeToNewLights() { + Messages.subscribe('Hifi-Light-Mod-Receiver'); + Messages.messageReceived.connect(handleLightModMessages); +} + +function handleLightModMessages(channel, message, sender) { + if (channel !== 'Hifi-Light-Mod-Receiver') { + return; + } + if (sender !== MyAvatar.sessionUUID) { + return; + } + var parsedMessage = JSON.parse(message); + var light = message.light; + makeSliders(light); +} + +subScribeToNewLights(); + + // diffuseColor: { red: 255, green: 255, blue: 255 }, + // ambientColor: { red: 255, green: 255, blue: 255 }, + // specularColor: { red: 255, green: 255, blue: 255 }, + + // constantAttenuation: 1, + // linearAttenuation: 0, + // quadraticAttenuation: 0, + // exponent: 0, + // cutoff: 180, // in degrees \ No newline at end of file From e43b60f9f54c27b72e2377f32defe489647a415f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 11:40:47 -0800 Subject: [PATCH 041/209] other variations --- examples/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 382d5cac7a..cd82db22b9 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1105,7 +1105,7 @@ function MyController(hand) { this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); } if (USE_OVERLAY_LINES_FOR_MOVING === true) { - this.overlayLineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) From 4d9cb6a6df3f3c07866ca4d6fa2170b939f7196b Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 11:41:34 -0800 Subject: [PATCH 042/209] other variations --- .../handControllerGrab-all-overlays.js | 1649 +++++++++++++++++ .../handControllerGrab-particles.js | 1649 +++++++++++++++++ .../handControllerGrab-pointlight.js | 1649 +++++++++++++++++ .../handControllerGrab-spotlight.js | 1649 +++++++++++++++++ 4 files changed, 6596 insertions(+) create mode 100644 examples/controllers/handControllerGrab-all-overlays.js create mode 100644 examples/controllers/handControllerGrab-particles.js create mode 100644 examples/controllers/handControllerGrab-pointlight.js create mode 100644 examples/controllers/handControllerGrab-spotlight.js diff --git a/examples/controllers/handControllerGrab-all-overlays.js b/examples/controllers/handControllerGrab-all-overlays.js new file mode 100644 index 0000000000..acb47b2260 --- /dev/null +++ b/examples/controllers/handControllerGrab-all-overlays.js @@ -0,0 +1,1649 @@ +// handControllerGrab.js +// +// Created by Eric Levin on 9/2/15 +// Additions by James B. Pollack @imgntn on 9/24/2015 +// Additions By Seth Alves on 10/20/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// Also supports touch and equipping objects. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ + +Script.include("../libraries/utils.js"); + +// +// add lines where the hand ray picking is happening +// +var WANT_DEBUG = false; + +// +// these tune time-averaging and "on" value for analog trigger +// + +var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value +var TRIGGER_ON_VALUE = 0.4; +var TRIGGER_OFF_VALUE = 0.15; + +var BUMPER_ON_VALUE = 0.5; + +// +// distant manipulation +// + +var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects + +var NO_INTERSECT_COLOR = { + red: 10, + green: 10, + blue: 255 +}; // line color when pick misses +var INTERSECT_COLOR = { + red: 250, + green: 10, + blue: 10 +}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { + x: 1000, + y: 1000, + z: 1000 +}; + +var LINE_LENGTH = 500; +var PICK_MAX_DISTANCE = 500; // max length of pick-ray + +// +// near grabbing +// + +var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected +var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. +var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected +var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things +var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object +var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed + +// +// equip +// + +var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; +var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position + +// +// other constants +// + +var RIGHT_HAND = 1; +var LEFT_HAND = 0; + +var ZERO_VEC = { + x: 0, + y: 0, + z: 0 +}; + +var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; +var MSEC_PER_SEC = 1000.0; + +// these control how long an abandoned pointer line or action will hang around +var LIFETIME = 10; +var ACTION_TTL = 15; // seconds +var ACTION_TTL_REFRESH = 5; +var PICKS_PER_SECOND_PER_HAND = 5; +var MSECS_PER_SEC = 1000.0; +var GRABBABLE_PROPERTIES = [ + "position", + "rotation", + "gravity", + "ignoreForCollisions", + "collisionsWillMove", + "locked", + "name" +]; + +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js + +var DEFAULT_GRABBABLE_DATA = { + grabbable: true, + invertSolidWhileHeld: false +}; + +//we've created various ways of visualizing looking for and moving distant objects +var USE_ENTITY_LINES_FOR_SEARCHING = false; +var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_PARTICLE_BEAM_FOR_SEARCHING = false; + +var USE_ENTITY_LINES_FOR_MOVING = false; +var USE_OVERLAY_LINES_FOR_MOVING = true; +var USE_PARTICLE_BEAM_FOR_MOVING = false; + +var USE_SPOTLIGHT = false; +var USE_POINTLIGHT = false; + +// states for the state machine +var STATE_OFF = 0; +var STATE_SEARCHING = 1; +var STATE_DISTANCE_HOLDING = 2; +var STATE_CONTINUE_DISTANCE_HOLDING = 3; +var STATE_NEAR_GRABBING = 4; +var STATE_CONTINUE_NEAR_GRABBING = 5; +var STATE_NEAR_TRIGGER = 6; +var STATE_CONTINUE_NEAR_TRIGGER = 7; +var STATE_FAR_TRIGGER = 8; +var STATE_CONTINUE_FAR_TRIGGER = 9; +var STATE_RELEASE = 10; +var STATE_EQUIP_SEARCHING = 11; +var STATE_EQUIP = 12 +var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down +var STATE_CONTINUE_EQUIP = 14; +var STATE_WAITING_FOR_BUMPER_RELEASE = 15; +var STATE_EQUIP_SPRING = 16; + + + +function stateToName(state) { + switch (state) { + case STATE_OFF: + return "off"; + case STATE_SEARCHING: + return "searching"; + case STATE_DISTANCE_HOLDING: + return "distance_holding"; + case STATE_CONTINUE_DISTANCE_HOLDING: + return "continue_distance_holding"; + case STATE_NEAR_GRABBING: + return "near_grabbing"; + case STATE_CONTINUE_NEAR_GRABBING: + return "continue_near_grabbing"; + case STATE_NEAR_TRIGGER: + return "near_trigger"; + case STATE_CONTINUE_NEAR_TRIGGER: + return "continue_near_trigger"; + case STATE_FAR_TRIGGER: + return "far_trigger"; + case STATE_CONTINUE_FAR_TRIGGER: + return "continue_far_trigger"; + case STATE_RELEASE: + return "release"; + case STATE_EQUIP_SEARCHING: + return "equip_searching"; + case STATE_EQUIP: + return "equip"; + case STATE_CONTINUE_EQUIP_BD: + return "continue_equip_bd"; + case STATE_CONTINUE_EQUIP: + return "continue_equip"; + case STATE_WAITING_FOR_BUMPER_RELEASE: + return "waiting_for_bumper_release"; + case STATE_EQUIP_SPRING: + return "state_equip_spring"; + } + + return "unknown"; +} + +function getTag() { + return "grab-" + MyAvatar.sessionUUID; +} + +function entityIsGrabbedByOther(entityID) { + // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. + var actionIDs = Entities.getActionIDs(entityID); + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments["tag"]; + if (tag == getTag()) { + // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. + continue; + } + if (tag.slice(0, 5) == "grab-") { + // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. + return true; + } + } + return false; +} + +function getSpatialOffsetPosition(hand, spatialKey) { + var position = Vec3.ZERO; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { + position = spatialKey.leftRelativePosition; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { + position = spatialKey.rightRelativePosition; + } + if (spatialKey.relativePosition) { + position = spatialKey.relativePosition; + } + + return position; +} + +var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + +function getSpatialOffsetRotation(hand, spatialKey) { + var rotation = Quat.IDENTITY; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { + rotation = spatialKey.leftRelativeRotation; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { + rotation = spatialKey.rightRelativeRotation; + } + if (spatialKey.relativeRotation) { + rotation = spatialKey.relativeRotation; + } + + // Flip left hand + if (hand !== RIGHT_HAND) { + rotation = Quat.multiply(yFlip, rotation); + } + + return rotation; +} + +function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + } + + var SPATIAL_CONTROLLERS_PER_PALM = 2; + var TIP_CONTROLLER_OFFSET = 1; + this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; + this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; + + this.actionID = null; // action this script created... + this.grabbedEntity = null; // on this entity. + this.state = STATE_OFF; + this.pointer = null; // entity-id of line object + this.triggerValue = 0; // rolling average of trigger value + this.rawTriggerValue = 0; + this.rawBumperValue = 0; + + //for visualizations + this.overlayLine = null; + this.particleBeam = null; + + //for lights + this.spotlight = null; + this.pointlight = null; + + this.ignoreIK = false; + this.offsetPosition = Vec3.ZERO; + this.offsetRotation = Quat.IDENTITY; + + var _this = this; + + this.update = function() { + + this.updateSmoothedTrigger(); + + switch (this.state) { + case STATE_OFF: + this.off(); + this.touchTest(); + break; + case STATE_SEARCHING: + this.search(); + break; + case STATE_EQUIP_SEARCHING: + this.search(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; + case STATE_NEAR_GRABBING: + case STATE_EQUIP: + this.nearGrabbing(); + break; + case STATE_WAITING_FOR_BUMPER_RELEASE: + this.waitingForBumperRelease(); + break; + case STATE_EQUIP_SPRING: + this.pullTowardEquipPosition() + break; + case STATE_CONTINUE_NEAR_GRABBING: + case STATE_CONTINUE_EQUIP_BD: + case STATE_CONTINUE_EQUIP: + this.continueNearGrabbing(); + break; + case STATE_NEAR_TRIGGER: + this.nearTrigger(); + break; + case STATE_CONTINUE_NEAR_TRIGGER: + this.continueNearTrigger(); + break; + case STATE_FAR_TRIGGER: + this.farTrigger(); + break; + case STATE_CONTINUE_FAR_TRIGGER: + this.continueFarTrigger(); + break; + case STATE_RELEASE: + this.release(); + break; + } + }; + + this.setState = function(newState) { + if (WANT_DEBUG) { + print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); + } + this.state = newState; + }; + + this.debugLine = function(closePoint, farPoint, color) { + Entities.addEntity({ + type: "Line", + name: "Grab Debug Entity", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + }; + + this.lineOn = function(closePoint, farPoint, color) { + // draw a line + if (this.pointer === null) { + this.pointer = Entities.addEntity({ + type: "Line", + name: "grab pointer", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: LIFETIME, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } else { + var age = Entities.getEntityProperties(this.pointer, "age").age; + this.pointer = Entities.editEntity(this.pointer, { + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: age + LIFETIME + }); + } + }; + + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine === null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, // always ignore this + visible: true, + alpha: 1 + }; + + this.overlayLine = Overlays.addOverlay("line3d", lineProperties); + + } else { + var success = Overlays.editOverlay(this.overlayLine, { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + visible: true, + ignoreRayIntersection: true, // always ignore this + alpha: 1 + }); + } + }; + + this.handleParticleBeam = function(position, orientation, color) { + + var rotation = Quat.angleAxis(0, { + x: 1, + y: 0, + z: 0 + }); + + var finalRotation = Quat.multiply(orientation, rotation); + + if (this.particleBeam === null) { + this.createParticleBeam(position, finalRotation, color); + } else { + this.updateParticleBeam(position, finalRotation, color); + } + }; + + this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); + + var distance = Vec3.distance(handPosition, objectPosition); + var speed = distance * 1; + + var lifepsan = distance / speed; + var lifespan = 1; + + if (this.particleBeam === null) { + this.createParticleBeam(objectPosition, finalRotation, color, speed); + } else { + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + } + }; + + this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + + var particleBeamProperties = { + type: "ParticleEffect", + isEmitting: true, + position: position, + visible: false, + //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), + "name": "Particle Beam", + "color": color, + "maxParticles": 2000, + "lifespan": LINE_LENGTH / 10, + "emitRate": 50, + "emitSpeed": 5, + "speedSpread": 2, + "emitOrientation": { + "x": -1, + "y": 0, + "z": 0, + "w": 1 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitRadiusStart": 0.5, + "polarStart": 0, + "polarFinish": 0, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + x: 0, + y: 0, + z: 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.01, + "radiusSpread": 0, + // "radiusStart": 0.01, + // "radiusFinish": 0.01, + // "colorSpread": { + // "red": 0, + // "green": 0, + // "blue": 0 + // }, + // "colorStart": color, + // "colorFinish": color, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 1, + "alphaFinish": 1, + "additiveBlending": 1, + "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" + } + + this.particleBeam = Entities.addEntity(particleBeamProperties); + }; + + this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { + + Entities.editEntity(this.particleBeam, { + rotation: orientation, + position: position, + visible: true, + color: color, + emitSpeed: speed, + lifepsan: lifepsan + + }) + + }; + + this.evalLightWorldTransform = function(modelPos, modelRot) { + + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + }; + + this.handleSpotlight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + Entities.editEntity(this.spotlight, { + //without this, this light would maintain rotation with its parent + rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + }) + } + }; + + this.handlePointLight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + + var lightProperties = { + type: "Light", + isSpotlight: false, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.pointlight === null) { + this.pointlight = Entities.addEntity(lightProperties); + } else { + + } + }; + + this.lineOff = function() { + if (this.pointer !== null) { + Entities.deleteEntity(this.pointer); + } + this.pointer = null; + }; + + this.overlayLineOff = function() { + if (this.overlayLine !== null) { + Overlays.deleteOverlay(this.overlayLine); + } + this.overlayLine = null; + }; + + this.particleBeamOff = function() { + if (this.particleBeam !== null) { + Entities.editEntity(this.particleBeam, { + visible: false + }) + } + } + + this.turnLightsOff = function() { + if (this.spotlight !== null) { + Entities.deleteEntity(this.spotlight); + this.spotlight = null; + } + + if (this.pointlight !== null) { + Entities.deleteEntity(this.pointlight); + this.pointlight = null; + } + }; + + + this.turnOffVisualizations = function() { + if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOff(); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + }; + + this.triggerPress = function(value) { + _this.rawTriggerValue = value; + }; + + this.bumperPress = function(value) { + _this.rawBumperValue = value; + }; + + this.updateSmoothedTrigger = function() { + var triggerValue = this.rawTriggerValue; + // smooth out trigger value + this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + }; + + this.triggerSmoothedSqueezed = function() { + return this.triggerValue > TRIGGER_ON_VALUE; + }; + + this.triggerSmoothedReleased = function() { + return this.triggerValue < TRIGGER_OFF_VALUE; + }; + + this.triggerSqueezed = function() { + var triggerValue = this.rawTriggerValue; + return triggerValue > TRIGGER_ON_VALUE; + }; + + this.bumperSqueezed = function() { + return _this.rawBumperValue > BUMPER_ON_VALUE; + }; + + this.bumperReleased = function() { + return _this.rawBumperValue < BUMPER_ON_VALUE; + }; + + this.off = function() { + if (this.triggerSmoothedSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_SEARCHING); + return; + } + if (this.bumperSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_EQUIP_SEARCHING); + return; + } + }; + + this.search = function() { + this.grabbedEntity = null; + + if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { + this.setState(STATE_RELEASE); + return; + } + + // the trigger is being pressed, do a ray test + var handPosition = this.getHandPosition(); + var distantPickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()), + length: PICK_MAX_DISTANCE + }; + + // don't pick 60x per second. + var pickRays = []; + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + pickRays = [distantPickRay]; + this.lastPickTime = now; + } + + for (var index = 0; index < pickRays.length; ++index) { + var pickRay = pickRays[index]; + var directionNormalized = Vec3.normalize(pickRay.direction); + var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); + var pickRayBacked = { + origin: Vec3.subtract(pickRay.origin, directionBacked), + direction: pickRay.direction + }; + + if (WANT_DEBUG) { + this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { + red: 0, + green: 255, + blue: 0 + }) + } + + var intersection = Entities.findRayIntersection(pickRayBacked, true); + + if (intersection.intersects) { + // the ray is intersecting something we can move. + var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); + + if (intersection.properties.name == "Grab Debug Entity") { + continue; + } + + if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { + continue; + } + if (intersectionDistance > pickRay.length) { + // too far away for this ray. + continue; + } + if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { + // the hand is very close to the intersected object. go into close-grabbing mode. + if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!intersection.properties.locked) { + this.grabbedEntity = intersection.entityID; + if (this.state == STATE_SEARCHING) { + this.setState(STATE_NEAR_GRABBING); + } else { // equipping + if (typeof grabbableData.spatialKey !== 'undefined') { + // TODO + // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch + // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + } else { + this.setState(STATE_EQUIP); + } + } + return; + } + } else if (!entityIsGrabbedByOther(intersection.entityID)) { + // don't allow two people to distance grab the same object + if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { + // the hand is far from the intersected object. go into distance-holding mode + this.grabbedEntity = intersection.entityID; + if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { + // if a distance pick in equip mode hits something with a spatialKey, equip it + // TODO use STATE_EQUIP_SPRING here once it works right. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + return; + } else if (this.state == STATE_SEARCHING) { + this.setState(STATE_DISTANCE_HOLDING); + return; + } + } else if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_FAR_TRIGGER); + return; + } + } + } + } + + // forward ray test failed, try sphere test. + if (WANT_DEBUG) { + Entities.addEntity({ + type: "Sphere", + name: "Grab Debug Entity", + dimensions: { + x: GRAB_RADIUS, + y: GRAB_RADIUS, + z: GRAB_RADIUS + }, + visible: true, + position: handPosition, + color: { + red: 0, + green: 255, + blue: 0 + }, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } + + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = PICK_MAX_DISTANCE; + var i, props, distance, grabbableData; + this.grabbedEntity = null; + for (i = 0; i < nearbyEntities.length; i++) { + var grabbableDataForCandidate = + getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); + if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { + continue; + } + var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); + + if (propsForCandidate.type == 'Unknown') { + continue; + } + + if (propsForCandidate.type == 'Light') { + continue; + } + + if (propsForCandidate.type == 'ParticleEffect') { + continue; + } + + if (propsForCandidate.type == 'PolyLine') { + continue; + } + + if (propsForCandidate.type == 'Zone') { + continue; + } + + if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { + continue; + } + + if (propsForCandidate.name == "Grab Debug Entity") { + continue; + } + + if (propsForCandidate.name == "grab pointer") { + continue; + } + + distance = Vec3.distance(propsForCandidate.position, handPosition); + if (distance < minDistance) { + this.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + props = propsForCandidate; + grabbableData = grabbableDataForCandidate; + } + } + if (this.grabbedEntity !== null) { + if (grabbableData.wantsTrigger) { + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!props.locked && props.collisionsWillMove) { + this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) + return; + } + } + + //search line visualizations + if (USE_ENTITY_LINES_FOR_SEARCHING === true) { + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + } + + }; + + this.distanceHolding = function() { + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var now = Date.now(); + + // add the action and initialize some variables + this.currentObjectPosition = grabbedProperties.position; + this.currentObjectRotation = grabbedProperties.rotation; + this.currentObjectTime = now; + this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); + this.handPreviousRotation = handRotation; + this.currentCameraOrientation = Camera.orientation; + + // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object + this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); + if (this.radiusScalar < 1.0) { + this.radiusScalar = 1.0; + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + tag: getTag(), + ttl: ACTION_TTL + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + + if (this.actionID !== null) { + this.setState(STATE_CONTINUE_DISTANCE_HOLDING); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + } + + this.currentAvatarPosition = MyAvatar.position; + this.currentAvatarOrientation = MyAvatar.orientation; + + this.turnOffVisualizations(); + }; + + this.continueDistanceHolding = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + var handPosition = this.getHandPosition(); + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && + typeof grabbableData.spatialKey !== 'undefined') { + var saveGrabbedID = this.grabbedEntity; + this.release(); + this.setState(STATE_EQUIP); + this.grabbedEntity = saveGrabbedID; + return; + } + + + // the action was set up on a previous call. update the targets. + var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; + if (radius < 1.0) { + radius = 1.0; + } + + // how far did avatar move this timestep? + var currentPosition = MyAvatar.position; + var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); + this.currentAvatarPosition = currentPosition; + + // How far did the avatar turn this timestep? + // Note: The following code is too long because we need a Quat.quatBetween() function + // that returns the minimum quaternion between two quaternions. + var currentOrientation = MyAvatar.orientation; + if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) { + var negativeCurrentOrientation = { + x: -currentOrientation.x, + y: -currentOrientation.y, + z: -currentOrientation.z, + w: -currentOrientation.w + }; + var avatarDeltaOrientation = Quat.multiply(negativeCurrentOrientation, Quat.inverse(this.currentAvatarOrientation)); + } else { + var avatarDeltaOrientation = Quat.multiply(currentOrientation, Quat.inverse(this.currentAvatarOrientation)); + } + var handToAvatar = Vec3.subtract(handControllerPosition, this.currentAvatarPosition); + var objectToAvatar = Vec3.subtract(this.currentObjectPosition, this.currentAvatarPosition); + var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar); + var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar); + this.currentAvatarOrientation = currentOrientation; + + // how far did hand move this timestep? + var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); + this.handRelativePreviousPosition = handToAvatar; + + // magnify the hand movement but not the change from avatar movement & rotation + handMoved = Vec3.subtract(handMoved, handMovementFromTurning); + var superHandMoved = Vec3.multiply(handMoved, radius); + + // Move the object by the magnified amount and then by amount from avatar movement & rotation + var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); + newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); + newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); + + var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters + var now = Date.now(); + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentObjectPosition = newObjectPosition; + this.currentObjectTime = now; + + // this doubles hand rotation + var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, + handRotation, + DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), + Quat.inverse(this.handPreviousRotation)); + this.handPreviousRotation = handRotation; + this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); + + Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + + + //visualizations + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } + if (USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); + } + if (USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + } + if (USE_POINTLIGHT === true) { + this.handlePointLight(this.grabbedEntity); + } + if (USE_SPOTLIGHT === true) { + this.handleSpotlight(this.grabbedEntity); + } + + Entities.updateAction(this.grabbedEntity, this.actionID, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + ttl: ACTION_TTL + }); + + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + }; + + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } + + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.ignoreIK = false; + + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } else { + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + + } + + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; + + this.currentObjectTime = Date.now(); + }; + + this.continueNearGrabbing = function() { + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { + this.setState(STATE_CONTINUE_EQUIP); + return; + } + if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { + this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); + return; + } + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { + this.setState(STATE_CONTINUE_EQUIP_BD); + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + return; + } + + // Keep track of the fingertip velocity to impart when we release the object. + // Note that the idea of using a constant 'tip' velocity regardless of the + // object's actual held offset is an idea intended to make it easier to throw things: + // Because we might catch something or transfer it between hands without a good idea + // of it's actual offset, let's try imparting a velocity which is at a fixed radius + // from the palm. + + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var now = Date.now(); + + var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentHandControllerTipPosition = handControllerPosition; + this.currentObjectTime = now; + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); + + if (this.state === STATE_CONTINUE_EQUIP_BD) { + Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + } + + if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + // if less than a 5 seconds left, refresh the actions ttl + Entities.updateAction(this.grabbedEntity, this.actionID, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + } + }; + + this.waitingForBumperRelease = function() { + if (this.bumperReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + Entities.callEntityMethod(this.grabbedEntity, "unequip"); + this.endHandGrasp(); + + } + }; + + this.pullTowardEquipPosition = function() { + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + // use a spring to pull the object to where it will be when equipped + var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + var targetRotation = Quat.multiply(handRotation, relativeRotation); + var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); + var targetPosition = Vec3.sum(handPosition, offset); + + if (typeof this.equipSpringID === 'undefined' || + this.equipSpringID === null || + this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + if (this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = null; + this.setState(STATE_OFF); + return; + } + } else { + Entities.updateAction(this.grabbedEntity, this.equipSpringID, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + } + + if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { + Entities.deleteAction(this.grabbedEntity, this.equipSpringID); + this.equipSpringID = null; + this.setState(STATE_EQUIP); + } + }; + + this.nearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.setState(STATE_CONTINUE_NEAR_TRIGGER); + }; + + this.farTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.setState(STATE_CONTINUE_FAR_TRIGGER); + }; + + this.continueNearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); + }; + + this.continueFarTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + var handPosition = this.getHandPosition(); + var pickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()) + }; + + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + var intersection = Entities.findRayIntersection(pickRay, true); + this.lastPickTime = now; + if (intersection.entityID != this.grabbedEntity) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + } + + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); + }; + + _this.allTouchedIDs = {}; + + this.touchTest = function() { + var maxDistance = 0.05; + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); + var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); + var ids = []; + + if (leftEntities.length !== 0) { + leftEntities.forEach(function(entity) { + ids.push(entity); + }); + + } + + if (rightEntities.length !== 0) { + rightEntities.forEach(function(entity) { + ids.push(entity); + }); + } + + ids.forEach(function(id) { + + var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); + if (props.name === 'pointer') { + return; + } else { + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id]) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + + } else { + //we are in another state + return; + } + } + + }); + + }; + + this.startTouch = function(entityID) { + Entities.callEntityMethod(entityID, "startTouch"); + }; + + this.continueTouch = function(entityID) { + Entities.callEntityMethod(entityID, "continueTouch"); + }; + + this.stopTouch = function(entityID) { + Entities.callEntityMethod(entityID, "stopTouch"); + }; + + this.release = function() { + + this.turnLightsOff(); + this.turnOffVisualizations(); + + if (this.grabbedEntity !== null) { + if (this.actionID !== null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); + } + } + + this.deactivateEntity(this.grabbedEntity); + + this.grabbedEntity = null; + this.actionID = null; + this.setState(STATE_OFF); + }; + + this.cleanup = function() { + this.release(); + this.endHandGrasp(); + Entities.deleteEntity(this.particleBeam); + Entities.deleteEntity(this.spotLight); + Entities.deleteEntity(this.pointLight); + }; + + this.activateEntity = function(entityID, grabbedProperties) { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); + var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["activated"] = true; + data["avatarId"] = MyAvatar.sessionUUID; + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done + if (data["refCount"] == 1) { + data["gravity"] = grabbedProperties.gravity; + data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; + var whileHeldProperties = { + gravity: { + x: 0, + y: 0, + z: 0 + } + }; + if (invertSolidWhileHeld) { + whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; + } + Entities.editEntity(entityID, whileHeldProperties); + } + + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + return data; + }; + + this.deactivateEntity = function(entityID) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + if (data && data["refCount"]) { + data["refCount"] = data["refCount"] - 1; + if (data["refCount"] < 1) { + Entities.editEntity(entityID, { + gravity: data["gravity"], + ignoreForCollisions: data["ignoreForCollisions"], + collisionsWillMove: data["collisionsWillMove"] + }); + data = null; + } + } else { + data = null; + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + }; + + + //this is our handler, where we do the actual work of changing animation settings + this.graspHand = function(animationProperties) { + var result = {}; + //full alpha on overlay for this hand + //set grab to true + //set idle to false + //full alpha on the blend btw open and grab + if (_this.hand === RIGHT_HAND) { + result['rightHandOverlayAlpha'] = 1.0; + result['isRightHandGrab'] = true; + result['isRightHandIdle'] = false; + result['rightHandGrabBlend'] = 1.0; + } else if (_this.hand === LEFT_HAND) { + result['leftHandOverlayAlpha'] = 1.0; + result['isLeftHandGrab'] = true; + result['isLeftHandIdle'] = false; + result['leftHandGrabBlend'] = 1.0; + } + //return an object with our updated settings + return result; + }; + + this.graspHandler = null + + this.startHandGrasp = function() { + if (this.hand === RIGHT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); + } else if (this.hand === LEFT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); + } + }; + + this.endHandGrasp = function() { + // Tell the animation system we don't need any more callbacks. + MyAvatar.removeAnimationStateHandler(this.graspHandler); + }; + +}; + +var rightController = new MyController(RIGHT_HAND); +var leftController = new MyController(LEFT_HAND); + +//preload the particle beams so that they are full length when you start searching +if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + rightController.createParticleBeam(); + leftController.createParticleBeam(); +} + +var MAPPING_NAME = "com.highfidelity.handControllerGrab"; + +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); +mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); + +mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); +mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); + +Controller.enableMapping(MAPPING_NAME); + +//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items +var handToDisable = 'none'; + +function update() { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { + leftController.update(); + } + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { + rightController.update(); + } +} + +Messages.subscribe('Hifi-Hand-Disabler'); + +handleHandDisablerMessages = function(channel, message, sender) { + + if (sender === MyAvatar.sessionUUID) { + if (message === 'left') { + handToDisable = LEFT_HAND; + } + if (message === 'right') { + handToDisable = RIGHT_HAND; + } + if (message === 'both') { + handToDisable = 'both'; + } + if (message === 'none') { + handToDisable = 'none'; + } + } + +} + +Messages.messageReceived.connect(handleHandDisablerMessages); + +function cleanup() { + rightController.cleanup(); + leftController.cleanup(); + Controller.disableMapping(MAPPING_NAME); +} + +Script.scriptEnding.connect(cleanup); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/controllers/handControllerGrab-particles.js b/examples/controllers/handControllerGrab-particles.js new file mode 100644 index 0000000000..d9ecb18b01 --- /dev/null +++ b/examples/controllers/handControllerGrab-particles.js @@ -0,0 +1,1649 @@ +// handControllerGrab.js +// +// Created by Eric Levin on 9/2/15 +// Additions by James B. Pollack @imgntn on 9/24/2015 +// Additions By Seth Alves on 10/20/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// Also supports touch and equipping objects. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ + +Script.include("../libraries/utils.js"); + +// +// add lines where the hand ray picking is happening +// +var WANT_DEBUG = false; + +// +// these tune time-averaging and "on" value for analog trigger +// + +var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value +var TRIGGER_ON_VALUE = 0.4; +var TRIGGER_OFF_VALUE = 0.15; + +var BUMPER_ON_VALUE = 0.5; + +// +// distant manipulation +// + +var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects + +var NO_INTERSECT_COLOR = { + red: 10, + green: 10, + blue: 255 +}; // line color when pick misses +var INTERSECT_COLOR = { + red: 250, + green: 10, + blue: 10 +}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { + x: 1000, + y: 1000, + z: 1000 +}; + +var LINE_LENGTH = 500; +var PICK_MAX_DISTANCE = 500; // max length of pick-ray + +// +// near grabbing +// + +var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected +var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. +var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected +var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things +var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object +var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed + +// +// equip +// + +var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; +var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position + +// +// other constants +// + +var RIGHT_HAND = 1; +var LEFT_HAND = 0; + +var ZERO_VEC = { + x: 0, + y: 0, + z: 0 +}; + +var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; +var MSEC_PER_SEC = 1000.0; + +// these control how long an abandoned pointer line or action will hang around +var LIFETIME = 10; +var ACTION_TTL = 15; // seconds +var ACTION_TTL_REFRESH = 5; +var PICKS_PER_SECOND_PER_HAND = 5; +var MSECS_PER_SEC = 1000.0; +var GRABBABLE_PROPERTIES = [ + "position", + "rotation", + "gravity", + "ignoreForCollisions", + "collisionsWillMove", + "locked", + "name" +]; + +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js + +var DEFAULT_GRABBABLE_DATA = { + grabbable: true, + invertSolidWhileHeld: false +}; + +//we've created various ways of visualizing looking for and moving distant objects +var USE_ENTITY_LINES_FOR_SEARCHING = false; +var USE_OVERLAY_LINES_FOR_SEARCHING = false; +var USE_PARTICLE_BEAM_FOR_SEARCHING = true; + +var USE_ENTITY_LINES_FOR_MOVING = false; +var USE_OVERLAY_LINES_FOR_MOVING = false; +var USE_PARTICLE_BEAM_FOR_MOVING = true; + +var USE_SPOTLIGHT = false; +var USE_POINTLIGHT = false; + +// states for the state machine +var STATE_OFF = 0; +var STATE_SEARCHING = 1; +var STATE_DISTANCE_HOLDING = 2; +var STATE_CONTINUE_DISTANCE_HOLDING = 3; +var STATE_NEAR_GRABBING = 4; +var STATE_CONTINUE_NEAR_GRABBING = 5; +var STATE_NEAR_TRIGGER = 6; +var STATE_CONTINUE_NEAR_TRIGGER = 7; +var STATE_FAR_TRIGGER = 8; +var STATE_CONTINUE_FAR_TRIGGER = 9; +var STATE_RELEASE = 10; +var STATE_EQUIP_SEARCHING = 11; +var STATE_EQUIP = 12 +var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down +var STATE_CONTINUE_EQUIP = 14; +var STATE_WAITING_FOR_BUMPER_RELEASE = 15; +var STATE_EQUIP_SPRING = 16; + + + +function stateToName(state) { + switch (state) { + case STATE_OFF: + return "off"; + case STATE_SEARCHING: + return "searching"; + case STATE_DISTANCE_HOLDING: + return "distance_holding"; + case STATE_CONTINUE_DISTANCE_HOLDING: + return "continue_distance_holding"; + case STATE_NEAR_GRABBING: + return "near_grabbing"; + case STATE_CONTINUE_NEAR_GRABBING: + return "continue_near_grabbing"; + case STATE_NEAR_TRIGGER: + return "near_trigger"; + case STATE_CONTINUE_NEAR_TRIGGER: + return "continue_near_trigger"; + case STATE_FAR_TRIGGER: + return "far_trigger"; + case STATE_CONTINUE_FAR_TRIGGER: + return "continue_far_trigger"; + case STATE_RELEASE: + return "release"; + case STATE_EQUIP_SEARCHING: + return "equip_searching"; + case STATE_EQUIP: + return "equip"; + case STATE_CONTINUE_EQUIP_BD: + return "continue_equip_bd"; + case STATE_CONTINUE_EQUIP: + return "continue_equip"; + case STATE_WAITING_FOR_BUMPER_RELEASE: + return "waiting_for_bumper_release"; + case STATE_EQUIP_SPRING: + return "state_equip_spring"; + } + + return "unknown"; +} + +function getTag() { + return "grab-" + MyAvatar.sessionUUID; +} + +function entityIsGrabbedByOther(entityID) { + // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. + var actionIDs = Entities.getActionIDs(entityID); + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments["tag"]; + if (tag == getTag()) { + // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. + continue; + } + if (tag.slice(0, 5) == "grab-") { + // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. + return true; + } + } + return false; +} + +function getSpatialOffsetPosition(hand, spatialKey) { + var position = Vec3.ZERO; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { + position = spatialKey.leftRelativePosition; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { + position = spatialKey.rightRelativePosition; + } + if (spatialKey.relativePosition) { + position = spatialKey.relativePosition; + } + + return position; +} + +var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + +function getSpatialOffsetRotation(hand, spatialKey) { + var rotation = Quat.IDENTITY; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { + rotation = spatialKey.leftRelativeRotation; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { + rotation = spatialKey.rightRelativeRotation; + } + if (spatialKey.relativeRotation) { + rotation = spatialKey.relativeRotation; + } + + // Flip left hand + if (hand !== RIGHT_HAND) { + rotation = Quat.multiply(yFlip, rotation); + } + + return rotation; +} + +function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + } + + var SPATIAL_CONTROLLERS_PER_PALM = 2; + var TIP_CONTROLLER_OFFSET = 1; + this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; + this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; + + this.actionID = null; // action this script created... + this.grabbedEntity = null; // on this entity. + this.state = STATE_OFF; + this.pointer = null; // entity-id of line object + this.triggerValue = 0; // rolling average of trigger value + this.rawTriggerValue = 0; + this.rawBumperValue = 0; + + //for visualizations + this.overlayLine = null; + this.particleBeam = null; + + //for lights + this.spotlight = null; + this.pointlight = null; + + this.ignoreIK = false; + this.offsetPosition = Vec3.ZERO; + this.offsetRotation = Quat.IDENTITY; + + var _this = this; + + this.update = function() { + + this.updateSmoothedTrigger(); + + switch (this.state) { + case STATE_OFF: + this.off(); + this.touchTest(); + break; + case STATE_SEARCHING: + this.search(); + break; + case STATE_EQUIP_SEARCHING: + this.search(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; + case STATE_NEAR_GRABBING: + case STATE_EQUIP: + this.nearGrabbing(); + break; + case STATE_WAITING_FOR_BUMPER_RELEASE: + this.waitingForBumperRelease(); + break; + case STATE_EQUIP_SPRING: + this.pullTowardEquipPosition() + break; + case STATE_CONTINUE_NEAR_GRABBING: + case STATE_CONTINUE_EQUIP_BD: + case STATE_CONTINUE_EQUIP: + this.continueNearGrabbing(); + break; + case STATE_NEAR_TRIGGER: + this.nearTrigger(); + break; + case STATE_CONTINUE_NEAR_TRIGGER: + this.continueNearTrigger(); + break; + case STATE_FAR_TRIGGER: + this.farTrigger(); + break; + case STATE_CONTINUE_FAR_TRIGGER: + this.continueFarTrigger(); + break; + case STATE_RELEASE: + this.release(); + break; + } + }; + + this.setState = function(newState) { + if (WANT_DEBUG) { + print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); + } + this.state = newState; + }; + + this.debugLine = function(closePoint, farPoint, color) { + Entities.addEntity({ + type: "Line", + name: "Grab Debug Entity", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + }; + + this.lineOn = function(closePoint, farPoint, color) { + // draw a line + if (this.pointer === null) { + this.pointer = Entities.addEntity({ + type: "Line", + name: "grab pointer", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: LIFETIME, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } else { + var age = Entities.getEntityProperties(this.pointer, "age").age; + this.pointer = Entities.editEntity(this.pointer, { + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: age + LIFETIME + }); + } + }; + + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine === null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, // always ignore this + visible: true, + alpha: 1 + }; + + this.overlayLine = Overlays.addOverlay("line3d", lineProperties); + + } else { + var success = Overlays.editOverlay(this.overlayLine, { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + visible: true, + ignoreRayIntersection: true, // always ignore this + alpha: 1 + }); + } + }; + + this.handleParticleBeam = function(position, orientation, color) { + + var rotation = Quat.angleAxis(0, { + x: 1, + y: 0, + z: 0 + }); + + var finalRotation = Quat.multiply(orientation, rotation); + + if (this.particleBeam === null) { + this.createParticleBeam(position, finalRotation, color); + } else { + this.updateParticleBeam(position, finalRotation, color); + } + }; + + this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); + + var distance = Vec3.distance(handPosition, objectPosition); + var speed = distance * 1; + + var lifepsan = distance / speed; + var lifespan = 1; + + if (this.particleBeam === null) { + this.createParticleBeam(objectPosition, finalRotation, color, speed); + } else { + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + } + }; + + this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + + var particleBeamProperties = { + type: "ParticleEffect", + isEmitting: true, + position: position, + visible: false, + //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), + "name": "Particle Beam", + "color": color, + "maxParticles": 2000, + "lifespan": LINE_LENGTH / 10, + "emitRate": 50, + "emitSpeed": 5, + "speedSpread": 2, + "emitOrientation": { + "x": -1, + "y": 0, + "z": 0, + "w": 1 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitRadiusStart": 0.5, + "polarStart": 0, + "polarFinish": 0, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + x: 0, + y: 0, + z: 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.01, + "radiusSpread": 0, + // "radiusStart": 0.01, + // "radiusFinish": 0.01, + // "colorSpread": { + // "red": 0, + // "green": 0, + // "blue": 0 + // }, + // "colorStart": color, + // "colorFinish": color, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 1, + "alphaFinish": 1, + "additiveBlending": 1, + "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" + } + + this.particleBeam = Entities.addEntity(particleBeamProperties); + }; + + this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { + + Entities.editEntity(this.particleBeam, { + rotation: orientation, + position: position, + visible: true, + color: color, + emitSpeed: speed, + lifepsan: lifepsan + + }) + + }; + + this.evalLightWorldTransform = function(modelPos, modelRot) { + + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + }; + + this.handleSpotlight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + Entities.editEntity(this.spotlight, { + //without this, this light would maintain rotation with its parent + rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + }) + } + }; + + this.handlePointLight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + + var lightProperties = { + type: "Light", + isSpotlight: false, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.pointlight === null) { + this.pointlight = Entities.addEntity(lightProperties); + } else { + + } + }; + + this.lineOff = function() { + if (this.pointer !== null) { + Entities.deleteEntity(this.pointer); + } + this.pointer = null; + }; + + this.overlayLineOff = function() { + if (this.overlayLine !== null) { + Overlays.deleteOverlay(this.overlayLine); + } + this.overlayLine = null; + }; + + this.particleBeamOff = function() { + if (this.particleBeam !== null) { + Entities.editEntity(this.particleBeam, { + visible: false + }) + } + } + + this.turnLightsOff = function() { + if (this.spotlight !== null) { + Entities.deleteEntity(this.spotlight); + this.spotlight = null; + } + + if (this.pointlight !== null) { + Entities.deleteEntity(this.pointlight); + this.pointlight = null; + } + }; + + + this.turnOffVisualizations = function() { + if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOff(); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + }; + + this.triggerPress = function(value) { + _this.rawTriggerValue = value; + }; + + this.bumperPress = function(value) { + _this.rawBumperValue = value; + }; + + this.updateSmoothedTrigger = function() { + var triggerValue = this.rawTriggerValue; + // smooth out trigger value + this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + }; + + this.triggerSmoothedSqueezed = function() { + return this.triggerValue > TRIGGER_ON_VALUE; + }; + + this.triggerSmoothedReleased = function() { + return this.triggerValue < TRIGGER_OFF_VALUE; + }; + + this.triggerSqueezed = function() { + var triggerValue = this.rawTriggerValue; + return triggerValue > TRIGGER_ON_VALUE; + }; + + this.bumperSqueezed = function() { + return _this.rawBumperValue > BUMPER_ON_VALUE; + }; + + this.bumperReleased = function() { + return _this.rawBumperValue < BUMPER_ON_VALUE; + }; + + this.off = function() { + if (this.triggerSmoothedSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_SEARCHING); + return; + } + if (this.bumperSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_EQUIP_SEARCHING); + return; + } + }; + + this.search = function() { + this.grabbedEntity = null; + + if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { + this.setState(STATE_RELEASE); + return; + } + + // the trigger is being pressed, do a ray test + var handPosition = this.getHandPosition(); + var distantPickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()), + length: PICK_MAX_DISTANCE + }; + + // don't pick 60x per second. + var pickRays = []; + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + pickRays = [distantPickRay]; + this.lastPickTime = now; + } + + for (var index = 0; index < pickRays.length; ++index) { + var pickRay = pickRays[index]; + var directionNormalized = Vec3.normalize(pickRay.direction); + var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); + var pickRayBacked = { + origin: Vec3.subtract(pickRay.origin, directionBacked), + direction: pickRay.direction + }; + + if (WANT_DEBUG) { + this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { + red: 0, + green: 255, + blue: 0 + }) + } + + var intersection = Entities.findRayIntersection(pickRayBacked, true); + + if (intersection.intersects) { + // the ray is intersecting something we can move. + var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); + + if (intersection.properties.name == "Grab Debug Entity") { + continue; + } + + if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { + continue; + } + if (intersectionDistance > pickRay.length) { + // too far away for this ray. + continue; + } + if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { + // the hand is very close to the intersected object. go into close-grabbing mode. + if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!intersection.properties.locked) { + this.grabbedEntity = intersection.entityID; + if (this.state == STATE_SEARCHING) { + this.setState(STATE_NEAR_GRABBING); + } else { // equipping + if (typeof grabbableData.spatialKey !== 'undefined') { + // TODO + // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch + // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + } else { + this.setState(STATE_EQUIP); + } + } + return; + } + } else if (!entityIsGrabbedByOther(intersection.entityID)) { + // don't allow two people to distance grab the same object + if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { + // the hand is far from the intersected object. go into distance-holding mode + this.grabbedEntity = intersection.entityID; + if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { + // if a distance pick in equip mode hits something with a spatialKey, equip it + // TODO use STATE_EQUIP_SPRING here once it works right. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + return; + } else if (this.state == STATE_SEARCHING) { + this.setState(STATE_DISTANCE_HOLDING); + return; + } + } else if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_FAR_TRIGGER); + return; + } + } + } + } + + // forward ray test failed, try sphere test. + if (WANT_DEBUG) { + Entities.addEntity({ + type: "Sphere", + name: "Grab Debug Entity", + dimensions: { + x: GRAB_RADIUS, + y: GRAB_RADIUS, + z: GRAB_RADIUS + }, + visible: true, + position: handPosition, + color: { + red: 0, + green: 255, + blue: 0 + }, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } + + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = PICK_MAX_DISTANCE; + var i, props, distance, grabbableData; + this.grabbedEntity = null; + for (i = 0; i < nearbyEntities.length; i++) { + var grabbableDataForCandidate = + getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); + if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { + continue; + } + var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); + + if (propsForCandidate.type == 'Unknown') { + continue; + } + + if (propsForCandidate.type == 'Light') { + continue; + } + + if (propsForCandidate.type == 'ParticleEffect') { + continue; + } + + if (propsForCandidate.type == 'PolyLine') { + continue; + } + + if (propsForCandidate.type == 'Zone') { + continue; + } + + if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { + continue; + } + + if (propsForCandidate.name == "Grab Debug Entity") { + continue; + } + + if (propsForCandidate.name == "grab pointer") { + continue; + } + + distance = Vec3.distance(propsForCandidate.position, handPosition); + if (distance < minDistance) { + this.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + props = propsForCandidate; + grabbableData = grabbableDataForCandidate; + } + } + if (this.grabbedEntity !== null) { + if (grabbableData.wantsTrigger) { + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!props.locked && props.collisionsWillMove) { + this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) + return; + } + } + + //search line visualizations + if (USE_ENTITY_LINES_FOR_SEARCHING === true) { + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + } + + }; + + this.distanceHolding = function() { + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var now = Date.now(); + + // add the action and initialize some variables + this.currentObjectPosition = grabbedProperties.position; + this.currentObjectRotation = grabbedProperties.rotation; + this.currentObjectTime = now; + this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); + this.handPreviousRotation = handRotation; + this.currentCameraOrientation = Camera.orientation; + + // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object + this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); + if (this.radiusScalar < 1.0) { + this.radiusScalar = 1.0; + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + tag: getTag(), + ttl: ACTION_TTL + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + + if (this.actionID !== null) { + this.setState(STATE_CONTINUE_DISTANCE_HOLDING); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + } + + this.currentAvatarPosition = MyAvatar.position; + this.currentAvatarOrientation = MyAvatar.orientation; + + this.turnOffVisualizations(); + }; + + this.continueDistanceHolding = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + var handPosition = this.getHandPosition(); + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && + typeof grabbableData.spatialKey !== 'undefined') { + var saveGrabbedID = this.grabbedEntity; + this.release(); + this.setState(STATE_EQUIP); + this.grabbedEntity = saveGrabbedID; + return; + } + + + // the action was set up on a previous call. update the targets. + var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; + if (radius < 1.0) { + radius = 1.0; + } + + // how far did avatar move this timestep? + var currentPosition = MyAvatar.position; + var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); + this.currentAvatarPosition = currentPosition; + + // How far did the avatar turn this timestep? + // Note: The following code is too long because we need a Quat.quatBetween() function + // that returns the minimum quaternion between two quaternions. + var currentOrientation = MyAvatar.orientation; + if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) { + var negativeCurrentOrientation = { + x: -currentOrientation.x, + y: -currentOrientation.y, + z: -currentOrientation.z, + w: -currentOrientation.w + }; + var avatarDeltaOrientation = Quat.multiply(negativeCurrentOrientation, Quat.inverse(this.currentAvatarOrientation)); + } else { + var avatarDeltaOrientation = Quat.multiply(currentOrientation, Quat.inverse(this.currentAvatarOrientation)); + } + var handToAvatar = Vec3.subtract(handControllerPosition, this.currentAvatarPosition); + var objectToAvatar = Vec3.subtract(this.currentObjectPosition, this.currentAvatarPosition); + var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar); + var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar); + this.currentAvatarOrientation = currentOrientation; + + // how far did hand move this timestep? + var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); + this.handRelativePreviousPosition = handToAvatar; + + // magnify the hand movement but not the change from avatar movement & rotation + handMoved = Vec3.subtract(handMoved, handMovementFromTurning); + var superHandMoved = Vec3.multiply(handMoved, radius); + + // Move the object by the magnified amount and then by amount from avatar movement & rotation + var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); + newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); + newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); + + var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters + var now = Date.now(); + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentObjectPosition = newObjectPosition; + this.currentObjectTime = now; + + // this doubles hand rotation + var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, + handRotation, + DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), + Quat.inverse(this.handPreviousRotation)); + this.handPreviousRotation = handRotation; + this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); + + Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + + + //visualizations + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } + if (USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); + } + if (USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + } + if (USE_POINTLIGHT === true) { + this.handlePointLight(this.grabbedEntity); + } + if (USE_SPOTLIGHT === true) { + this.handleSpotlight(this.grabbedEntity); + } + + Entities.updateAction(this.grabbedEntity, this.actionID, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + ttl: ACTION_TTL + }); + + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + }; + + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } + + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.ignoreIK = false; + + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } else { + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + + } + + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; + + this.currentObjectTime = Date.now(); + }; + + this.continueNearGrabbing = function() { + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { + this.setState(STATE_CONTINUE_EQUIP); + return; + } + if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { + this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); + return; + } + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { + this.setState(STATE_CONTINUE_EQUIP_BD); + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + return; + } + + // Keep track of the fingertip velocity to impart when we release the object. + // Note that the idea of using a constant 'tip' velocity regardless of the + // object's actual held offset is an idea intended to make it easier to throw things: + // Because we might catch something or transfer it between hands without a good idea + // of it's actual offset, let's try imparting a velocity which is at a fixed radius + // from the palm. + + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var now = Date.now(); + + var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentHandControllerTipPosition = handControllerPosition; + this.currentObjectTime = now; + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); + + if (this.state === STATE_CONTINUE_EQUIP_BD) { + Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + } + + if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + // if less than a 5 seconds left, refresh the actions ttl + Entities.updateAction(this.grabbedEntity, this.actionID, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + } + }; + + this.waitingForBumperRelease = function() { + if (this.bumperReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + Entities.callEntityMethod(this.grabbedEntity, "unequip"); + this.endHandGrasp(); + + } + }; + + this.pullTowardEquipPosition = function() { + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + // use a spring to pull the object to where it will be when equipped + var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + var targetRotation = Quat.multiply(handRotation, relativeRotation); + var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); + var targetPosition = Vec3.sum(handPosition, offset); + + if (typeof this.equipSpringID === 'undefined' || + this.equipSpringID === null || + this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + if (this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = null; + this.setState(STATE_OFF); + return; + } + } else { + Entities.updateAction(this.grabbedEntity, this.equipSpringID, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + } + + if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { + Entities.deleteAction(this.grabbedEntity, this.equipSpringID); + this.equipSpringID = null; + this.setState(STATE_EQUIP); + } + }; + + this.nearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.setState(STATE_CONTINUE_NEAR_TRIGGER); + }; + + this.farTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.setState(STATE_CONTINUE_FAR_TRIGGER); + }; + + this.continueNearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); + }; + + this.continueFarTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + var handPosition = this.getHandPosition(); + var pickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()) + }; + + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + var intersection = Entities.findRayIntersection(pickRay, true); + this.lastPickTime = now; + if (intersection.entityID != this.grabbedEntity) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + } + + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); + }; + + _this.allTouchedIDs = {}; + + this.touchTest = function() { + var maxDistance = 0.05; + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); + var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); + var ids = []; + + if (leftEntities.length !== 0) { + leftEntities.forEach(function(entity) { + ids.push(entity); + }); + + } + + if (rightEntities.length !== 0) { + rightEntities.forEach(function(entity) { + ids.push(entity); + }); + } + + ids.forEach(function(id) { + + var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); + if (props.name === 'pointer') { + return; + } else { + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id]) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + + } else { + //we are in another state + return; + } + } + + }); + + }; + + this.startTouch = function(entityID) { + Entities.callEntityMethod(entityID, "startTouch"); + }; + + this.continueTouch = function(entityID) { + Entities.callEntityMethod(entityID, "continueTouch"); + }; + + this.stopTouch = function(entityID) { + Entities.callEntityMethod(entityID, "stopTouch"); + }; + + this.release = function() { + + this.turnLightsOff(); + this.turnOffVisualizations(); + + if (this.grabbedEntity !== null) { + if (this.actionID !== null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); + } + } + + this.deactivateEntity(this.grabbedEntity); + + this.grabbedEntity = null; + this.actionID = null; + this.setState(STATE_OFF); + }; + + this.cleanup = function() { + this.release(); + this.endHandGrasp(); + Entities.deleteEntity(this.particleBeam); + Entities.deleteEntity(this.spotLight); + Entities.deleteEntity(this.pointLight); + }; + + this.activateEntity = function(entityID, grabbedProperties) { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); + var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["activated"] = true; + data["avatarId"] = MyAvatar.sessionUUID; + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done + if (data["refCount"] == 1) { + data["gravity"] = grabbedProperties.gravity; + data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; + var whileHeldProperties = { + gravity: { + x: 0, + y: 0, + z: 0 + } + }; + if (invertSolidWhileHeld) { + whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; + } + Entities.editEntity(entityID, whileHeldProperties); + } + + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + return data; + }; + + this.deactivateEntity = function(entityID) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + if (data && data["refCount"]) { + data["refCount"] = data["refCount"] - 1; + if (data["refCount"] < 1) { + Entities.editEntity(entityID, { + gravity: data["gravity"], + ignoreForCollisions: data["ignoreForCollisions"], + collisionsWillMove: data["collisionsWillMove"] + }); + data = null; + } + } else { + data = null; + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + }; + + + //this is our handler, where we do the actual work of changing animation settings + this.graspHand = function(animationProperties) { + var result = {}; + //full alpha on overlay for this hand + //set grab to true + //set idle to false + //full alpha on the blend btw open and grab + if (_this.hand === RIGHT_HAND) { + result['rightHandOverlayAlpha'] = 1.0; + result['isRightHandGrab'] = true; + result['isRightHandIdle'] = false; + result['rightHandGrabBlend'] = 1.0; + } else if (_this.hand === LEFT_HAND) { + result['leftHandOverlayAlpha'] = 1.0; + result['isLeftHandGrab'] = true; + result['isLeftHandIdle'] = false; + result['leftHandGrabBlend'] = 1.0; + } + //return an object with our updated settings + return result; + }; + + this.graspHandler = null + + this.startHandGrasp = function() { + if (this.hand === RIGHT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); + } else if (this.hand === LEFT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); + } + }; + + this.endHandGrasp = function() { + // Tell the animation system we don't need any more callbacks. + MyAvatar.removeAnimationStateHandler(this.graspHandler); + }; + +}; + +var rightController = new MyController(RIGHT_HAND); +var leftController = new MyController(LEFT_HAND); + +//preload the particle beams so that they are full length when you start searching +if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + rightController.createParticleBeam(); + leftController.createParticleBeam(); +} + +var MAPPING_NAME = "com.highfidelity.handControllerGrab"; + +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); +mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); + +mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); +mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); + +Controller.enableMapping(MAPPING_NAME); + +//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items +var handToDisable = 'none'; + +function update() { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { + leftController.update(); + } + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { + rightController.update(); + } +} + +Messages.subscribe('Hifi-Hand-Disabler'); + +handleHandDisablerMessages = function(channel, message, sender) { + + if (sender === MyAvatar.sessionUUID) { + if (message === 'left') { + handToDisable = LEFT_HAND; + } + if (message === 'right') { + handToDisable = RIGHT_HAND; + } + if (message === 'both') { + handToDisable = 'both'; + } + if (message === 'none') { + handToDisable = 'none'; + } + } + +} + +Messages.messageReceived.connect(handleHandDisablerMessages); + +function cleanup() { + rightController.cleanup(); + leftController.cleanup(); + Controller.disableMapping(MAPPING_NAME); +} + +Script.scriptEnding.connect(cleanup); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/controllers/handControllerGrab-pointlight.js b/examples/controllers/handControllerGrab-pointlight.js new file mode 100644 index 0000000000..fc14e6026e --- /dev/null +++ b/examples/controllers/handControllerGrab-pointlight.js @@ -0,0 +1,1649 @@ +// handControllerGrab.js +// +// Created by Eric Levin on 9/2/15 +// Additions by James B. Pollack @imgntn on 9/24/2015 +// Additions By Seth Alves on 10/20/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// Also supports touch and equipping objects. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ + +Script.include("../libraries/utils.js"); + +// +// add lines where the hand ray picking is happening +// +var WANT_DEBUG = false; + +// +// these tune time-averaging and "on" value for analog trigger +// + +var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value +var TRIGGER_ON_VALUE = 0.4; +var TRIGGER_OFF_VALUE = 0.15; + +var BUMPER_ON_VALUE = 0.5; + +// +// distant manipulation +// + +var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects + +var NO_INTERSECT_COLOR = { + red: 10, + green: 10, + blue: 255 +}; // line color when pick misses +var INTERSECT_COLOR = { + red: 250, + green: 10, + blue: 10 +}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { + x: 1000, + y: 1000, + z: 1000 +}; + +var LINE_LENGTH = 500; +var PICK_MAX_DISTANCE = 500; // max length of pick-ray + +// +// near grabbing +// + +var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected +var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. +var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected +var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things +var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object +var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed + +// +// equip +// + +var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; +var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position + +// +// other constants +// + +var RIGHT_HAND = 1; +var LEFT_HAND = 0; + +var ZERO_VEC = { + x: 0, + y: 0, + z: 0 +}; + +var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; +var MSEC_PER_SEC = 1000.0; + +// these control how long an abandoned pointer line or action will hang around +var LIFETIME = 10; +var ACTION_TTL = 15; // seconds +var ACTION_TTL_REFRESH = 5; +var PICKS_PER_SECOND_PER_HAND = 5; +var MSECS_PER_SEC = 1000.0; +var GRABBABLE_PROPERTIES = [ + "position", + "rotation", + "gravity", + "ignoreForCollisions", + "collisionsWillMove", + "locked", + "name" +]; + +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js + +var DEFAULT_GRABBABLE_DATA = { + grabbable: true, + invertSolidWhileHeld: false +}; + +//we've created various ways of visualizing looking for and moving distant objects +var USE_ENTITY_LINES_FOR_SEARCHING = false; +var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_PARTICLE_BEAM_FOR_SEARCHING = false; + +var USE_ENTITY_LINES_FOR_MOVING = true; +var USE_OVERLAY_LINES_FOR_MOVING = false; +var USE_PARTICLE_BEAM_FOR_MOVING = false; + +var USE_SPOTLIGHT = false; +var USE_POINTLIGHT = true; + +// states for the state machine +var STATE_OFF = 0; +var STATE_SEARCHING = 1; +var STATE_DISTANCE_HOLDING = 2; +var STATE_CONTINUE_DISTANCE_HOLDING = 3; +var STATE_NEAR_GRABBING = 4; +var STATE_CONTINUE_NEAR_GRABBING = 5; +var STATE_NEAR_TRIGGER = 6; +var STATE_CONTINUE_NEAR_TRIGGER = 7; +var STATE_FAR_TRIGGER = 8; +var STATE_CONTINUE_FAR_TRIGGER = 9; +var STATE_RELEASE = 10; +var STATE_EQUIP_SEARCHING = 11; +var STATE_EQUIP = 12 +var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down +var STATE_CONTINUE_EQUIP = 14; +var STATE_WAITING_FOR_BUMPER_RELEASE = 15; +var STATE_EQUIP_SPRING = 16; + + + +function stateToName(state) { + switch (state) { + case STATE_OFF: + return "off"; + case STATE_SEARCHING: + return "searching"; + case STATE_DISTANCE_HOLDING: + return "distance_holding"; + case STATE_CONTINUE_DISTANCE_HOLDING: + return "continue_distance_holding"; + case STATE_NEAR_GRABBING: + return "near_grabbing"; + case STATE_CONTINUE_NEAR_GRABBING: + return "continue_near_grabbing"; + case STATE_NEAR_TRIGGER: + return "near_trigger"; + case STATE_CONTINUE_NEAR_TRIGGER: + return "continue_near_trigger"; + case STATE_FAR_TRIGGER: + return "far_trigger"; + case STATE_CONTINUE_FAR_TRIGGER: + return "continue_far_trigger"; + case STATE_RELEASE: + return "release"; + case STATE_EQUIP_SEARCHING: + return "equip_searching"; + case STATE_EQUIP: + return "equip"; + case STATE_CONTINUE_EQUIP_BD: + return "continue_equip_bd"; + case STATE_CONTINUE_EQUIP: + return "continue_equip"; + case STATE_WAITING_FOR_BUMPER_RELEASE: + return "waiting_for_bumper_release"; + case STATE_EQUIP_SPRING: + return "state_equip_spring"; + } + + return "unknown"; +} + +function getTag() { + return "grab-" + MyAvatar.sessionUUID; +} + +function entityIsGrabbedByOther(entityID) { + // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. + var actionIDs = Entities.getActionIDs(entityID); + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments["tag"]; + if (tag == getTag()) { + // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. + continue; + } + if (tag.slice(0, 5) == "grab-") { + // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. + return true; + } + } + return false; +} + +function getSpatialOffsetPosition(hand, spatialKey) { + var position = Vec3.ZERO; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { + position = spatialKey.leftRelativePosition; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { + position = spatialKey.rightRelativePosition; + } + if (spatialKey.relativePosition) { + position = spatialKey.relativePosition; + } + + return position; +} + +var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + +function getSpatialOffsetRotation(hand, spatialKey) { + var rotation = Quat.IDENTITY; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { + rotation = spatialKey.leftRelativeRotation; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { + rotation = spatialKey.rightRelativeRotation; + } + if (spatialKey.relativeRotation) { + rotation = spatialKey.relativeRotation; + } + + // Flip left hand + if (hand !== RIGHT_HAND) { + rotation = Quat.multiply(yFlip, rotation); + } + + return rotation; +} + +function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + } + + var SPATIAL_CONTROLLERS_PER_PALM = 2; + var TIP_CONTROLLER_OFFSET = 1; + this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; + this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; + + this.actionID = null; // action this script created... + this.grabbedEntity = null; // on this entity. + this.state = STATE_OFF; + this.pointer = null; // entity-id of line object + this.triggerValue = 0; // rolling average of trigger value + this.rawTriggerValue = 0; + this.rawBumperValue = 0; + + //for visualizations + this.overlayLine = null; + this.particleBeam = null; + + //for lights + this.spotlight = null; + this.pointlight = null; + + this.ignoreIK = false; + this.offsetPosition = Vec3.ZERO; + this.offsetRotation = Quat.IDENTITY; + + var _this = this; + + this.update = function() { + + this.updateSmoothedTrigger(); + + switch (this.state) { + case STATE_OFF: + this.off(); + this.touchTest(); + break; + case STATE_SEARCHING: + this.search(); + break; + case STATE_EQUIP_SEARCHING: + this.search(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; + case STATE_NEAR_GRABBING: + case STATE_EQUIP: + this.nearGrabbing(); + break; + case STATE_WAITING_FOR_BUMPER_RELEASE: + this.waitingForBumperRelease(); + break; + case STATE_EQUIP_SPRING: + this.pullTowardEquipPosition() + break; + case STATE_CONTINUE_NEAR_GRABBING: + case STATE_CONTINUE_EQUIP_BD: + case STATE_CONTINUE_EQUIP: + this.continueNearGrabbing(); + break; + case STATE_NEAR_TRIGGER: + this.nearTrigger(); + break; + case STATE_CONTINUE_NEAR_TRIGGER: + this.continueNearTrigger(); + break; + case STATE_FAR_TRIGGER: + this.farTrigger(); + break; + case STATE_CONTINUE_FAR_TRIGGER: + this.continueFarTrigger(); + break; + case STATE_RELEASE: + this.release(); + break; + } + }; + + this.setState = function(newState) { + if (WANT_DEBUG) { + print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); + } + this.state = newState; + }; + + this.debugLine = function(closePoint, farPoint, color) { + Entities.addEntity({ + type: "Line", + name: "Grab Debug Entity", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + }; + + this.lineOn = function(closePoint, farPoint, color) { + // draw a line + if (this.pointer === null) { + this.pointer = Entities.addEntity({ + type: "Line", + name: "grab pointer", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: LIFETIME, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } else { + var age = Entities.getEntityProperties(this.pointer, "age").age; + this.pointer = Entities.editEntity(this.pointer, { + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: age + LIFETIME + }); + } + }; + + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine === null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, // always ignore this + visible: true, + alpha: 1 + }; + + this.overlayLine = Overlays.addOverlay("line3d", lineProperties); + + } else { + var success = Overlays.editOverlay(this.overlayLine, { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + visible: true, + ignoreRayIntersection: true, // always ignore this + alpha: 1 + }); + } + }; + + this.handleParticleBeam = function(position, orientation, color) { + + var rotation = Quat.angleAxis(0, { + x: 1, + y: 0, + z: 0 + }); + + var finalRotation = Quat.multiply(orientation, rotation); + + if (this.particleBeam === null) { + this.createParticleBeam(position, finalRotation, color); + } else { + this.updateParticleBeam(position, finalRotation, color); + } + }; + + this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); + + var distance = Vec3.distance(handPosition, objectPosition); + var speed = distance * 1; + + var lifepsan = distance / speed; + var lifespan = 1; + + if (this.particleBeam === null) { + this.createParticleBeam(objectPosition, finalRotation, color, speed); + } else { + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + } + }; + + this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + + var particleBeamProperties = { + type: "ParticleEffect", + isEmitting: true, + position: position, + visible: false, + //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), + "name": "Particle Beam", + "color": color, + "maxParticles": 2000, + "lifespan": LINE_LENGTH / 10, + "emitRate": 50, + "emitSpeed": 5, + "speedSpread": 2, + "emitOrientation": { + "x": -1, + "y": 0, + "z": 0, + "w": 1 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitRadiusStart": 0.5, + "polarStart": 0, + "polarFinish": 0, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + x: 0, + y: 0, + z: 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.01, + "radiusSpread": 0, + // "radiusStart": 0.01, + // "radiusFinish": 0.01, + // "colorSpread": { + // "red": 0, + // "green": 0, + // "blue": 0 + // }, + // "colorStart": color, + // "colorFinish": color, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 1, + "alphaFinish": 1, + "additiveBlending": 1, + "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" + } + + this.particleBeam = Entities.addEntity(particleBeamProperties); + }; + + this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { + + Entities.editEntity(this.particleBeam, { + rotation: orientation, + position: position, + visible: true, + color: color, + emitSpeed: speed, + lifepsan: lifepsan + + }) + + }; + + this.evalLightWorldTransform = function(modelPos, modelRot) { + + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + }; + + this.handleSpotlight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + Entities.editEntity(this.spotlight, { + //without this, this light would maintain rotation with its parent + rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + }) + } + }; + + this.handlePointLight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + + var lightProperties = { + type: "Light", + isSpotlight: false, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.pointlight === null) { + this.pointlight = Entities.addEntity(lightProperties); + } else { + + } + }; + + this.lineOff = function() { + if (this.pointer !== null) { + Entities.deleteEntity(this.pointer); + } + this.pointer = null; + }; + + this.overlayLineOff = function() { + if (this.overlayLine !== null) { + Overlays.deleteOverlay(this.overlayLine); + } + this.overlayLine = null; + }; + + this.particleBeamOff = function() { + if (this.particleBeam !== null) { + Entities.editEntity(this.particleBeam, { + visible: false + }) + } + } + + this.turnLightsOff = function() { + if (this.spotlight !== null) { + Entities.deleteEntity(this.spotlight); + this.spotlight = null; + } + + if (this.pointlight !== null) { + Entities.deleteEntity(this.pointlight); + this.pointlight = null; + } + }; + + + this.turnOffVisualizations = function() { + if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOff(); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + }; + + this.triggerPress = function(value) { + _this.rawTriggerValue = value; + }; + + this.bumperPress = function(value) { + _this.rawBumperValue = value; + }; + + this.updateSmoothedTrigger = function() { + var triggerValue = this.rawTriggerValue; + // smooth out trigger value + this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + }; + + this.triggerSmoothedSqueezed = function() { + return this.triggerValue > TRIGGER_ON_VALUE; + }; + + this.triggerSmoothedReleased = function() { + return this.triggerValue < TRIGGER_OFF_VALUE; + }; + + this.triggerSqueezed = function() { + var triggerValue = this.rawTriggerValue; + return triggerValue > TRIGGER_ON_VALUE; + }; + + this.bumperSqueezed = function() { + return _this.rawBumperValue > BUMPER_ON_VALUE; + }; + + this.bumperReleased = function() { + return _this.rawBumperValue < BUMPER_ON_VALUE; + }; + + this.off = function() { + if (this.triggerSmoothedSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_SEARCHING); + return; + } + if (this.bumperSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_EQUIP_SEARCHING); + return; + } + }; + + this.search = function() { + this.grabbedEntity = null; + + if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { + this.setState(STATE_RELEASE); + return; + } + + // the trigger is being pressed, do a ray test + var handPosition = this.getHandPosition(); + var distantPickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()), + length: PICK_MAX_DISTANCE + }; + + // don't pick 60x per second. + var pickRays = []; + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + pickRays = [distantPickRay]; + this.lastPickTime = now; + } + + for (var index = 0; index < pickRays.length; ++index) { + var pickRay = pickRays[index]; + var directionNormalized = Vec3.normalize(pickRay.direction); + var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); + var pickRayBacked = { + origin: Vec3.subtract(pickRay.origin, directionBacked), + direction: pickRay.direction + }; + + if (WANT_DEBUG) { + this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { + red: 0, + green: 255, + blue: 0 + }) + } + + var intersection = Entities.findRayIntersection(pickRayBacked, true); + + if (intersection.intersects) { + // the ray is intersecting something we can move. + var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); + + if (intersection.properties.name == "Grab Debug Entity") { + continue; + } + + if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { + continue; + } + if (intersectionDistance > pickRay.length) { + // too far away for this ray. + continue; + } + if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { + // the hand is very close to the intersected object. go into close-grabbing mode. + if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!intersection.properties.locked) { + this.grabbedEntity = intersection.entityID; + if (this.state == STATE_SEARCHING) { + this.setState(STATE_NEAR_GRABBING); + } else { // equipping + if (typeof grabbableData.spatialKey !== 'undefined') { + // TODO + // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch + // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + } else { + this.setState(STATE_EQUIP); + } + } + return; + } + } else if (!entityIsGrabbedByOther(intersection.entityID)) { + // don't allow two people to distance grab the same object + if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { + // the hand is far from the intersected object. go into distance-holding mode + this.grabbedEntity = intersection.entityID; + if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { + // if a distance pick in equip mode hits something with a spatialKey, equip it + // TODO use STATE_EQUIP_SPRING here once it works right. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + return; + } else if (this.state == STATE_SEARCHING) { + this.setState(STATE_DISTANCE_HOLDING); + return; + } + } else if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_FAR_TRIGGER); + return; + } + } + } + } + + // forward ray test failed, try sphere test. + if (WANT_DEBUG) { + Entities.addEntity({ + type: "Sphere", + name: "Grab Debug Entity", + dimensions: { + x: GRAB_RADIUS, + y: GRAB_RADIUS, + z: GRAB_RADIUS + }, + visible: true, + position: handPosition, + color: { + red: 0, + green: 255, + blue: 0 + }, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } + + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = PICK_MAX_DISTANCE; + var i, props, distance, grabbableData; + this.grabbedEntity = null; + for (i = 0; i < nearbyEntities.length; i++) { + var grabbableDataForCandidate = + getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); + if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { + continue; + } + var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); + + if (propsForCandidate.type == 'Unknown') { + continue; + } + + if (propsForCandidate.type == 'Light') { + continue; + } + + if (propsForCandidate.type == 'ParticleEffect') { + continue; + } + + if (propsForCandidate.type == 'PolyLine') { + continue; + } + + if (propsForCandidate.type == 'Zone') { + continue; + } + + if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { + continue; + } + + if (propsForCandidate.name == "Grab Debug Entity") { + continue; + } + + if (propsForCandidate.name == "grab pointer") { + continue; + } + + distance = Vec3.distance(propsForCandidate.position, handPosition); + if (distance < minDistance) { + this.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + props = propsForCandidate; + grabbableData = grabbableDataForCandidate; + } + } + if (this.grabbedEntity !== null) { + if (grabbableData.wantsTrigger) { + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!props.locked && props.collisionsWillMove) { + this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) + return; + } + } + + //search line visualizations + if (USE_ENTITY_LINES_FOR_SEARCHING === true) { + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + } + + }; + + this.distanceHolding = function() { + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var now = Date.now(); + + // add the action and initialize some variables + this.currentObjectPosition = grabbedProperties.position; + this.currentObjectRotation = grabbedProperties.rotation; + this.currentObjectTime = now; + this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); + this.handPreviousRotation = handRotation; + this.currentCameraOrientation = Camera.orientation; + + // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object + this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); + if (this.radiusScalar < 1.0) { + this.radiusScalar = 1.0; + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + tag: getTag(), + ttl: ACTION_TTL + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + + if (this.actionID !== null) { + this.setState(STATE_CONTINUE_DISTANCE_HOLDING); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + } + + this.currentAvatarPosition = MyAvatar.position; + this.currentAvatarOrientation = MyAvatar.orientation; + + this.turnOffVisualizations(); + }; + + this.continueDistanceHolding = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + var handPosition = this.getHandPosition(); + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && + typeof grabbableData.spatialKey !== 'undefined') { + var saveGrabbedID = this.grabbedEntity; + this.release(); + this.setState(STATE_EQUIP); + this.grabbedEntity = saveGrabbedID; + return; + } + + + // the action was set up on a previous call. update the targets. + var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; + if (radius < 1.0) { + radius = 1.0; + } + + // how far did avatar move this timestep? + var currentPosition = MyAvatar.position; + var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); + this.currentAvatarPosition = currentPosition; + + // How far did the avatar turn this timestep? + // Note: The following code is too long because we need a Quat.quatBetween() function + // that returns the minimum quaternion between two quaternions. + var currentOrientation = MyAvatar.orientation; + if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) { + var negativeCurrentOrientation = { + x: -currentOrientation.x, + y: -currentOrientation.y, + z: -currentOrientation.z, + w: -currentOrientation.w + }; + var avatarDeltaOrientation = Quat.multiply(negativeCurrentOrientation, Quat.inverse(this.currentAvatarOrientation)); + } else { + var avatarDeltaOrientation = Quat.multiply(currentOrientation, Quat.inverse(this.currentAvatarOrientation)); + } + var handToAvatar = Vec3.subtract(handControllerPosition, this.currentAvatarPosition); + var objectToAvatar = Vec3.subtract(this.currentObjectPosition, this.currentAvatarPosition); + var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar); + var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar); + this.currentAvatarOrientation = currentOrientation; + + // how far did hand move this timestep? + var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); + this.handRelativePreviousPosition = handToAvatar; + + // magnify the hand movement but not the change from avatar movement & rotation + handMoved = Vec3.subtract(handMoved, handMovementFromTurning); + var superHandMoved = Vec3.multiply(handMoved, radius); + + // Move the object by the magnified amount and then by amount from avatar movement & rotation + var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); + newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); + newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); + + var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters + var now = Date.now(); + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentObjectPosition = newObjectPosition; + this.currentObjectTime = now; + + // this doubles hand rotation + var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, + handRotation, + DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), + Quat.inverse(this.handPreviousRotation)); + this.handPreviousRotation = handRotation; + this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); + + Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + + + //visualizations + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } + if (USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); + } + if (USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + } + if (USE_POINTLIGHT === true) { + this.handlePointLight(this.grabbedEntity); + } + if (USE_SPOTLIGHT === true) { + this.handleSpotlight(this.grabbedEntity); + } + + Entities.updateAction(this.grabbedEntity, this.actionID, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + ttl: ACTION_TTL + }); + + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + }; + + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } + + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.ignoreIK = false; + + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } else { + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + + } + + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; + + this.currentObjectTime = Date.now(); + }; + + this.continueNearGrabbing = function() { + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { + this.setState(STATE_CONTINUE_EQUIP); + return; + } + if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { + this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); + return; + } + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { + this.setState(STATE_CONTINUE_EQUIP_BD); + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + return; + } + + // Keep track of the fingertip velocity to impart when we release the object. + // Note that the idea of using a constant 'tip' velocity regardless of the + // object's actual held offset is an idea intended to make it easier to throw things: + // Because we might catch something or transfer it between hands without a good idea + // of it's actual offset, let's try imparting a velocity which is at a fixed radius + // from the palm. + + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var now = Date.now(); + + var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentHandControllerTipPosition = handControllerPosition; + this.currentObjectTime = now; + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); + + if (this.state === STATE_CONTINUE_EQUIP_BD) { + Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + } + + if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + // if less than a 5 seconds left, refresh the actions ttl + Entities.updateAction(this.grabbedEntity, this.actionID, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + } + }; + + this.waitingForBumperRelease = function() { + if (this.bumperReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + Entities.callEntityMethod(this.grabbedEntity, "unequip"); + this.endHandGrasp(); + + } + }; + + this.pullTowardEquipPosition = function() { + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + // use a spring to pull the object to where it will be when equipped + var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + var targetRotation = Quat.multiply(handRotation, relativeRotation); + var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); + var targetPosition = Vec3.sum(handPosition, offset); + + if (typeof this.equipSpringID === 'undefined' || + this.equipSpringID === null || + this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + if (this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = null; + this.setState(STATE_OFF); + return; + } + } else { + Entities.updateAction(this.grabbedEntity, this.equipSpringID, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + } + + if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { + Entities.deleteAction(this.grabbedEntity, this.equipSpringID); + this.equipSpringID = null; + this.setState(STATE_EQUIP); + } + }; + + this.nearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.setState(STATE_CONTINUE_NEAR_TRIGGER); + }; + + this.farTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.setState(STATE_CONTINUE_FAR_TRIGGER); + }; + + this.continueNearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); + }; + + this.continueFarTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + var handPosition = this.getHandPosition(); + var pickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()) + }; + + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + var intersection = Entities.findRayIntersection(pickRay, true); + this.lastPickTime = now; + if (intersection.entityID != this.grabbedEntity) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + } + + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); + }; + + _this.allTouchedIDs = {}; + + this.touchTest = function() { + var maxDistance = 0.05; + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); + var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); + var ids = []; + + if (leftEntities.length !== 0) { + leftEntities.forEach(function(entity) { + ids.push(entity); + }); + + } + + if (rightEntities.length !== 0) { + rightEntities.forEach(function(entity) { + ids.push(entity); + }); + } + + ids.forEach(function(id) { + + var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); + if (props.name === 'pointer') { + return; + } else { + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id]) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + + } else { + //we are in another state + return; + } + } + + }); + + }; + + this.startTouch = function(entityID) { + Entities.callEntityMethod(entityID, "startTouch"); + }; + + this.continueTouch = function(entityID) { + Entities.callEntityMethod(entityID, "continueTouch"); + }; + + this.stopTouch = function(entityID) { + Entities.callEntityMethod(entityID, "stopTouch"); + }; + + this.release = function() { + + this.turnLightsOff(); + this.turnOffVisualizations(); + + if (this.grabbedEntity !== null) { + if (this.actionID !== null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); + } + } + + this.deactivateEntity(this.grabbedEntity); + + this.grabbedEntity = null; + this.actionID = null; + this.setState(STATE_OFF); + }; + + this.cleanup = function() { + this.release(); + this.endHandGrasp(); + Entities.deleteEntity(this.particleBeam); + Entities.deleteEntity(this.spotLight); + Entities.deleteEntity(this.pointLight); + }; + + this.activateEntity = function(entityID, grabbedProperties) { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); + var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["activated"] = true; + data["avatarId"] = MyAvatar.sessionUUID; + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done + if (data["refCount"] == 1) { + data["gravity"] = grabbedProperties.gravity; + data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; + var whileHeldProperties = { + gravity: { + x: 0, + y: 0, + z: 0 + } + }; + if (invertSolidWhileHeld) { + whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; + } + Entities.editEntity(entityID, whileHeldProperties); + } + + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + return data; + }; + + this.deactivateEntity = function(entityID) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + if (data && data["refCount"]) { + data["refCount"] = data["refCount"] - 1; + if (data["refCount"] < 1) { + Entities.editEntity(entityID, { + gravity: data["gravity"], + ignoreForCollisions: data["ignoreForCollisions"], + collisionsWillMove: data["collisionsWillMove"] + }); + data = null; + } + } else { + data = null; + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + }; + + + //this is our handler, where we do the actual work of changing animation settings + this.graspHand = function(animationProperties) { + var result = {}; + //full alpha on overlay for this hand + //set grab to true + //set idle to false + //full alpha on the blend btw open and grab + if (_this.hand === RIGHT_HAND) { + result['rightHandOverlayAlpha'] = 1.0; + result['isRightHandGrab'] = true; + result['isRightHandIdle'] = false; + result['rightHandGrabBlend'] = 1.0; + } else if (_this.hand === LEFT_HAND) { + result['leftHandOverlayAlpha'] = 1.0; + result['isLeftHandGrab'] = true; + result['isLeftHandIdle'] = false; + result['leftHandGrabBlend'] = 1.0; + } + //return an object with our updated settings + return result; + }; + + this.graspHandler = null + + this.startHandGrasp = function() { + if (this.hand === RIGHT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); + } else if (this.hand === LEFT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); + } + }; + + this.endHandGrasp = function() { + // Tell the animation system we don't need any more callbacks. + MyAvatar.removeAnimationStateHandler(this.graspHandler); + }; + +}; + +var rightController = new MyController(RIGHT_HAND); +var leftController = new MyController(LEFT_HAND); + +//preload the particle beams so that they are full length when you start searching +if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + rightController.createParticleBeam(); + leftController.createParticleBeam(); +} + +var MAPPING_NAME = "com.highfidelity.handControllerGrab"; + +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); +mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); + +mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); +mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); + +Controller.enableMapping(MAPPING_NAME); + +//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items +var handToDisable = 'none'; + +function update() { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { + leftController.update(); + } + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { + rightController.update(); + } +} + +Messages.subscribe('Hifi-Hand-Disabler'); + +handleHandDisablerMessages = function(channel, message, sender) { + + if (sender === MyAvatar.sessionUUID) { + if (message === 'left') { + handToDisable = LEFT_HAND; + } + if (message === 'right') { + handToDisable = RIGHT_HAND; + } + if (message === 'both') { + handToDisable = 'both'; + } + if (message === 'none') { + handToDisable = 'none'; + } + } + +} + +Messages.messageReceived.connect(handleHandDisablerMessages); + +function cleanup() { + rightController.cleanup(); + leftController.cleanup(); + Controller.disableMapping(MAPPING_NAME); +} + +Script.scriptEnding.connect(cleanup); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/controllers/handControllerGrab-spotlight.js b/examples/controllers/handControllerGrab-spotlight.js new file mode 100644 index 0000000000..ea05a44f78 --- /dev/null +++ b/examples/controllers/handControllerGrab-spotlight.js @@ -0,0 +1,1649 @@ +// handControllerGrab.js +// +// Created by Eric Levin on 9/2/15 +// Additions by James B. Pollack @imgntn on 9/24/2015 +// Additions By Seth Alves on 10/20/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// Also supports touch and equipping objects. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ + +Script.include("../libraries/utils.js"); + +// +// add lines where the hand ray picking is happening +// +var WANT_DEBUG = false; + +// +// these tune time-averaging and "on" value for analog trigger +// + +var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value +var TRIGGER_ON_VALUE = 0.4; +var TRIGGER_OFF_VALUE = 0.15; + +var BUMPER_ON_VALUE = 0.5; + +// +// distant manipulation +// + +var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects + +var NO_INTERSECT_COLOR = { + red: 10, + green: 10, + blue: 255 +}; // line color when pick misses +var INTERSECT_COLOR = { + red: 250, + green: 10, + blue: 10 +}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { + x: 1000, + y: 1000, + z: 1000 +}; + +var LINE_LENGTH = 500; +var PICK_MAX_DISTANCE = 500; // max length of pick-ray + +// +// near grabbing +// + +var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected +var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. +var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected +var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things +var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object +var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed + +// +// equip +// + +var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; +var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position + +// +// other constants +// + +var RIGHT_HAND = 1; +var LEFT_HAND = 0; + +var ZERO_VEC = { + x: 0, + y: 0, + z: 0 +}; + +var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; +var MSEC_PER_SEC = 1000.0; + +// these control how long an abandoned pointer line or action will hang around +var LIFETIME = 10; +var ACTION_TTL = 15; // seconds +var ACTION_TTL_REFRESH = 5; +var PICKS_PER_SECOND_PER_HAND = 5; +var MSECS_PER_SEC = 1000.0; +var GRABBABLE_PROPERTIES = [ + "position", + "rotation", + "gravity", + "ignoreForCollisions", + "collisionsWillMove", + "locked", + "name" +]; + +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js + +var DEFAULT_GRABBABLE_DATA = { + grabbable: true, + invertSolidWhileHeld: false +}; + +//we've created various ways of visualizing looking for and moving distant objects +var USE_ENTITY_LINES_FOR_SEARCHING = false; +var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_PARTICLE_BEAM_FOR_SEARCHING = false; + +var USE_ENTITY_LINES_FOR_MOVING = true; +var USE_OVERLAY_LINES_FOR_MOVING = false; +var USE_PARTICLE_BEAM_FOR_MOVING = false; + +var USE_SPOTLIGHT = true; +var USE_POINTLIGHT = false; + +// states for the state machine +var STATE_OFF = 0; +var STATE_SEARCHING = 1; +var STATE_DISTANCE_HOLDING = 2; +var STATE_CONTINUE_DISTANCE_HOLDING = 3; +var STATE_NEAR_GRABBING = 4; +var STATE_CONTINUE_NEAR_GRABBING = 5; +var STATE_NEAR_TRIGGER = 6; +var STATE_CONTINUE_NEAR_TRIGGER = 7; +var STATE_FAR_TRIGGER = 8; +var STATE_CONTINUE_FAR_TRIGGER = 9; +var STATE_RELEASE = 10; +var STATE_EQUIP_SEARCHING = 11; +var STATE_EQUIP = 12 +var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down +var STATE_CONTINUE_EQUIP = 14; +var STATE_WAITING_FOR_BUMPER_RELEASE = 15; +var STATE_EQUIP_SPRING = 16; + + + +function stateToName(state) { + switch (state) { + case STATE_OFF: + return "off"; + case STATE_SEARCHING: + return "searching"; + case STATE_DISTANCE_HOLDING: + return "distance_holding"; + case STATE_CONTINUE_DISTANCE_HOLDING: + return "continue_distance_holding"; + case STATE_NEAR_GRABBING: + return "near_grabbing"; + case STATE_CONTINUE_NEAR_GRABBING: + return "continue_near_grabbing"; + case STATE_NEAR_TRIGGER: + return "near_trigger"; + case STATE_CONTINUE_NEAR_TRIGGER: + return "continue_near_trigger"; + case STATE_FAR_TRIGGER: + return "far_trigger"; + case STATE_CONTINUE_FAR_TRIGGER: + return "continue_far_trigger"; + case STATE_RELEASE: + return "release"; + case STATE_EQUIP_SEARCHING: + return "equip_searching"; + case STATE_EQUIP: + return "equip"; + case STATE_CONTINUE_EQUIP_BD: + return "continue_equip_bd"; + case STATE_CONTINUE_EQUIP: + return "continue_equip"; + case STATE_WAITING_FOR_BUMPER_RELEASE: + return "waiting_for_bumper_release"; + case STATE_EQUIP_SPRING: + return "state_equip_spring"; + } + + return "unknown"; +} + +function getTag() { + return "grab-" + MyAvatar.sessionUUID; +} + +function entityIsGrabbedByOther(entityID) { + // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. + var actionIDs = Entities.getActionIDs(entityID); + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments["tag"]; + if (tag == getTag()) { + // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. + continue; + } + if (tag.slice(0, 5) == "grab-") { + // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. + return true; + } + } + return false; +} + +function getSpatialOffsetPosition(hand, spatialKey) { + var position = Vec3.ZERO; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { + position = spatialKey.leftRelativePosition; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { + position = spatialKey.rightRelativePosition; + } + if (spatialKey.relativePosition) { + position = spatialKey.relativePosition; + } + + return position; +} + +var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + +function getSpatialOffsetRotation(hand, spatialKey) { + var rotation = Quat.IDENTITY; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { + rotation = spatialKey.leftRelativeRotation; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { + rotation = spatialKey.rightRelativeRotation; + } + if (spatialKey.relativeRotation) { + rotation = spatialKey.relativeRotation; + } + + // Flip left hand + if (hand !== RIGHT_HAND) { + rotation = Quat.multiply(yFlip, rotation); + } + + return rotation; +} + +function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + } + + var SPATIAL_CONTROLLERS_PER_PALM = 2; + var TIP_CONTROLLER_OFFSET = 1; + this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; + this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; + + this.actionID = null; // action this script created... + this.grabbedEntity = null; // on this entity. + this.state = STATE_OFF; + this.pointer = null; // entity-id of line object + this.triggerValue = 0; // rolling average of trigger value + this.rawTriggerValue = 0; + this.rawBumperValue = 0; + + //for visualizations + this.overlayLine = null; + this.particleBeam = null; + + //for lights + this.spotlight = null; + this.pointlight = null; + + this.ignoreIK = false; + this.offsetPosition = Vec3.ZERO; + this.offsetRotation = Quat.IDENTITY; + + var _this = this; + + this.update = function() { + + this.updateSmoothedTrigger(); + + switch (this.state) { + case STATE_OFF: + this.off(); + this.touchTest(); + break; + case STATE_SEARCHING: + this.search(); + break; + case STATE_EQUIP_SEARCHING: + this.search(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; + case STATE_NEAR_GRABBING: + case STATE_EQUIP: + this.nearGrabbing(); + break; + case STATE_WAITING_FOR_BUMPER_RELEASE: + this.waitingForBumperRelease(); + break; + case STATE_EQUIP_SPRING: + this.pullTowardEquipPosition() + break; + case STATE_CONTINUE_NEAR_GRABBING: + case STATE_CONTINUE_EQUIP_BD: + case STATE_CONTINUE_EQUIP: + this.continueNearGrabbing(); + break; + case STATE_NEAR_TRIGGER: + this.nearTrigger(); + break; + case STATE_CONTINUE_NEAR_TRIGGER: + this.continueNearTrigger(); + break; + case STATE_FAR_TRIGGER: + this.farTrigger(); + break; + case STATE_CONTINUE_FAR_TRIGGER: + this.continueFarTrigger(); + break; + case STATE_RELEASE: + this.release(); + break; + } + }; + + this.setState = function(newState) { + if (WANT_DEBUG) { + print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); + } + this.state = newState; + }; + + this.debugLine = function(closePoint, farPoint, color) { + Entities.addEntity({ + type: "Line", + name: "Grab Debug Entity", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + }; + + this.lineOn = function(closePoint, farPoint, color) { + // draw a line + if (this.pointer === null) { + this.pointer = Entities.addEntity({ + type: "Line", + name: "grab pointer", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: LIFETIME, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } else { + var age = Entities.getEntityProperties(this.pointer, "age").age; + this.pointer = Entities.editEntity(this.pointer, { + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: age + LIFETIME + }); + } + }; + + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine === null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, // always ignore this + visible: true, + alpha: 1 + }; + + this.overlayLine = Overlays.addOverlay("line3d", lineProperties); + + } else { + var success = Overlays.editOverlay(this.overlayLine, { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + visible: true, + ignoreRayIntersection: true, // always ignore this + alpha: 1 + }); + } + }; + + this.handleParticleBeam = function(position, orientation, color) { + + var rotation = Quat.angleAxis(0, { + x: 1, + y: 0, + z: 0 + }); + + var finalRotation = Quat.multiply(orientation, rotation); + + if (this.particleBeam === null) { + this.createParticleBeam(position, finalRotation, color); + } else { + this.updateParticleBeam(position, finalRotation, color); + } + }; + + this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); + + var distance = Vec3.distance(handPosition, objectPosition); + var speed = distance * 1; + + var lifepsan = distance / speed; + var lifespan = 1; + + if (this.particleBeam === null) { + this.createParticleBeam(objectPosition, finalRotation, color, speed); + } else { + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + } + }; + + this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + + var particleBeamProperties = { + type: "ParticleEffect", + isEmitting: true, + position: position, + visible: false, + //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), + "name": "Particle Beam", + "color": color, + "maxParticles": 2000, + "lifespan": LINE_LENGTH / 10, + "emitRate": 50, + "emitSpeed": 5, + "speedSpread": 2, + "emitOrientation": { + "x": -1, + "y": 0, + "z": 0, + "w": 1 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitRadiusStart": 0.5, + "polarStart": 0, + "polarFinish": 0, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + x: 0, + y: 0, + z: 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.01, + "radiusSpread": 0, + // "radiusStart": 0.01, + // "radiusFinish": 0.01, + // "colorSpread": { + // "red": 0, + // "green": 0, + // "blue": 0 + // }, + // "colorStart": color, + // "colorFinish": color, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 1, + "alphaFinish": 1, + "additiveBlending": 1, + "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" + } + + this.particleBeam = Entities.addEntity(particleBeamProperties); + }; + + this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { + + Entities.editEntity(this.particleBeam, { + rotation: orientation, + position: position, + visible: true, + color: color, + emitSpeed: speed, + lifepsan: lifepsan + + }) + + }; + + this.evalLightWorldTransform = function(modelPos, modelRot) { + + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + }; + + this.handleSpotlight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + Entities.editEntity(this.spotlight, { + //without this, this light would maintain rotation with its parent + rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + }) + } + }; + + this.handlePointLight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + + var lightProperties = { + type: "Light", + isSpotlight: false, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.pointlight === null) { + this.pointlight = Entities.addEntity(lightProperties); + } else { + + } + }; + + this.lineOff = function() { + if (this.pointer !== null) { + Entities.deleteEntity(this.pointer); + } + this.pointer = null; + }; + + this.overlayLineOff = function() { + if (this.overlayLine !== null) { + Overlays.deleteOverlay(this.overlayLine); + } + this.overlayLine = null; + }; + + this.particleBeamOff = function() { + if (this.particleBeam !== null) { + Entities.editEntity(this.particleBeam, { + visible: false + }) + } + } + + this.turnLightsOff = function() { + if (this.spotlight !== null) { + Entities.deleteEntity(this.spotlight); + this.spotlight = null; + } + + if (this.pointlight !== null) { + Entities.deleteEntity(this.pointlight); + this.pointlight = null; + } + }; + + + this.turnOffVisualizations = function() { + if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOff(); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + }; + + this.triggerPress = function(value) { + _this.rawTriggerValue = value; + }; + + this.bumperPress = function(value) { + _this.rawBumperValue = value; + }; + + this.updateSmoothedTrigger = function() { + var triggerValue = this.rawTriggerValue; + // smooth out trigger value + this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + }; + + this.triggerSmoothedSqueezed = function() { + return this.triggerValue > TRIGGER_ON_VALUE; + }; + + this.triggerSmoothedReleased = function() { + return this.triggerValue < TRIGGER_OFF_VALUE; + }; + + this.triggerSqueezed = function() { + var triggerValue = this.rawTriggerValue; + return triggerValue > TRIGGER_ON_VALUE; + }; + + this.bumperSqueezed = function() { + return _this.rawBumperValue > BUMPER_ON_VALUE; + }; + + this.bumperReleased = function() { + return _this.rawBumperValue < BUMPER_ON_VALUE; + }; + + this.off = function() { + if (this.triggerSmoothedSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_SEARCHING); + return; + } + if (this.bumperSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_EQUIP_SEARCHING); + return; + } + }; + + this.search = function() { + this.grabbedEntity = null; + + if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { + this.setState(STATE_RELEASE); + return; + } + + // the trigger is being pressed, do a ray test + var handPosition = this.getHandPosition(); + var distantPickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()), + length: PICK_MAX_DISTANCE + }; + + // don't pick 60x per second. + var pickRays = []; + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + pickRays = [distantPickRay]; + this.lastPickTime = now; + } + + for (var index = 0; index < pickRays.length; ++index) { + var pickRay = pickRays[index]; + var directionNormalized = Vec3.normalize(pickRay.direction); + var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); + var pickRayBacked = { + origin: Vec3.subtract(pickRay.origin, directionBacked), + direction: pickRay.direction + }; + + if (WANT_DEBUG) { + this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { + red: 0, + green: 255, + blue: 0 + }) + } + + var intersection = Entities.findRayIntersection(pickRayBacked, true); + + if (intersection.intersects) { + // the ray is intersecting something we can move. + var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); + + if (intersection.properties.name == "Grab Debug Entity") { + continue; + } + + if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { + continue; + } + if (intersectionDistance > pickRay.length) { + // too far away for this ray. + continue; + } + if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { + // the hand is very close to the intersected object. go into close-grabbing mode. + if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!intersection.properties.locked) { + this.grabbedEntity = intersection.entityID; + if (this.state == STATE_SEARCHING) { + this.setState(STATE_NEAR_GRABBING); + } else { // equipping + if (typeof grabbableData.spatialKey !== 'undefined') { + // TODO + // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch + // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + } else { + this.setState(STATE_EQUIP); + } + } + return; + } + } else if (!entityIsGrabbedByOther(intersection.entityID)) { + // don't allow two people to distance grab the same object + if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { + // the hand is far from the intersected object. go into distance-holding mode + this.grabbedEntity = intersection.entityID; + if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { + // if a distance pick in equip mode hits something with a spatialKey, equip it + // TODO use STATE_EQUIP_SPRING here once it works right. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + return; + } else if (this.state == STATE_SEARCHING) { + this.setState(STATE_DISTANCE_HOLDING); + return; + } + } else if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_FAR_TRIGGER); + return; + } + } + } + } + + // forward ray test failed, try sphere test. + if (WANT_DEBUG) { + Entities.addEntity({ + type: "Sphere", + name: "Grab Debug Entity", + dimensions: { + x: GRAB_RADIUS, + y: GRAB_RADIUS, + z: GRAB_RADIUS + }, + visible: true, + position: handPosition, + color: { + red: 0, + green: 255, + blue: 0 + }, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } + + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = PICK_MAX_DISTANCE; + var i, props, distance, grabbableData; + this.grabbedEntity = null; + for (i = 0; i < nearbyEntities.length; i++) { + var grabbableDataForCandidate = + getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); + if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { + continue; + } + var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); + + if (propsForCandidate.type == 'Unknown') { + continue; + } + + if (propsForCandidate.type == 'Light') { + continue; + } + + if (propsForCandidate.type == 'ParticleEffect') { + continue; + } + + if (propsForCandidate.type == 'PolyLine') { + continue; + } + + if (propsForCandidate.type == 'Zone') { + continue; + } + + if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { + continue; + } + + if (propsForCandidate.name == "Grab Debug Entity") { + continue; + } + + if (propsForCandidate.name == "grab pointer") { + continue; + } + + distance = Vec3.distance(propsForCandidate.position, handPosition); + if (distance < minDistance) { + this.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + props = propsForCandidate; + grabbableData = grabbableDataForCandidate; + } + } + if (this.grabbedEntity !== null) { + if (grabbableData.wantsTrigger) { + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!props.locked && props.collisionsWillMove) { + this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) + return; + } + } + + //search line visualizations + if (USE_ENTITY_LINES_FOR_SEARCHING === true) { + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + } + + }; + + this.distanceHolding = function() { + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var now = Date.now(); + + // add the action and initialize some variables + this.currentObjectPosition = grabbedProperties.position; + this.currentObjectRotation = grabbedProperties.rotation; + this.currentObjectTime = now; + this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); + this.handPreviousRotation = handRotation; + this.currentCameraOrientation = Camera.orientation; + + // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object + this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); + if (this.radiusScalar < 1.0) { + this.radiusScalar = 1.0; + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + tag: getTag(), + ttl: ACTION_TTL + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + + if (this.actionID !== null) { + this.setState(STATE_CONTINUE_DISTANCE_HOLDING); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + } + + this.currentAvatarPosition = MyAvatar.position; + this.currentAvatarOrientation = MyAvatar.orientation; + + this.turnOffVisualizations(); + }; + + this.continueDistanceHolding = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + var handPosition = this.getHandPosition(); + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && + typeof grabbableData.spatialKey !== 'undefined') { + var saveGrabbedID = this.grabbedEntity; + this.release(); + this.setState(STATE_EQUIP); + this.grabbedEntity = saveGrabbedID; + return; + } + + + // the action was set up on a previous call. update the targets. + var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; + if (radius < 1.0) { + radius = 1.0; + } + + // how far did avatar move this timestep? + var currentPosition = MyAvatar.position; + var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); + this.currentAvatarPosition = currentPosition; + + // How far did the avatar turn this timestep? + // Note: The following code is too long because we need a Quat.quatBetween() function + // that returns the minimum quaternion between two quaternions. + var currentOrientation = MyAvatar.orientation; + if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) { + var negativeCurrentOrientation = { + x: -currentOrientation.x, + y: -currentOrientation.y, + z: -currentOrientation.z, + w: -currentOrientation.w + }; + var avatarDeltaOrientation = Quat.multiply(negativeCurrentOrientation, Quat.inverse(this.currentAvatarOrientation)); + } else { + var avatarDeltaOrientation = Quat.multiply(currentOrientation, Quat.inverse(this.currentAvatarOrientation)); + } + var handToAvatar = Vec3.subtract(handControllerPosition, this.currentAvatarPosition); + var objectToAvatar = Vec3.subtract(this.currentObjectPosition, this.currentAvatarPosition); + var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar); + var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar); + this.currentAvatarOrientation = currentOrientation; + + // how far did hand move this timestep? + var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); + this.handRelativePreviousPosition = handToAvatar; + + // magnify the hand movement but not the change from avatar movement & rotation + handMoved = Vec3.subtract(handMoved, handMovementFromTurning); + var superHandMoved = Vec3.multiply(handMoved, radius); + + // Move the object by the magnified amount and then by amount from avatar movement & rotation + var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); + newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); + newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); + + var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters + var now = Date.now(); + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentObjectPosition = newObjectPosition; + this.currentObjectTime = now; + + // this doubles hand rotation + var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, + handRotation, + DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), + Quat.inverse(this.handPreviousRotation)); + this.handPreviousRotation = handRotation; + this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); + + Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + + + //visualizations + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } + if (USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); + } + if (USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + } + if (USE_POINTLIGHT === true) { + this.handlePointLight(this.grabbedEntity); + } + if (USE_SPOTLIGHT === true) { + this.handleSpotlight(this.grabbedEntity); + } + + Entities.updateAction(this.grabbedEntity, this.actionID, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + ttl: ACTION_TTL + }); + + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + }; + + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } + + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.ignoreIK = false; + + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } else { + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + + } + + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; + + this.currentObjectTime = Date.now(); + }; + + this.continueNearGrabbing = function() { + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { + this.setState(STATE_CONTINUE_EQUIP); + return; + } + if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { + this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); + return; + } + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { + this.setState(STATE_CONTINUE_EQUIP_BD); + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + return; + } + + // Keep track of the fingertip velocity to impart when we release the object. + // Note that the idea of using a constant 'tip' velocity regardless of the + // object's actual held offset is an idea intended to make it easier to throw things: + // Because we might catch something or transfer it between hands without a good idea + // of it's actual offset, let's try imparting a velocity which is at a fixed radius + // from the palm. + + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var now = Date.now(); + + var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentHandControllerTipPosition = handControllerPosition; + this.currentObjectTime = now; + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); + + if (this.state === STATE_CONTINUE_EQUIP_BD) { + Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + } + + if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + // if less than a 5 seconds left, refresh the actions ttl + Entities.updateAction(this.grabbedEntity, this.actionID, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + } + }; + + this.waitingForBumperRelease = function() { + if (this.bumperReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + Entities.callEntityMethod(this.grabbedEntity, "unequip"); + this.endHandGrasp(); + + } + }; + + this.pullTowardEquipPosition = function() { + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + // use a spring to pull the object to where it will be when equipped + var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + var targetRotation = Quat.multiply(handRotation, relativeRotation); + var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); + var targetPosition = Vec3.sum(handPosition, offset); + + if (typeof this.equipSpringID === 'undefined' || + this.equipSpringID === null || + this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + if (this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = null; + this.setState(STATE_OFF); + return; + } + } else { + Entities.updateAction(this.grabbedEntity, this.equipSpringID, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + } + + if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { + Entities.deleteAction(this.grabbedEntity, this.equipSpringID); + this.equipSpringID = null; + this.setState(STATE_EQUIP); + } + }; + + this.nearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.setState(STATE_CONTINUE_NEAR_TRIGGER); + }; + + this.farTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.setState(STATE_CONTINUE_FAR_TRIGGER); + }; + + this.continueNearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); + }; + + this.continueFarTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + var handPosition = this.getHandPosition(); + var pickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()) + }; + + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + var intersection = Entities.findRayIntersection(pickRay, true); + this.lastPickTime = now; + if (intersection.entityID != this.grabbedEntity) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + } + + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); + }; + + _this.allTouchedIDs = {}; + + this.touchTest = function() { + var maxDistance = 0.05; + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); + var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); + var ids = []; + + if (leftEntities.length !== 0) { + leftEntities.forEach(function(entity) { + ids.push(entity); + }); + + } + + if (rightEntities.length !== 0) { + rightEntities.forEach(function(entity) { + ids.push(entity); + }); + } + + ids.forEach(function(id) { + + var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); + if (props.name === 'pointer') { + return; + } else { + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id]) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + + } else { + //we are in another state + return; + } + } + + }); + + }; + + this.startTouch = function(entityID) { + Entities.callEntityMethod(entityID, "startTouch"); + }; + + this.continueTouch = function(entityID) { + Entities.callEntityMethod(entityID, "continueTouch"); + }; + + this.stopTouch = function(entityID) { + Entities.callEntityMethod(entityID, "stopTouch"); + }; + + this.release = function() { + + this.turnLightsOff(); + this.turnOffVisualizations(); + + if (this.grabbedEntity !== null) { + if (this.actionID !== null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); + } + } + + this.deactivateEntity(this.grabbedEntity); + + this.grabbedEntity = null; + this.actionID = null; + this.setState(STATE_OFF); + }; + + this.cleanup = function() { + this.release(); + this.endHandGrasp(); + Entities.deleteEntity(this.particleBeam); + Entities.deleteEntity(this.spotLight); + Entities.deleteEntity(this.pointLight); + }; + + this.activateEntity = function(entityID, grabbedProperties) { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); + var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["activated"] = true; + data["avatarId"] = MyAvatar.sessionUUID; + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done + if (data["refCount"] == 1) { + data["gravity"] = grabbedProperties.gravity; + data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; + var whileHeldProperties = { + gravity: { + x: 0, + y: 0, + z: 0 + } + }; + if (invertSolidWhileHeld) { + whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; + } + Entities.editEntity(entityID, whileHeldProperties); + } + + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + return data; + }; + + this.deactivateEntity = function(entityID) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + if (data && data["refCount"]) { + data["refCount"] = data["refCount"] - 1; + if (data["refCount"] < 1) { + Entities.editEntity(entityID, { + gravity: data["gravity"], + ignoreForCollisions: data["ignoreForCollisions"], + collisionsWillMove: data["collisionsWillMove"] + }); + data = null; + } + } else { + data = null; + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + }; + + + //this is our handler, where we do the actual work of changing animation settings + this.graspHand = function(animationProperties) { + var result = {}; + //full alpha on overlay for this hand + //set grab to true + //set idle to false + //full alpha on the blend btw open and grab + if (_this.hand === RIGHT_HAND) { + result['rightHandOverlayAlpha'] = 1.0; + result['isRightHandGrab'] = true; + result['isRightHandIdle'] = false; + result['rightHandGrabBlend'] = 1.0; + } else if (_this.hand === LEFT_HAND) { + result['leftHandOverlayAlpha'] = 1.0; + result['isLeftHandGrab'] = true; + result['isLeftHandIdle'] = false; + result['leftHandGrabBlend'] = 1.0; + } + //return an object with our updated settings + return result; + }; + + this.graspHandler = null + + this.startHandGrasp = function() { + if (this.hand === RIGHT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); + } else if (this.hand === LEFT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); + } + }; + + this.endHandGrasp = function() { + // Tell the animation system we don't need any more callbacks. + MyAvatar.removeAnimationStateHandler(this.graspHandler); + }; + +}; + +var rightController = new MyController(RIGHT_HAND); +var leftController = new MyController(LEFT_HAND); + +//preload the particle beams so that they are full length when you start searching +if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + rightController.createParticleBeam(); + leftController.createParticleBeam(); +} + +var MAPPING_NAME = "com.highfidelity.handControllerGrab"; + +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); +mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); + +mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); +mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); + +Controller.enableMapping(MAPPING_NAME); + +//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items +var handToDisable = 'none'; + +function update() { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { + leftController.update(); + } + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { + rightController.update(); + } +} + +Messages.subscribe('Hifi-Hand-Disabler'); + +handleHandDisablerMessages = function(channel, message, sender) { + + if (sender === MyAvatar.sessionUUID) { + if (message === 'left') { + handToDisable = LEFT_HAND; + } + if (message === 'right') { + handToDisable = RIGHT_HAND; + } + if (message === 'both') { + handToDisable = 'both'; + } + if (message === 'none') { + handToDisable = 'none'; + } + } + +} + +Messages.messageReceived.connect(handleHandDisablerMessages); + +function cleanup() { + rightController.cleanup(); + leftController.cleanup(); + Controller.disableMapping(MAPPING_NAME); +} + +Script.scriptEnding.connect(cleanup); +Script.update.connect(update); \ No newline at end of file From 8d691f2132f4acdeb7f98692d1ec97236b77b086 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 14 Dec 2015 11:44:42 -0800 Subject: [PATCH 043/209] light ball --- examples/flowArts/lightBall/lightBall.js | 0 .../flowArts/lightBall/lightBallSpawner.js | 51 +++++++++++++++++++ .../entities/src/ParticleEffectEntityItem.cpp | 4 +- 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 examples/flowArts/lightBall/lightBall.js create mode 100644 examples/flowArts/lightBall/lightBallSpawner.js diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js new file mode 100644 index 0000000000..f758c26bbe --- /dev/null +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -0,0 +1,51 @@ +var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation()))); + +var lightBall = Entities.addEntity({ + position: center, + type: "ParticleEffect", + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": {red: 20, green: 20, blue: 255}, + color: {red: 10, green: 0, blue: 255}, + "colorFinish": {red: 250, green: 200, blue:255}, + // "maxParticles": 100000, + "lifespan": 1, + "emitRate": 1000, + "emitSpeed": .1, + "speedSpread": .01, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": 3, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .01, + "y": .01, + "z": .01 + }, + "particleRadius": 0.04, + "radiusSpread": 0, + "radiusStart": 0.05, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + "additiveBlending": 0, + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" +}) + +function cleanup() { + Entities.deleteEntity(lightBall); +} + +Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 5600c85650..f4210f4486 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -52,13 +52,13 @@ const float ParticleEffectEntityItem::MINIMUM_ALPHA = 0.0f; const float ParticleEffectEntityItem::MAXIMUM_ALPHA = 1.0f; const quint32 ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES = 1000; const quint32 ParticleEffectEntityItem::MINIMUM_MAX_PARTICLES = 1; -const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 10000; +const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 100000; const float ParticleEffectEntityItem::DEFAULT_LIFESPAN = 3.0f; const float ParticleEffectEntityItem::MINIMUM_LIFESPAN = 0.0f; const float ParticleEffectEntityItem::MAXIMUM_LIFESPAN = 86400.0f; // 1 day const float ParticleEffectEntityItem::DEFAULT_EMIT_RATE = 15.0f; const float ParticleEffectEntityItem::MINIMUM_EMIT_RATE = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 1000.0f; +const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 100000.0f; const float ParticleEffectEntityItem::DEFAULT_EMIT_SPEED = 5.0f; const float ParticleEffectEntityItem::MINIMUM_EMIT_SPEED = 0.0f; const float ParticleEffectEntityItem::MAXIMUM_EMIT_SPEED = 1000.0f; // Approx mach 3 From 18458a843147f55b4163cac6af1e5dd6b37c2468 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 12:04:44 -0800 Subject: [PATCH 044/209] test scene --- examples/lights/testScene.js | 104 +++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 examples/lights/testScene.js diff --git a/examples/lights/testScene.js b/examples/lights/testScene.js new file mode 100644 index 0000000000..eeb5f4ffd7 --- /dev/null +++ b/examples/lights/testScene.js @@ -0,0 +1,104 @@ + // These constants define the Spotlight position and orientation relative to the model + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + var basePosition, avatarRot; + avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); + basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(SPAWN_RANGE * 3, Quat.getFront(avatarRot))); + + var ground = Entities.addEntity({ + type: "Model", + modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/woodFloor.fbx", + dimensions: { + x: 100, + y: 2, + z: 100 + }, + position: basePosition, + shapeType: 'box' + }); + + var light, block; + + basePosition.y += 2; + + function createLight() { + var lightProperties = { + name: 'Hifi-Spotlight' + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: box, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + rotation: lightTransform.q, + } + light = Entities.addEntity(lightProperties); + + var message = { + light: { + id: light, + type: 'spotlight', + initialProperties:lightProperties + } + }; + Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); + + } + + function createBlock() { + var blockProperties = { + name: 'Hifi-Spotlight-Block', + type: 'Box', + dimensions: { + x: 1, + y: 1, + z: 1 + }, + collisionsWillMove: true, + shapeType: 'Box', + color: { + red: 0, + green: 0 + blue: 255 + }, + position: basePosition + } + + block = Entities.addEntity(block); + } + + function evalLightWorldTransform(modelPos, modelRot) { + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + } + + function cleanup() { + Entities.deleteEntity(ground); + Entities.deleteEntity(light); + } + + createBlock(); + createLight(); \ No newline at end of file From 76487bca7ac69c8fdaa2ec9e8eaaa281871b378e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 13:01:03 -0800 Subject: [PATCH 045/209] updates --- .../handControllerGrab-particles.js | 47 +++++++++++-------- .../handControllerGrab-pointlight.js | 47 +++++++++++-------- .../handControllerGrab-spotlight.js | 47 +++++++++++-------- examples/controllers/handControllerGrab.js | 47 +++++++++++-------- 4 files changed, 108 insertions(+), 80 deletions(-) diff --git a/examples/controllers/handControllerGrab-particles.js b/examples/controllers/handControllerGrab-particles.js index d9ecb18b01..bfe51927d0 100644 --- a/examples/controllers/handControllerGrab-particles.js +++ b/examples/controllers/handControllerGrab-particles.js @@ -437,47 +437,49 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - + var lifespan = LINE_LENGTH / 10; + var speed = 5; + var spread = 2; if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color); + this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(position, finalRotation, color); + this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); } }; - this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); var distance = Vec3.distance(handPosition, objectPosition); - var speed = distance * 1; + var speed = 5; + var spread = 0; + + var lifespan = distance / speed; - var lifepsan = distance / speed; - var lifespan = 1; if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed); + this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } }; - this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, position: position, visible: false, - //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": LINE_LENGTH / 10, + "lifespan": lifespan, "emitRate": 50, - "emitSpeed": 5, - "speedSpread": 2, + "emitSpeed": speed, + "speedSpread": spread, "emitOrientation": { "x": -1, "y": 0, @@ -519,22 +521,23 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 1, + "additiveBlending": 0, "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); }; - this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - + this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { + print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, visible: true, color: color, emitSpeed: speed, - lifepsan: lifepsan + speedSpread:spread, + lifespan: lifespan }) @@ -1108,7 +1111,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); @@ -1399,7 +1403,10 @@ function MyController(hand) { } } - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; diff --git a/examples/controllers/handControllerGrab-pointlight.js b/examples/controllers/handControllerGrab-pointlight.js index fc14e6026e..e7bb4e3e9f 100644 --- a/examples/controllers/handControllerGrab-pointlight.js +++ b/examples/controllers/handControllerGrab-pointlight.js @@ -437,47 +437,49 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - + var lifespan = LINE_LENGTH / 10; + var speed = 5; + var spread = 2; if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color); + this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(position, finalRotation, color); + this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); } }; - this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); var distance = Vec3.distance(handPosition, objectPosition); - var speed = distance * 1; + var speed = 5; + var spread = 0; + + var lifespan = distance / speed; - var lifepsan = distance / speed; - var lifespan = 1; if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed); + this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } }; - this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, position: position, visible: false, - //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": LINE_LENGTH / 10, + "lifespan": lifespan, "emitRate": 50, - "emitSpeed": 5, - "speedSpread": 2, + "emitSpeed": speed, + "speedSpread": spread, "emitOrientation": { "x": -1, "y": 0, @@ -519,22 +521,23 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 1, + "additiveBlending": 0, "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); }; - this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - + this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { + print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, visible: true, color: color, emitSpeed: speed, - lifepsan: lifepsan + speedSpread:spread, + lifespan: lifespan }) @@ -1108,7 +1111,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); @@ -1399,7 +1403,10 @@ function MyController(hand) { } } - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; diff --git a/examples/controllers/handControllerGrab-spotlight.js b/examples/controllers/handControllerGrab-spotlight.js index ea05a44f78..ee6dcfa681 100644 --- a/examples/controllers/handControllerGrab-spotlight.js +++ b/examples/controllers/handControllerGrab-spotlight.js @@ -437,47 +437,49 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - + var lifespan = LINE_LENGTH / 10; + var speed = 5; + var spread = 2; if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color); + this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(position, finalRotation, color); + this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); } }; - this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); var distance = Vec3.distance(handPosition, objectPosition); - var speed = distance * 1; + var speed = 5; + var spread = 0; + + var lifespan = distance / speed; - var lifepsan = distance / speed; - var lifespan = 1; if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed); + this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } }; - this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, position: position, visible: false, - //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": LINE_LENGTH / 10, + "lifespan": lifespan, "emitRate": 50, - "emitSpeed": 5, - "speedSpread": 2, + "emitSpeed": speed, + "speedSpread": spread, "emitOrientation": { "x": -1, "y": 0, @@ -519,22 +521,23 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 1, + "additiveBlending": 0, "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); }; - this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - + this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { + print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, visible: true, color: color, emitSpeed: speed, - lifepsan: lifepsan + speedSpread:spread, + lifespan: lifespan }) @@ -1108,7 +1111,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); @@ -1399,7 +1403,10 @@ function MyController(hand) { } } - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index cd82db22b9..b6f1a82c3f 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -437,47 +437,49 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - + var lifespan = LINE_LENGTH / 10; + var speed = 5; + var spread = 2; if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color); + this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(position, finalRotation, color); + this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); } }; - this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); var distance = Vec3.distance(handPosition, objectPosition); - var speed = distance * 1; + var speed = 5; + var spread = 0; + + var lifespan = distance / speed; - var lifepsan = distance / speed; - var lifespan = 1; if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed); + this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } }; - this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, position: position, visible: false, - //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": LINE_LENGTH / 10, + "lifespan": lifespan, "emitRate": 50, - "emitSpeed": 5, - "speedSpread": 2, + "emitSpeed": speed, + "speedSpread": spread, "emitOrientation": { "x": -1, "y": 0, @@ -519,22 +521,23 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 1, + "additiveBlending": 0, "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); }; - this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - + this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { + print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, visible: true, color: color, emitSpeed: speed, - lifepsan: lifepsan + speedSpread:spread, + lifespan: lifespan }) @@ -1108,7 +1111,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); @@ -1399,7 +1403,10 @@ function MyController(hand) { } } - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; From e3e1bc1dc611b0bbb00860807a04018aa04c7105 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 13:01:44 -0800 Subject: [PATCH 046/209] updates --- .../handControllerGrab-all-overlays.js | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/examples/controllers/handControllerGrab-all-overlays.js b/examples/controllers/handControllerGrab-all-overlays.js index acb47b2260..67e2b1f0a7 100644 --- a/examples/controllers/handControllerGrab-all-overlays.js +++ b/examples/controllers/handControllerGrab-all-overlays.js @@ -437,47 +437,49 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - + var lifespan = LINE_LENGTH / 10; + var speed = 5; + var spread = 2; if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color); + this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(position, finalRotation, color); + this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); } }; - this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); var distance = Vec3.distance(handPosition, objectPosition); - var speed = distance * 1; + var speed = 5; + var spread = 0; + + var lifespan = distance / speed; - var lifepsan = distance / speed; - var lifespan = 1; if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed); + this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } }; - this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, position: position, visible: false, - //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": LINE_LENGTH / 10, + "lifespan": lifespan, "emitRate": 50, - "emitSpeed": 5, - "speedSpread": 2, + "emitSpeed": speed, + "speedSpread": spread, "emitOrientation": { "x": -1, "y": 0, @@ -519,22 +521,23 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 1, + "additiveBlending": 0, "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); }; - this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - + this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { + print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, visible: true, color: color, emitSpeed: speed, - lifepsan: lifepsan + speedSpread:spread, + lifespan: lifespan }) @@ -1108,7 +1111,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); @@ -1399,7 +1403,10 @@ function MyController(hand) { } } - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; From 761dfeaccd72edbd4cd79ce66bb9d9f517b229d1 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 14 Dec 2015 14:53:08 -0800 Subject: [PATCH 047/209] 2 balls --- .../flowArts/lightBall/lightBallSpawner.js | 73 ++++++++++++++++++- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index f758c26bbe..da09829257 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -1,16 +1,80 @@ -var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation()))); +var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); + +var containerBall = Entities.addEntity({ + type: "Sphere", + position: center, + dimensions: {x: .1, y: .1, z: .1}, + color: {red: 50, green: 10, blue: 50}, + collisionsWillMove: true, + gravity: {x: 0, y: -.1, z: 0} +}); var lightBall = Entities.addEntity({ position: center, type: "ParticleEffect", + parentID: containerBall, isEmitting: true, "name": "ParticlesTest Emitter", "colorStart": {red: 20, green: 20, blue: 255}, color: {red: 10, green: 0, blue: 255}, "colorFinish": {red: 250, green: 200, blue:255}, - // "maxParticles": 100000, + "maxParticles": 20000, "lifespan": 1, - "emitRate": 1000, + "emitRate": 10000, + "emitSpeed": .1, + "speedSpread": .01, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": 3, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .01, + "y": .01, + "z": .01 + }, + "particleRadius": 0.04, + "radiusSpread": 0, + "radiusStart": 0.05, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + "additiveBlending": 0, + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" +}) + +var containerBall2 = Entities.addEntity({ + type: "Sphere", + position: Vec3.sum(center, {x: 0.5, y: 0, z: 0}), + dimensions: {x: .1, y: .1, z: .1}, + color: {red: 200, green: 10, blue: 50}, + collisionsWillMove: true, + gravity: {x: 0, y: -.1, z: 0} +}); + +var lightBall2 = Entities.addEntity({ + position: Vec3.sum(center, {x: 0.5, y: 0, z: 0}), + type: "ParticleEffect", + parentID: containerBall2, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": {red: 200, green: 20, blue: 0}, + color: {red: 255, green: 0, blue: 10}, + "colorFinish": {red: 250, green: 200, blue:255}, + "maxParticles": 100000, + "lifespan": 1, + "emitRate": 10000, "emitSpeed": .1, "speedSpread": .01, "emitDimensions": { @@ -46,6 +110,9 @@ var lightBall = Entities.addEntity({ function cleanup() { Entities.deleteEntity(lightBall); + Entities.deleteEntity(lightBall2); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(containerBall2); } Script.scriptEnding.connect(cleanup); \ No newline at end of file From ea0ffa589930f3528ea347e33709f865e6e645c4 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 16:39:25 -0800 Subject: [PATCH 048/209] support changing values for lights via message --- examples/lights/box.js | 18 ++- examples/lights/light_modifier.js | 197 ++++++++++++++++++++++-------- examples/lights/testScene.js | 38 ++++-- 3 files changed, 183 insertions(+), 70 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index ac3cac7ab3..a8e708b344 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -1,5 +1,11 @@ (function() { + var AXIS_SCALE = 1; + var COLOR_MAX = 255; + var INTENSITY_MAX = 10; + var CUTOFF_MAX = 360; + var EXPONENT_MAX = 1; + function Box() { return this; } @@ -7,6 +13,8 @@ Box.prototype = { preload: function(entityID) { this.entityID = entityID; + var userData = Entities.getEntityProperties(this.entityID, "userData"); + this.userData = JSON.parse(userData); }, startNearGrab: function() { this.setInitialProperties(); @@ -31,7 +39,8 @@ continueDistantGrab: function() { var currentPosition = this.getClampedPosition(); var distance = Vec3.distance(this.initialProperties.position, currentPosition); - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance); + if () + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance); Entities.editEntity(this.entityID) { position: currentPosition, @@ -49,16 +58,17 @@ this.sendValueToSlider(); }, - scaleValueBasedOnDistanceFromStart: function(value, min1, max1, min2, max2) { + scaleValueBasedOnDistanceFromStart: function(value, max2) { var min1 = 0; var max1 = 1; var min2 = 0; - var max2 = 255; + var max2 = max2; return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); }, sendValueToSlider: function() { var message = { - boxID: this.entityID, + lightID:userData.lightID, + sliderType:userData.sliderType, sliderValue: this.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index 6ae702bf7f..f1c27b4e4b 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -28,7 +28,7 @@ var PURPLE = { }; var WHITE = { - r: 255 + r: 255, g: 255, b: 255 }; @@ -48,24 +48,48 @@ var PER_ROW_OFFSET = { function entitySlider(light, color, sliderType, row) { this.light = light; - this.lightID = light.id; + this.lightID = light.id.replace(/[{}]/g, ""); this.initialProperties = light.initialProperties; this.color = color; this.sliderType = sliderType; this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); - var formattedMessage = { - 'color_red': this.initialProperties.color.r, - 'color_green': this.initialProperties.color.g, - 'color_blue': this.initialProperties.color.b, - 'intensity': this.initialProperties.intensity, - 'exponent': this.initialProperties.exponent, - 'cutoff': this.initialProperties.cutoff, + var message = { + lightID: this.lightID, + sliderType: this.sliderType, + sliderValue: null + }; + + if (this.sliderType === 'color_red') { + message.sliderValue = this.initialProperties.color.red + this.setValueFromMessage(message); + } + if (this.sliderType === 'color_green') { + message.sliderValue = this.initialProperties.color.green + this.setValueFromMessage(message); + } + if (this.sliderType === 'color_blue') { + message.sliderValue = this.initialProperties.color.blue + this.setValueFromMessage(message); } - this.setValueFromMessage(formattedMessage); - this.setInitialSliderPositions(); + if (this.sliderType === 'intensity') { + message.sliderValue = this.initialProperties.intensity + this.setValueFromMessage(message); + } + if (this.sliderType === 'exponent') { + message.sliderValue = this.initialProperties.exponent + this.setValueFromMessage(message); + } + + if (this.sliderType === 'cutoff') { + message.sliderValue = this.initialProperties.cutoff + this.setValueFromMessage(message); + } + + // this.setInitialSliderPositions(); + this.subscribeToBoxMessages(); return this; } @@ -103,31 +127,44 @@ entitySlider.prototype = { dimensions: BOX_DIMENSIONS, color: this.color, position: position, - script: BOX_SCRIPT_URL + script: BOX_SCRIPT_URL, + userData: JSON.stringify({ + lightModifierKey: { + lightID: this.lightID, + sliderType: this.sliderType + } + }) }; this.boxIndicator = Entities.addEntity(properties); }, - handleValueMessages: function(channel, message, sender) { - if (channel !== 'Hifi-Slider-Value-Reciever') { + setValueFromMessage: function(message) { + print('VALUE MESSAGE::'+JSON.stringify(message)) + print('LIGHT ID::'+this.lightID); + + //message is not for our light + if (message.lightID !== this.lightID) { + print('not our light') return; } - //easily protect from other people editing your values, but group editing might be fun so lets try that first. - // if (sender !== MyAvatar.sessionUUID) { - // return; - // } - var parsedMessage = JSON.parse(message); - setValueFromMessage(parsedMessage); - }, - setValueFromMessage: function(message) { + + //message is not our type + if (message.sliderType !== this.sliderType) { + print('not our slider type') + return + } + + print('SHOULD SET SOME VALUE:::' + message.sliderType); + var lightProperties = Entities.getEntityProperties(this.lightID); + // print('LIGHT PROPERTIES::'+JSON.stringify(lightProperties)); if (this.sliderType === 'color_red') { Entities.editEntity(this.lightID, { color: { red: message.sliderValue, - green: lightProperties.color.g, - blue: lightProperties.color.b + green: lightProperties.color.green, + blue: lightProperties.color.blue } }); } @@ -135,9 +172,9 @@ entitySlider.prototype = { if (this.sliderType === 'color_green') { Entities.editEntity(this.lightID, { color: { - red: lightProperties.color.r + red: lightProperties.color.red, green: message.sliderValue, - blue: lightProperties.color.b + blue: lightProperties.color.blue } }); } @@ -145,14 +182,15 @@ entitySlider.prototype = { if (this.sliderType === 'color_blue') { Entities.editEntity(this.lightID, { color: { - red: lightProperties.color.r, - green: lightProperties.color.g, + red: lightProperties.color.red, + green: lightProperties.color.green, blue: message.sliderValue, } }); } if (this.sliderType === 'intensity') { + print('CHANGING INTENSITY TO::' + message.sliderValue) Entities.editEntity(this.lightID, { intensity: message.sliderValue }); @@ -171,17 +209,22 @@ entitySlider.prototype = { } }, subscribeToBoxMessages: function() { + print('subscribing to box messages'); Messages.subscribe('Hifi-Slider-Value-Reciever'); - Messages.messageReceived.connect(this.handleValueMessages); + Messages.messageReceived.connect(handleValueMessages); }, - setInitialSliderPositions:function(){ + setInitialSliderPositions: function() { + var COLOR_MAX = 255; + var INTENSITY_MAX = 10; + var CUTOFF_MAX = 360; + var EXPONENT_MAX = 1; - var distanceRed = (this.initialProperties.color.r / 255) * AXIS_SCALE; - var distanceGreen = (this.initialProperties.color.g / 255) * AXIS_SCALE; - var distanceBlue = (this.initialProperties.color.b / 255) * AXIS_SCALE; - var distanceIntensity = (this.initialProperties.intensity / 255) * AXIS_SCALE; - var distanceCutoff = (this.initialProperties.cutoff / 360) * AXIS_SCALE; - var distanceExponent = (this.initialProperties.exponent / 255) * AXIS_SCALE; + var distanceRed = (this.initialProperties.color.red / COLOR_MAX) * AXIS_SCALE; + var distanceGreen = (this.initialProperties.color.green / COLOR_MAX) * AXIS_SCALE; + var distanceBlue = (this.initialProperties.color.blue / COLOR_MAX) * AXIS_SCALE; + var distanceIntensity = (this.initialProperties.intensity / INTENSITY_MAX) * AXIS_SCALE; + var distanceCutoff = (this.initialProperties.cutoff / CUTOFF_MAX) * AXIS_SCALE; + var distanceExponent = (this.initialProperties.exponent / EXPONENT_MAX) * AXIS_SCALE; }, cleanup: function() { Entities.deleteEntity(this.boxIndicator); @@ -190,8 +233,18 @@ entitySlider.prototype = { } }; -//create them for a given light +var sliders = []; +var slidersRef = { + 'color_red': null, + 'color_green': null, + 'color_blue': null, + intensity: null, + cutoff: null, + exponent: null +} + function makeSliders(light) { + print('light in makesliders:::' + light) if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -205,22 +258,31 @@ function makeSliders(light) { var USE_EXPONENT_SLIDER = false; } if (USE_COLOR_SLIDER === true) { - var r = new entitySlider(RED, 'color_red', 1); - var g = new entitySlider(GREEN, 'color_green', 2); - var b = new entitySlider(BLUE, 'color_blue', 3); + slidersRef.color_red = new entitySlider(light, RED, 'color_red', 1); + slidersRef.color_green = new entitySlider(light, GREEN, 'color_green', 2); + slidersRef.color_blue = new entitySlider(light, BLUE, 'color_blue', 3); + + sliders.push(slidersRef.color_red); + sliders.push(slidersRef.color_green); + sliders.push(slidersRef.color_blue); + } if (USE_INTENSITY_SLIDER === true) { - var intensity = new entitySlider(WHITE, 'intensity', 4); + slidersRef.intensity = new entitySlider(light, WHITE, 'intensity', 4); + sliders.push(slidersRef.intensity); } if (USE_CUTOFF_SLIDER === true) { - var cutoff = new entitySlider(PURPLE, 'cutoff', 5); + slidersRef.cutoff = new entitySlider(light, PURPLE, 'cutoff', 5); + sliders.push(slidersRef.cutoff); } if (USE_EXPONENT_SLIDER === true) { - var exponent = new entitySlider(PURPLE, 'exponent', 6); + slidersRef.exponent = new entitySlider(light, PURPLE, 'exponent', 6); + sliders.push(slidersRef.exponent); } }; function subScribeToNewLights() { + print('subscribing to light messages') Messages.subscribe('Hifi-Light-Mod-Receiver'); Messages.messageReceived.connect(handleLightModMessages); } @@ -233,18 +295,47 @@ function handleLightModMessages(channel, message, sender) { return; } var parsedMessage = JSON.parse(message); - var light = message.light; - makeSliders(light); + + print('MESSAGE LIGHT:::' + message) + makeSliders(parsedMessage.light); } +function handleValueMessages(channel, message, sender) { + + + if (channel !== 'Hifi-Slider-Value-Reciever') { + return; + } + print('HANDLE VALUE MESSAGE') + //easily protect from other people editing your values, but group editing might be fun so lets try that first. + // if (sender !== MyAvatar.sessionUUID) { + // return; + // } + var parsedMessage = JSON.parse(message); + + slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage) + + // this.setValueFromMessage(parsedMessage); +} + +function cleanup() { + while (sliders.length > 0) { + var slider = sliders.pop(); + slider.cleanup(); + } + Messages.messageReceived.disconnect(handleLightModMessages); + delete sliders +} + +Script.scriptEnding.connect(cleanup); subScribeToNewLights(); - // diffuseColor: { red: 255, green: 255, blue: 255 }, - // ambientColor: { red: 255, green: 255, blue: 255 }, - // specularColor: { red: 255, green: 255, blue: 255 }, +// diffuseColor: { red: 255, green: 255, blue: 255 }, +// ambientColor: { red: 255, green: 255, blue: 255 }, +// specularColor: { red: 255, green: 255, blue: 255 }, - // constantAttenuation: 1, - // linearAttenuation: 0, - // quadraticAttenuation: 0, - // exponent: 0, - // cutoff: 180, // in degrees \ No newline at end of file +// constantAttenuation: 1, +// linearAttenuation: 0, +// quadraticAttenuation: 0, +// exponent: 0, +// cutoff: 180, // in degrees \ No newline at end of file diff --git a/examples/lights/testScene.js b/examples/lights/testScene.js index eeb5f4ffd7..4cc0058bea 100644 --- a/examples/lights/testScene.js +++ b/examples/lights/testScene.js @@ -12,7 +12,7 @@ var basePosition, avatarRot; avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); - basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(SPAWN_RANGE * 3, Quat.getFront(avatarRot))); + basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(-3, Quat.getUp(avatarRot))); var ground = Entities.addEntity({ type: "Model", @@ -28,11 +28,14 @@ var light, block; - basePosition.y += 2; + // basePosition.y += 2; function createLight() { + print('making light' + block) + var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); + var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); var lightProperties = { - name: 'Hifi-Spotlight' + name: 'Hifi-Spotlight', type: "Light", isSpotlight: true, dimensions: { @@ -40,33 +43,40 @@ y: 2, z: 20 }, - parentID: box, + parentID: block, color: { red: 255, - green: 255, + green: 0, blue: 255 }, intensity: 2, exponent: 0.3, cutoff: 20, - lifetime: LIFETIME, + lifetime: -1, position: lightTransform.p, - rotation: lightTransform.q, - } + rotation: lightTransform.q + }; + light = Entities.addEntity(lightProperties); var message = { light: { id: light, type: 'spotlight', - initialProperties:lightProperties + initialProperties: lightProperties } }; + Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); + print('SENT MESSAGE') } function createBlock() { + print('making block'); + + var position = basePosition; + position.y += 5; var blockProperties = { name: 'Hifi-Spotlight-Block', type: 'Box', @@ -76,16 +86,15 @@ z: 1 }, collisionsWillMove: true, - shapeType: 'Box', color: { red: 0, - green: 0 + green: 0, blue: 255 }, - position: basePosition + position: position } - block = Entities.addEntity(block); + block = Entities.addEntity(blockProperties); } function evalLightWorldTransform(modelPos, modelRot) { @@ -96,9 +105,12 @@ } function cleanup() { + Entities.deleteEntity(block); Entities.deleteEntity(ground); Entities.deleteEntity(light); } + Script.scriptEnding.connect(cleanup); + createBlock(); createLight(); \ No newline at end of file From 8bdced85763a6b8643d8f1b0bf63fa921b4747cd Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 16:51:12 -0800 Subject: [PATCH 049/209] more work --- examples/lights/box.js | 22 +++++++++++++++++----- examples/lights/light_modifier.js | 26 +++++++++++++++----------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index a8e708b344..e43ae22a49 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -26,7 +26,8 @@ this.initialProperties = Entities.getEntityProperties(this.entityID); }, getClampedPosition: function() { - dPosition = Vec3.subtract(MyAvatar.position, previousPosition); + + dPosition = Vec3.subtract(MyAvatar.position, this.previousPosition); //convert to localFrame dPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), dPosition); @@ -39,8 +40,19 @@ continueDistantGrab: function() { var currentPosition = this.getClampedPosition(); var distance = Vec3.distance(this.initialProperties.position, currentPosition); - if () - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance); + + if (userData.sliderType === 'color_red' || userData.sliderType === 'color_green' || userData.sliderType === 'color_blue') { + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, COLOR_MAX); + } + if (userData.sliderType === 'intensity') { + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, INTENSITY_MAX); + } + if (userData.sliderType === 'cutoff') { + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, CUTOFF_MAX); + } + if (userData.sliderType === 'exponent') { + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); + } Entities.editEntity(this.entityID) { position: currentPosition, @@ -67,8 +79,8 @@ }, sendValueToSlider: function() { var message = { - lightID:userData.lightID, - sliderType:userData.sliderType, + lightID: userData.lightID, + sliderType: userData.sliderType, sliderValue: this.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index f1c27b4e4b..983ea5bcb9 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -1,6 +1,8 @@ // given a selected light, instantiate some entities that represent various values you can dynamically adjust // + + var BOX_SCRIPT_URL = Script.resolvePath('box.js'); var RED = { @@ -54,6 +56,9 @@ function entitySlider(light, color, sliderType, row) { this.sliderType = sliderType; this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); + this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); + this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(this.avatarRot))); + var message = { lightID: this.lightID, sliderType: this.sliderType, @@ -97,8 +102,14 @@ function entitySlider(light, color, sliderType, row) { entitySlider.prototype = { createAxis: function() { //start of line - var position; - //1 meter along orientationAxis + var position = Vec3.sum(this.basePosition, this.verticalOffset); + + //line starts on left and goes to right + //set the end of the line to the right + var rightVector = Quat.getRight(this.avatarRot); + var extension = Vec3.multiply(AXIS_SCALE, rightVector); + var endOfAxis = Vec3.sum(position, extension); + var endOfAxis; var properties = { type: 'Line', @@ -139,8 +150,6 @@ entitySlider.prototype = { this.boxIndicator = Entities.addEntity(properties); }, setValueFromMessage: function(message) { - print('VALUE MESSAGE::'+JSON.stringify(message)) - print('LIGHT ID::'+this.lightID); //message is not for our light if (message.lightID !== this.lightID) { @@ -154,10 +163,9 @@ entitySlider.prototype = { return } - print('SHOULD SET SOME VALUE:::' + message.sliderType); + print('should set:::' + this.sliderType); var lightProperties = Entities.getEntityProperties(this.lightID); - // print('LIGHT PROPERTIES::'+JSON.stringify(lightProperties)); if (this.sliderType === 'color_red') { Entities.editEntity(this.lightID, { @@ -190,7 +198,6 @@ entitySlider.prototype = { } if (this.sliderType === 'intensity') { - print('CHANGING INTENSITY TO::' + message.sliderValue) Entities.editEntity(this.lightID, { intensity: message.sliderValue }); @@ -209,7 +216,6 @@ entitySlider.prototype = { } }, subscribeToBoxMessages: function() { - print('subscribing to box messages'); Messages.subscribe('Hifi-Slider-Value-Reciever'); Messages.messageReceived.connect(handleValueMessages); }, @@ -296,17 +302,15 @@ function handleLightModMessages(channel, message, sender) { } var parsedMessage = JSON.parse(message); - print('MESSAGE LIGHT:::' + message) makeSliders(parsedMessage.light); } function handleValueMessages(channel, message, sender) { - + if (channel !== 'Hifi-Slider-Value-Reciever') { return; } - print('HANDLE VALUE MESSAGE') //easily protect from other people editing your values, but group editing might be fun so lets try that first. // if (sender !== MyAvatar.sessionUUID) { // return; From 112dd4209b3efa8032c8b5918429c3b633d2a85f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 17:27:01 -0800 Subject: [PATCH 050/209] prep for incoming --- examples/lights/box.js | 2 +- examples/lights/light_modifier.js | 49 ++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index e43ae22a49..806d6be389 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -72,7 +72,7 @@ }, scaleValueBasedOnDistanceFromStart: function(value, max2) { var min1 = 0; - var max1 = 1; + var max1 = AXIS_SCALE; var min2 = 0; var max2 = max2; return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index 983ea5bcb9..ac29b65f74 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -93,8 +93,10 @@ function entitySlider(light, color, sliderType, row) { this.setValueFromMessage(message); } - // this.setInitialSliderPositions(); + this.setInitialSliderPositions(); this.subscribeToBoxMessages(); + this.createAxis(); + this.createBoxIndicator(); return this; } @@ -133,11 +135,37 @@ entitySlider.prototype = { this.axis = Entities.addEntity(properties); }, createBoxIndicator: function() { + var position = Vec3.sum(this.basePosition, this.verticalOffset); + + //line starts on left and goes to right + //set the end of the line to the right + var rightVector = Quat.getRight(this.avatarRot); + var initialDistance; + if (this.sliderType === 'color_red') { + initialDistance = this.distanceRed; + } + if (this.sliderType === 'color_green') { + initialDistance = this.distanceGreen; + } + if (this.sliderType === 'color_blue') { + initialDistance = this.distanceBlue; + } + if (this.sliderType === 'intensity') { + initialDistance = this.distanceRed; + } + if (this.sliderType === 'cutoff') { + initialDistance = this.distanceCutoff; + } + if (this.sliderType === 'exponent') { + initialDistance = this.distanceExponent; + } + var extension = Vec3.multiply(initialDistance, rightVector); + var endOfAxis = Vec3.sum(position, extension); var properties = { type: 'Box', dimensions: BOX_DIMENSIONS, color: this.color, - position: position, + position: endOfAxis, script: BOX_SCRIPT_URL, userData: JSON.stringify({ lightModifierKey: { @@ -225,12 +253,12 @@ entitySlider.prototype = { var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; - var distanceRed = (this.initialProperties.color.red / COLOR_MAX) * AXIS_SCALE; - var distanceGreen = (this.initialProperties.color.green / COLOR_MAX) * AXIS_SCALE; - var distanceBlue = (this.initialProperties.color.blue / COLOR_MAX) * AXIS_SCALE; - var distanceIntensity = (this.initialProperties.intensity / INTENSITY_MAX) * AXIS_SCALE; - var distanceCutoff = (this.initialProperties.cutoff / CUTOFF_MAX) * AXIS_SCALE; - var distanceExponent = (this.initialProperties.exponent / EXPONENT_MAX) * AXIS_SCALE; + this.distanceRed = (this.initialProperties.color.red / COLOR_MAX) * AXIS_SCALE; + this.distanceGreen = (this.initialProperties.color.green / COLOR_MAX) * AXIS_SCALE; + this.distanceBlue = (this.initialProperties.color.blue / COLOR_MAX) * AXIS_SCALE; + this.distanceIntensity = (this.initialProperties.intensity / INTENSITY_MAX) * AXIS_SCALE; + this.distanceCutoff = (this.initialProperties.cutoff / CUTOFF_MAX) * AXIS_SCALE; + this.distanceExponent = (this.initialProperties.exponent / EXPONENT_MAX) * AXIS_SCALE; }, cleanup: function() { Entities.deleteEntity(this.boxIndicator); @@ -307,7 +335,6 @@ function handleLightModMessages(channel, message, sender) { function handleValueMessages(channel, message, sender) { - if (channel !== 'Hifi-Slider-Value-Reciever') { return; } @@ -318,8 +345,6 @@ function handleValueMessages(channel, message, sender) { var parsedMessage = JSON.parse(message); slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage) - - // this.setValueFromMessage(parsedMessage); } function cleanup() { @@ -334,6 +359,8 @@ function cleanup() { Script.scriptEnding.connect(cleanup); subScribeToNewLights(); + +//other light properties // diffuseColor: { red: 255, green: 255, blue: 255 }, // ambientColor: { red: 255, green: 255, blue: 255 }, // specularColor: { red: 255, green: 255, blue: 255 }, From 109aa89619b10fc108c2980a47933d4596a95631 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 18:42:00 -0800 Subject: [PATCH 051/209] end of day --- examples/lights/box.js | 22 +++++++++++----------- examples/lights/light_modifier.js | 3 +++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index 806d6be389..b1f9252073 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -13,8 +13,9 @@ Box.prototype = { preload: function(entityID) { this.entityID = entityID; - var userData = Entities.getEntityProperties(this.entityID, "userData"); - this.userData = JSON.parse(userData); + var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); + var parsedUserData = JSON.parse(entityProperties.userData); + var userData = parsedUserData.lightModifierKey; }, startNearGrab: function() { this.setInitialProperties(); @@ -26,10 +27,10 @@ this.initialProperties = Entities.getEntityProperties(this.entityID); }, getClampedPosition: function() { - - dPosition = Vec3.subtract(MyAvatar.position, this.previousPosition); + var dPosition; + // dPosition = Vec3.subtract(MyAvatar.position, this.previousPosition); //convert to localFrame - dPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), dPosition); + // dPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), dPosition); return dPosition; }, @@ -52,12 +53,12 @@ } if (userData.sliderType === 'exponent') { this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); - } + }; - Entities.editEntity(this.entityID) { + Entities.editEntity(this.entityID, { position: currentPosition, - rotation: this.getClampedRotation() - } + // rotation: this.getClampedRotation() + }); }, releaseGrab: function() { Entities.editEntity(this.entityID, { @@ -84,8 +85,7 @@ sliderValue: this.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); - }; - + } }; return new Box(); diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index ac29b65f74..2e11c5e22e 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -115,6 +115,7 @@ entitySlider.prototype = { var endOfAxis; var properties = { type: 'Line', + name: 'Hifi-Slider-Axis::'+this.sliderType, color: this.color, collisionsWillMove: false, ignoreForCollisions: true, @@ -135,6 +136,7 @@ entitySlider.prototype = { this.axis = Entities.addEntity(properties); }, createBoxIndicator: function() { + print('BOX COLOR IS:::'+JSON.stringify(this.color)); var position = Vec3.sum(this.basePosition, this.verticalOffset); //line starts on left and goes to right @@ -163,6 +165,7 @@ entitySlider.prototype = { var endOfAxis = Vec3.sum(position, extension); var properties = { type: 'Box', + name: 'Hifi-Slider::'+this.sliderType, dimensions: BOX_DIMENSIONS, color: this.color, position: endOfAxis, From c561a53f7c283a7c80e7aa7d921409f73a4971d7 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 15 Dec 2015 09:56:28 -0800 Subject: [PATCH 052/209] Going to change additive blending to world position prop --- .../flowArts/lightBall/lightBallSpawner.js | 151 ++++++++++-------- .../RenderableParticleEffectEntityItem.cpp | 4 +- .../entities/src/ParticleEffectEntityItem.cpp | 17 +- 3 files changed, 102 insertions(+), 70 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index da09829257..8f220129b2 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -1,81 +1,101 @@ + +Script.include("../../libraries/utils.js"); + var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); +var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); + +var raveRoom = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + position: center, + visible:false +}); + +var colorPalette = [{ + red: 250, + green: 137, + blue: 162 +}, { + red: 204, + green: 244, + blue: 249 +}, { + red: 146, + green: 206, + blue: 116 +}, { + red: 240, + green: 87, + blue: 129 +}]; + var containerBall = Entities.addEntity({ type: "Sphere", position: center, dimensions: {x: .1, y: .1, z: .1}, - color: {red: 50, green: 10, blue: 50}, + color: {red: 1500, green: 10, blue: 50}, collisionsWillMove: true, - gravity: {x: 0, y: -.1, z: 0} + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 2, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + // gravity: {x: 0, y: -.1, z: 0} }); +var lightZone = Entities.addEntity({ + type: "Zone", + shapeType: 'box', + keyLightIntensity: 0.2, + keyLightColor: { + red: 50, + green: 0, + blue: 50 + }, + keyLightAmbientIntensity: .2, + position: MyAvatar.position, + dimensions: { + x: 100, + y: 100, + z: 100 + } +}); + +var light = Entities.addEntity({ + type: 'Light', + position: center, + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + var lightBall = Entities.addEntity({ position: center, type: "ParticleEffect", parentID: containerBall, isEmitting: true, "name": "ParticlesTest Emitter", - "colorStart": {red: 20, green: 20, blue: 255}, + "colorStart": {red: 200, green: 20, blue: 40}, color: {red: 10, green: 0, blue: 255}, "colorFinish": {red: 250, green: 200, blue:255}, - "maxParticles": 20000, - "lifespan": 1, - "emitRate": 10000, - "emitSpeed": .1, - "speedSpread": .01, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": 3, - "azimuthStart": -3.1415927410125732, - "azimuthFinish": 3.1415927410125732, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": .01, - "y": .01, - "z": .01 - }, - "particleRadius": 0.04, - "radiusSpread": 0, - "radiusStart": 0.05, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - "additiveBlending": 0, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" -}) - -var containerBall2 = Entities.addEntity({ - type: "Sphere", - position: Vec3.sum(center, {x: 0.5, y: 0, z: 0}), - dimensions: {x: .1, y: .1, z: .1}, - color: {red: 200, green: 10, blue: 50}, - collisionsWillMove: true, - gravity: {x: 0, y: -.1, z: 0} -}); - -var lightBall2 = Entities.addEntity({ - position: Vec3.sum(center, {x: 0.5, y: 0, z: 0}), - type: "ParticleEffect", - parentID: containerBall2, - isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": {red: 200, green: 20, blue: 0}, - color: {red: 255, green: 0, blue: 10}, - "colorFinish": {red: 250, green: 200, blue:255}, "maxParticles": 100000, - "lifespan": 1, + "lifespan": 7, "emitRate": 10000, - "emitSpeed": .1, + "emitSpeed": .02, "speedSpread": .01, "emitDimensions": { "x": 0, @@ -83,9 +103,9 @@ var lightBall2 = Entities.addEntity({ "z": 0 }, "polarStart": 0, - "polarFinish": 3, - "azimuthStart": -3.1415927410125732, - "azimuthFinish": 3.1415927410125732, + "polarFinish": Math.PI, + "azimuthStart": -Math.PI, + "azimuthFinish": Math.PI, "emitAcceleration": { "x": 0, "y": 0, @@ -108,11 +128,14 @@ var lightBall2 = Entities.addEntity({ "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" }) + + function cleanup() { Entities.deleteEntity(lightBall); - Entities.deleteEntity(lightBall2); Entities.deleteEntity(containerBall); - Entities.deleteEntity(containerBall2); + Entities.deleteEntity(raveRoom); + Entities.deleteEntity(lightZone) + Entities.deleteEntity(light); } Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 4abd8dbafd..42e9fa446c 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -240,8 +240,8 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { auto position = getPosition(); auto rotation = getRotation(); Transform transform; - transform.setTranslation(position); - transform.setRotation(rotation); + //transform.setTranslation(position); + // transform.setRotation(rotation); render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [=](ParticlePayloadData& payload) { diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index f4210f4486..8f6f60fa26 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "EntityTree.h" #include "EntityTreeElement.h" @@ -640,12 +642,18 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { Particle particle; - particle.seed = randFloatInRange(0.0f, 1.0f); - + std::random_device rd; + + std::mt19937_64 el(rd()); + std::uniform_real_distribution uniform_dist(-1.0, 1.0); + + particle.seed = randFloatInRange(-1.0f, 1.0f); + particle.position = getPosition(); // Position, velocity, and acceleration if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) { // Emit along z-axis from position - particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z); + + particle.velocity = (_emitSpeed + 0.2f * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z); particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } else { @@ -691,10 +699,11 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { radii.z > 0.0f ? z / (radii.z * radii.z) : 0.0f )); - particle.position = _emitOrientation * emitPosition; + particle.position += _emitOrientation * emitPosition; } particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); + // particle.velocity = (_emitSpeed + uniform_dist(el) * _speedSpread) * (_emitOrientation * emitDirection); particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } From dca83a054ea3b278e1ca2a8f1c1cb23e1740ff19 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 15 Dec 2015 10:30:57 -0800 Subject: [PATCH 053/209] Changed additiveBlending to emitterShouldTrail --- .../flowArts/lightBall/lightBallSpawner.js | 9 ++++---- .../RenderableParticleEffectEntityItem.cpp | 6 +++-- .../entities/src/EntityItemProperties.cpp | 16 ++++++------- libraries/entities/src/EntityItemProperties.h | 2 +- libraries/entities/src/EntityPropertyFlags.h | 2 +- .../entities/src/ParticleEffectEntityItem.cpp | 23 ++++++++++++------- .../entities/src/ParticleEffectEntityItem.h | 10 ++++---- 7 files changed, 39 insertions(+), 29 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index 8f220129b2..7744c1210e 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -41,7 +41,7 @@ var containerBall = Entities.addEntity({ spatialKey: { relativePosition: { x: 0, - y: 2, + y: 1, z: 0 } }, @@ -93,9 +93,9 @@ var lightBall = Entities.addEntity({ color: {red: 10, green: 0, blue: 255}, "colorFinish": {red: 250, green: 200, blue:255}, "maxParticles": 100000, - "lifespan": 7, + "lifespan": 2, "emitRate": 10000, - "emitSpeed": .02, + "emitSpeed": .2, "speedSpread": .01, "emitDimensions": { "x": 0, @@ -125,7 +125,8 @@ var lightBall = Entities.addEntity({ "alphaStart": 0, "alphaFinish": 0.5, "additiveBlending": 0, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + emitterShouldTrail: false }) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 42e9fa446c..91a4811011 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -240,8 +240,10 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { auto position = getPosition(); auto rotation = getRotation(); Transform transform; - //transform.setTranslation(position); - // transform.setRotation(rotation); + if (!getEmitterShouldTrail()) { + transform.setTranslation(position); + transform.setRotation(rotation); + } render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [=](ParticlePayloadData& payload) { diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 98a099fcaa..3a2fdf55d4 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -195,7 +195,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread); CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart); CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish); - CHECK_PROPERTY_CHANGE(PROP_ADDITIVE_BLENDING, additiveBlending); + CHECK_PROPERTY_CHANGE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible); @@ -354,7 +354,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ADDITIVE_BLENDING, additiveBlending); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); } @@ -515,7 +515,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(additiveBlending, bool, setAdditiveBlending); + COPY_PROPERTY_FROM_QSCRIPTVALUE(emitterShouldTrail , bool, setEmitterShouldTrail); COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel); @@ -670,7 +670,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float); ADD_PROPERTY_TO_MAP(PROP_ALPHA_START, AlphaStart, alphaStart, float); ADD_PROPERTY_TO_MAP(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float); - ADD_PROPERTY_TO_MAP(PROP_ADDITIVE_BLENDING, AdditiveBlending, additiveBlending, bool); + ADD_PROPERTY_TO_MAP(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool); ADD_PROPERTY_TO_MAP(PROP_MODEL_URL, ModelURL, modelURL, QString); ADD_PROPERTY_TO_MAP(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString); ADD_PROPERTY_TO_MAP(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, glm::vec3); @@ -980,7 +980,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish()); - APPEND_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, properties.getAdditiveBlending()); + APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, properties.getEmitterShouldTrail()); } if (properties.getType() == EntityTypes::Zone) { @@ -1265,7 +1265,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ADDITIVE_BLENDING, bool, setAdditiveBlending); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); } if (properties.getType() == EntityTypes::Zone) { @@ -1608,8 +1608,8 @@ QList EntityItemProperties::listChangedProperties() { if (alphaFinishChanged()) { out += "alphaFinish"; } - if (additiveBlendingChanged()) { - out += "additiveBlending"; + if (emitterShouldTrailChanged()) { + out += "emitterShouldTrail"; } if (modelURLChanged()) { out += "modelURL"; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index c13519996a..5420e75aed 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -161,7 +161,7 @@ public: DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD); DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float, ParticleEffectEntityItem::DEFAULT_RADIUS_START); DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH); - DEFINE_PROPERTY(PROP_ADDITIVE_BLENDING, AdditiveBlending, additiveBlending, bool, ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING); + DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, ParticleEffectEntityItem::DEFAULT_EMITTER_SHOULD_TRAIL); DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID); DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup); DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 3bca911a56..2ba86a491e 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -149,7 +149,7 @@ enum EntityPropertyList { PROP_ANIMATION_HOLD, PROP_ANIMATION_START_AUTOMATICALLY, - PROP_ADDITIVE_BLENDING, + PROP_EMITTER_SHOULD_TRAIL, PROP_PARENT_ID, PROP_PARENT_JOINT_INDEX, diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 8f6f60fa26..7d9af11862 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -93,7 +93,7 @@ const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS; const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS; const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = ""; -const bool ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING = false; +const bool ParticleEffectEntityItem::DEFAULT_EMITTER_SHOULD_TRAIL = false; EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -333,7 +333,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(additiveBlending, getAdditiveBlending); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitterShouldTrail, getEmitterShouldTrail); return properties; @@ -372,7 +372,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(additiveBlending, setAdditiveBlending); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitterShouldTrail, setEmitterShouldTrail); if (somethingChanged) { bool wantDebug = false; @@ -465,7 +465,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch } if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING) { - READ_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, bool, setAdditiveBlending); + READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); } return bytesRead; @@ -505,7 +505,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea requestedProperties += PROP_POLAR_FINISH; requestedProperties += PROP_AZIMUTH_START; requestedProperties += PROP_AZIMUTH_FINISH; - requestedProperties += PROP_ADDITIVE_BLENDING; + requestedProperties += PROP_EMITTER_SHOULD_TRAIL; return requestedProperties; } @@ -548,7 +548,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_POLAR_FINISH, getPolarFinish()); APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, getAzimuthStart()); APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, getAzimuthFinish()); - APPEND_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, getAdditiveBlending()); + APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, getEmitterShouldTrail()); } bool ParticleEffectEntityItem::isEmittingParticles() const { @@ -648,7 +648,9 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { std::uniform_real_distribution uniform_dist(-1.0, 1.0); particle.seed = randFloatInRange(-1.0f, 1.0f); - particle.position = getPosition(); + if (getEmitterShouldTrail()) { + particle.position = getPosition(); + } // Position, velocity, and acceleration if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) { // Emit along z-axis from position @@ -699,7 +701,12 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { radii.z > 0.0f ? z / (radii.z * radii.z) : 0.0f )); - particle.position += _emitOrientation * emitPosition; + if (getEmitterShouldTrail()) { + particle.position += _emitOrientation * emitPosition; + } + else { + particle.position = _emitOrientation * emitPosition; + } } particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index c35a45baeb..7bedbde6d8 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -207,10 +207,10 @@ public: } } - static const bool DEFAULT_ADDITIVE_BLENDING; - bool getAdditiveBlending() const { return _additiveBlending; } - void setAdditiveBlending(bool additiveBlending) { - _additiveBlending = additiveBlending; + static const bool DEFAULT_EMITTER_SHOULD_TRAIL; + bool getEmitterShouldTrail() const { return _emitterShouldTrail; } + void setEmitterShouldTrail(bool emitterShouldTrail) { + _emitterShouldTrail = emitterShouldTrail; } virtual bool supportsDetailedRayIntersection() const { return false; } @@ -280,7 +280,7 @@ protected: float _timeUntilNextEmit { 0.0f }; - bool _additiveBlending { DEFAULT_ADDITIVE_BLENDING }; + bool _emitterShouldTrail { DEFAULT_EMITTER_SHOULD_TRAIL }; }; #endif // hifi_ParticleEffectEntityItem_h From 22756d168b25af08f004d5b7b8de24dd59134db4 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 15 Dec 2015 10:35:35 -0800 Subject: [PATCH 054/209] Changed grammar to support boolean and and or. --- libraries/animation/src/AnimExpression.cpp | 64 ++++++++++------------ libraries/animation/src/AnimExpression.h | 16 +++--- tests/QTestExtensions.h | 2 +- 3 files changed, 39 insertions(+), 43 deletions(-) diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index b76aaff3f9..5fc1bc9b4f 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -78,7 +78,15 @@ AnimExpression::Token AnimExpression::consumeIdentifier(const QString& str, QStr } int pos = (int)(begin - str.begin()); int len = (int)(iter - begin); - return Token(QStringRef(const_cast(&str), pos, len)); + + QStringRef stringRef(const_cast(&str), pos, len); + if (stringRef == "true") { + return Token(true); + } else if (stringRef == "false") { + return Token(false); + } else { + return Token(stringRef); + } } // TODO: not very efficient or accruate, but it's close enough for now. @@ -198,19 +206,19 @@ AnimExpression::Token AnimExpression::consumeNot(const QString& str, QString::co /* Expr → Term Expr' -Expr' → + Term Expr' - | – Term Expr' +Expr' → '||' Term Expr' | ε Term → Factor Term' -Term' → * Term' - | / Term' +Term' → '&&' Term' | ε Factor → INT + | BOOL | FLOAT | IDENTIFIER - | (Expr) + | '(' Expr ')' */ +// Expr → Term Expr' bool AnimExpression::parseExpr(const QString& str, QString::const_iterator& iter) { if (!parseTerm(str, iter)) { return false; @@ -221,9 +229,10 @@ bool AnimExpression::parseExpr(const QString& str, QString::const_iterator& iter return true; } +// Expr' → '||' Term Expr' | ε bool AnimExpression::parseExprPrime(const QString& str, QString::const_iterator& iter) { auto token = consumeToken(str, iter); - if (token.type == Token::Plus) { + if (token.type == Token::Or) { if (!parseTerm(str, iter)) { unconsumeToken(token); return false; @@ -232,18 +241,7 @@ bool AnimExpression::parseExprPrime(const QString& str, QString::const_iterator& unconsumeToken(token); return false; } - _opCodes.push_back(OpCode {OpCode::Add}); - return true; - } else if (token.type == Token::Minus) { - if (!parseTerm(str, iter)) { - unconsumeToken(token); - return false; - } - if (!parseExprPrime(str, iter)) { - unconsumeToken(token); - return false; - } - _opCodes.push_back(OpCode {OpCode::Subtract}); + _opCodes.push_back(OpCode {OpCode::Or}); return true; } else { unconsumeToken(token); @@ -251,6 +249,7 @@ bool AnimExpression::parseExprPrime(const QString& str, QString::const_iterator& } } +// Term → Factor Term' bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter) { if (!parseFactor(str, iter)) { return false; @@ -261,9 +260,10 @@ bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter return true; } +// Term' → '&&' Term' | ε bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& iter) { auto token = consumeToken(str, iter); - if (token.type == Token::Multiply) { + if (token.type == Token::And) { if (!parseTerm(str, iter)) { unconsumeToken(token); return false; @@ -272,18 +272,7 @@ bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& unconsumeToken(token); return false; } - _opCodes.push_back(OpCode {OpCode::Multiply}); - return true; - } else if (token.type == Token::Divide) { - if (!parseTerm(str, iter)) { - unconsumeToken(token); - return false; - } - if (!parseTermPrime(str, iter)) { - unconsumeToken(token); - return false; - } - _opCodes.push_back(OpCode {OpCode::Divide}); + _opCodes.push_back(OpCode {OpCode::And}); return true; } else { unconsumeToken(token); @@ -291,11 +280,15 @@ bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& } } +// Factor → INT | BOOL | FLOAT | IDENTIFIER | '(' Expr ')' bool AnimExpression::parseFactor(const QString& str, QString::const_iterator& iter) { auto token = consumeToken(str, iter); if (token.type == Token::Int) { _opCodes.push_back(OpCode {token.intVal}); return true; + } else if (token.type == Token::Bool) { + _opCodes.push_back(OpCode {(bool)token.intVal}); + return true; } else if (token.type == Token::Float) { _opCodes.push_back(OpCode {token.floatVal}); return true; @@ -351,7 +344,7 @@ AnimExpression::OpCode AnimExpression::evaluate(const AnimVariantMap& map) const case OpCode::UnaryMinus: evalUnaryMinus(map, stack); break; } } - return stack.top(); + return coerseToValue(map, stack.top()); } #define POP_BOOL(NAME) \ @@ -602,8 +595,7 @@ AnimExpression::OpCode AnimExpression::coerseToValue(const AnimVariantMap& map, const AnimVariant& var = map.get(opCode.strVal); switch (var.getType()) { case AnimVariant::Type::Bool: - qCWarning(animation) << "AnimExpression: type missmatch, expected a number not a bool"; - return OpCode(0); + return OpCode((bool)var.getBool()); break; case AnimVariant::Type::Int: return OpCode(var.getInt()); @@ -631,6 +623,7 @@ AnimExpression::OpCode AnimExpression::coerseToValue(const AnimVariantMap& map, } } +#ifndef NDEBUG void AnimExpression::dumpOpCodes() const { QString tmp; for (auto& op : _opCodes) { @@ -660,3 +653,4 @@ void AnimExpression::dumpOpCodes() const { qCDebug(animation).nospace().noquote() << "opCodes =" << tmp; qCDebug(animation).resetFormat(); } +#endif diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 6e204483d5..8a1961b326 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -27,6 +27,7 @@ protected: enum Type { End = 0, Identifier, + Bool, Int, Float, And, @@ -50,8 +51,9 @@ protected: }; Token(Type type) : type {type} {} Token(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} - Token(int val) : type {Type::Int}, intVal {val} {} - Token(float val) : type {Type::Float}, floatVal {val} {} + explicit Token(int val) : type {Type::Int}, intVal {val} {} + explicit Token(bool val) : type {Type::Bool}, intVal {val} {} + explicit Token(float val) : type {Type::Float}, floatVal {val} {} Type type {End}; QString strVal; int intVal {0}; @@ -81,11 +83,11 @@ protected: UnaryMinus }; OpCode(Type type) : type {type} {} - OpCode(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} - OpCode(const QString& str) : type {Type::Identifier}, strVal {str} {} - OpCode(int val) : type {Type::Int}, intVal {val} {} - OpCode(bool val) : type {Type::Bool}, intVal {(int)val} {} - OpCode(float val) : type {Type::Float}, floatVal {val} {} + explicit OpCode(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} + explicit OpCode(const QString& str) : type {Type::Identifier}, strVal {str} {} + explicit OpCode(int val) : type {Type::Int}, intVal {val} {} + explicit OpCode(bool val) : type {Type::Bool}, intVal {(int)val} {} + explicit OpCode(float val) : type {Type::Float}, floatVal {val} {} bool coerceBool(const AnimVariantMap& map) const { if (type == Int || type == Bool) { diff --git a/tests/QTestExtensions.h b/tests/QTestExtensions.h index 16e51b41ee..b7b9795a9a 100644 --- a/tests/QTestExtensions.h +++ b/tests/QTestExtensions.h @@ -274,7 +274,7 @@ struct ByteData { QTextStream & operator << (QTextStream& stream, const ByteData & wrapper) { // Print bytes as hex - stream << QByteArray::fromRawData(wrapper.data, wrapper.length).toHex(); + stream << QByteArray::fromRawData(wrapper.data, (int)wrapper.length).toHex(); return stream; } From ab85e2967a9bca036abac6b49c5199fba4d4e54c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 15 Dec 2015 13:18:30 -0800 Subject: [PATCH 055/209] AnimExpression: support for unary not. --- libraries/animation/src/AnimExpression.cpp | 32 +++++++-- libraries/animation/src/AnimExpression.h | 1 + tests/animation/src/AnimTests.cpp | 77 ++++++++-------------- 3 files changed, 53 insertions(+), 57 deletions(-) diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index 5fc1bc9b4f..79004a72a6 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -208,9 +208,11 @@ AnimExpression::Token AnimExpression::consumeNot(const QString& str, QString::co Expr → Term Expr' Expr' → '||' Term Expr' | ε -Term → Factor Term' -Term' → '&&' Term' +Term → Unary Term' +Term' → '&&' Unary Term' | ε +Unary → '!' Unary + | Factor Factor → INT | BOOL | FLOAT @@ -249,9 +251,9 @@ bool AnimExpression::parseExprPrime(const QString& str, QString::const_iterator& } } -// Term → Factor Term' +// Term → Unary Term' bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter) { - if (!parseFactor(str, iter)) { + if (!parseUnary(str, iter)) { return false; } if (!parseTermPrime(str, iter)) { @@ -260,11 +262,11 @@ bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter return true; } -// Term' → '&&' Term' | ε +// Term' → '&&' Unary Term' | ε bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& iter) { auto token = consumeToken(str, iter); if (token.type == Token::And) { - if (!parseTerm(str, iter)) { + if (!parseUnary(str, iter)) { unconsumeToken(token); return false; } @@ -280,6 +282,24 @@ bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& } } +// Unary → '!' Unary | Factor +bool AnimExpression::parseUnary(const QString& str, QString::const_iterator& iter) { + + auto token = consumeToken(str, iter); + if (token.type == Token::Not) { + if (!parseUnary(str, iter)) { + unconsumeToken(token); + return false; + } + _opCodes.push_back(OpCode {OpCode::Not}); + return true; + } + unconsumeToken(token); + + return parseFactor(str, iter); +} + + // Factor → INT | BOOL | FLOAT | IDENTIFIER | '(' Expr ')' bool AnimExpression::parseFactor(const QString& str, QString::const_iterator& iter) { auto token = consumeToken(str, iter); diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 8a1961b326..468217f5b3 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -119,6 +119,7 @@ protected: bool parseExprPrime(const QString& str, QString::const_iterator& iter); bool parseTerm(const QString& str, QString::const_iterator& iter); bool parseTermPrime(const QString& str, QString::const_iterator& iter); + bool parseUnary(const QString& str, QString::const_iterator& iter); bool parseFactor(const QString& str, QString::const_iterator& iter); OpCode evaluate(const AnimVariantMap& map) const; diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 63eb39dc48..6812bb63b6 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -522,43 +522,19 @@ void AnimTests::testExpressionParser() { QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::And); } - /* - e = AnimExpression("2 + 3"); - QVERIFY(e._opCodes.size() == 3); - if (e._opCodes.size() == 3) { - QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[0].intVal == 2); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[1].intVal == 3); - QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Add); + e = AnimExpression("!(true || false) && true"); + QVERIFY(e._opCodes.size() == 6); + if (e._opCodes.size() == 6) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Bool); + QVERIFY(e._opCodes[0].intVal == (int)true); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Bool); + QVERIFY(e._opCodes[1].intVal == (int)false); + QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Or); + QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Not); + QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Bool); + QVERIFY(e._opCodes[4].intVal == (int)true); + QVERIFY(e._opCodes[5].type == AnimExpression::OpCode::And); } - - e = AnimExpression("2 + 3 * 10"); - QVERIFY(e._opCodes.size() == 5); - if (e._opCodes.size() == 5) { - QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[0].intVal == 2); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[1].intVal == 3); - QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[2].intVal == 10); - QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Multiply); - QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Add); - } - - e = AnimExpression("(2 + 3) * 10"); - QVERIFY(e._opCodes.size() == 5); - if (e._opCodes.size() == 5) { - QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[0].intVal == 2); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[1].intVal == 3); - QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Add); - QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[3].intVal == 10); - QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Multiply); - } - */ } #define TEST_BOOL_EXPR(EXPR) \ @@ -630,23 +606,22 @@ void AnimTests::testExpressionEvaluator() { TEST_BOOL_EXPR(f || false); TEST_BOOL_EXPR(f || true); -/* - result = AnimExpression("(2 + 3) * (5 + 3)").evaluate(vars); - QVERIFY(result.type == AnimExpression::OpCode::Int); - QVERIFY(result.intVal == (2 + 3) * (5 + 3)); + TEST_BOOL_EXPR(!true); + TEST_BOOL_EXPR(!false); + TEST_BOOL_EXPR(!true || true); - result = AnimExpression("(ten + twenty) * 5").evaluate(vars); - QVERIFY(result.type == AnimExpression::OpCode::Int); - QVERIFY(result.intVal == (10 + 20) * 5); + TEST_BOOL_EXPR(!true && !false || !true); + TEST_BOOL_EXPR(!true && !false || true); + TEST_BOOL_EXPR(!true && false || !true); + TEST_BOOL_EXPR(!true && false || true); + TEST_BOOL_EXPR(true && !false || !true); + TEST_BOOL_EXPR(true && !false || true); + TEST_BOOL_EXPR(true && false || !true); + TEST_BOOL_EXPR(true && false || true); - result = AnimExpression("(ten + twenty) * 5.0").evaluate(vars); - QVERIFY(result.type == AnimExpression::OpCode::Float); - QVERIFY(result.floatVal == (10 + 20) * 5.0f); - - result = AnimExpression("five * forty").evaluate(vars); - QVERIFY(result.type == AnimExpression::OpCode::Float); - QVERIFY(result.floatVal == 5.0f * 40.0f); -*/ + TEST_BOOL_EXPR(!(true && f) || !t); + TEST_BOOL_EXPR(!!!(t) && (!!f || true)); + TEST_BOOL_EXPR(!(true && f) && true); } From d4f55ed6d2da961544888a74b22fb45777cbbf8a Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 15 Dec 2015 15:55:03 -0800 Subject: [PATCH 056/209] working lsiders --- examples/controllers/handControllerGrab.js | 56 ++++++++++++++++- examples/lights/box.js | 73 +++++++++++++--------- examples/lights/light_modifier.js | 61 ++++++++++-------- examples/lights/testScene.js | 1 + 4 files changed, 135 insertions(+), 56 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 07894b46d1..d9e75c8836 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -816,6 +816,19 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + var defaultConstrainData = { + axisBasePosition:false, + endOfAxis: false, + } + + var constraintData = getEntityCustomData('lightModifierKey', this.grabbedEntity, defaultConstrainData); + + // var constrainX = constraintData.constrain.x; + // var constrainY = constraintData.constrain.y; + // var constrainZ = constraintData.constrain.z; + + // print('constrainY'+constrainY); + // mix in head motion if (MOVE_WITH_HEAD) { var objDistance = Vec3.length(objectToAvatar); @@ -826,8 +839,21 @@ function MyController(hand) { this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } + var clampedVector; + var targetPosition; + if (constraintData.axisBasePosition !== false) { + clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisBasePosition, constraintData.endOfAxis); + targetPosition = clampedVector; + } else { + targetPosition = { + x: this.currentObjectPosition.x, + y: this.currentObjectPosition.y, + z: this.currentObjectPosition.z + } + } + Entities.updateAction(this.grabbedEntity, this.actionID, { - targetPosition: this.currentObjectPosition, + targetPosition: targetPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, @@ -836,6 +862,34 @@ function MyController(hand) { this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); }; + this.projectVectorAlongAxis = function(position, axisStart, axisEnd) { + + var aPrime = Vec3.subtract(position, axisStart); + + var bPrime = Vec3.subtract(axisEnd, axisStart); + + var bPrimeMagnitude = Vec3.length(bPrime); + + var dotProduct = Vec3.dot(aPrime, bPrime); + + var scalar = dotProduct / bPrimeMagnitude; + + print('SCALAR:::'+scalar); + + if(scalar<0){ + scalar = 0; + } + + if(scalar>1){ + scalar = 1; + } + + var projection = Vec3.sum(axisStart, Vec3.multiply(scalar, Vec3.normalize(bPrime))); + + return projection + + }, + this.nearGrabbing = function() { var now = Date.now(); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); diff --git a/examples/lights/box.js b/examples/lights/box.js index b1f9252073..3bcebc64d3 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -14,51 +14,64 @@ preload: function(entityID) { this.entityID = entityID; var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); + print('USER DATA:::' + entityProperties.userData) var parsedUserData = JSON.parse(entityProperties.userData); - var userData = parsedUserData.lightModifierKey; + this.userData = parsedUserData.lightModifierKey; + this.bPrime = Vec3.subtract(this.userData.endOfAxis, this.userData.axisBasePosition); + this.bPrimeMagnitude = Vec3.length(this.bPrime); + }, startNearGrab: function() { this.setInitialProperties(); }, startDistantGrab: function() { + // Entities.editEntity(this.entityID, { + // parentID: MyAvatar.sessionUUID, + // parentJointIndex: MyAvatar.getJointIndex("LeftHand") + // }); this.setInitialProperties(); }, setInitialProperties: function() { this.initialProperties = Entities.getEntityProperties(this.entityID); }, - getClampedPosition: function() { - var dPosition; - // dPosition = Vec3.subtract(MyAvatar.position, this.previousPosition); - //convert to localFrame - // dPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), dPosition); + clampPosition: function() { + + var currentProperties = Entities.getEntityProperties(this.entityID); + + var aPrime = Vec3.subtract(this.userData.axisBasePosition, currentProperties.position); + + var dotProduct = Vec3.dot(aPrime, this.bPrime); + + var scalar = dotProduct / this.bPrimeMagnitude; + + print('SCALAR:::' + scalar); + + var projection = Vec3.sum(this.userData.axisBasePosition, Vec3.multiply(scalar, Vec3.normalize(this.bPrime))); + + this.currentProjection = projection; - return dPosition; - }, - getClampedRotation: function() { - var rotation = initialProperties.rotation; - return rotation; }, continueDistantGrab: function() { - var currentPosition = this.getClampedPosition(); - var distance = Vec3.distance(this.initialProperties.position, currentPosition); + // this.clampPosition(); + print('distant grab') + var currentPosition = Entities.getEntityProperties(this.entityID, "position").position; - if (userData.sliderType === 'color_red' || userData.sliderType === 'color_green' || userData.sliderType === 'color_blue') { - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, COLOR_MAX); + var distance = Vec3.distance(this.axisBasePosition, this.currentProjection); + + if (this.userData.sliderType === 'color_red' || this.userData.sliderType === 'color_green' || this.userData.sliderType === 'color_blue') { + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, COLOR_MAX); } - if (userData.sliderType === 'intensity') { - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, INTENSITY_MAX); + if (this.userData.sliderType === 'intensity') { + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, INTENSITY_MAX); } - if (userData.sliderType === 'cutoff') { - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, CUTOFF_MAX); + if (this.userData.sliderType === 'cutoff') { + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, CUTOFF_MAX); } - if (userData.sliderType === 'exponent') { - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); + if (this.userData.sliderType === 'exponent') { + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); }; - Entities.editEntity(this.entityID, { - position: currentPosition, - // rotation: this.getClampedRotation() - }); + }, releaseGrab: function() { Entities.editEntity(this.entityID, { @@ -66,7 +79,8 @@ x: 0, y: 0, z: 0 - } + }, + parentID: null }) this.sendValueToSlider(); @@ -79,10 +93,11 @@ return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); }, sendValueToSlider: function() { + var _t = this; var message = { - lightID: userData.lightID, - sliderType: userData.sliderType, - sliderValue: this.sliderValue + lightID: _t.userData.lightID, + sliderType: _t.userData.sliderType, + sliderValue: _t.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); } diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index 2e11c5e22e..f54af5b54f 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -3,36 +3,36 @@ -var BOX_SCRIPT_URL = Script.resolvePath('box.js'); +var BOX_SCRIPT_URL = Script.resolvePath('box.js?'+Math.random(0,100)); var RED = { - r: 255, - g: 0, - b: 0 + red: 255, + green: 0, + blue: 0 }; var GREEN = { - r: 0, - g: 255, - b: 0 + red: 0, + green: 255, + blue: 0 }; var BLUE = { - r: 0, - g: 0, - b: 255 + red: 0, + green: 0, + blue: 255 }; var PURPLE = { - r: 255, - g: 0, - b: 255 + red: 255, + green: 0, + blue: 255 }; var WHITE = { - r: 255, - g: 255, - b: 255 + red: 255, + green: 255, + blue: 255 }; var AXIS_SCALE = 1; @@ -44,7 +44,7 @@ var BOX_DIMENSIONS = { }; var PER_ROW_OFFSET = { x: 0, - y: 0.2, + y: -0.2, z: 0 }; @@ -55,6 +55,7 @@ function entitySlider(light, color, sliderType, row) { this.color = color; this.sliderType = sliderType; this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); + print('slider : ' + this.sliderType + "should have an offset of : " + this.verticalOffset); this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(this.avatarRot))); @@ -111,11 +112,11 @@ entitySlider.prototype = { var rightVector = Quat.getRight(this.avatarRot); var extension = Vec3.multiply(AXIS_SCALE, rightVector); var endOfAxis = Vec3.sum(position, extension); - - var endOfAxis; + this.endOfAxis = endOfAxis; + print('endOfAxis:::' + JSON.stringify(endOfAxis)) var properties = { type: 'Line', - name: 'Hifi-Slider-Axis::'+this.sliderType, + name: 'Hifi-Slider-Axis::' + this.sliderType, color: this.color, collisionsWillMove: false, ignoreForCollisions: true, @@ -129,14 +130,14 @@ entitySlider.prototype = { x: 0, y: 0, z: 0 - }, endOfAxis], + }, extension], lineWidth: 5, }; this.axis = Entities.addEntity(properties); }, createBoxIndicator: function() { - print('BOX COLOR IS:::'+JSON.stringify(this.color)); + print('BOX COLOR IS:::' + JSON.stringify(this.color)); var position = Vec3.sum(this.basePosition, this.verticalOffset); //line starts on left and goes to right @@ -162,18 +163,26 @@ entitySlider.prototype = { initialDistance = this.distanceExponent; } var extension = Vec3.multiply(initialDistance, rightVector); - var endOfAxis = Vec3.sum(position, extension); + var sliderPosition = Vec3.sum(position, extension); var properties = { type: 'Box', - name: 'Hifi-Slider::'+this.sliderType, + name: 'Hifi-Slider::' + this.sliderType, dimensions: BOX_DIMENSIONS, + collisionsWillMove: true, color: this.color, - position: endOfAxis, + position: sliderPosition, script: BOX_SCRIPT_URL, userData: JSON.stringify({ lightModifierKey: { lightID: this.lightID, - sliderType: this.sliderType + sliderType: this.sliderType, + axisBasePosition: position, + endOfAxis: this.endOfAxis, + }, + constraintKey: { + constrain: { + y: position.y + } } }) }; diff --git a/examples/lights/testScene.js b/examples/lights/testScene.js index 4cc0058bea..0e0a226c0b 100644 --- a/examples/lights/testScene.js +++ b/examples/lights/testScene.js @@ -15,6 +15,7 @@ basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(-3, Quat.getUp(avatarRot))); var ground = Entities.addEntity({ + name:'Hifi-Light-Mod-Floor', type: "Model", modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/woodFloor.fbx", dimensions: { From d9c93130e5a148a2758e9c7016a16467cbd7b5b3 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 15 Dec 2015 18:02:11 -0800 Subject: [PATCH 057/209] In a state where non uniform random vals are clear --- .../flowArts/lightBall/lightBallSpawner.js | 39 +++++++------------ .../entities/src/ParticleEffectEntityItem.cpp | 2 +- 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index 7744c1210e..dd521b4fd4 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -12,21 +12,9 @@ var raveRoom = Entities.addEntity({ }); var colorPalette = [{ - red: 250, - green: 137, + red: 25, + green: 20, blue: 162 -}, { - red: 204, - green: 244, - blue: 249 -}, { - red: 146, - green: 206, - blue: 116 -}, { - red: 240, - green: 87, - blue: 129 }]; @@ -34,7 +22,7 @@ var containerBall = Entities.addEntity({ type: "Sphere", position: center, dimensions: {x: .1, y: .1, z: .1}, - color: {red: 1500, green: 10, blue: 50}, + color: {red: 15, green: 10, blue: 150}, collisionsWillMove: true, userData: JSON.stringify({ grabbableKey: { @@ -90,13 +78,13 @@ var lightBall = Entities.addEntity({ isEmitting: true, "name": "ParticlesTest Emitter", "colorStart": {red: 200, green: 20, blue: 40}, - color: {red: 10, green: 0, blue: 255}, - "colorFinish": {red: 250, green: 200, blue:255}, + color: {red: 200, green: 200, blue: 255}, + "colorFinish": {red: 25, green: 20, blue:255}, "maxParticles": 100000, - "lifespan": 2, - "emitRate": 10000, - "emitSpeed": .2, - "speedSpread": .01, + "lifespan": 5, + "emitRate": 500, + "emitSpeed": .02, + "speedSpread": .0, "emitDimensions": { "x": 0, "y": 0, @@ -112,9 +100,9 @@ var lightBall = Entities.addEntity({ "z": 0 }, "accelerationSpread": { - "x": .01, - "y": .01, - "z": .01 + "x": .00, + "y": .00, + "z": .00 }, "particleRadius": 0.04, "radiusSpread": 0, @@ -124,9 +112,8 @@ var lightBall = Entities.addEntity({ "alphaSpread": .5, "alphaStart": 0, "alphaFinish": 0.5, - "additiveBlending": 0, "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - emitterShouldTrail: false + emitterShouldTrail: true }) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 7d9af11862..954074ec17 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -645,7 +645,7 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { std::random_device rd; std::mt19937_64 el(rd()); - std::uniform_real_distribution uniform_dist(-1.0, 1.0); + std::uniform_real_distribution uniform_dist(0.0, 1.0); particle.seed = randFloatInRange(-1.0f, 1.0f); if (getEmitterShouldTrail()) { From 9a2d9997e90c99edd49ce1b7452511c80e1bccb5 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 15 Dec 2015 18:20:12 -0800 Subject: [PATCH 058/209] prep for feedback --- examples/controllers/handControllerGrab.js | 234 ++++++++++--------- examples/lights/light_loader.js | 8 + examples/lights/light_modifier.js | 113 ++++----- examples/lights/light_modifier_test_scene.js | 128 ++++++++++ examples/lights/{box.js => slider.js} | 49 ++-- examples/lights/testScene.js | 117 ---------- 6 files changed, 331 insertions(+), 318 deletions(-) create mode 100644 examples/lights/light_loader.js create mode 100644 examples/lights/light_modifier_test_scene.js rename examples/lights/{box.js => slider.js} (67%) delete mode 100644 examples/lights/testScene.js diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index d9e75c8836..c452519522 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -218,6 +218,7 @@ function getSpatialOffsetPosition(hand, spatialKey) { } var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + function getSpatialOffsetRotation(hand, spatialKey) { var rotation = Quat.IDENTITY; @@ -261,9 +262,9 @@ function MyController(hand) { this.triggerValue = 0; // rolling average of trigger value this.rawTriggerValue = 0; this.rawBumperValue = 0; - + this.overlayLine = null; - + this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; @@ -816,33 +817,36 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); - var defaultConstrainData = { - axisBasePosition:false, - endOfAxis: false, - } - var constraintData = getEntityCustomData('lightModifierKey', this.grabbedEntity, defaultConstrainData); - - // var constrainX = constraintData.constrain.x; - // var constrainY = constraintData.constrain.y; - // var constrainZ = constraintData.constrain.z; - - // print('constrainY'+constrainY); // mix in head motion if (MOVE_WITH_HEAD) { var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { x: 0.0, y: 0.0, z: objDistance }); - var after = Vec3.multiplyQbyV(Camera.orientation, { x: 0.0, y: 0.0, z: objDistance }); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); var change = Vec3.subtract(before, after); this.currentCameraOrientation = Camera.orientation; this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } + var defaultConstraintData = { + axisStart: false, + axisEnd: false, + } + + var constraintData = getEntityCustomData('lightModifierKey', this.grabbedEntity, defaultConstraintData); var clampedVector; var targetPosition; - if (constraintData.axisBasePosition !== false) { - clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisBasePosition, constraintData.endOfAxis); + if (constraintData.startAxis !== false) { + clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisStart, constraintData.axisEnd); targetPosition = clampedVector; } else { targetPosition = { @@ -859,121 +863,121 @@ function MyController(hand) { angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, ttl: ACTION_TTL }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + }; this.projectVectorAlongAxis = function(position, axisStart, axisEnd) { - var aPrime = Vec3.subtract(position, axisStart); + var aPrime = Vec3.subtract(position, axisStart); - var bPrime = Vec3.subtract(axisEnd, axisStart); + var bPrime = Vec3.subtract(axisEnd, axisStart); - var bPrimeMagnitude = Vec3.length(bPrime); + var bPrimeMagnitude = Vec3.length(bPrime); - var dotProduct = Vec3.dot(aPrime, bPrime); + var dotProduct = Vec3.dot(aPrime, bPrime); - var scalar = dotProduct / bPrimeMagnitude; + var scalar = dotProduct / bPrimeMagnitude; - print('SCALAR:::'+scalar); + if (scalar < 0) { + scalar = 0; + } - if(scalar<0){ - scalar = 0; - } + if (scalar > 1) { + scalar = 1; + } - if(scalar>1){ - scalar = 1; - } + var projection = Vec3.sum(axisStart, Vec3.multiply(scalar, Vec3.normalize(bPrime))); - var projection = Vec3.sum(axisStart, Vec3.multiply(scalar, Vec3.normalize(bPrime))); + return projection - return projection + }, - }, + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - this.nearGrabbing = function() { - var now = Date.now(); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } - if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } + this.lineOff(); + this.overlayLineOff(); - this.lineOff(); - this.overlayLineOff(); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { - Entities.editEntity(this.grabbedEntity, { - collisionsWillMove: false + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.ignoreIK = false; + + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK }); - } - - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { - // if an object is "equipped" and has a spatialKey, use it. - this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - } else { - this.ignoreIK = false; - - var objectRotation = grabbedProperties.rotation; - this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var currentObjectPosition = grabbedProperties.position; - var offset = Vec3.subtract(currentObjectPosition, handPosition); - this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); - } - - this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("hold", this.grabbedEntity, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, - ignoreIK: this.ignoreIK - }); - if (this.actionID === NULL_ACTION_ID) { - this.actionID = null; - } else { - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - if (this.state == STATE_NEAR_GRABBING) { - this.setState(STATE_CONTINUE_NEAR_GRABBING); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; } else { - // equipping - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - this.startHandGrasp(); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); - this.setState(STATE_CONTINUE_EQUIP_BD); } - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); - - } - - this.currentHandControllerTipPosition = - (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; - - this.currentObjectTime = Date.now(); - }; + this.currentObjectTime = Date.now(); + }; this.continueNearGrabbing = function() { if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { @@ -1358,10 +1362,10 @@ Controller.enableMapping(MAPPING_NAME); var handToDisable = 'none'; function update() { - if (handToDisable !== LEFT_HAND && handToDisable!=='both') { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { leftController.update(); } - if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { rightController.update(); } } @@ -1369,7 +1373,7 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { - + if (sender === MyAvatar.sessionUUID) { if (message === 'left') { handToDisable = LEFT_HAND; @@ -1377,11 +1381,11 @@ handleHandDisablerMessages = function(channel, message, sender) { if (message === 'right') { handToDisable = RIGHT_HAND; } - if(message==='both'){ - handToDisable='both'; + if (message === 'both') { + handToDisable = 'both'; } - if(message==='none'){ - handToDisable='none'; + if (message === 'none') { + handToDisable = 'none'; } } @@ -1396,4 +1400,4 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -Script.update.connect(update); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/lights/light_loader.js b/examples/lights/light_loader.js new file mode 100644 index 0000000000..8edaa20f57 --- /dev/null +++ b/examples/lights/light_loader.js @@ -0,0 +1,8 @@ +var grabScript = Script.resolvePath('../controllers/handControllerGrab.js'); +Script.load(grabScript); +var lightModifier = Script.resolvePath('light_modifier.js'); +Script.load(lightModifier); +Script.setTimeout(function() { + var lightModifierTestScene = Script.resolvePath('light_modifier_test_scene.js'); + Script.load(lightModifierTestScene); +}, 750) \ No newline at end of file diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index f54af5b54f..cbb4e3ff10 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -1,9 +1,22 @@ -// given a selected light, instantiate some entities that represent various values you can dynamically adjust +// +// light_modifier.js +// +// Created byJames Pollack @imgntn on 10/19/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Given a selected light, instantiate some entities that represent various values you can dynamically adjust by grabbing and moving. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +var AXIS_SCALE = 1; +var COLOR_MAX = 255; +var INTENSITY_MAX = 0.05; +var CUTOFF_MAX = 360; +var EXPONENT_MAX = 1; - -var BOX_SCRIPT_URL = Script.resolvePath('box.js?'+Math.random(0,100)); +var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); var RED = { red: 255, @@ -35,13 +48,12 @@ var WHITE = { blue: 255 }; -var AXIS_SCALE = 1; - -var BOX_DIMENSIONS = { - x: 0.05, - y: 0.05, - z: 0.05 +var SLIDER_DIMENSIONS = { + x: 0.075, + y: 0.075, + z: 0.075 }; + var PER_ROW_OFFSET = { x: 0, y: -0.2, @@ -55,10 +67,8 @@ function entitySlider(light, color, sliderType, row) { this.color = color; this.sliderType = sliderType; this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); - print('slider : ' + this.sliderType + "should have an offset of : " + this.verticalOffset); - this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); - this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(this.avatarRot))); + this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); var message = { lightID: this.lightID, @@ -95,9 +105,8 @@ function entitySlider(light, color, sliderType, row) { } this.setInitialSliderPositions(); - this.subscribeToBoxMessages(); this.createAxis(); - this.createBoxIndicator(); + this.createSliderIndicator(); return this; } @@ -113,7 +122,6 @@ entitySlider.prototype = { var extension = Vec3.multiply(AXIS_SCALE, rightVector); var endOfAxis = Vec3.sum(position, extension); this.endOfAxis = endOfAxis; - print('endOfAxis:::' + JSON.stringify(endOfAxis)) var properties = { type: 'Line', name: 'Hifi-Slider-Axis::' + this.sliderType, @@ -136,10 +144,8 @@ entitySlider.prototype = { this.axis = Entities.addEntity(properties); }, - createBoxIndicator: function() { - print('BOX COLOR IS:::' + JSON.stringify(this.color)); + createSliderIndicator: function() { var position = Vec3.sum(this.basePosition, this.verticalOffset); - //line starts on left and goes to right //set the end of the line to the right var rightVector = Quat.getRight(this.avatarRot); @@ -154,7 +160,7 @@ entitySlider.prototype = { initialDistance = this.distanceBlue; } if (this.sliderType === 'intensity') { - initialDistance = this.distanceRed; + initialDistance = this.distanceIntensity; } if (this.sliderType === 'cutoff') { initialDistance = this.distanceCutoff; @@ -165,30 +171,26 @@ entitySlider.prototype = { var extension = Vec3.multiply(initialDistance, rightVector); var sliderPosition = Vec3.sum(position, extension); var properties = { - type: 'Box', + type: 'Sphere', name: 'Hifi-Slider::' + this.sliderType, - dimensions: BOX_DIMENSIONS, + dimensions: SLIDER_DIMENSIONS, collisionsWillMove: true, color: this.color, position: sliderPosition, - script: BOX_SCRIPT_URL, + script: SLIDER_SCRIPT_URL, userData: JSON.stringify({ lightModifierKey: { lightID: this.lightID, sliderType: this.sliderType, - axisBasePosition: position, - endOfAxis: this.endOfAxis, - }, - constraintKey: { - constrain: { - y: position.y - } + axisStart: position, + axisEnd: this.endOfAxis, } }) }; - this.boxIndicator = Entities.addEntity(properties); + this.sliderIndicator = Entities.addEntity(properties); }, + setValueFromMessage: function(message) { //message is not for our light @@ -203,8 +205,6 @@ entitySlider.prototype = { return } - print('should set:::' + this.sliderType); - var lightProperties = Entities.getEntityProperties(this.lightID); if (this.sliderType === 'color_red') { @@ -255,28 +255,15 @@ entitySlider.prototype = { }); } }, - subscribeToBoxMessages: function() { - Messages.subscribe('Hifi-Slider-Value-Reciever'); - Messages.messageReceived.connect(handleValueMessages); - }, setInitialSliderPositions: function() { - var COLOR_MAX = 255; - var INTENSITY_MAX = 10; - var CUTOFF_MAX = 360; - var EXPONENT_MAX = 1; - this.distanceRed = (this.initialProperties.color.red / COLOR_MAX) * AXIS_SCALE; this.distanceGreen = (this.initialProperties.color.green / COLOR_MAX) * AXIS_SCALE; this.distanceBlue = (this.initialProperties.color.blue / COLOR_MAX) * AXIS_SCALE; this.distanceIntensity = (this.initialProperties.intensity / INTENSITY_MAX) * AXIS_SCALE; this.distanceCutoff = (this.initialProperties.cutoff / CUTOFF_MAX) * AXIS_SCALE; this.distanceExponent = (this.initialProperties.exponent / EXPONENT_MAX) * AXIS_SCALE; - }, - cleanup: function() { - Entities.deleteEntity(this.boxIndicator); - Entities.deleteEntity(this.axis); - Messages.messageReceived.disconnect(this.handleValueMessages); } + }; var sliders = []; @@ -288,9 +275,9 @@ var slidersRef = { cutoff: null, exponent: null } +var light = null; function makeSliders(light) { - print('light in makesliders:::' + light) if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -325,14 +312,19 @@ function makeSliders(light) { slidersRef.exponent = new entitySlider(light, PURPLE, 'exponent', 6); sliders.push(slidersRef.exponent); } + subscribeToSliderMessages(); }; function subScribeToNewLights() { - print('subscribing to light messages') Messages.subscribe('Hifi-Light-Mod-Receiver'); Messages.messageReceived.connect(handleLightModMessages); } +function subscribeToSliderMessages() { + Messages.subscribe('Hifi-Slider-Value-Reciever'); + Messages.messageReceived.connect(handleValueMessages); +} + function handleLightModMessages(channel, message, sender) { if (channel !== 'Hifi-Light-Mod-Receiver') { return; @@ -343,6 +335,7 @@ function handleLightModMessages(channel, message, sender) { var parsedMessage = JSON.parse(message); makeSliders(parsedMessage.light); + light = parsedMessage.light.id } function handleValueMessages(channel, message, sender) { @@ -356,27 +349,39 @@ function handleValueMessages(channel, message, sender) { // } var parsedMessage = JSON.parse(message); - slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage) + slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage); } function cleanup() { - while (sliders.length > 0) { - var slider = sliders.pop(); - slider.cleanup(); + var i; + for (i = 0; i < sliders.length; i++) { + Entities.deleteEntity(sliders[i].axis); + Entities.deleteEntity(sliders[i].sliderIndicator); } + Messages.messageReceived.disconnect(handleLightModMessages); - delete sliders + Messages.messageReceived.disconnect(handleValueMessages); + Entities.deletingEntity.disconnect(deleteEntity); + } Script.scriptEnding.connect(cleanup); subScribeToNewLights(); +function deleteEntity(entityID) { + if (entityID === light) { + // cleanup(); + } +} + + +Entities.deletingEntity.connect(deleteEntity); + //other light properties // diffuseColor: { red: 255, green: 255, blue: 255 }, // ambientColor: { red: 255, green: 255, blue: 255 }, // specularColor: { red: 255, green: 255, blue: 255 }, - // constantAttenuation: 1, // linearAttenuation: 0, // quadraticAttenuation: 0, diff --git a/examples/lights/light_modifier_test_scene.js b/examples/lights/light_modifier_test_scene.js new file mode 100644 index 0000000000..d997816957 --- /dev/null +++ b/examples/lights/light_modifier_test_scene.js @@ -0,0 +1,128 @@ +// +// light_modifier_test_scene.js +// +// Created byJames Pollack @imgntn on 10/19/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Given a selected light, instantiate some entities that represent various values you can dynamically adjust. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 +}; +var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 +}); + +var basePosition, avatarRot; +avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); +basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(-3, Quat.getUp(avatarRot))); + +var ground = Entities.addEntity({ + name: 'Hifi-Light-Mod-Floor', + //type: "Model", + type: 'Box', + color: { + red: 100, + green: 100, + blue: 100 + }, + //modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/woodFloor.fbx", + dimensions: { + x: 100, + y: 2, + z: 100 + }, + position: basePosition, + shapeType: 'box' +}); + +var light, block; + +function createLight() { + var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); + var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); + var lightProperties = { + name: 'Hifi-Spotlight', + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: block, + color: { + red: 255, + green: 0, + blue: 255 + }, + intensity: 0.035, + exponent: 1, + cutoff: 30, + lifetime: -1, + position: lightTransform.p, + rotation: lightTransform.q + }; + + light = Entities.addEntity(lightProperties); + + var message = { + light: { + id: light, + type: 'spotlight', + initialProperties: lightProperties + } + }; + + Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); + +} + +function createBlock() { + var position = basePosition; + position.y += 5; + var blockProperties = { + name: 'Hifi-Spotlight-Block', + type: 'Box', + dimensions: { + x: 1, + y: 1, + z: 1 + }, + collisionsWillMove: true, + color: { + red: 0, + green: 0, + blue: 255 + }, + position: position + } + + block = Entities.addEntity(blockProperties); +} + +function evalLightWorldTransform(modelPos, modelRot) { + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; +} + +function cleanup() { + print('CLEANUP TEST SCENE SCRIPT') + Entities.deleteEntity(block); + Entities.deleteEntity(ground); + Entities.deleteEntity(light); +} + +Script.scriptEnding.connect(cleanup); + +createBlock(); +createLight(); \ No newline at end of file diff --git a/examples/lights/box.js b/examples/lights/slider.js similarity index 67% rename from examples/lights/box.js rename to examples/lights/slider.js index 3bcebc64d3..ab90019b9f 100644 --- a/examples/lights/box.js +++ b/examples/lights/slider.js @@ -2,61 +2,40 @@ var AXIS_SCALE = 1; var COLOR_MAX = 255; - var INTENSITY_MAX = 10; + var INTENSITY_MAX = 0.05; var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; - function Box() { + function Slider() { return this; } - Box.prototype = { + Slider.prototype = { preload: function(entityID) { this.entityID = entityID; var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); - print('USER DATA:::' + entityProperties.userData) var parsedUserData = JSON.parse(entityProperties.userData); this.userData = parsedUserData.lightModifierKey; - this.bPrime = Vec3.subtract(this.userData.endOfAxis, this.userData.axisBasePosition); - this.bPrimeMagnitude = Vec3.length(this.bPrime); - }, startNearGrab: function() { this.setInitialProperties(); }, startDistantGrab: function() { - // Entities.editEntity(this.entityID, { - // parentID: MyAvatar.sessionUUID, - // parentJointIndex: MyAvatar.getJointIndex("LeftHand") - // }); this.setInitialProperties(); }, setInitialProperties: function() { this.initialProperties = Entities.getEntityProperties(this.entityID); }, - clampPosition: function() { - - var currentProperties = Entities.getEntityProperties(this.entityID); - - var aPrime = Vec3.subtract(this.userData.axisBasePosition, currentProperties.position); - - var dotProduct = Vec3.dot(aPrime, this.bPrime); - - var scalar = dotProduct / this.bPrimeMagnitude; - - print('SCALAR:::' + scalar); - - var projection = Vec3.sum(this.userData.axisBasePosition, Vec3.multiply(scalar, Vec3.normalize(this.bPrime))); - - this.currentProjection = projection; - + continueNearGrab: function() { + // this.continueDistantGrab(); }, continueDistantGrab: function() { - // this.clampPosition(); - print('distant grab') + this.setSliderValueBasedOnDistance(); + }, + setSliderValueBasedOnDistance: function() { var currentPosition = Entities.getEntityProperties(this.entityID, "position").position; - var distance = Vec3.distance(this.axisBasePosition, this.currentProjection); + var distance = Vec3.distance(this.userData.axisStart, currentPosition); if (this.userData.sliderType === 'color_red' || this.userData.sliderType === 'color_green' || this.userData.sliderType === 'color_blue') { this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, COLOR_MAX); @@ -71,6 +50,8 @@ this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); }; + print('SLIDER VALUE:::' + this.sliderValue) + this.sendValueToSlider(); }, releaseGrab: function() { @@ -80,7 +61,11 @@ y: 0, z: 0 }, - parentID: null + angularVelocity: { + x: 0, + y: 0, + z: 0 + } }) this.sendValueToSlider(); @@ -103,5 +88,5 @@ } }; - return new Box(); + return new Slider(); }); \ No newline at end of file diff --git a/examples/lights/testScene.js b/examples/lights/testScene.js deleted file mode 100644 index 0e0a226c0b..0000000000 --- a/examples/lights/testScene.js +++ /dev/null @@ -1,117 +0,0 @@ - // These constants define the Spotlight position and orientation relative to the model - var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 - }; - var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 - }); - - var basePosition, avatarRot; - avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); - basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(-3, Quat.getUp(avatarRot))); - - var ground = Entities.addEntity({ - name:'Hifi-Light-Mod-Floor', - type: "Model", - modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/woodFloor.fbx", - dimensions: { - x: 100, - y: 2, - z: 100 - }, - position: basePosition, - shapeType: 'box' - }); - - var light, block; - - // basePosition.y += 2; - - function createLight() { - print('making light' + block) - var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); - var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); - var lightProperties = { - name: 'Hifi-Spotlight', - type: "Light", - isSpotlight: true, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - parentID: block, - color: { - red: 255, - green: 0, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: -1, - position: lightTransform.p, - rotation: lightTransform.q - }; - - light = Entities.addEntity(lightProperties); - - var message = { - light: { - id: light, - type: 'spotlight', - initialProperties: lightProperties - } - }; - - Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); - print('SENT MESSAGE') - - } - - function createBlock() { - print('making block'); - - var position = basePosition; - position.y += 5; - var blockProperties = { - name: 'Hifi-Spotlight-Block', - type: 'Box', - dimensions: { - x: 1, - y: 1, - z: 1 - }, - collisionsWillMove: true, - color: { - red: 0, - green: 0, - blue: 255 - }, - position: position - } - - block = Entities.addEntity(blockProperties); - } - - function evalLightWorldTransform(modelPos, modelRot) { - return { - p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), - q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) - }; - } - - function cleanup() { - Entities.deleteEntity(block); - Entities.deleteEntity(ground); - Entities.deleteEntity(light); - } - - Script.scriptEnding.connect(cleanup); - - createBlock(); - createLight(); \ No newline at end of file From 61bad36d5c1b0a0ad40747724372c121040e60d5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 15 Dec 2015 18:49:04 -0800 Subject: [PATCH 059/209] tweaks --- examples/flowArts/lightBall/lightBallSpawner.js | 5 +++-- libraries/entities/src/ParticleEffectEntityItem.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index dd521b4fd4..505df7d83b 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -24,6 +24,7 @@ var containerBall = Entities.addEntity({ dimensions: {x: .1, y: .1, z: .1}, color: {red: 15, green: 10, blue: 150}, collisionsWillMove: true, + visible: false, userData: JSON.stringify({ grabbableKey: { spatialKey: { @@ -82,8 +83,8 @@ var lightBall = Entities.addEntity({ "colorFinish": {red: 25, green: 20, blue:255}, "maxParticles": 100000, "lifespan": 5, - "emitRate": 500, - "emitSpeed": .02, + "emitRate": 5000, + "emitSpeed": .1, "speedSpread": .0, "emitDimensions": { "x": 0, diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 954074ec17..4d46439554 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -666,13 +666,14 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { float elevationMinZ = sin(PI_OVER_TWO - _polarFinish); float elevationMaxZ = sin(PI_OVER_TWO - _polarStart); - float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat()); + // float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat()); + float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * uniform_dist(el)); float azimuth; if (_azimuthFinish >= _azimuthStart) { - azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat(); + azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * uniform_dist(el); } else { - azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * randFloat(); + azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * uniform_dist(el); } glm::vec3 emitDirection; From adf6cf8aa3f3d41ad79013ae8d2ee724de3b738c Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 16 Dec 2015 00:58:00 -0800 Subject: [PATCH 060/209] vary colors --- examples/lights/light_modifier.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index cbb4e3ff10..ed11b9c618 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -48,6 +48,12 @@ var WHITE = { blue: 255 }; +var ORANGE={ + red:255, + green:0, + blue:128 +} + var SLIDER_DIMENSIONS = { x: 0.075, y: 0.075, @@ -309,7 +315,7 @@ function makeSliders(light) { sliders.push(slidersRef.cutoff); } if (USE_EXPONENT_SLIDER === true) { - slidersRef.exponent = new entitySlider(light, PURPLE, 'exponent', 6); + slidersRef.exponent = new entitySlider(light, ORANGE, 'exponent', 6); sliders.push(slidersRef.exponent); } subscribeToSliderMessages(); From 5a9549a2d951442bdc0b3fbf269f7984d126599b Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 16 Dec 2015 01:21:22 -0800 Subject: [PATCH 061/209] headers --- examples/lights/light_modifier.js | 2 +- examples/lights/light_modifier_test_scene.js | 2 +- examples/lights/slider.js | 10 ++++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index ed11b9c618..132934f5d2 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -1,7 +1,7 @@ // // light_modifier.js // -// Created byJames Pollack @imgntn on 10/19/2015 +// Created byJames Pollack @imgntn on 12/15/2015 // Copyright 2015 High Fidelity, Inc. // // Given a selected light, instantiate some entities that represent various values you can dynamically adjust by grabbing and moving. diff --git a/examples/lights/light_modifier_test_scene.js b/examples/lights/light_modifier_test_scene.js index d997816957..e70812cb45 100644 --- a/examples/lights/light_modifier_test_scene.js +++ b/examples/lights/light_modifier_test_scene.js @@ -1,7 +1,7 @@ // // light_modifier_test_scene.js // -// Created byJames Pollack @imgntn on 10/19/2015 +// Created byJames Pollack @imgntn on 12/15/2015 // Copyright 2015 High Fidelity, Inc. // // Given a selected light, instantiate some entities that represent various values you can dynamically adjust. diff --git a/examples/lights/slider.js b/examples/lights/slider.js index ab90019b9f..ab59b6eed1 100644 --- a/examples/lights/slider.js +++ b/examples/lights/slider.js @@ -1,3 +1,13 @@ +// +// slider.js +// +// Created byJames Pollack @imgntn on 12/15/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Entity script that sends a scaled value to a light based on its distance from the start of its constraint axis. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html (function() { var AXIS_SCALE = 1; From 28a5dba2d32a0a2a96ff161fff58a4647a07f07e Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 16 Dec 2015 01:31:24 -0800 Subject: [PATCH 062/209] rename files --- examples/lights/lightLoader.js | 20 +++++++++++++++++++ .../{light_modifier.js => lightModifier.js} | 8 ++++---- ...est_scene.js => lightModifierTestScene.js} | 5 ++--- examples/lights/light_loader.js | 8 -------- examples/lights/slider.js | 5 +++-- 5 files changed, 29 insertions(+), 17 deletions(-) create mode 100644 examples/lights/lightLoader.js rename examples/lights/{light_modifier.js => lightModifier.js} (98%) rename examples/lights/{light_modifier_test_scene.js => lightModifierTestScene.js} (95%) delete mode 100644 examples/lights/light_loader.js diff --git a/examples/lights/lightLoader.js b/examples/lights/lightLoader.js new file mode 100644 index 0000000000..e4022e7bc1 --- /dev/null +++ b/examples/lights/lightLoader.js @@ -0,0 +1,20 @@ +// +// lightLoader.js +// +// Created by James Pollack @imgntn on 12/15/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Loads a test scene showing sliders that you can grab and move to change entity properties. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var grabScript = Script.resolvePath('../controllers/handControllerGrab.js'); +Script.load(grabScript); +var lightModifier = Script.resolvePath('lightModifier.js'); +Script.load(lightModifier); +Script.setTimeout(function() { + var lightModifierTestScene = Script.resolvePath('lightModifierTestScene.js'); + Script.load(lightModifierTestScene); +}, 750) \ No newline at end of file diff --git a/examples/lights/light_modifier.js b/examples/lights/lightModifier.js similarity index 98% rename from examples/lights/light_modifier.js rename to examples/lights/lightModifier.js index 132934f5d2..ffd1469a4a 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/lightModifier.js @@ -1,7 +1,7 @@ // -// light_modifier.js +// lightModifier.js // -// Created byJames Pollack @imgntn on 12/15/2015 +// Created by James Pollack @imgntn on 12/15/2015 // Copyright 2015 High Fidelity, Inc. // // Given a selected light, instantiate some entities that represent various values you can dynamically adjust by grabbing and moving. @@ -201,13 +201,13 @@ entitySlider.prototype = { //message is not for our light if (message.lightID !== this.lightID) { - print('not our light') + // print('not our light') return; } //message is not our type if (message.sliderType !== this.sliderType) { - print('not our slider type') + // print('not our slider type') return } diff --git a/examples/lights/light_modifier_test_scene.js b/examples/lights/lightModifierTestScene.js similarity index 95% rename from examples/lights/light_modifier_test_scene.js rename to examples/lights/lightModifierTestScene.js index e70812cb45..214d900130 100644 --- a/examples/lights/light_modifier_test_scene.js +++ b/examples/lights/lightModifierTestScene.js @@ -1,7 +1,7 @@ // -// light_modifier_test_scene.js +// lightModifierTestScene.js // -// Created byJames Pollack @imgntn on 12/15/2015 +// Created by James Pollack @imgntn on 12/15/2015 // Copyright 2015 High Fidelity, Inc. // // Given a selected light, instantiate some entities that represent various values you can dynamically adjust. @@ -116,7 +116,6 @@ function evalLightWorldTransform(modelPos, modelRot) { } function cleanup() { - print('CLEANUP TEST SCENE SCRIPT') Entities.deleteEntity(block); Entities.deleteEntity(ground); Entities.deleteEntity(light); diff --git a/examples/lights/light_loader.js b/examples/lights/light_loader.js deleted file mode 100644 index 8edaa20f57..0000000000 --- a/examples/lights/light_loader.js +++ /dev/null @@ -1,8 +0,0 @@ -var grabScript = Script.resolvePath('../controllers/handControllerGrab.js'); -Script.load(grabScript); -var lightModifier = Script.resolvePath('light_modifier.js'); -Script.load(lightModifier); -Script.setTimeout(function() { - var lightModifierTestScene = Script.resolvePath('light_modifier_test_scene.js'); - Script.load(lightModifierTestScene); -}, 750) \ No newline at end of file diff --git a/examples/lights/slider.js b/examples/lights/slider.js index ab59b6eed1..c17704b0db 100644 --- a/examples/lights/slider.js +++ b/examples/lights/slider.js @@ -1,13 +1,14 @@ // // slider.js // -// Created byJames Pollack @imgntn on 12/15/2015 +// Created by James Pollack @imgntn on 12/15/2015 // Copyright 2015 High Fidelity, Inc. // // Entity script that sends a scaled value to a light based on its distance from the start of its constraint axis. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// (function() { var AXIS_SCALE = 1; @@ -60,7 +61,7 @@ this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); }; - print('SLIDER VALUE:::' + this.sliderValue) + //print('SLIDER VALUE:::' + this.sliderValue) this.sendValueToSlider(); }, From b0bcbb03f2bee5fa5c299c9f20774fd0d7ddea04 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 11:57:54 -0800 Subject: [PATCH 063/209] remove floor and move sliders up a bit --- examples/lights/lightModifier.js | 84 +++++++++++++++++++++-- examples/lights/lightModifierTestScene.js | 46 ++++--------- examples/lights/slider.js | 3 +- 3 files changed, 92 insertions(+), 41 deletions(-) diff --git a/examples/lights/lightModifier.js b/examples/lights/lightModifier.js index ffd1469a4a..0a584b127c 100644 --- a/examples/lights/lightModifier.js +++ b/examples/lights/lightModifier.js @@ -10,6 +10,19 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +// Script.include('../libraries/lightOverlayManager.js'); +// var lightOverlayManager = new LightOverlayManager(); +// lightOverlayManager.setVisible(true); + + // var pickRay = Camera.computePickRay(event.x, event.y); + // var lightResult = lightOverlayManager.findRayIntersection(pickRay) + + +var DEFAULT_PARENT_ID = '{00000000-0000-0000-0000-000000000000}' +var SHOULD_STAY_WITH_AVATAR = false; +var VERTICAL_SLIDERS = false; + var AXIS_SCALE = 1; var COLOR_MAX = 255; var INTENSITY_MAX = 0.05; @@ -48,10 +61,10 @@ var WHITE = { blue: 255 }; -var ORANGE={ - red:255, - green:0, - blue:128 +var ORANGE = { + red: 255, + green: 0, + blue: 128 } var SLIDER_DIMENSIONS = { @@ -75,6 +88,7 @@ function entitySlider(light, color, sliderType, row) { this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); + this.basePosition.y +=1; var message = { lightID: this.lightID, @@ -190,6 +204,10 @@ entitySlider.prototype = { sliderType: this.sliderType, axisStart: position, axisEnd: this.endOfAxis, + }, + releaseVelocityKey: { + disableReleaseVelocity: true, + customReleaseVelocity: false } }) }; @@ -201,13 +219,13 @@ entitySlider.prototype = { //message is not for our light if (message.lightID !== this.lightID) { - // print('not our light') + // print('not our light') return; } //message is not our type if (message.sliderType !== this.sliderType) { - // print('not our slider type') + // print('not our slider type') return } @@ -381,8 +399,62 @@ function deleteEntity(entityID) { } + Entities.deletingEntity.connect(deleteEntity); +// search for lights to make grabbable + +// var USE_DEBOUNCE = true; +// var sinceLastUpdate = 0; + +// function searchForLightsToVisualize() { + +// var deltaTime = interval(); + +// if (USE_DEBOUNCE === true) { +// sinceLastUpdate = sinceLastUpdate + deltaTime; + +// if (sinceLastUpdate > 60) { +// sinceLastUpdate = 0; +// } else { +// return; +// } +// } + +// print('SEARCHING FOR LIGHTS'); + +// var entitites = Entities.findEntities(MyAvatar.position, 50); +// for (i = 0; i < entities.length; i++) { +// var entityProperties = Entities.getEntityProperties(entities[i], ['type', 'parentID']) +// var parentID = entityProperties.parentID; +// var type = entityProperties.type; + +// if (type !== 'Light') { +// return; +// } + +// if (type === "Light" && parentID !== DEFAULT_PARENT_ID && parentID !== null) { +// var light = entities[i]; +// //do something with the light. +// } + +// } + +// } + +// function interval() { +// var lastTime = new Date().getTime(); + +// return function getInterval() { +// var newTime = new Date().getTime(); +// var delta = newTime - lastTime; +// lastTime = newTime; +// return delta; +// }; +// } + + + //other light properties // diffuseColor: { red: 255, green: 255, blue: 255 }, diff --git a/examples/lights/lightModifierTestScene.js b/examples/lights/lightModifierTestScene.js index 214d900130..5748f0d4ed 100644 --- a/examples/lights/lightModifierTestScene.js +++ b/examples/lights/lightModifierTestScene.js @@ -9,39 +9,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 -}; -var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 -}); var basePosition, avatarRot; avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); -basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(-3, Quat.getUp(avatarRot))); - -var ground = Entities.addEntity({ - name: 'Hifi-Light-Mod-Floor', - //type: "Model", - type: 'Box', - color: { - red: 100, - green: 100, - blue: 100 - }, - //modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/woodFloor.fbx", - dimensions: { - x: 100, - y: 2, - z: 100 - }, - position: basePosition, - shapeType: 'box' -}); +basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(0, Quat.getUp(avatarRot))); var light, block; @@ -87,7 +58,7 @@ function createLight() { function createBlock() { var position = basePosition; - position.y += 5; + position.y += 3; var blockProperties = { name: 'Hifi-Spotlight-Block', type: 'Box', @@ -103,12 +74,22 @@ function createBlock() { blue: 255 }, position: position - } + }; block = Entities.addEntity(blockProperties); } function evalLightWorldTransform(modelPos, modelRot) { + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); return { p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) @@ -117,7 +98,6 @@ function evalLightWorldTransform(modelPos, modelRot) { function cleanup() { Entities.deleteEntity(block); - Entities.deleteEntity(ground); Entities.deleteEntity(light); } diff --git a/examples/lights/slider.js b/examples/lights/slider.js index c17704b0db..dc02e0bdba 100644 --- a/examples/lights/slider.js +++ b/examples/lights/slider.js @@ -9,6 +9,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + (function() { var AXIS_SCALE = 1; @@ -61,9 +62,7 @@ this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); }; - //print('SLIDER VALUE:::' + this.sliderValue) this.sendValueToSlider(); - }, releaseGrab: function() { Entities.editEntity(this.entityID, { From 6cd86e8a6bf2371079416dfa3b5c387eddc05696 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 12:23:10 -0800 Subject: [PATCH 064/209] midday --- examples/lights/lightModifier.js | 68 +++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/examples/lights/lightModifier.js b/examples/lights/lightModifier.js index 0a584b127c..e928679f08 100644 --- a/examples/lights/lightModifier.js +++ b/examples/lights/lightModifier.js @@ -11,17 +11,20 @@ // +//some experimental options +var ONLY_I_CAN_EDIT = false; +var SLIDERS_SHOULD_STAY_WITH_AVATAR = false; +var VERTICAL_SLIDERS = false; + // Script.include('../libraries/lightOverlayManager.js'); // var lightOverlayManager = new LightOverlayManager(); // lightOverlayManager.setVisible(true); - // var pickRay = Camera.computePickRay(event.x, event.y); - // var lightResult = lightOverlayManager.findRayIntersection(pickRay) - +// var pickRay = Camera.computePickRay(event.x, event.y); +// var lightResult = lightOverlayManager.findRayIntersection(pickRay) var DEFAULT_PARENT_ID = '{00000000-0000-0000-0000-000000000000}' -var SHOULD_STAY_WITH_AVATAR = false; -var VERTICAL_SLIDERS = false; + var AXIS_SCALE = 1; var COLOR_MAX = 255; @@ -88,7 +91,7 @@ function entitySlider(light, color, sliderType, row) { this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); - this.basePosition.y +=1; + this.basePosition.y += 1; var message = { lightID: this.lightID, @@ -134,14 +137,23 @@ function entitySlider(light, color, sliderType, row) { entitySlider.prototype = { createAxis: function() { //start of line - var position = Vec3.sum(this.basePosition, this.verticalOffset); + var position; + var extension; - //line starts on left and goes to right - //set the end of the line to the right - var rightVector = Quat.getRight(this.avatarRot); - var extension = Vec3.multiply(AXIS_SCALE, rightVector); - var endOfAxis = Vec3.sum(position, extension); - this.endOfAxis = endOfAxis; + if (VERTICAL_SLIDERS == true) { + position = Vec3.sum(this.basePosition, Vec3.multiply(row, (Vec3.multiply(0.2, Quat.getRight(this.avatarRot))))); + //line starts on bottom and goes up + var upVector = Quat.getUp(this.avatarRot); + extension = Vec3.multiply(AXIS_SCALE, upVector); + } else { + position = Vec3.sum(this.basePosition, this.verticalOffset); + //line starts on left and goes to right + //set the end of the line to the right + var rightVector = Quat.getRight(this.avatarRot); + extension = Vec3.multiply(AXIS_SCALE, rightVector); + } + + this.endOfAxis = Vec3.sum(position, extension); var properties = { type: 'Line', name: 'Hifi-Slider-Axis::' + this.sliderType, @@ -165,10 +177,18 @@ entitySlider.prototype = { this.axis = Entities.addEntity(properties); }, createSliderIndicator: function() { - var position = Vec3.sum(this.basePosition, this.verticalOffset); - //line starts on left and goes to right - //set the end of the line to the right - var rightVector = Quat.getRight(this.avatarRot); + var extensionVector; + var position; + if (VERTICAL_SLIDERS == true) { + position = Vec3.sum(this.basePosition, Vec3.multiply(row, (Vec3.multiply(0.2, Quat.getRight(this.avatarRot))))); + extensionVector = Quat.getUp(this.avatarRot); + + } else { + position = Vec3.sum(this.basePosition, this.verticalOffset); + extensionVector = Quat.getRight(this.avatarRot); + + } + var initialDistance; if (this.sliderType === 'color_red') { initialDistance = this.distanceRed; @@ -188,11 +208,13 @@ entitySlider.prototype = { if (this.sliderType === 'exponent') { initialDistance = this.distanceExponent; } - var extension = Vec3.multiply(initialDistance, rightVector); + + var extension = Vec3.multiply(initialDistance, extensionVector); var sliderPosition = Vec3.sum(position, extension); + var properties = { type: 'Sphere', - name: 'Hifi-Slider::' + this.sliderType, + name: 'Hifi-Slider-' + this.sliderType, dimensions: SLIDER_DIMENSIONS, collisionsWillMove: true, color: this.color, @@ -367,10 +389,9 @@ function handleValueMessages(channel, message, sender) { if (channel !== 'Hifi-Slider-Value-Reciever') { return; } - //easily protect from other people editing your values, but group editing might be fun so lets try that first. - // if (sender !== MyAvatar.sessionUUID) { - // return; - // } + if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) { + return; + } var parsedMessage = JSON.parse(message); slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage); @@ -455,7 +476,6 @@ Entities.deletingEntity.connect(deleteEntity); - //other light properties // diffuseColor: { red: 255, green: 255, blue: 255 }, // ambientColor: { red: 255, green: 255, blue: 255 }, From b25fc5be6cfde2bf383b2050693ff00da92f2452 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 17 Dec 2015 09:52:34 +1300 Subject: [PATCH 065/209] Don't send a domain-server check in when shutting down --- libraries/networking/src/NodeList.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index e591ee8a31..bc79ddd5fd 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -234,6 +234,7 @@ void NodeList::addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes) void NodeList::sendDomainServerCheckIn() { if (_isShuttingDown) { qCDebug(networking) << "Refusing to send a domain-server check in while shutting down."; + return; } if (_publicSockAddr.isNull()) { From e37d68449bb3b344936bc5ad0845098c878cc57f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 13:57:40 -0800 Subject: [PATCH 066/209] rename folder --- examples/controllers/handControllerGrab.js | 4 ++-- examples/{lights => light_modifier}/lightLoader.js | 0 examples/{lights => light_modifier}/lightModifier.js | 0 examples/{lights => light_modifier}/lightModifierTestScene.js | 0 examples/{lights => light_modifier}/slider.js | 0 5 files changed, 2 insertions(+), 2 deletions(-) rename examples/{lights => light_modifier}/lightLoader.js (100%) rename examples/{lights => light_modifier}/lightModifier.js (100%) rename examples/{lights => light_modifier}/lightModifierTestScene.js (100%) rename examples/{lights => light_modifier}/slider.js (100%) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index c452519522..e7d1b5f84b 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -944,7 +944,7 @@ function MyController(hand) { relativeRotation: this.offsetRotation, ttl: ACTION_TTL, kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, + kinematicSetVelocity: false, ignoreIK: this.ignoreIK }); if (this.actionID === NULL_ACTION_ID) { @@ -1029,7 +1029,7 @@ function MyController(hand) { relativeRotation: this.offsetRotation, ttl: ACTION_TTL, kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, + kinematicSetVelocity: false, ignoreIK: this.ignoreIK }); this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); diff --git a/examples/lights/lightLoader.js b/examples/light_modifier/lightLoader.js similarity index 100% rename from examples/lights/lightLoader.js rename to examples/light_modifier/lightLoader.js diff --git a/examples/lights/lightModifier.js b/examples/light_modifier/lightModifier.js similarity index 100% rename from examples/lights/lightModifier.js rename to examples/light_modifier/lightModifier.js diff --git a/examples/lights/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js similarity index 100% rename from examples/lights/lightModifierTestScene.js rename to examples/light_modifier/lightModifierTestScene.js diff --git a/examples/lights/slider.js b/examples/light_modifier/slider.js similarity index 100% rename from examples/lights/slider.js rename to examples/light_modifier/slider.js From fcfa3969125e956b983401983a5964a86721968a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 13:58:55 -0800 Subject: [PATCH 067/209] syntax tweak --- examples/flowArts/lightBall/lightBallSpawner.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index 505df7d83b..20a9c312fc 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -24,7 +24,6 @@ var containerBall = Entities.addEntity({ dimensions: {x: .1, y: .1, z: .1}, color: {red: 15, green: 10, blue: 150}, collisionsWillMove: true, - visible: false, userData: JSON.stringify({ grabbableKey: { spatialKey: { @@ -85,7 +84,7 @@ var lightBall = Entities.addEntity({ "lifespan": 5, "emitRate": 5000, "emitSpeed": .1, - "speedSpread": .0, + "speedSpread": 0.0, "emitDimensions": { "x": 0, "y": 0, From 40e6e4b13389fb57d5ef627113beda458eabcf76 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 14:01:50 -0800 Subject: [PATCH 068/209] add readme --- examples/light_modifier/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 examples/light_modifier/README.md diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md new file mode 100644 index 0000000000..d978c73b5b --- /dev/null +++ b/examples/light_modifier/README.md @@ -0,0 +1,24 @@ +This PR demonstrates one way in-world editing of objects might work. We start with a spotlight. When you distant grab the sliders, you can move them along their axis to change their values. You may also rotate / move the block to which the spotlight is attached. + +To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js +To reset, I recommend stopping all scripts then re-loading lightLoader.js + +When you run the lightLoader.js script, 4 scripts will be loaded: +- handControllerGrab.js (custom) +- lightModifier.js (listens for message to create sliders for a given light) +- lightModifierTestScene.js (creates a light and parents it to a block, then sends a message ^^) +- slider.js (attached to each slider entity) + + + +Current sliders are (top to bottom): +red +green +blue +intensity +cutoff +exponent + +To-Do: Determine how to enter / exit edit mode , support near grab, add other input types (checkbox, etc), prevent velocity drift on slider release,button to hide entity + +![capture](https://cloud.githubusercontent.com/assets/843228/11830366/2f2dfe70-a359-11e5-84f0-33a380ebeac7.PNG) From e0b8c6b48b46e1f380a5940a16c6dcb702ae3c89 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 14:24:31 -0800 Subject: [PATCH 069/209] show light volumes --- examples/light_modifier/lightModifier.js | 32 +++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index e928679f08..b33b6fc0f1 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -10,22 +10,37 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - //some experimental options var ONLY_I_CAN_EDIT = false; var SLIDERS_SHOULD_STAY_WITH_AVATAR = false; var VERTICAL_SLIDERS = false; +var SHOW_OVERLAYS = true; +var SHOW_LIGHT_VOLUME = true; -// Script.include('../libraries/lightOverlayManager.js'); -// var lightOverlayManager = new LightOverlayManager(); -// lightOverlayManager.setVisible(true); +//variables for managing overlays +var selectionDisplay; +var selectionManager; +var lightOverlayManager; +if (SHOW_OVERLAYS === true) { + Script.include('../libraries/entitySelectionTool.js'); + + selectionDisplay = SelectionDisplay; + selectionManager = SelectionManager; + Script.include('../libraries/lightOverlayManager.js'); + lightOverlayManager = new LightOverlayManager(); + selectionManager.addEventListener(function() { + selectionDisplay.updateHandles(); + lightOverlayManager.updatePositions(); + }); + + lightOverlayManager.setVisible(true); +} // var pickRay = Camera.computePickRay(event.x, event.y); // var lightResult = lightOverlayManager.findRayIntersection(pickRay) var DEFAULT_PARENT_ID = '{00000000-0000-0000-0000-000000000000}' - var AXIS_SCALE = 1; var COLOR_MAX = 255; var INTENSITY_MAX = 0.05; @@ -323,7 +338,9 @@ var slidersRef = { } var light = null; -function makeSliders(light) { +function makeSliders(light) { // selectionManager.setSelections([entityID]); + + if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -382,6 +399,9 @@ function handleLightModMessages(channel, message, sender) { makeSliders(parsedMessage.light); light = parsedMessage.light.id + if (SHOW_LIGHT_VOLUME === true) { + selectionManager.setSelections([parsedMessage.light.id]); + } } function handleValueMessages(channel, message, sender) { From 40a096ca8d9c2e1166387531b154da2d263c3759 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 14:34:01 -0800 Subject: [PATCH 070/209] kinematic grab things --- examples/controllers/handControllerGrab.js | 25 ++++++++++++++++--- examples/light_modifier/lightModifier.js | 3 +-- .../light_modifier/lightModifierTestScene.js | 8 +++++- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index e7d1b5f84b..ce519880af 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -944,7 +944,7 @@ function MyController(hand) { relativeRotation: this.offsetRotation, ttl: ACTION_TTL, kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: false, + kinematicSetVelocity: true, ignoreIK: this.ignoreIK }); if (this.actionID === NULL_ACTION_ID) { @@ -1029,7 +1029,7 @@ function MyController(hand) { relativeRotation: this.offsetRotation, ttl: ACTION_TTL, kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: false, + kinematicSetVelocity: true, ignoreIK: this.ignoreIK }); this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); @@ -1243,7 +1243,26 @@ function MyController(hand) { this.overlayLineOff(); if (this.grabbedEntity !== null) { if (this.actionID !== null) { - Entities.deleteAction(this.grabbedEntity, this.actionID); + //add velocity whatnot + var defaultReleaseVelocityData = { + disableReleaseVelocity: false + }; + + var releaseVelocityData = getEntityCustomData('releaseVelocityKey', this.grabbedEntity, defaultReleaseVelocityData); + if (releaseVelocityData.disableReleaseVelocity === true) { + Entities.updateAction(this.grabbedEntity, this.actionID, { + ttl: 1, + kinematic: false, + kinematicSetVelocity: false, + + }); + // Entities.deleteAction(this.grabbedEntity, this.actionID); + + } else { + //don't make adjustments + Entities.deleteAction(this.grabbedEntity, this.actionID); + + } } } diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index b33b6fc0f1..b79c00da92 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -243,8 +243,7 @@ entitySlider.prototype = { axisEnd: this.endOfAxis, }, releaseVelocityKey: { - disableReleaseVelocity: true, - customReleaseVelocity: false + disableReleaseVelocity: true } }) }; diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 5748f0d4ed..e939353b8c 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -73,7 +73,13 @@ function createBlock() { green: 0, blue: 255 }, - position: position + position: position, + userData: JSON.stringify({ + + releaseVelocityKey: { + disableReleaseVelocity: true + } + }) }; block = Entities.addEntity(blockProperties); From b29a6b16a954f4e5427fdbe96517c65153d355ed Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 14:40:56 -0800 Subject: [PATCH 071/209] modularizing flow art tools --- examples/flowArts/flowArtsHutSpawner.js | 77 ++++++ .../flowArts/lightBall/lightBallSpawner.js | 239 +++++++++--------- 2 files changed, 194 insertions(+), 122 deletions(-) create mode 100644 examples/flowArts/flowArtsHutSpawner.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js new file mode 100644 index 0000000000..d3c60548ea --- /dev/null +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -0,0 +1,77 @@ +// +// flowArtsHutSpawner.js +// examples +// +// Created by Eric Levin on 5/14/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creates a special flow arts hut with a numch of flow art toys people can go in and play with +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +Script.include("../../libraries/utils.js"); +Script.include("lightBall/lightBallSpawner.js"); + +var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); +basePosition.y = MyAvatar.position.y + 1 +var lightBall = LightBallSpawner(basePosition); +var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); + +var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; + +var raveRoom = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + position: basePosition, + dimensions:roomDimensions, + visible: true +}); + +var floor = Entities.addEntity({ + type: "Box", + position: Vec3.sum(basePosition, {x: 0, y: -1.5, z: 0}), + dimensions: {x: roomDimensions.x, y: 0.6, z: roomDimensions.z}, + color: {red: 50, green: 10, blue: 100}, + shapeType: 'box' +}); + + + + + +var lightZone = Entities.addEntity({ + type: "Zone", + shapeType: 'box', + keyLightIntensity: 0.2, + keyLightColor: { + red: 50, + green: 0, + blue: 50 + }, + keyLightAmbientIntensity: .2, + position: MyAvatar.position, + dimensions: { + x: 100, + y: 100, + z: 100 + } +}); + + + + + + +function cleanup() { + + Entities.deleteEntity(raveRoom); + Entities.deleteEntity(lightZone) + Entities.deleteEntity(floor); + lightBall.cleanup(); +} + +Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index 20a9c312fc..7325f16a64 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -1,129 +1,124 @@ + Script.include("../../libraries/utils.js"); -Script.include("../../libraries/utils.js"); + LightBallSpawner = function(basePosition) { -var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); -var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); - -var raveRoom = Entities.addEntity({ - type: "Model", - modelURL: modelURL, - position: center, - visible:false -}); - -var colorPalette = [{ - red: 25, - green: 20, - blue: 162 -}]; + var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; -var containerBall = Entities.addEntity({ - type: "Sphere", - position: center, - dimensions: {x: .1, y: .1, z: .1}, - color: {red: 15, green: 10, blue: 150}, - collisionsWillMove: true, - userData: JSON.stringify({ - grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: 1, - z: 0 - } + var containerBall = Entities.addEntity({ + type: "Sphere", + position: Vec3.sum(basePosition, { + x: 0, + y: .5, + z: 0 + }), + dimensions: { + x: .1, + y: .1, + z: .1 }, - invertSolidWhileHeld: true + color: { + red: 15, + green: 10, + blue: 150 + }, + collisionsWillMove: true, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 1, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var lightBall = Entities.addEntity({ + type: "ParticleEffect", + parentID: containerBall, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": { + red: 25, + green: 20, + blue: 255 + }, + "maxParticles": 100000, + "lifespan": 5, + "emitRate": 5000, + "emitSpeed": .1, + "speedSpread": 0.0, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": Math.PI, + "azimuthStart": -Math.PI, + "azimuthFinish": Math.PI, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .00, + "z": .00 + }, + "particleRadius": 0.04, + "radiusSpread": 0, + "radiusStart": 0.05, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + emitterShouldTrail: true + }) + + + + function cleanup() { + Entities.deleteEntity(lightBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); } - }) - // gravity: {x: 0, y: -.1, z: 0} -}); -var lightZone = Entities.addEntity({ - type: "Zone", - shapeType: 'box', - keyLightIntensity: 0.2, - keyLightColor: { - red: 50, - green: 0, - blue: 50 - }, - keyLightAmbientIntensity: .2, - position: MyAvatar.position, - dimensions: { - x: 100, - y: 100, - z: 100 - } -}); - -var light = Entities.addEntity({ - type: 'Light', - position: center, - parentID: containerBall, - dimensions: { - x: 30, - y: 30, - z: 30 - }, - color: colorPalette[randInt(0, colorPalette.length)], - intensity: 5 - }); - - -var lightBall = Entities.addEntity({ - position: center, - type: "ParticleEffect", - parentID: containerBall, - isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": {red: 200, green: 20, blue: 40}, - color: {red: 200, green: 200, blue: 255}, - "colorFinish": {red: 25, green: 20, blue:255}, - "maxParticles": 100000, - "lifespan": 5, - "emitRate": 5000, - "emitSpeed": .1, - "speedSpread": 0.0, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": Math.PI, - "azimuthStart": -Math.PI, - "azimuthFinish": Math.PI, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 - }, - "particleRadius": 0.04, - "radiusSpread": 0, - "radiusStart": 0.05, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - emitterShouldTrail: true -}) - - - -function cleanup() { - Entities.deleteEntity(lightBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(raveRoom); - Entities.deleteEntity(lightZone) - Entities.deleteEntity(light); -} - -Script.scriptEnding.connect(cleanup); \ No newline at end of file + this.cleanup = cleanup; + } \ No newline at end of file From f1ec28e169896581a1eb5788d9e89453d6c93378 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 14:55:01 -0800 Subject: [PATCH 072/209] visualize volumes --- examples/libraries/lightOverlayManager.js | 19 +++++++++++++------ examples/light_modifier/lightModifier.js | 2 ++ .../light_modifier/lightModifierTestScene.js | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/libraries/lightOverlayManager.js b/examples/libraries/lightOverlayManager.js index 0942fae723..2d3618096b 100644 --- a/examples/libraries/lightOverlayManager.js +++ b/examples/libraries/lightOverlayManager.js @@ -53,7 +53,9 @@ LightOverlayManager = function() { if (visible != isVisible) { visible = isVisible; for (var id in entityOverlays) { - Overlays.editOverlay(entityOverlays[id], { visible: visible }); + Overlays.editOverlay(entityOverlays[id], { + visible: visible + }); } } }; @@ -61,8 +63,7 @@ LightOverlayManager = function() { // Allocate or get an unused overlay function getOverlay() { if (unusedOverlays.length == 0) { - var overlay = Overlays.addOverlay("image3d", { - }); + var overlay = Overlays.addOverlay("image3d", {}); allOverlays.push(overlay); } else { var overlay = unusedOverlays.pop(); @@ -72,7 +73,9 @@ LightOverlayManager = function() { function releaseOverlay(overlay) { unusedOverlays.push(overlay); - Overlays.editOverlay(overlay, { visible: false }); + Overlays.editOverlay(overlay, { + visible: false + }); } function addEntity(entityID) { @@ -88,7 +91,11 @@ LightOverlayManager = function() { visible: visible, alpha: 0.9, scale: 0.5, - color: { red: 255, green: 255, blue: 255 } + color: { + red: 255, + green: 255, + blue: 255 + } }); } } @@ -123,4 +130,4 @@ LightOverlayManager = function() { Overlays.deleteOverlay(allOverlays[i]); } }); -}; +}; \ No newline at end of file diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index b79c00da92..4d5a326cae 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -36,6 +36,7 @@ if (SHOW_OVERLAYS === true) { lightOverlayManager.setVisible(true); } +// var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking // var pickRay = Camera.computePickRay(event.x, event.y); // var lightResult = lightOverlayManager.findRayIntersection(pickRay) @@ -427,6 +428,7 @@ function cleanup() { Messages.messageReceived.disconnect(handleValueMessages); Entities.deletingEntity.disconnect(deleteEntity); + lightOverlayManager.setVisible(false); } Script.scriptEnding.connect(cleanup); diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index e939353b8c..84fb779469 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -26,7 +26,7 @@ function createLight() { dimensions: { x: 2, y: 2, - z: 20 + z: 8 }, parentID: block, color: { From f55994b99317472a9b39e4ddeee619700899b96f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 15:07:31 -0800 Subject: [PATCH 073/209] cleanup --- examples/light_modifier/lightModifier.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 4d5a326cae..7cd442e9ed 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -23,19 +23,27 @@ var selectionManager; var lightOverlayManager; if (SHOW_OVERLAYS === true) { + + Script.include('../libraries/gridTool.js'); Script.include('../libraries/entitySelectionTool.js'); + Script.include('../libraries/lightOverlayManager.js'); + + var grid = Grid(); + gridTool = GridTool({ + horizontalGrid: grid + }); + gridTool.setVisible(false); selectionDisplay = SelectionDisplay; selectionManager = SelectionManager; - Script.include('../libraries/lightOverlayManager.js'); lightOverlayManager = new LightOverlayManager(); selectionManager.addEventListener(function() { selectionDisplay.updateHandles(); lightOverlayManager.updatePositions(); }); - lightOverlayManager.setVisible(true); } + // var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking // var pickRay = Camera.computePickRay(event.x, event.y); // var lightResult = lightOverlayManager.findRayIntersection(pickRay) From 4155e3af71a9efc3bc79772364e475864d2187d6 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 15:22:56 -0800 Subject: [PATCH 074/209] refactoring --- examples/flowArts/flowArtsHutSpawner.js | 8 +- examples/flowArts/lightBall/lightBall.js | 124 ++++++++++++++++++ .../flowArts/lightBall/lightBallSpawner.js | 124 ------------------ .../flowArts/raveStick/createRaveStick.js | 0 4 files changed, 126 insertions(+), 130 deletions(-) delete mode 100644 examples/flowArts/lightBall/lightBallSpawner.js create mode 100644 examples/flowArts/raveStick/createRaveStick.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index d3c60548ea..c8f7dbed78 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -14,11 +14,11 @@ Script.include("../../libraries/utils.js"); -Script.include("lightBall/lightBallSpawner.js"); +Script.include("lightBall/LightBall.js"); var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); basePosition.y = MyAvatar.position.y + 1 -var lightBall = LightBallSpawner(basePosition); +var lightBall = LightBall(basePosition); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; @@ -62,10 +62,6 @@ var lightZone = Entities.addEntity({ }); - - - - function cleanup() { Entities.deleteEntity(raveRoom); diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index e69de29bb2..6f44ed6d74 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -0,0 +1,124 @@ + Script.include("../../libraries/utils.js"); + + LightBall = function(basePosition) { + + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; + + + var containerBall = Entities.addEntity({ + type: "Sphere", + position: Vec3.sum(basePosition, { + x: 0, + y: .5, + z: 0 + }), + dimensions: { + x: .1, + y: .1, + z: .1 + }, + color: { + red: 15, + green: 10, + blue: 150 + }, + collisionsWillMove: true, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 1, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var lightBall = Entities.addEntity({ + type: "ParticleEffect", + parentID: containerBall, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": { + red: 25, + green: 20, + blue: 255 + }, + "maxParticles": 100000, + "lifespan": 5, + "emitRate": 5000, + "emitSpeed": .1, + "speedSpread": 0.0, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": Math.PI, + "azimuthStart": -Math.PI, + "azimuthFinish": Math.PI, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .00, + "z": .00 + }, + "particleRadius": 0.04, + "radiusSpread": 0, + "radiusStart": 0.05, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), + emitterShouldTrail: true + }) + + + + function cleanup() { + Entities.deleteEntity(lightBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } + + this.cleanup = cleanup; + } \ No newline at end of file diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js deleted file mode 100644 index 7325f16a64..0000000000 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ /dev/null @@ -1,124 +0,0 @@ - Script.include("../../libraries/utils.js"); - - LightBallSpawner = function(basePosition) { - - var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); - var colorPalette = [{ - red: 25, - green: 20, - blue: 162 - }]; - - - var containerBall = Entities.addEntity({ - type: "Sphere", - position: Vec3.sum(basePosition, { - x: 0, - y: .5, - z: 0 - }), - dimensions: { - x: .1, - y: .1, - z: .1 - }, - color: { - red: 15, - green: 10, - blue: 150 - }, - collisionsWillMove: true, - userData: JSON.stringify({ - grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: 1, - z: 0 - } - }, - invertSolidWhileHeld: true - } - }) - }); - - - var light = Entities.addEntity({ - type: 'Light', - parentID: containerBall, - dimensions: { - x: 30, - y: 30, - z: 30 - }, - color: colorPalette[randInt(0, colorPalette.length)], - intensity: 5 - }); - - - var lightBall = Entities.addEntity({ - type: "ParticleEffect", - parentID: containerBall, - isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": { - red: 200, - green: 20, - blue: 40 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - "colorFinish": { - red: 25, - green: 20, - blue: 255 - }, - "maxParticles": 100000, - "lifespan": 5, - "emitRate": 5000, - "emitSpeed": .1, - "speedSpread": 0.0, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": Math.PI, - "azimuthStart": -Math.PI, - "azimuthFinish": Math.PI, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 - }, - "particleRadius": 0.04, - "radiusSpread": 0, - "radiusStart": 0.05, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - emitterShouldTrail: true - }) - - - - function cleanup() { - Entities.deleteEntity(lightBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(light); - } - - this.cleanup = cleanup; - } \ No newline at end of file diff --git a/examples/flowArts/raveStick/createRaveStick.js b/examples/flowArts/raveStick/createRaveStick.js new file mode 100644 index 0000000000..e69de29bb2 From 6a77ae5db2cbead0c901ca40e788a73929ad8bc5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 15:47:34 -0800 Subject: [PATCH 075/209] adding rave stick --- examples/flowArts/flowArtsHutSpawner.js | 9 +- examples/flowArts/lightBall/lightBall.js | 232 +++++++++--------- examples/flowArts/raveStick/RaveStick.js | 24 ++ .../flowArts/raveStick/createRaveStick.js | 0 4 files changed, 145 insertions(+), 120 deletions(-) create mode 100644 examples/flowArts/raveStick/RaveStick.js delete mode 100644 examples/flowArts/raveStick/createRaveStick.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index c8f7dbed78..ffd73dbdca 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -15,10 +15,12 @@ Script.include("../../libraries/utils.js"); Script.include("lightBall/LightBall.js"); +Script.include("raveStick/RaveStick.js"); var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); -basePosition.y = MyAvatar.position.y + 1 -var lightBall = LightBall(basePosition); +basePosition.y = MyAvatar.position.y + 1; +var lightBall = new LightBall(basePosition); +var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 1, z: 1})); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; @@ -41,8 +43,6 @@ var floor = Entities.addEntity({ - - var lightZone = Entities.addEntity({ type: "Zone", shapeType: 'box', @@ -68,6 +68,7 @@ function cleanup() { Entities.deleteEntity(lightZone) Entities.deleteEntity(floor); lightBall.cleanup(); + raveStick.cleanup(); } Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index 6f44ed6d74..e2d65874fa 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -1,124 +1,124 @@ - Script.include("../../libraries/utils.js"); +Script.include("../../libraries/utils.js"); - LightBall = function(basePosition) { +LightBall = function(spawnPosition) { - var colorPalette = [{ + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; + + + var containerBall = Entities.addEntity({ + type: "Sphere", + position: Vec3.sum(spawnPosition, { + x: 0, + y: .5, + z: 0 + }), + dimensions: { + x: .1, + y: .1, + z: .1 + }, + color: { + red: 15, + green: 10, + blue: 150 + }, + collisionsWillMove: true, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: .7, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var lightBall = Entities.addEntity({ + type: "ParticleEffect", + parentID: containerBall, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": { red: 25, green: 20, - blue: 162 - }]; - - - var containerBall = Entities.addEntity({ - type: "Sphere", - position: Vec3.sum(basePosition, { - x: 0, - y: .5, - z: 0 - }), - dimensions: { - x: .1, - y: .1, - z: .1 - }, - color: { - red: 15, - green: 10, - blue: 150 - }, - collisionsWillMove: true, - userData: JSON.stringify({ - grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: 1, - z: 0 - } - }, - invertSolidWhileHeld: true - } - }) - }); - - - var light = Entities.addEntity({ - type: 'Light', - parentID: containerBall, - dimensions: { - x: 30, - y: 30, - z: 30 - }, - color: colorPalette[randInt(0, colorPalette.length)], - intensity: 5 - }); - - - var lightBall = Entities.addEntity({ - type: "ParticleEffect", - parentID: containerBall, - isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": { - red: 200, - green: 20, - blue: 40 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - "colorFinish": { - red: 25, - green: 20, - blue: 255 - }, - "maxParticles": 100000, - "lifespan": 5, - "emitRate": 5000, - "emitSpeed": .1, - "speedSpread": 0.0, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": Math.PI, - "azimuthStart": -Math.PI, - "azimuthFinish": Math.PI, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 - }, - "particleRadius": 0.04, - "radiusSpread": 0, - "radiusStart": 0.05, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), - emitterShouldTrail: true - }) + blue: 255 + }, + "maxParticles": 100000, + "lifespan": 2, + "emitRate": 10000, + "emitSpeed": .1, + "speedSpread": 0.0, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": Math.PI, + "azimuthStart": -Math.PI, + "azimuthFinish": Math.PI, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .00, + "z": .00 + }, + "particleRadius": 0.02, + "radiusSpread": 0, + "radiusStart": 0.03, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), + emitterShouldTrail: true + }) - function cleanup() { - Entities.deleteEntity(lightBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(light); - } + function cleanup() { + Entities.deleteEntity(lightBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } - this.cleanup = cleanup; - } \ No newline at end of file + this.cleanup = cleanup; +} \ No newline at end of file diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js new file mode 100644 index 0000000000..2703436bec --- /dev/null +++ b/examples/flowArts/raveStick/RaveStick.js @@ -0,0 +1,24 @@ +Script.include("../../libraries/utils.js"); +var modelURL = "file:///C:/Users/Eric/Desktop/raveStick.fbx?v1" + Math.random(); + +RaveStick = function(spawnPosition) { + + var stick = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + position: spawnPosition, + shapeType: 'box', + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) + }); + + + function cleanup() { + Entities.deleteEntity(stick); + } + + this.cleanup = cleanup; +} \ No newline at end of file diff --git a/examples/flowArts/raveStick/createRaveStick.js b/examples/flowArts/raveStick/createRaveStick.js deleted file mode 100644 index e69de29bb2..0000000000 From 263557cc1ac008e5ae98ed1c5ea977cc20aae6fa Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 16:18:57 -0800 Subject: [PATCH 076/209] setting dimensions for rave stick --- examples/flowArts/lightBall/lightBall.js | 3 ++- examples/flowArts/raveStick/RaveStick.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index e2d65874fa..698c62a71d 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -27,12 +27,13 @@ LightBall = function(spawnPosition) { blue: 150 }, collisionsWillMove: true, + gravity: {x: 0, y: -.5, z: 0}, userData: JSON.stringify({ grabbableKey: { spatialKey: { relativePosition: { x: 0, - y: .7, + y: .1, z: 0 } }, diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js index 2703436bec..bee5c995f9 100644 --- a/examples/flowArts/raveStick/RaveStick.js +++ b/examples/flowArts/raveStick/RaveStick.js @@ -8,6 +8,7 @@ RaveStick = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', + dimensions: {x: 0.17, y: 0.48, z: 0.17}, userData: JSON.stringify({ grabbableKey: { invertSolidWhileHeld: true From d8c877831664a37949932217b75be6937236c468 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 16:50:27 -0800 Subject: [PATCH 077/209] rave stick in right orientation --- examples/flowArts/flowArtsHutSpawner.js | 6 +- examples/flowArts/raveStick/RaveStick.js | 16 +++- .../raveStick/raveStickEntityScript.js | 81 +++++++++++++++++++ 3 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 examples/flowArts/raveStick/raveStickEntityScript.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index ffd73dbdca..8e39a4b1d8 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -19,8 +19,12 @@ Script.include("raveStick/RaveStick.js"); var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); basePosition.y = MyAvatar.position.y + 1; + +// RAVE ITEMS var lightBall = new LightBall(basePosition); -var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 1, z: 1})); +var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); + + var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js index bee5c995f9..046932c473 100644 --- a/examples/flowArts/raveStick/RaveStick.js +++ b/examples/flowArts/raveStick/RaveStick.js @@ -1,6 +1,6 @@ Script.include("../../libraries/utils.js"); var modelURL = "file:///C:/Users/Eric/Desktop/raveStick.fbx?v1" + Math.random(); - +var scriptURL = Script.resolvePath("raveStickEntityScript.js"); RaveStick = function(spawnPosition) { var stick = Entities.addEntity({ @@ -8,9 +8,21 @@ RaveStick = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', - dimensions: {x: 0.17, y: 0.48, z: 0.17}, + dimensions: { + x: 0.06, + y: 0.06, + z: 0.8 + }, userData: JSON.stringify({ grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.4 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) + }, invertSolidWhileHeld: true } }) diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js new file mode 100644 index 0000000000..cfe1e3a2fd --- /dev/null +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -0,0 +1,81 @@ +// raveStickEntityScript.js +// +// Script Type: Entity +// Created by Eric Levin on 9/21/15. +// Additions by James B. Pollack @imgntn on 9/24/15 +// Copyright 2015 High Fidelity, Inc. +// +// This entity script create light trails on a given object as it moves. +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + Script.include("../../libraries/utils.js"); + var _this; + // this is the "constructor" for the entity as a JS object we don't do much here + var Doll = function() { + _this = this; + this.screamSounds = [SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/KenDoll_1%2303.wav")]; + }; + + Doll.prototype = { + audioInjector: null, + isGrabbed: false, + setLeftHand: function() { + this.hand = 'left'; + }, + + setRightHand: function() { + this.hand = 'right'; + }, + + startNearGrab: function() { + Entities.editEntity(this.entityID, { + animation: { + url: "https://hifi-public.s3.amazonaws.com/models/Bboys/zombie_scream.fbx", + running: true + } + }); + + var position = Entities.getEntityProperties(this.entityID, "position").position; + this.audioInjector = Audio.playSound(this.screamSounds[randInt(0, this.screamSounds.length)], { + position: position, + volume: 0.1 + }); + + this.isGrabbed = true; + this.initialHand = this.hand; + }, + + continueNearGrab: function() { + var props = Entities.getEntityProperties(this.entityID, ["position"]); + var audioOptions = { + position: props.position + }; + this.audioInjector.options = audioOptions; + }, + + releaseGrab: function() { + if (this.isGrabbed === true && this.hand === this.initialHand) { + this.audioInjector.stop(); + Entities.editEntity(this.entityID, { + animation: { + // Providing actual model fbx for animation used to work, now contorts doll into a weird ball + // See bug: https://app.asana.com/0/26225263936266/70097355490098 + // url: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx", + running: false, + } + }); + + this.isGrabbed = false; + } + }, + + preload: function(entityID) { + this.entityID = entityID; + }, + }; + // entity scripts always need to return a newly constructed object of our type + return new Doll(); +}); From f9f496ef5ab2d0e65e9d20500fb6f6fe521492d2 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 17:32:30 -0800 Subject: [PATCH 078/209] adding beam effect --- examples/flowArts/flowArtsHutSpawner.js | 2 +- examples/flowArts/raveStick/RaveStick.js | 5 +- .../raveStick/raveStickEntityScript.js | 128 +++++++++++------- 3 files changed, 85 insertions(+), 50 deletions(-) diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 8e39a4b1d8..aa87ddbd10 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -50,7 +50,7 @@ var floor = Entities.addEntity({ var lightZone = Entities.addEntity({ type: "Zone", shapeType: 'box', - keyLightIntensity: 0.2, + keyLightIntensity: 0.4, keyLightColor: { red: 50, green: 0, diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js index 046932c473..5151b528cc 100644 --- a/examples/flowArts/raveStick/RaveStick.js +++ b/examples/flowArts/raveStick/RaveStick.js @@ -8,10 +8,11 @@ RaveStick = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', + script: scriptURL, dimensions: { x: 0.06, y: 0.06, - z: 0.8 + z: 0.31 }, userData: JSON.stringify({ grabbableKey: { @@ -19,7 +20,7 @@ RaveStick = function(spawnPosition) { relativePosition: { x: 0, y: 0, - z: -0.4 + z: -0.1 }, relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) }, diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index cfe1e3a2fd..67571e49fa 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -1,8 +1,7 @@ // raveStickEntityScript.js // // Script Type: Entity -// Created by Eric Levin on 9/21/15. -// Additions by James B. Pollack @imgntn on 9/24/15 +// Created by Eric Levin on 12/16/15. // Copyright 2015 High Fidelity, Inc. // // This entity script create light trails on a given object as it moves. @@ -14,68 +13,103 @@ Script.include("../../libraries/utils.js"); var _this; // this is the "constructor" for the entity as a JS object we don't do much here - var Doll = function() { + var RaveStick = function() { _this = this; - this.screamSounds = [SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/KenDoll_1%2303.wav")]; }; - Doll.prototype = { - audioInjector: null, + RaveStick.prototype = { isGrabbed: false, - setLeftHand: function() { - this.hand = 'left'; - }, - - setRightHand: function() { - this.hand = 'right'; - }, startNearGrab: function() { - Entities.editEntity(this.entityID, { - animation: { - url: "https://hifi-public.s3.amazonaws.com/models/Bboys/zombie_scream.fbx", - running: true - } - }); - - var position = Entities.getEntityProperties(this.entityID, "position").position; - this.audioInjector = Audio.playSound(this.screamSounds[randInt(0, this.screamSounds.length)], { - position: position, - volume: 0.1 - }); - - this.isGrabbed = true; - this.initialHand = this.hand; + // this.createBeam(); }, continueNearGrab: function() { - var props = Entities.getEntityProperties(this.entityID, ["position"]); - var audioOptions = { - position: props.position - }; - this.audioInjector.options = audioOptions; + }, releaseGrab: function() { - if (this.isGrabbed === true && this.hand === this.initialHand) { - this.audioInjector.stop(); - Entities.editEntity(this.entityID, { - animation: { - // Providing actual model fbx for animation used to work, now contorts doll into a weird ball - // See bug: https://app.asana.com/0/26225263936266/70097355490098 - // url: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx", - running: false, - } - }); - this.isGrabbed = false; - } }, preload: function(entityID) { this.entityID = entityID; + this.createBeam(); }, + + unload: function() { + Entities.deleteEntity(this.beam); + }, + + createBeam: function() { + + var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); + var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); + position.z += 0.1; + position.x += -0.035; + var props = { + type: "ParticleEffect", + position: position, + parentID: this.entityID, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": { + red: 0, + green: 200, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": { + red: 25, + green: 200, + blue: 5 + }, + "maxParticles": 100000, + "lifespan": 2, + "emitRate": 1000, + emitOrientation: forwardQuat, + "emitSpeed": .4, + "speedSpread": 0.0, + // "emitDimensions": { + // "x": .1, + // "y": .1, + // "z": .1 + // }, + "polarStart": 0, + "polarFinish": .0, + "azimuthStart": .1, + "azimuthFinish": .01, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .00, + "z": .00 + }, + "radiusStart": 0.03, + radiusFinish: 0.025, + "alpha": 0.7, + "alphaSpread": .1, + "alphaStart": 0.5, + "alphaFinish": 0.5, + // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "textures": "file:///C:/Users/Eric/Desktop/beamParticle.png?v1" + Math.random(), + emitterShouldTrail: false + } + this.beam = Entities.addEntity(props); + + } }; // entity scripts always need to return a newly constructed object of our type - return new Doll(); -}); + return new RaveStick(); +}); \ No newline at end of file From bb67ca87e238a4db2b613e15c3de787d93544955 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 17:52:39 -0800 Subject: [PATCH 079/209] lightsabers --- examples/flowArts/flowArtsHutSpawner.js | 2 ++ .../raveStick/raveStickEntityScript.js | 26 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index aa87ddbd10..b9d89859df 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -23,6 +23,7 @@ basePosition.y = MyAvatar.position.y + 1; // RAVE ITEMS var lightBall = new LightBall(basePosition); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); +var raveStick2 = new RaveStick(Vec3.sum(basePosition, {x: 2, y: 0.5, z: 1})); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); @@ -73,6 +74,7 @@ function cleanup() { Entities.deleteEntity(floor); lightBall.cleanup(); raveStick.cleanup(); + raveStick2.cleanup(); } Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 67571e49fa..0372fd388f 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -15,6 +15,15 @@ // this is the "constructor" for the entity as a JS object we don't do much here var RaveStick = function() { _this = this; + this.colorPalette = [{ + red: 0, + green: 200, + blue: 40 + }, { + red: 200, + green: 10, + blue: 40 + }]; }; RaveStick.prototype = { @@ -39,6 +48,7 @@ unload: function() { Entities.deleteEntity(this.beam); + // Entities.deleteEntity(this.beamTrail); }, createBeam: function() { @@ -50,27 +60,20 @@ var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); position.z += 0.1; position.x += -0.035; + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", position: position, parentID: this.entityID, isEmitting: true, "name": "ParticlesTest Emitter", - "colorStart": { - red: 0, - green: 200, - blue: 40 - }, + "colorStart": color, color: { red: 200, green: 200, blue: 255 }, - "colorFinish": { - red: 25, - green: 200, - blue: 5 - }, + "colorFinish": color, "maxParticles": 100000, "lifespan": 2, "emitRate": 1000, @@ -108,6 +111,9 @@ } this.beam = Entities.addEntity(props); + // props.emitterShouldTrail = true; + // this.beamTrail = Entities.addEntity(props); + } }; // entity scripts always need to return a newly constructed object of our type From b127b6a9e887874b0cfa253c9dcb447a2e91f7d4 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 08:55:57 -0800 Subject: [PATCH 080/209] separating out rave stick --- examples/flowArts/flowArtsHutSpawner.js | 5 + examples/flowArts/lightSaber/LightSaber.js | 38 ++++++ .../lightSaber/lightSaberEntityScript.js | 121 ++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 examples/flowArts/lightSaber/LightSaber.js create mode 100644 examples/flowArts/lightSaber/lightSaberEntityScript.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index b9d89859df..920fcc90ea 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -16,6 +16,9 @@ Script.include("../../libraries/utils.js"); Script.include("lightBall/LightBall.js"); Script.include("raveStick/RaveStick.js"); +Script.include("lightSaber/LightSaber.js"); + + var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); basePosition.y = MyAvatar.position.y + 1; @@ -24,6 +27,7 @@ basePosition.y = MyAvatar.position.y + 1; var lightBall = new LightBall(basePosition); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var raveStick2 = new RaveStick(Vec3.sum(basePosition, {x: 2, y: 0.5, z: 1})); +var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); @@ -75,6 +79,7 @@ function cleanup() { lightBall.cleanup(); raveStick.cleanup(); raveStick2.cleanup(); + lightSaber.cleanup(); } Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/flowArts/lightSaber/LightSaber.js b/examples/flowArts/lightSaber/LightSaber.js new file mode 100644 index 0000000000..12ac3f3b60 --- /dev/null +++ b/examples/flowArts/lightSaber/LightSaber.js @@ -0,0 +1,38 @@ +Script.include("../../libraries/utils.js"); +var modelURL = "file:///C:/Users/Eric/Desktop/lightSaber.fbx?v1" + Math.random(); +var scriptURL = Script.resolvePath("lightSaberEntityScript.js"); +LightSaber = function(spawnPosition) { + + var stick = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + position: spawnPosition, + shapeType: 'box', + script: scriptURL, + dimensions: { + x: 0.06, + y: 0.06, + z: 0.31 + }, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.1 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) + }, + invertSolidWhileHeld: true + } + }) + }); + + + function cleanup() { + Entities.deleteEntity(stick); + } + + this.cleanup = cleanup; +} \ No newline at end of file diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js new file mode 100644 index 0000000000..5ff3c65afd --- /dev/null +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -0,0 +1,121 @@ +// lightSaberEntityScript.js +// +// Script Type: Entity +// Created by Eric Levin on 12/16/15. +// Copyright 2015 High Fidelity, Inc. +// +// This entity script creates a lightsaber. +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + Script.include("../../libraries/utils.js"); + var _this; + // this is the "constructor" for the entity as a JS object we don't do much here + var LightSaber = function() { + _this = this; + this.colorPalette = [{ + red: 0, + green: 200, + blue: 40 + }, { + red: 200, + green: 10, + blue: 40 + }]; + }; + + LightSaber.prototype = { + isGrabbed: false, + + startNearGrab: function() { + // this.createBeam(); + this.createBeam(); + }, + + continueNearGrab: function() { + + }, + + releaseGrab: function() { + + }, + + preload: function(entityID) { + this.entityID = entityID; + }, + + unload: function() { + Entities.deleteEntity(this.beam); + // Entities.deleteEntity(this.beamTrail); + }, + + createBeam: function() { + + var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); + var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); + position.z += 0.1; + position.x += -0.035; + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; + var props = { + type: "ParticleEffect", + position: position, + parentID: this.entityID, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": color, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": color, + "maxParticles": 100000, + "lifespan": 2, + "emitRate": 1000, + emitOrientation: forwardQuat, + "emitSpeed": .4, + "speedSpread": 0.0, + // "emitDimensions": { + // "x": .1, + // "y": .1, + // "z": .1 + // }, + "polarStart": 0, + "polarFinish": .0, + "azimuthStart": .1, + "azimuthFinish": .01, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .00, + "z": .00 + }, + "radiusStart": 0.03, + radiusFinish: 0.025, + "alpha": 0.7, + "alphaSpread": .1, + "alphaStart": 0.5, + "alphaFinish": 0.5, + // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "textures": "file:///C:/Users/Eric/Desktop/beamParticle.png?v1" + Math.random(), + emitterShouldTrail: false + } + this.beam = Entities.addEntity(props); + + // props.emitterShouldTrail = true; + // this.beamTrail = Entities.addEntity(props); + + } + }; + // entity scripts always need to return a newly constructed object of our type + return new LightSaber(); +}); \ No newline at end of file From 064c05e98cb3f421e36ed3c827af4b643d86996a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 10:04:51 -0800 Subject: [PATCH 081/209] light trails --- examples/flowArts/flowArtsHutSpawner.js | 2 +- examples/flowArts/lightBall/particles.js | 129 ++++++++++++++++++ .../lightSaber/lightSaberEntityScript.js | 21 +-- .../raveStick/raveStickEntityScript.js | 49 ++++++- 4 files changed, 189 insertions(+), 12 deletions(-) create mode 100644 examples/flowArts/lightBall/particles.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 920fcc90ea..1ed3325b9c 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -27,7 +27,7 @@ basePosition.y = MyAvatar.position.y + 1; var lightBall = new LightBall(basePosition); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var raveStick2 = new RaveStick(Vec3.sum(basePosition, {x: 2, y: 0.5, z: 1})); -var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); +// var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); diff --git a/examples/flowArts/lightBall/particles.js b/examples/flowArts/lightBall/particles.js new file mode 100644 index 0000000000..86616d5099 --- /dev/null +++ b/examples/flowArts/lightBall/particles.js @@ -0,0 +1,129 @@ +Script.include("../../libraries/utils.js"); + +LightBall = function(spawnPosition) { + + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; + + + var containerBall = Entities.addEntity({ + type: "Sphere", + position: Vec3.sum(spawnPosition, { + x: 0, + y: .5, + z: 0 + }), + dimensions: { + x: .1, + y: .1, + z: .1 + }, + color: { + red: 15, + green: 10, + blue: 150 + }, + collisionsWillMove: true, + gravity: {x: 0, y: -.5, z: 0}, + visible: false, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: .1, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var lightBall = Entities.addEntity({ + type: "ParticleEffect", + position: spawnPosition, + // parentID: containerBall, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": { + red: 25, + green: 20, + blue: 255 + }, + "maxParticles": 100000, + "lifespan": 2, + "emitRate": 10000, + "emitSpeed": .0, + "speedSpread": 0.0, + "emitDimensions": { + "x": 5, + "y":0 , + "z": 0 + }, + // "polarStart": 0, + // "polarFinish": Math.PI, + // "azimuthStart": -Math.PI, + // "azimuthFinish": Math.PI, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .0, + "z": .00 + }, + "particleRadius": 0.02, + "radiusSpread": 0, + "radiusStart": 0.03, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), + emitterShouldTrail: true + }) + + + + function cleanup() { + Entities.deleteEntity(lightBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } + + this.cleanup = cleanup; +} + +LightBall(); \ No newline at end of file diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index 5ff3c65afd..ea1f408abd 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -31,7 +31,7 @@ startNearGrab: function() { // this.createBeam(); - this.createBeam(); + }, continueNearGrab: function() { @@ -44,6 +44,7 @@ preload: function(entityID) { this.entityID = entityID; + this.createBeam(); }, unload: function() { @@ -53,11 +54,12 @@ createBeam: function() { - var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); - var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + + this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); + var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); forwardVec = Vec3.normalize(forwardVec); var forwardQuat = orientationOf(forwardVec); - var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); + var position = Vec3.sum(this.props.position, Vec3.multiply(Quat.getFront(this.props.rotation), 0.1)); position.z += 0.1; position.x += -0.035; var color = this.colorPalette[randInt(0, this.colorPalette.length)]; @@ -66,7 +68,6 @@ position: position, parentID: this.entityID, isEmitting: true, - "name": "ParticlesTest Emitter", "colorStart": color, color: { red: 200, @@ -80,11 +81,11 @@ emitOrientation: forwardQuat, "emitSpeed": .4, "speedSpread": 0.0, - // "emitDimensions": { - // "x": .1, - // "y": .1, - // "z": .1 - // }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, "polarStart": 0, "polarFinish": .0, "azimuthStart": .1, diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 0372fd388f..95e37ee79b 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -13,6 +13,11 @@ Script.include("../../libraries/utils.js"); var _this; // this is the "constructor" for the entity as a JS object we don't do much here + var LIFETIME = 6000; + var DRAWING_DEPTH = 0.8; + var LINE_DIMENSIONS = 100; + var MAX_POINTS_PER_LINE = 50; + var MIN_POINT_DISTANCE = 0.02; var RaveStick = function() { _this = this; this.colorPalette = [{ @@ -24,6 +29,21 @@ green: 10, blue: 40 }]; + var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png"; + this.trail = Entities.addEntity({ + type: "PolyLine", + dimensions: {x: LINE_DIMENSIONS, y: LINE_DIMENSIONS, z: LINE_DIMENSIONS}, + color: { + red: 255, + green: 255, + blue: 255 + }, + textures: texture, + lifetime: LIFETIME + }) + this.points = []; + this.normals = []; + this.strokeWidths = []; }; RaveStick.prototype = { @@ -31,9 +51,31 @@ startNearGrab: function() { // this.createBeam(); + this.trailBasePosition = Entities.getEntityProperties(this.entityID, "position").position; + Entities.editEntity(this.trail, { + position: this.trailBasePosition + }); + this.points = []; + this.normals = []; + this.strokeWidths = []; }, continueNearGrab: function() { + var position = Entities.getEntityProperties(this.entityID, "position").position; + var localPoint = Vec3.subtract(position, this.trailBasePosition); + if (this.points.length >=1 && Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { + //Need a minimum distance to avoid binormal NANs + return; + } + this.points.push(localPoint); + var normal = computeNormal(position, Camera.getPosition()); + this.normals.push(normal); + this.strokeWidths.push(0.04); + Entities.editEntity(this.trail, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths + }) }, @@ -48,6 +90,7 @@ unload: function() { Entities.deleteEntity(this.beam); + Entities.deleteEntity(this.trail); // Entities.deleteEntity(this.beamTrail); }, @@ -60,7 +103,7 @@ var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); position.z += 0.1; position.x += -0.035; - var color = this.colorPalette[randInt(0, this.colorPalette.length)]; + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", position: position, @@ -118,4 +161,8 @@ }; // entity scripts always need to return a newly constructed object of our type return new RaveStick(); + + function computeNormal(p1, p2) { + return Vec3.normalize(Vec3.subtract(p2, p1)); + } }); \ No newline at end of file From f7811cf5dc5bc33af18788a21b8c46d9ad8d8fe7 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 10:25:51 -0800 Subject: [PATCH 082/209] light trails from rave stick --- .../raveStick/raveStickEntityScript.js | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 95e37ee79b..7b84f473ea 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -18,6 +18,8 @@ var LINE_DIMENSIONS = 100; var MAX_POINTS_PER_LINE = 50; var MIN_POINT_DISTANCE = 0.02; + var STROKE_WIDTH = 0.05 + var ugLSD = 25; var RaveStick = function() { _this = this; this.colorPalette = [{ @@ -32,7 +34,11 @@ var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png"; this.trail = Entities.addEntity({ type: "PolyLine", - dimensions: {x: LINE_DIMENSIONS, y: LINE_DIMENSIONS, z: LINE_DIMENSIONS}, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, color: { red: 255, green: 255, @@ -58,29 +64,58 @@ this.points = []; this.normals = []; this.strokeWidths = []; + this.setupEraseInterval(); }, continueNearGrab: function() { - var position = Entities.getEntityProperties(this.entityID, "position").position; + var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); + var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.2)); + // position.z += 0.1; + // position.x += -0.035; var localPoint = Vec3.subtract(position, this.trailBasePosition); - if (this.points.length >=1 && Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { + if (this.points.length >= 1 && Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { //Need a minimum distance to avoid binormal NANs return; } + if (this.points.length === MAX_POINTS_PER_LINE) { + this.points.shift(); + this.normals.shift(); + this.strokeWidths.shift(); + } + this.points.push(localPoint); - var normal = computeNormal(position, Camera.getPosition()); + var normal = Quat.getUp(props.rotation); this.normals.push(normal); - this.strokeWidths.push(0.04); + this.strokeWidths.push(STROKE_WIDTH); Entities.editEntity(this.trail, { linePoints: this.points, normals: this.normals, strokeWidths: this.strokeWidths - }) + }); + }, - releaseGrab: function() { + setupEraseInterval: function() { + this.trailEraseInterval = Script.setInterval(function() { + if (_this.points.length > 0) { + _this.points.shift(); + _this.normals.shift(); + _this.strokeWidths.shift(); + Entities.editEntity(_this.trail, { + linePoints: _this.points, + strokeWidths: _this.strokeWidths, + normals: _this.normals + }); + } + }, ugLSD); + }, + releaseGrab: function() { + Script.clearInterval(this.trailEraseInterval); }, preload: function(entityID) { @@ -91,7 +126,7 @@ unload: function() { Entities.deleteEntity(this.beam); Entities.deleteEntity(this.trail); - // Entities.deleteEntity(this.beamTrail); + Script.clearInterval(this.trailEraseInterval); }, createBeam: function() { @@ -111,6 +146,7 @@ isEmitting: true, "name": "ParticlesTest Emitter", "colorStart": color, + colorSpread: {red: 200, green : 10, blue: 10}, color: { red: 200, green: 200, @@ -118,16 +154,11 @@ }, "colorFinish": color, "maxParticles": 100000, - "lifespan": 2, + "lifespan": 1, "emitRate": 1000, emitOrientation: forwardQuat, - "emitSpeed": .4, + "emitSpeed": .2, "speedSpread": 0.0, - // "emitDimensions": { - // "x": .1, - // "y": .1, - // "z": .1 - // }, "polarStart": 0, "polarFinish": .0, "azimuthStart": .1, From cd911b31d29413a56ae1d54e215e70b4ef895ea5 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 10:26:54 -0800 Subject: [PATCH 083/209] dont accidentally constrain all objects --- examples/controllers/handControllerGrab.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index ce519880af..9efbff7c58 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -845,7 +845,8 @@ function MyController(hand) { var constraintData = getEntityCustomData('lightModifierKey', this.grabbedEntity, defaultConstraintData); var clampedVector; var targetPosition; - if (constraintData.startAxis !== false) { + if (constraintData.axisStart !== false) { + print('CONSTRAINING OBJECT') clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisStart, constraintData.axisEnd); targetPosition = clampedVector; } else { From 57e51afd46c661db3545cef4345327137abc2338 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 10:35:20 -0800 Subject: [PATCH 084/209] light stick --- examples/flowArts/flowArtsHutSpawner.js | 4 +--- examples/flowArts/lightSaber/lightSaberEntityScript.js | 6 +++--- examples/flowArts/raveStick/raveStickEntityScript.js | 5 ++++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 1ed3325b9c..2f9b2052d1 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -26,8 +26,7 @@ basePosition.y = MyAvatar.position.y + 1; // RAVE ITEMS var lightBall = new LightBall(basePosition); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); -var raveStick2 = new RaveStick(Vec3.sum(basePosition, {x: 2, y: 0.5, z: 1})); -// var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); +var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); @@ -78,7 +77,6 @@ function cleanup() { Entities.deleteEntity(floor); lightBall.cleanup(); raveStick.cleanup(); - raveStick2.cleanup(); lightSaber.cleanup(); } diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index ea1f408abd..5175de25bb 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -31,7 +31,7 @@ startNearGrab: function() { // this.createBeam(); - + }, continueNearGrab: function() { @@ -44,7 +44,7 @@ preload: function(entityID) { this.entityID = entityID; - this.createBeam(); + this.createBeam(); }, unload: function() { @@ -62,7 +62,7 @@ var position = Vec3.sum(this.props.position, Vec3.multiply(Quat.getFront(this.props.rotation), 0.1)); position.z += 0.1; position.x += -0.035; - var color = this.colorPalette[randInt(0, this.colorPalette.length)]; + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", position: position, diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 7b84f473ea..20c21d3a79 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -116,6 +116,7 @@ releaseGrab: function() { Script.clearInterval(this.trailEraseInterval); + this.trailEraseInterval = null; }, preload: function(entityID) { @@ -126,7 +127,9 @@ unload: function() { Entities.deleteEntity(this.beam); Entities.deleteEntity(this.trail); - Script.clearInterval(this.trailEraseInterval); + if(this.trailEraseInterval) { + Script.clearInterval(this.trailEraseInterval); + } }, createBeam: function() { From d4481818b2e991512afb6e8819ed5c910d7cf801 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 10:50:58 -0800 Subject: [PATCH 085/209] lightsaber oriented right --- .../flowArts/lightSaber/lightSaberEntityScript.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index 5175de25bb..2faf0abff9 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -30,8 +30,9 @@ isGrabbed: false, startNearGrab: function() { - // this.createBeam(); - + Entities.editEntity(this.beam, { + isEmitting: true + }); }, continueNearGrab: function() { @@ -39,7 +40,9 @@ }, releaseGrab: function() { - + Entities.editEntity(this.beam, { + isEmitting: false + }); }, preload: function(entityID) { @@ -57,7 +60,7 @@ this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); - forwardVec = Vec3.normalize(forwardVec); + // forwardVec = Vec3.normalize(forwardVec); var forwardQuat = orientationOf(forwardVec); var position = Vec3.sum(this.props.position, Vec3.multiply(Quat.getFront(this.props.rotation), 0.1)); position.z += 0.1; @@ -67,7 +70,7 @@ type: "ParticleEffect", position: position, parentID: this.entityID, - isEmitting: true, + isEmitting: false, "colorStart": color, color: { red: 200, From 5cc5a2ab33aa2df0edfb622849d17b220c3c1a00 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 10:58:14 -0800 Subject: [PATCH 086/209] working non kinematic release --- examples/controllers/handControllerGrab.js | 71 ++++++++++++------- examples/light_modifier/lightLoader.js | 6 +- examples/light_modifier/lightModifier.js | 8 +-- .../light_modifier/lightModifierTestScene.js | 3 +- 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 9efbff7c58..f21df807b4 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -817,26 +817,35 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + var defaultMoveWithHeadData = { + disableMoveWithHead: false + }; + var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData); - // mix in head motion - if (MOVE_WITH_HEAD) { - var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var after = Vec3.multiplyQbyV(Camera.orientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var change = Vec3.subtract(before, after); - this.currentCameraOrientation = Camera.orientation; - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + if (handControllerData.disableMoveWithHead !== true) { + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + } else { + print('should not head move!'); } + var defaultConstraintData = { axisStart: false, axisEnd: false, @@ -846,7 +855,6 @@ function MyController(hand) { var clampedVector; var targetPosition; if (constraintData.axisStart !== false) { - print('CONSTRAINING OBJECT') clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisStart, constraintData.axisEnd); targetPosition = clampedVector; } else { @@ -1249,15 +1257,29 @@ function MyController(hand) { disableReleaseVelocity: false }; - var releaseVelocityData = getEntityCustomData('releaseVelocityKey', this.grabbedEntity, defaultReleaseVelocityData); + var releaseVelocityData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultReleaseVelocityData); if (releaseVelocityData.disableReleaseVelocity === true) { - Entities.updateAction(this.grabbedEntity, this.actionID, { - ttl: 1, - kinematic: false, - kinematicSetVelocity: false, + print('SHOULD NOT BE KINEMATIC AT RELEASE') + // Entities.updateAction(this.grabbedEntity, this.actionID, { + // ttl: 1, + // kinematic: false, + // kinematicSetVelocity: false, + // }); + Entities.deleteAction(this.grabbedEntity, this.actionID); - }); - // Entities.deleteAction(this.grabbedEntity, this.actionID); + Entities.editEntity(this.grabbedEntity,{ + velocity:{ + x:0, + y:0, + z:0 + }, + angularVelocity:{ + x:0, + y:0, + z:0 + } + }) + Entities.deleteAction(this.grabbedEntity, this.actionID); } else { //don't make adjustments @@ -1266,7 +1288,6 @@ function MyController(hand) { } } } - this.deactivateEntity(this.grabbedEntity); this.grabbedEntity = null; diff --git a/examples/light_modifier/lightLoader.js b/examples/light_modifier/lightLoader.js index e4022e7bc1..83618f85c2 100644 --- a/examples/light_modifier/lightLoader.js +++ b/examples/light_modifier/lightLoader.js @@ -10,11 +10,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var grabScript = Script.resolvePath('../controllers/handControllerGrab.js'); +var grabScript = Script.resolvePath('../controllers/handControllerGrab.js?' + Math.random(0 - 100)); Script.load(grabScript); -var lightModifier = Script.resolvePath('lightModifier.js'); +var lightModifier = Script.resolvePath('lightModifier.js?' + Math.random(0 - 100)); Script.load(lightModifier); Script.setTimeout(function() { - var lightModifierTestScene = Script.resolvePath('lightModifierTestScene.js'); + var lightModifierTestScene = Script.resolvePath('lightModifierTestScene.js?' + Math.random(0 - 100)); Script.load(lightModifierTestScene); }, 750) \ No newline at end of file diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 7cd442e9ed..8eae5cc2a4 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -251,15 +251,15 @@ entitySlider.prototype = { axisStart: position, axisEnd: this.endOfAxis, }, - releaseVelocityKey: { - disableReleaseVelocity: true + handControllerKey: { + disableReleaseVelocity: true, + disableMoveWithHead: true } - }) + }), }; this.sliderIndicator = Entities.addEntity(properties); }, - setValueFromMessage: function(message) { //message is not for our light diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 84fb779469..761eb4786d 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -75,8 +75,7 @@ function createBlock() { }, position: position, userData: JSON.stringify({ - - releaseVelocityKey: { + handControllerKey: { disableReleaseVelocity: true } }) From 2aaefbcfcbbcc0d6e3ed7d4cfbb932467131d4a4 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 11:32:48 -0800 Subject: [PATCH 087/209] refactoring, adding headers --- examples/flowArts/flowArtsHutSpawner.js | 13 +-- examples/flowArts/lightBall/lightBall.js | 90 +++++++++++-------- examples/flowArts/lightSaber/LightSaber.js | 21 ++++- .../lightSaber/lightSaberEntityScript.js | 74 +++++++-------- examples/flowArts/lightTrails.js | 23 +---- examples/flowArts/raveStick/RaveStick.js | 41 ++++++++- .../raveStick/raveStickEntityScript.js | 67 +++++++------- .../RenderableParticleEffectEntityItem.cpp | 1 + .../entities/src/ParticleEffectEntityItem.cpp | 11 +-- 9 files changed, 195 insertions(+), 146 deletions(-) diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 2f9b2052d1..03c0ca112f 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -1,11 +1,11 @@ // // flowArtsHutSpawner.js -// examples +// examples/flowArts // -// Created by Eric Levin on 5/14/15. +// Created by Eric Levin on 12/17/15. // Copyright 2014 High Fidelity, Inc. // -// This script creates a special flow arts hut with a numch of flow art toys people can go in and play with +// This script creates a special flow arts hut with a bunch of flow art toys people can go in and play with // // // Distributed under the Apache License, Version 2.0. @@ -29,12 +29,13 @@ var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); -var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); +var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/RaveRoom.fbx"; var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; var raveRoom = Entities.addEntity({ type: "Model", + name: "Rave Hut Room", modelURL: modelURL, position: basePosition, dimensions:roomDimensions, @@ -43,7 +44,8 @@ var raveRoom = Entities.addEntity({ var floor = Entities.addEntity({ type: "Box", - position: Vec3.sum(basePosition, {x: 0, y: -1.5, z: 0}), + name: "Rave Floor", + position: Vec3.sum(basePosition, {x: 0, y: -1.2, z: 0}), dimensions: {x: roomDimensions.x, y: 0.6, z: roomDimensions.z}, color: {red: 50, green: 10, blue: 100}, shapeType: 'box' @@ -53,6 +55,7 @@ var floor = Entities.addEntity({ var lightZone = Entities.addEntity({ type: "Zone", + name: "Rave Hut Zone", shapeType: 'box', keyLightIntensity: 0.4, keyLightColor: { diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index 698c62a71d..a8cdf894d1 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -1,3 +1,17 @@ +// +// LightBall.js +// examples/lightBall +// +// Created by Eric Levin on 12/17/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creats a particle light ball which makes particle trails as you move it. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + Script.include("../../libraries/utils.js"); LightBall = function(spawnPosition) { @@ -11,6 +25,7 @@ LightBall = function(spawnPosition) { var containerBall = Entities.addEntity({ type: "Sphere", + name: "containerBall", position: Vec3.sum(spawnPosition, { x: 0, y: .5, @@ -27,7 +42,11 @@ LightBall = function(spawnPosition) { blue: 150 }, collisionsWillMove: true, - gravity: {x: 0, y: -.5, z: 0}, + gravity: { + x: 0, + y: -.5, + z: 0 + }, userData: JSON.stringify({ grabbableKey: { spatialKey: { @@ -45,6 +64,7 @@ LightBall = function(spawnPosition) { var light = Entities.addEntity({ type: 'Light', + name: "ballLight", parentID: containerBall, dimensions: { x: 30, @@ -60,8 +80,8 @@ LightBall = function(spawnPosition) { type: "ParticleEffect", parentID: containerBall, isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": { + name: "particleBall", + colorStart: { red: 200, green: 20, blue: 40 @@ -71,45 +91,45 @@ LightBall = function(spawnPosition) { green: 200, blue: 255 }, - "colorFinish": { + colorFinish: { red: 25, green: 20, blue: 255 }, - "maxParticles": 100000, - "lifespan": 2, - "emitRate": 10000, - "emitSpeed": .1, - "speedSpread": 0.0, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 + maxParticles: 100000, + lifespan: 2, + emitRate: 10000, + emitSpeed: .1, + lifetime: -1, + speedSpread: 0.0, + emitDimensions: { + x: 0, + y: 0, + z: 0 }, - "polarStart": 0, - "polarFinish": Math.PI, - "azimuthStart": -Math.PI, - "azimuthFinish": Math.PI, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 + polarStart: 0, + polarFinish: Math.PI, + azimuthStart: -Math.PI, + azimuthFinish: Math.PI, + emitAcceleration: { + x: 0, + y: 0, + z: 0 }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 + accelerationSpread: { + x: .00, + y: .00, + z: .00 }, - "particleRadius": 0.02, - "radiusSpread": 0, - "radiusStart": 0.03, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), + particleRadius: 0.02, + radiusSpread: 0, + radiusStart: 0.03, + radiusFinish: 0.0003, + alpha: 0, + alphaSpread: .5, + alphaStart: 0, + alphaFinish: 0.5, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", emitterShouldTrail: true }) diff --git a/examples/flowArts/lightSaber/LightSaber.js b/examples/flowArts/lightSaber/LightSaber.js index 12ac3f3b60..8a4f3f2902 100644 --- a/examples/flowArts/lightSaber/LightSaber.js +++ b/examples/flowArts/lightSaber/LightSaber.js @@ -1,10 +1,25 @@ +// +// LightSaber.js +// examples +// +// Created by Eric Levin on 12/17/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creates a lightsaber which activates on grab +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + Script.include("../../libraries/utils.js"); -var modelURL = "file:///C:/Users/Eric/Desktop/lightSaber.fbx?v1" + Math.random(); +var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/lightSaber.fbx"; var scriptURL = Script.resolvePath("lightSaberEntityScript.js"); LightSaber = function(spawnPosition) { - var stick = Entities.addEntity({ + var saberHandle = Entities.addEntity({ type: "Model", + name: "LightSaber Handle", modelURL: modelURL, position: spawnPosition, shapeType: 'box', @@ -31,7 +46,7 @@ LightSaber = function(spawnPosition) { function cleanup() { - Entities.deleteEntity(stick); + Entities.deleteEntity(saberHandle); } this.cleanup = cleanup; diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index 2faf0abff9..6f396bf6e3 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -1,10 +1,10 @@ // lightSaberEntityScript.js // // Script Type: Entity -// Created by Eric Levin on 12/16/15. +// Created by Eric Levin on 12/17/15. // Copyright 2015 High Fidelity, Inc. // -// This entity script creates a lightsaber. +// This entity script creates the logic for displaying the lightsaber beam. // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // @@ -35,10 +35,6 @@ }); }, - continueNearGrab: function() { - - }, - releaseGrab: function() { Entities.editEntity(this.beam, { isEmitting: false @@ -52,7 +48,6 @@ unload: function() { Entities.deleteEntity(this.beam); - // Entities.deleteEntity(this.beamTrail); }, createBeam: function() { @@ -68,56 +63,53 @@ var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", + name: "LightSaber Beam", position: position, parentID: this.entityID, isEmitting: false, - "colorStart": color, + colorStart: color, color: { red: 200, green: 200, blue: 255 }, - "colorFinish": color, - "maxParticles": 100000, - "lifespan": 2, - "emitRate": 1000, + colorFinish: color, + maxParticles: 100000, + lifespan: 2, + emitRate: 1000, emitOrientation: forwardQuat, - "emitSpeed": .4, - "speedSpread": 0.0, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 + emitSpeed: .4, + speedSpread: 0.0, + emitDimensions: { + x: 0, + y: 0, + z: 0 }, - "polarStart": 0, - "polarFinish": .0, - "azimuthStart": .1, - "azimuthFinish": .01, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 + accelerationSpread: { + x: .00, + y: .00, + z: .00 }, - "radiusStart": 0.03, - radiusFinish: 0.025, - "alpha": 0.7, - "alphaSpread": .1, - "alphaStart": 0.5, - "alphaFinish": 0.5, - // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - "textures": "file:///C:/Users/Eric/Desktop/beamParticle.png?v1" + Math.random(), + radiusStart: 0.03, + adiusFinish: 0.025, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", emitterShouldTrail: false } this.beam = Entities.addEntity(props); - // props.emitterShouldTrail = true; - // this.beamTrail = Entities.addEntity(props); - } }; // entity scripts always need to return a newly constructed object of our type diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 8e0dc98bbb..522ecce851 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -1,11 +1,11 @@ // -// hydraPaint.js +// lightTrails.js // examples // // Created by Eric Levin on 5/14/15. // Copyright 2014 High Fidelity, Inc. // -// This script allows you to paint with the hydra! +// This script creates light trails as you move your hydra hands // // // Distributed under the Apache License, Version 2.0. @@ -25,24 +25,6 @@ var LIFETIME = 6000; var DRAWING_DEPTH = 0.8; var LINE_DIMENSIONS = 100; -var lightZone = Entities.addEntity({ - type: "Zone", - shapeType: 'box', - keyLightIntensity: 0.02, - keyLightColor: { - red: 5, - green: 0, - blue: 5 - }, - keyLightAmbientIntensity: .05, - position: MyAvatar.position, - dimensions: { - x: 100, - y: 100, - z: 100 - } -}); - var MIN_POINT_DISTANCE = 0.02; @@ -192,7 +174,6 @@ function update(deltaTime) { function scriptEnding() { leftController.cleanup(); rightController.cleanup(); - Entities.deleteEntity(lightZone); } function vectorIsZero(v) { diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js index 5151b528cc..fd3c98b6e5 100644 --- a/examples/flowArts/raveStick/RaveStick.js +++ b/examples/flowArts/raveStick/RaveStick.js @@ -1,10 +1,32 @@ +// +// RaveStick.js +// examples/flowArats/raveStick +// +// Created by Eric Levin on 12/17/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creates a rave stick which makes pretty light trails as you paint +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + Script.include("../../libraries/utils.js"); -var modelURL = "file:///C:/Users/Eric/Desktop/raveStick.fbx?v1" + Math.random(); +var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx"; var scriptURL = Script.resolvePath("raveStickEntityScript.js"); RaveStick = function(spawnPosition) { - + var colorPalette = [{ + red: 0, + green: 200, + blue: 40 + }, { + red: 200, + green: 10, + blue: 40 + }]; var stick = Entities.addEntity({ type: "Model", + name: "raveStick", modelURL: modelURL, position: spawnPosition, shapeType: 'box', @@ -29,9 +51,24 @@ RaveStick = function(spawnPosition) { }) }); + var light = Entities.addEntity({ + type: 'Light', + name: "raveLight", + parentID: stick, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + function cleanup() { Entities.deleteEntity(stick); + Entities.deleteEntity(light); } this.cleanup = cleanup; diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 20c21d3a79..2c484e601d 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -46,7 +46,9 @@ }, textures: texture, lifetime: LIFETIME - }) + }); + + this.points = []; this.normals = []; this.strokeWidths = []; @@ -127,8 +129,8 @@ unload: function() { Entities.deleteEntity(this.beam); Entities.deleteEntity(this.trail); - if(this.trailEraseInterval) { - Script.clearInterval(this.trailEraseInterval); + if (this.trailEraseInterval) { + Script.clearInterval(this.trailEraseInterval); } }, @@ -147,43 +149,46 @@ position: position, parentID: this.entityID, isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": color, - colorSpread: {red: 200, green : 10, blue: 10}, + name: "raveBeam", + colorStart: color, + colorSpread: { + red: 200, + green: 10, + blue: 10 + }, color: { red: 200, green: 200, blue: 255 }, - "colorFinish": color, - "maxParticles": 100000, - "lifespan": 1, - "emitRate": 1000, + colorFinish: color, + maxParticles: 100000, + lifespan: 1, + emitRate: 1000, emitOrientation: forwardQuat, - "emitSpeed": .2, - "speedSpread": 0.0, - "polarStart": 0, - "polarFinish": .0, - "azimuthStart": .1, - "azimuthFinish": .01, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 + emitSpeed: .2, + speedSpread: 0.0, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 + accelerationSpread: { + x: .00, + y: .00, + z: .00 }, - "radiusStart": 0.03, + radiusStart: 0.03, radiusFinish: 0.025, - "alpha": 0.7, - "alphaSpread": .1, - "alphaStart": 0.5, - "alphaFinish": 0.5, - // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - "textures": "file:///C:/Users/Eric/Desktop/beamParticle.png?v1" + Math.random(), + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", emitterShouldTrail: false } this.beam = Entities.addEntity(props); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 91a4811011..43b9ae7870 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -245,6 +245,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { transform.setRotation(rotation); } + render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [=](ParticlePayloadData& payload) { payload.setVisibleFlag(true); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 4d46439554..413604dbdf 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -641,11 +641,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { Particle particle; - - std::random_device rd; - std::mt19937_64 el(rd()); - std::uniform_real_distribution uniform_dist(0.0, 1.0); particle.seed = randFloatInRange(-1.0f, 1.0f); if (getEmitterShouldTrail()) { @@ -667,13 +663,13 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { float elevationMinZ = sin(PI_OVER_TWO - _polarFinish); float elevationMaxZ = sin(PI_OVER_TWO - _polarStart); // float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat()); - float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * uniform_dist(el)); + float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) *randFloat()); float azimuth; if (_azimuthFinish >= _azimuthStart) { - azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * uniform_dist(el); + azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat(); } else { - azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * uniform_dist(el); + azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * randFloat(); } glm::vec3 emitDirection; @@ -711,7 +707,6 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { } particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); - // particle.velocity = (_emitSpeed + uniform_dist(el) * _speedSpread) * (_emitOrientation * emitDirection); particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } From 8d25a666d11dd6e3498e55fcae021f9c886edc4c Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 11:40:06 -0800 Subject: [PATCH 088/209] fixed bug where trail would remain after user released rave stick --- examples/flowArts/flowArtsHutSpawner.js | 1 - examples/flowArts/lightBall/lightBall.js | 2 +- .../flowArts/raveStick/raveStickEntityScript.js | 13 +++++-------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 03c0ca112f..3762c67fe4 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -72,7 +72,6 @@ var lightZone = Entities.addEntity({ } }); - function cleanup() { Entities.deleteEntity(raveRoom); diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index a8cdf894d1..1898f86eef 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -44,7 +44,7 @@ LightBall = function(spawnPosition) { collisionsWillMove: true, gravity: { x: 0, - y: -.5, + y: -0.5, z: 0 }, userData: JSON.stringify({ diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 2c484e601d..171b53e0cf 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -19,7 +19,7 @@ var MAX_POINTS_PER_LINE = 50; var MIN_POINT_DISTANCE = 0.02; var STROKE_WIDTH = 0.05 - var ugLSD = 25; + var ugLSD = 35; var RaveStick = function() { _this = this; this.colorPalette = [{ @@ -117,8 +117,10 @@ }, releaseGrab: function() { - Script.clearInterval(this.trailEraseInterval); - this.trailEraseInterval = null; + Script.setTimeout(function() { + Script.clearInterval(_this.trailEraseInterval); + _this.trailEraseInterval = null; + }, 3000); }, preload: function(entityID) { @@ -192,13 +194,8 @@ emitterShouldTrail: false } this.beam = Entities.addEntity(props); - - // props.emitterShouldTrail = true; - // this.beamTrail = Entities.addEntity(props); - } }; - // entity scripts always need to return a newly constructed object of our type return new RaveStick(); function computeNormal(p1, p2) { From 8e2128c69226e629291db183bf1fc77317826ee7 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 11:59:21 -0800 Subject: [PATCH 089/209] update light volume when you move light parent --- examples/controllers/handControllerGrab.js | 29 +- examples/libraries/entitySelectionTool.js | 3101 +++++++++++++---- examples/light_modifier/lightModifier.js | 2 +- .../light_modifier/lightModifierTestScene.js | 2 + examples/light_modifier/lightParent.js | 42 + 5 files changed, 2387 insertions(+), 789 deletions(-) create mode 100644 examples/light_modifier/lightParent.js diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f21df807b4..f53a66444f 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1256,27 +1256,21 @@ function MyController(hand) { var defaultReleaseVelocityData = { disableReleaseVelocity: false }; - + //sometimes we want things to stay right where they are when we let go. var releaseVelocityData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultReleaseVelocityData); if (releaseVelocityData.disableReleaseVelocity === true) { - print('SHOULD NOT BE KINEMATIC AT RELEASE') - // Entities.updateAction(this.grabbedEntity, this.actionID, { - // ttl: 1, - // kinematic: false, - // kinematicSetVelocity: false, - // }); - Entities.deleteAction(this.grabbedEntity, this.actionID); + Entities.deleteAction(this.grabbedEntity, this.actionID); - Entities.editEntity(this.grabbedEntity,{ - velocity:{ - x:0, - y:0, - z:0 + Entities.editEntity(this.grabbedEntity, { + velocity: { + x: 0, + y: 0, + z: 0 }, - angularVelocity:{ - x:0, - y:0, - z:0 + angularVelocity: { + x: 0, + y: 0, + z: 0 } }) Entities.deleteAction(this.grabbedEntity, this.actionID); @@ -1288,6 +1282,7 @@ function MyController(hand) { } } } + this.deactivateEntity(this.grabbedEntity); this.grabbedEntity = null; diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 6edbe6844b..9b213760c2 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -16,23 +16,73 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; SPACE_LOCAL = "local"; SPACE_WORLD = "world"; + SelectionManager = (function() { var that = {}; + + function subscribeToUpdateMessages() { + Messages.subscribe('entityToolUpdates'); + Messages.messageReceived.connect(handleEntitySelectionToolUpdates); + } + + function handleEntitySelectionToolUpdates(channel, message, sender) { + if (channel !== 'entityToolUpdates') { + return; + } + if (sender !== MyAvatar.sessionUUID) { + return; + } + + if (message === 'callUpdate') { + that._update(); + } + } + + subscribeToUpdateMessages(); + that.savedProperties = {}; that.selections = []; var listeners = []; that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0); - that.localPosition = { x: 0, y: 0, z: 0 }; - that.localDimensions = { x: 0, y: 0, z: 0 }; - that.localRegistrationPoint = { x: 0.5, y: 0.5, z: 0.5 }; + that.localPosition = { + x: 0, + y: 0, + z: 0 + }; + that.localDimensions = { + x: 0, + y: 0, + z: 0 + }; + that.localRegistrationPoint = { + x: 0.5, + y: 0.5, + z: 0.5 + }; that.worldRotation = Quat.fromPitchYawRollDegrees(0, 0, 0); - that.worldPosition = { x: 0, y: 0, z: 0 }; - that.worldDimensions = { x: 0, y: 0, z: 0 }; - that.worldRegistrationPoint = { x: 0.5, y: 0.5, z: 0.5 }; - that.centerPosition = { x: 0, y: 0, z: 0 }; + that.worldPosition = { + x: 0, + y: 0, + z: 0 + }; + that.worldDimensions = { + x: 0, + y: 0, + z: 0 + }; + that.worldRegistrationPoint = { + x: 0.5, + y: 0.5, + z: 0.5 + }; + that.centerPosition = { + x: 0, + y: 0, + z: 0 + }; that.saveProperties = function() { that.savedProperties = {}; @@ -177,9 +227,9 @@ function getRelativeCenterPosition(dimensions, registrationPoint) { } } -SelectionDisplay = (function () { +SelectionDisplay = (function() { var that = {}; - + var MINIMUM_DIMENSION = 0.001; var GRABBER_DISTANCE_TO_SIZE_RATIO = 0.0075; @@ -194,14 +244,18 @@ SelectionDisplay = (function () { var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.svg"; var showExtendedStretchHandles = false; - + var spaceMode = SPACE_LOCAL; var mode = "UNKNOWN"; var overlayNames = new Array(); var lastCameraPosition = Camera.getPosition(); var lastCameraOrientation = Camera.getOrientation(); - var handleHoverColor = { red: 224, green: 67, blue: 36 }; + var handleHoverColor = { + red: 224, + green: 67, + blue: 36 + }; var handleHoverAlpha = 1.0; var rotateOverlayTargetSize = 10000; // really big target @@ -221,19 +275,27 @@ SelectionDisplay = (function () { var pitchNormal; var rollNormal; var rotationNormal; - + var originalRotation; var originalPitch; var originalYaw; var originalRoll; - - var handleColor = { red: 255, green: 255, blue: 255 }; + + var handleColor = { + red: 255, + green: 255, + blue: 255 + }; var handleAlpha = 0.7; - var highlightedHandleColor = { red: 183, green: 64, blue: 44 }; + var highlightedHandleColor = { + red: 183, + green: 64, + blue: 44 + }; var highlightedHandleAlpha = 0.9; - + var previousHandle = false; var previousHandleColor; var previousHandleAlpha; @@ -242,115 +304,182 @@ SelectionDisplay = (function () { var grabberSizeEdge = 0.015; var grabberSizeFace = 0.025; var grabberAlpha = 1; - var grabberColorCorner = { red: 120, green: 120, blue: 120 }; - var grabberColorEdge = { red: 0, green: 0, blue: 0 }; - var grabberColorFace = { red: 120, green: 120, blue: 120 }; + var grabberColorCorner = { + red: 120, + green: 120, + blue: 120 + }; + var grabberColorEdge = { + red: 0, + green: 0, + blue: 0 + }; + var grabberColorFace = { + red: 120, + green: 120, + blue: 120 + }; var grabberLineWidth = 0.5; var grabberSolid = true; - var grabberMoveUpPosition = { x: 0, y: 0, z: 0 }; + var grabberMoveUpPosition = { + x: 0, + y: 0, + z: 0 + }; - var lightOverlayColor = { red: 255, green: 153, blue: 0 }; + var lightOverlayColor = { + red: 255, + green: 153, + blue: 0 + }; var grabberPropertiesCorner = { - position: { x:0, y: 0, z: 0}, - size: grabberSizeCorner, - color: grabberColorCorner, - alpha: 1, - solid: grabberSolid, - visible: false, - dashed: false, - lineWidth: grabberLineWidth, - drawInFront: true, - borderSize: 1.4, - }; + position: { + x: 0, + y: 0, + z: 0 + }, + size: grabberSizeCorner, + color: grabberColorCorner, + alpha: 1, + solid: grabberSolid, + visible: false, + dashed: false, + lineWidth: grabberLineWidth, + drawInFront: true, + borderSize: 1.4, + }; var grabberPropertiesEdge = { - position: { x:0, y: 0, z: 0}, - size: grabberSizeEdge, - color: grabberColorEdge, - alpha: 1, - solid: grabberSolid, - visible: false, - dashed: false, - lineWidth: grabberLineWidth, - drawInFront: true, - borderSize: 1.4, - }; + position: { + x: 0, + y: 0, + z: 0 + }, + size: grabberSizeEdge, + color: grabberColorEdge, + alpha: 1, + solid: grabberSolid, + visible: false, + dashed: false, + lineWidth: grabberLineWidth, + drawInFront: true, + borderSize: 1.4, + }; var grabberPropertiesFace = { - position: { x:0, y: 0, z: 0}, - size: grabberSizeFace, - color: grabberColorFace, - alpha: 1, - solid: grabberSolid, - visible: false, - dashed: false, - lineWidth: grabberLineWidth, - drawInFront: true, - borderSize: 1.4, - }; - + position: { + x: 0, + y: 0, + z: 0 + }, + size: grabberSizeFace, + color: grabberColorFace, + alpha: 1, + solid: grabberSolid, + visible: false, + dashed: false, + lineWidth: grabberLineWidth, + drawInFront: true, + borderSize: 1.4, + }; + var spotLightLineProperties = { color: lightOverlayColor, lineWidth: 1.5, }; - + var highlightBox = Overlays.addOverlay("cube", { - position: { x:0, y: 0, z: 0}, - size: 1, - color: { red: 90, green: 90, blue: 90}, - alpha: 1, - solid: false, - visible: false, - dashed: true, - lineWidth: 2.0, - ignoreRayIntersection: true, // this never ray intersects - drawInFront: true - }); + position: { + x: 0, + y: 0, + z: 0 + }, + size: 1, + color: { + red: 90, + green: 90, + blue: 90 + }, + alpha: 1, + solid: false, + visible: false, + dashed: true, + lineWidth: 2.0, + ignoreRayIntersection: true, // this never ray intersects + drawInFront: true + }); var selectionBox = Overlays.addOverlay("cube", { - position: { x:0, y: 0, z: 0}, - size: 1, - color: { red: 255, green: 0, blue: 0}, - alpha: 1, - solid: false, - visible: false, - dashed: false, - lineWidth: 1.0, - }); + position: { + x: 0, + y: 0, + z: 0 + }, + size: 1, + color: { + red: 255, + green: 0, + blue: 0 + }, + alpha: 1, + solid: false, + visible: false, + dashed: false, + lineWidth: 1.0, + }); var selectionBoxes = []; var rotationDegreesDisplay = Overlays.addOverlay("text3d", { - position: { x:0, y: 0, z: 0}, - text: "", - color: { red: 0, green: 0, blue: 0}, - backgroundColor: { red: 255, green: 255, blue: 255 }, - alpha: 0.7, - backgroundAlpha: 0.7, - visible: false, - isFacingAvatar: true, - drawInFront: true, - ignoreRayIntersection: true, - dimensions: { x: 0, y: 0 }, - lineHeight: 0.0, - topMargin: 0, - rightMargin: 0, - bottomMargin: 0, - leftMargin: 0, - }); + position: { + x: 0, + y: 0, + z: 0 + }, + text: "", + color: { + red: 0, + green: 0, + blue: 0 + }, + backgroundColor: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 0.7, + backgroundAlpha: 0.7, + visible: false, + isFacingAvatar: true, + drawInFront: true, + ignoreRayIntersection: true, + dimensions: { + x: 0, + y: 0 + }, + lineHeight: 0.0, + topMargin: 0, + rightMargin: 0, + bottomMargin: 0, + leftMargin: 0, + }); var grabberMoveUp = Overlays.addOverlay("image3d", { - url: HIFI_PUBLIC_BUCKET + "images/up-arrow.svg", - position: { x:0, y: 0, z: 0}, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: true, - drawInFront: true, - }); + url: HIFI_PUBLIC_BUCKET + "images/up-arrow.svg", + position: { + x: 0, + y: 0, + z: 0 + }, + color: handleColor, + alpha: handleAlpha, + visible: false, + size: 0.1, + scale: 0.1, + isFacingAvatar: true, + drawInFront: true, + }); // var normalLine = Overlays.addOverlay("line3d", { // visible: true, @@ -360,7 +489,7 @@ SelectionDisplay = (function () { // color: { red: 255, green: 255, blue: 0 }, // ignoreRayIntersection: true, // }); - + var grabberLBN = Overlays.addOverlay("cube", grabberPropertiesCorner); var grabberRBN = Overlays.addOverlay("cube", grabberPropertiesCorner); var grabberLBF = Overlays.addOverlay("cube", grabberPropertiesCorner); @@ -481,171 +610,324 @@ SelectionDisplay = (function () { ]; - var baseOverlayAngles = { x: 0, y: 0, z: 0 }; + var baseOverlayAngles = { + x: 0, + y: 0, + z: 0 + }; var baseOverlayRotation = Quat.fromVec3Degrees(baseOverlayAngles); var baseOfEntityProjectionOverlay = Overlays.addOverlay("rectangle3d", { - position: { x: 1, y: 0, z: 0}, - color: { red: 51, green: 152, blue: 203 }, - alpha: 0.5, - solid: true, - visible: false, - width: 300, height: 200, - rotation: baseOverlayRotation, - ignoreRayIntersection: true, // always ignore this - }); + position: { + x: 1, + y: 0, + z: 0 + }, + color: { + red: 51, + green: 152, + blue: 203 + }, + alpha: 0.5, + solid: true, + visible: false, + width: 300, + height: 200, + rotation: baseOverlayRotation, + ignoreRayIntersection: true, // always ignore this + }); - var yawOverlayAngles = { x: 90, y: 0, z: 0 }; + var yawOverlayAngles = { + x: 90, + y: 0, + z: 0 + }; var yawOverlayRotation = Quat.fromVec3Degrees(yawOverlayAngles); - var pitchOverlayAngles = { x: 0, y: 90, z: 0 }; + var pitchOverlayAngles = { + x: 0, + y: 90, + z: 0 + }; var pitchOverlayRotation = Quat.fromVec3Degrees(pitchOverlayAngles); - var rollOverlayAngles = { x: 0, y: 180, z: 0 }; + var rollOverlayAngles = { + x: 0, + y: 180, + z: 0 + }; var rollOverlayRotation = Quat.fromVec3Degrees(rollOverlayAngles); var xRailOverlay = Overlays.addOverlay("line3d", { - visible: false, - lineWidth: 1.0, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 255, green: 0, blue: 0 }, - ignoreRayIntersection: true, // always ignore this - visible: false, - }); + visible: false, + lineWidth: 1.0, + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: { + red: 255, + green: 0, + blue: 0 + }, + ignoreRayIntersection: true, // always ignore this + visible: false, + }); var yRailOverlay = Overlays.addOverlay("line3d", { - visible: false, - lineWidth: 1.0, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 255, blue: 0 }, - ignoreRayIntersection: true, // always ignore this - visible: false, - }); + visible: false, + lineWidth: 1.0, + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: { + red: 0, + green: 255, + blue: 0 + }, + ignoreRayIntersection: true, // always ignore this + visible: false, + }); var zRailOverlay = Overlays.addOverlay("line3d", { - visible: false, - lineWidth: 1.0, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 0, blue: 255 }, - ignoreRayIntersection: true, // always ignore this - visible: false, - }); + visible: false, + lineWidth: 1.0, + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: { + red: 0, + green: 0, + blue: 255 + }, + ignoreRayIntersection: true, // always ignore this + visible: false, + }); var rotateZeroOverlay = Overlays.addOverlay("line3d", { - visible: false, - lineWidth: 2.0, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 255, green: 0, blue: 0 }, - ignoreRayIntersection: true, // always ignore this - }); + visible: false, + lineWidth: 2.0, + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: { + red: 255, + green: 0, + blue: 0 + }, + ignoreRayIntersection: true, // always ignore this + }); var rotateCurrentOverlay = Overlays.addOverlay("line3d", { - visible: false, - lineWidth: 2.0, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 0, blue: 255 }, - ignoreRayIntersection: true, // always ignore this - }); + visible: false, + lineWidth: 2.0, + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: { + red: 0, + green: 0, + blue: 255 + }, + ignoreRayIntersection: true, // always ignore this + }); var rotateOverlayTarget = Overlays.addOverlay("circle3d", { - position: { x:0, y: 0, z: 0}, - size: rotateOverlayTargetSize, - color: { red: 0, green: 0, blue: 0 }, - alpha: 0.0, - solid: true, - visible: false, - rotation: yawOverlayRotation, - }); + position: { + x: 0, + y: 0, + z: 0 + }, + size: rotateOverlayTargetSize, + color: { + red: 0, + green: 0, + blue: 0 + }, + alpha: 0.0, + solid: true, + visible: false, + rotation: yawOverlayRotation, + }); var rotateOverlayInner = Overlays.addOverlay("circle3d", { - position: { x:0, y: 0, z: 0}, - size: 1, - color: { red: 51, green: 152, blue: 203 }, - alpha: 0.2, - solid: true, - visible: false, - rotation: yawOverlayRotation, - hasTickMarks: true, - majorTickMarksAngle: innerSnapAngle, - minorTickMarksAngle: 0, - majorTickMarksLength: -0.25, - minorTickMarksLength: 0, - majorTickMarksColor: { red: 0, green: 0, blue: 0 }, - minorTickMarksColor: { red: 0, green: 0, blue: 0 }, - ignoreRayIntersection: true, // always ignore this - }); + position: { + x: 0, + y: 0, + z: 0 + }, + size: 1, + color: { + red: 51, + green: 152, + blue: 203 + }, + alpha: 0.2, + solid: true, + visible: false, + rotation: yawOverlayRotation, + hasTickMarks: true, + majorTickMarksAngle: innerSnapAngle, + minorTickMarksAngle: 0, + majorTickMarksLength: -0.25, + minorTickMarksLength: 0, + majorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + minorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + ignoreRayIntersection: true, // always ignore this + }); var rotateOverlayOuter = Overlays.addOverlay("circle3d", { - position: { x:0, y: 0, z: 0}, - size: 1, - color: { red: 51, green: 152, blue: 203 }, - alpha: 0.2, - solid: true, - visible: false, - rotation: yawOverlayRotation, + position: { + x: 0, + y: 0, + z: 0 + }, + size: 1, + color: { + red: 51, + green: 152, + blue: 203 + }, + alpha: 0.2, + solid: true, + visible: false, + rotation: yawOverlayRotation, - hasTickMarks: true, - majorTickMarksAngle: 45.0, - minorTickMarksAngle: 5, - majorTickMarksLength: 0.25, - minorTickMarksLength: 0.1, - majorTickMarksColor: { red: 0, green: 0, blue: 0 }, - minorTickMarksColor: { red: 0, green: 0, blue: 0 }, - ignoreRayIntersection: true, // always ignore this - }); + hasTickMarks: true, + majorTickMarksAngle: 45.0, + minorTickMarksAngle: 5, + majorTickMarksLength: 0.25, + minorTickMarksLength: 0.1, + majorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + minorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + ignoreRayIntersection: true, // always ignore this + }); var rotateOverlayCurrent = Overlays.addOverlay("circle3d", { - position: { x:0, y: 0, z: 0}, - size: 1, - color: { red: 224, green: 67, blue: 36}, - alpha: 0.8, - solid: true, - visible: false, - rotation: yawOverlayRotation, - ignoreRayIntersection: true, // always ignore this - hasTickMarks: true, - majorTickMarksColor: { red: 0, green: 0, blue: 0 }, - minorTickMarksColor: { red: 0, green: 0, blue: 0 }, - }); + position: { + x: 0, + y: 0, + z: 0 + }, + size: 1, + color: { + red: 224, + green: 67, + blue: 36 + }, + alpha: 0.8, + solid: true, + visible: false, + rotation: yawOverlayRotation, + ignoreRayIntersection: true, // always ignore this + hasTickMarks: true, + majorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + minorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + }); var yawHandle = Overlays.addOverlay("image3d", { - url: ROTATE_ARROW_WEST_NORTH_URL, - position: { x:0, y: 0, z: 0}, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: false, - drawInFront: true, - }); + url: ROTATE_ARROW_WEST_NORTH_URL, + position: { + x: 0, + y: 0, + z: 0 + }, + color: handleColor, + alpha: handleAlpha, + visible: false, + size: 0.1, + scale: 0.1, + isFacingAvatar: false, + drawInFront: true, + }); var pitchHandle = Overlays.addOverlay("image3d", { - url: ROTATE_ARROW_WEST_NORTH_URL, - position: { x:0, y: 0, z: 0}, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: false, - drawInFront: true, - }); + url: ROTATE_ARROW_WEST_NORTH_URL, + position: { + x: 0, + y: 0, + z: 0 + }, + color: handleColor, + alpha: handleAlpha, + visible: false, + size: 0.1, + scale: 0.1, + isFacingAvatar: false, + drawInFront: true, + }); var rollHandle = Overlays.addOverlay("image3d", { - url: ROTATE_ARROW_WEST_NORTH_URL, - position: { x:0, y: 0, z: 0}, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: false, - drawInFront: true, - }); + url: ROTATE_ARROW_WEST_NORTH_URL, + position: { + x: 0, + y: 0, + z: 0 + }, + color: handleColor, + alpha: handleAlpha, + visible: false, + size: 0.1, + scale: 0.1, + isFacingAvatar: false, + drawInFront: true, + }); var allOverlays = [ highlightBox, @@ -703,7 +985,7 @@ SelectionDisplay = (function () { overlayNames[grabberEdgeNL] = "grabberEdgeNL"; overlayNames[grabberEdgeFR] = "grabberEdgeFR"; overlayNames[grabberEdgeFL] = "grabberEdgeFL"; - + overlayNames[yawHandle] = "yawHandle"; overlayNames[pitchHandle] = "pitchHandle"; overlayNames[rollHandle] = "rollHandle"; @@ -718,6 +1000,7 @@ SelectionDisplay = (function () { var activeTool = null; var grabberTools = {}; + function addGrabberTool(overlay, tool) { grabberTools[overlay] = { mode: tool.mode, @@ -727,8 +1010,8 @@ SelectionDisplay = (function () { } } - - that.cleanup = function () { + + that.cleanup = function() { for (var i = 0; i < allOverlays.length; i++) { Overlays.deleteOverlay(allOverlays[i]); } @@ -741,19 +1024,21 @@ SelectionDisplay = (function () { var properties = Entities.getEntityProperties(entityID); Overlays.editOverlay(highlightBox, { visible: true, - position: properties.boundingBox.center, + position: properties.boundingBox.center, dimensions: properties.dimensions, rotation: properties.rotation }); }; that.unhighlightSelectable = function(entityID) { - Overlays.editOverlay(highlightBox,{ visible: false}); + Overlays.editOverlay(highlightBox, { + visible: false + }); }; that.select = function(entityID, event) { var properties = Entities.getEntityProperties(SelectionManager.selections[0]); - + lastCameraPosition = Camera.getPosition(); lastCameraOrientation = Camera.getOrientation(); @@ -766,12 +1051,16 @@ SelectionDisplay = (function () { print(" event.y:" + event.y); Vec3.print(" current position:", properties.position); } - - + + } - Entities.editEntity(entityID, { localRenderAlpha: 0.1 }); - Overlays.editOverlay(highlightBox, { visible: false }); + Entities.editEntity(entityID, { + localRenderAlpha: 0.1 + }); + Overlays.editOverlay(highlightBox, { + visible: false + }); that.updateHandles(); } @@ -789,7 +1078,7 @@ SelectionDisplay = (function () { } var rotateHandleOffset = 0.05; - + var top, far, left, bottom, near, right, boundsCenter, objectCenter, BLN, BRN, BLF, TLN, TRN, TLF, TRF; var dimensions, rotation; @@ -828,136 +1117,320 @@ SelectionDisplay = (function () { * ------------------------------*/ - + var cameraPosition = Camera.getPosition(); if (cameraPosition.x > objectCenter.x) { // must be BRF or BRN if (cameraPosition.z < objectCenter.z) { - yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 90, z: 0 }); - pitchHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 90, z: 0 }); - rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 0 }); + yawHandleRotation = Quat.fromVec3Degrees({ + x: 270, + y: 90, + z: 0 + }); + pitchHandleRotation = Quat.fromVec3Degrees({ + x: 0, + y: 90, + z: 0 + }); + rollHandleRotation = Quat.fromVec3Degrees({ + x: 0, + y: 0, + z: 0 + }); - yawNormal = { x: 0, y: 1, z: 0 }; - pitchNormal = { x: 1, y: 0, z: 0 }; - rollNormal = { x: 0, y: 0, z: 1 }; + yawNormal = { + x: 0, + y: 1, + z: 0 + }; + pitchNormal = { + x: 1, + y: 0, + z: 0 + }; + rollNormal = { + x: 0, + y: 0, + z: 1 + }; - yawCorner = { x: left + rotateHandleOffset, - y: bottom - rotateHandleOffset, - z: near - rotateHandleOffset }; + yawCorner = { + x: left + rotateHandleOffset, + y: bottom - rotateHandleOffset, + z: near - rotateHandleOffset + }; - pitchCorner = { x: right - rotateHandleOffset, - y: top + rotateHandleOffset, - z: near - rotateHandleOffset}; + pitchCorner = { + x: right - rotateHandleOffset, + y: top + rotateHandleOffset, + z: near - rotateHandleOffset + }; - rollCorner = { x: left + rotateHandleOffset, - y: top + rotateHandleOffset, - z: far + rotateHandleOffset }; + rollCorner = { + x: left + rotateHandleOffset, + y: top + rotateHandleOffset, + z: far + rotateHandleOffset + }; - yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; - pitchCenter = { x: right, y: boundsCenter.y, z: boundsCenter.z}; - rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: far }; - + yawCenter = { + x: boundsCenter.x, + y: bottom, + z: boundsCenter.z + }; + pitchCenter = { + x: right, + y: boundsCenter.y, + z: boundsCenter.z + }; + rollCenter = { + x: boundsCenter.x, + y: boundsCenter.y, + z: far + }; + + + Overlays.editOverlay(pitchHandle, { + url: ROTATE_ARROW_WEST_SOUTH_URL + }); + Overlays.editOverlay(rollHandle, { + url: ROTATE_ARROW_WEST_SOUTH_URL + }); - Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_SOUTH_URL }); - Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_SOUTH_URL }); - } else { - - yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 0, z: 0 }); - pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 }); - rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 90 }); - yawNormal = { x: 0, y: 1, z: 0 }; - pitchNormal = { x: 1, y: 0, z: 0 }; - rollNormal = { x: 0, y: 0, z: 1 }; + yawHandleRotation = Quat.fromVec3Degrees({ + x: 270, + y: 0, + z: 0 + }); + pitchHandleRotation = Quat.fromVec3Degrees({ + x: 180, + y: 270, + z: 0 + }); + rollHandleRotation = Quat.fromVec3Degrees({ + x: 0, + y: 0, + z: 90 + }); + + yawNormal = { + x: 0, + y: 1, + z: 0 + }; + pitchNormal = { + x: 1, + y: 0, + z: 0 + }; + rollNormal = { + x: 0, + y: 0, + z: 1 + }; - yawCorner = { x: left + rotateHandleOffset, - y: bottom - rotateHandleOffset, - z: far + rotateHandleOffset }; + yawCorner = { + x: left + rotateHandleOffset, + y: bottom - rotateHandleOffset, + z: far + rotateHandleOffset + }; - pitchCorner = { x: right - rotateHandleOffset, - y: top + rotateHandleOffset, - z: far + rotateHandleOffset }; + pitchCorner = { + x: right - rotateHandleOffset, + y: top + rotateHandleOffset, + z: far + rotateHandleOffset + }; - rollCorner = { x: left + rotateHandleOffset, - y: top + rotateHandleOffset, - z: near - rotateHandleOffset}; + rollCorner = { + x: left + rotateHandleOffset, + y: top + rotateHandleOffset, + z: near - rotateHandleOffset + }; - yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; - pitchCenter = { x: right, y: boundsCenter.y, z: boundsCenter.z }; - rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: near}; + yawCenter = { + x: boundsCenter.x, + y: bottom, + z: boundsCenter.z + }; + pitchCenter = { + x: right, + y: boundsCenter.y, + z: boundsCenter.z + }; + rollCenter = { + x: boundsCenter.x, + y: boundsCenter.y, + z: near + }; - Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); - Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); + Overlays.editOverlay(pitchHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); + Overlays.editOverlay(rollHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); } } else { - + // must be BLF or BLN if (cameraPosition.z < objectCenter.z) { - - yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 180, z: 0 }); - pitchHandleRotation = Quat.fromVec3Degrees({ x: 90, y: 0, z: 90 }); - rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 }); - yawNormal = { x: 0, y: 1, z: 0 }; - pitchNormal = { x: 1, y: 0, z: 0 }; - rollNormal = { x: 0, y: 0, z: 1 }; + yawHandleRotation = Quat.fromVec3Degrees({ + x: 270, + y: 180, + z: 0 + }); + pitchHandleRotation = Quat.fromVec3Degrees({ + x: 90, + y: 0, + z: 90 + }); + rollHandleRotation = Quat.fromVec3Degrees({ + x: 0, + y: 0, + z: 180 + }); - yawCorner = { x: right - rotateHandleOffset, - y: bottom - rotateHandleOffset, - z: near - rotateHandleOffset }; + yawNormal = { + x: 0, + y: 1, + z: 0 + }; + pitchNormal = { + x: 1, + y: 0, + z: 0 + }; + rollNormal = { + x: 0, + y: 0, + z: 1 + }; - pitchCorner = { x: left + rotateHandleOffset, - y: top + rotateHandleOffset, - z: near - rotateHandleOffset }; + yawCorner = { + x: right - rotateHandleOffset, + y: bottom - rotateHandleOffset, + z: near - rotateHandleOffset + }; - rollCorner = { x: right - rotateHandleOffset, - y: top + rotateHandleOffset, - z: far + rotateHandleOffset}; + pitchCorner = { + x: left + rotateHandleOffset, + y: top + rotateHandleOffset, + z: near - rotateHandleOffset + }; - yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; - pitchCenter = { x: left, y: boundsCenter.y, z: boundsCenter.z }; - rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: far}; + rollCorner = { + x: right - rotateHandleOffset, + y: top + rotateHandleOffset, + z: far + rotateHandleOffset + }; - Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); - Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); + yawCenter = { + x: boundsCenter.x, + y: bottom, + z: boundsCenter.z + }; + pitchCenter = { + x: left, + y: boundsCenter.y, + z: boundsCenter.z + }; + rollCenter = { + x: boundsCenter.x, + y: boundsCenter.y, + z: far + }; + + Overlays.editOverlay(pitchHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); + Overlays.editOverlay(rollHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); } else { - - yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 270, z: 0 }); - pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 }); - rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 }); - yawNormal = { x: 0, y: 1, z: 0 }; - rollNormal = { x: 0, y: 0, z: 1 }; - pitchNormal = { x: 1, y: 0, z: 0 }; + yawHandleRotation = Quat.fromVec3Degrees({ + x: 270, + y: 270, + z: 0 + }); + pitchHandleRotation = Quat.fromVec3Degrees({ + x: 180, + y: 270, + z: 0 + }); + rollHandleRotation = Quat.fromVec3Degrees({ + x: 0, + y: 0, + z: 180 + }); - yawCorner = { x: right - rotateHandleOffset, - y: bottom - rotateHandleOffset, - z: far + rotateHandleOffset }; + yawNormal = { + x: 0, + y: 1, + z: 0 + }; + rollNormal = { + x: 0, + y: 0, + z: 1 + }; + pitchNormal = { + x: 1, + y: 0, + z: 0 + }; - rollCorner = { x: right - rotateHandleOffset, - y: top + rotateHandleOffset, - z: near - rotateHandleOffset }; + yawCorner = { + x: right - rotateHandleOffset, + y: bottom - rotateHandleOffset, + z: far + rotateHandleOffset + }; - pitchCorner = { x: left + rotateHandleOffset, - y: top + rotateHandleOffset, - z: far + rotateHandleOffset}; + rollCorner = { + x: right - rotateHandleOffset, + y: top + rotateHandleOffset, + z: near - rotateHandleOffset + }; - yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; - rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: near }; - pitchCenter = { x: left, y: boundsCenter.y, z: boundsCenter.z}; + pitchCorner = { + x: left + rotateHandleOffset, + y: top + rotateHandleOffset, + z: far + rotateHandleOffset + }; - Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); - Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); + yawCenter = { + x: boundsCenter.x, + y: bottom, + z: boundsCenter.z + }; + rollCenter = { + x: boundsCenter.x, + y: boundsCenter.y, + z: near + }; + pitchCenter = { + x: left, + y: boundsCenter.y, + z: boundsCenter.z + }; + + Overlays.editOverlay(pitchHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); + Overlays.editOverlay(rollHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); } } - + var rotateHandlesVisible = true; var rotationOverlaysVisible = false; var translateHandlesVisible = true; @@ -984,20 +1457,38 @@ SelectionDisplay = (function () { rotateHandlesVisible = false; translateHandlesVisible = false; } - + var rotation = selectionManager.worldRotation; var dimensions = selectionManager.worldDimensions; var position = selectionManager.worldPosition; - - Overlays.editOverlay(rotateOverlayTarget, { visible: rotationOverlaysVisible }); - Overlays.editOverlay(rotateZeroOverlay, { visible: rotationOverlaysVisible }); - Overlays.editOverlay(rotateCurrentOverlay, { visible: rotationOverlaysVisible }); + + Overlays.editOverlay(rotateOverlayTarget, { + visible: rotationOverlaysVisible + }); + Overlays.editOverlay(rotateZeroOverlay, { + visible: rotationOverlaysVisible + }); + Overlays.editOverlay(rotateCurrentOverlay, { + visible: rotationOverlaysVisible + }); // TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden - Overlays.editOverlay(yawHandle, { visible: rotateHandlesVisible, position: yawCorner, rotation: yawHandleRotation}); - Overlays.editOverlay(pitchHandle, { visible: rotateHandlesVisible, position: pitchCorner, rotation: pitchHandleRotation}); - Overlays.editOverlay(rollHandle, { visible: rotateHandlesVisible, position: rollCorner, rotation: rollHandleRotation}); + Overlays.editOverlay(yawHandle, { + visible: rotateHandlesVisible, + position: yawCorner, + rotation: yawHandleRotation + }); + Overlays.editOverlay(pitchHandle, { + visible: rotateHandlesVisible, + position: pitchCorner, + rotation: pitchHandleRotation + }); + Overlays.editOverlay(rollHandle, { + visible: rotateHandlesVisible, + position: rollCorner, + rotation: rollHandleRotation + }); }; that.setSpaceMode = function(newSpaceMode) { @@ -1016,8 +1507,7 @@ SelectionDisplay = (function () { that.updateHandles(); }; - that.unselectAll = function () { - }; + that.unselectAll = function() {}; that.updateHandles = function() { if (SelectionManager.selections.length == 0) { @@ -1061,34 +1551,138 @@ SelectionDisplay = (function () { var worldTop = SelectionManager.worldDimensions.y / 2; - var LBN = { x: left, y: bottom, z: near }; - var RBN = { x: right, y: bottom, z: near }; - var LBF = { x: left, y: bottom, z: far }; - var RBF = { x: right, y: bottom, z: far }; - var LTN = { x: left, y: top, z: near }; - var RTN = { x: right, y: top, z: near }; - var LTF = { x: left, y: top, z: far }; - var RTF = { x: right, y: top, z: far }; + var LBN = { + x: left, + y: bottom, + z: near + }; + var RBN = { + x: right, + y: bottom, + z: near + }; + var LBF = { + x: left, + y: bottom, + z: far + }; + var RBF = { + x: right, + y: bottom, + z: far + }; + var LTN = { + x: left, + y: top, + z: near + }; + var RTN = { + x: right, + y: top, + z: near + }; + var LTF = { + x: left, + y: top, + z: far + }; + var RTF = { + x: right, + y: top, + z: far + }; - var TOP = { x: center.x, y: top, z: center.z }; - var BOTTOM = { x: center.x, y: bottom, z: center.z }; - var LEFT = { x: left, y: center.y, z: center.z }; - var RIGHT = { x: right, y: center.y, z: center.z }; - var NEAR = { x: center.x, y: center.y, z: near }; - var FAR = { x: center.x, y: center.y, z: far }; + var TOP = { + x: center.x, + y: top, + z: center.z + }; + var BOTTOM = { + x: center.x, + y: bottom, + z: center.z + }; + var LEFT = { + x: left, + y: center.y, + z: center.z + }; + var RIGHT = { + x: right, + y: center.y, + z: center.z + }; + var NEAR = { + x: center.x, + y: center.y, + z: near + }; + var FAR = { + x: center.x, + y: center.y, + z: far + }; - var EdgeTR = { x: right, y: top, z: center.z }; - var EdgeTL = { x: left, y: top, z: center.z }; - var EdgeTF = { x: center.x, y: top, z: front }; - var EdgeTN = { x: center.x, y: top, z: near }; - var EdgeBR = { x: right, y: bottom, z: center.z }; - var EdgeBL = { x: left, y: bottom, z: center.z }; - var EdgeBF = { x: center.x, y: bottom, z: front }; - var EdgeBN = { x: center.x, y: bottom, z: near }; - var EdgeNR = { x: right, y: center.y, z: near }; - var EdgeNL = { x: left, y: center.y, z: near }; - var EdgeFR = { x: right, y: center.y, z: front }; - var EdgeFL = { x: left, y: center.y, z: front }; + var EdgeTR = { + x: right, + y: top, + z: center.z + }; + var EdgeTL = { + x: left, + y: top, + z: center.z + }; + var EdgeTF = { + x: center.x, + y: top, + z: front + }; + var EdgeTN = { + x: center.x, + y: top, + z: near + }; + var EdgeBR = { + x: right, + y: bottom, + z: center.z + }; + var EdgeBL = { + x: left, + y: bottom, + z: center.z + }; + var EdgeBF = { + x: center.x, + y: bottom, + z: front + }; + var EdgeBN = { + x: center.x, + y: bottom, + z: near + }; + var EdgeNR = { + x: right, + y: center.y, + z: near + }; + var EdgeNL = { + x: left, + y: center.y, + z: near + }; + var EdgeFR = { + x: right, + y: center.y, + z: front + }; + var EdgeFL = { + x: left, + y: center.y, + z: front + }; LBN = Vec3.multiplyQbyV(rotation, LBN); RBN = Vec3.multiplyQbyV(rotation, RBN); @@ -1151,7 +1745,7 @@ SelectionDisplay = (function () { var stretchHandlesVisible = spaceMode == SPACE_LOCAL; var extendedStretchHandlesVisible = stretchHandlesVisible && showExtendedStretchHandles; - if (selectionManager.selections.length == 1 ) { + if (selectionManager.selections.length == 1) { var properties = Entities.getEntityProperties(selectionManager.selections[0]); if (properties.type == "Light" && properties.isSpotlight == true) { var stretchHandlesVisible = false; @@ -1190,7 +1784,11 @@ SelectionDisplay = (function () { }); Overlays.editOverlay(grabberSpotLightCircle, { position: NEAR, - dimensions: { x: distance, y: distance, z: 1 }, + dimensions: { + x: distance, + y: distance, + z: 1 + }, lineWidth: 1.5, rotation: rotation, visible: true, @@ -1217,15 +1815,33 @@ SelectionDisplay = (function () { visible: true, }); - Overlays.editOverlay(grabberPointLightCircleX, { visible: false }); - Overlays.editOverlay(grabberPointLightCircleY, { visible: false }); - Overlays.editOverlay(grabberPointLightCircleZ, { visible: false }); - Overlays.editOverlay(grabberPointLightT, { visible: false }); - Overlays.editOverlay(grabberPointLightB, { visible: false }); - Overlays.editOverlay(grabberPointLightL, { visible: false }); - Overlays.editOverlay(grabberPointLightR, { visible: false }); - Overlays.editOverlay(grabberPointLightF, { visible: false }); - Overlays.editOverlay(grabberPointLightN, { visible: false }); + Overlays.editOverlay(grabberPointLightCircleX, { + visible: false + }); + Overlays.editOverlay(grabberPointLightCircleY, { + visible: false + }); + Overlays.editOverlay(grabberPointLightCircleZ, { + visible: false + }); + Overlays.editOverlay(grabberPointLightT, { + visible: false + }); + Overlays.editOverlay(grabberPointLightB, { + visible: false + }); + Overlays.editOverlay(grabberPointLightL, { + visible: false + }); + Overlays.editOverlay(grabberPointLightR, { + visible: false + }); + Overlays.editOverlay(grabberPointLightF, { + visible: false + }); + Overlays.editOverlay(grabberPointLightN, { + visible: false + }); } else if (properties.type == "Light" && properties.isSpotlight == false) { var stretchHandlesVisible = false; var extendedStretchHandlesVisible = false; @@ -1262,75 +1878,203 @@ SelectionDisplay = (function () { Overlays.editOverlay(grabberPointLightCircleX, { position: position, rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(0, 90, 0)), - dimensions: { x: properties.dimensions.z / 2.0, y: properties.dimensions.z / 2.0, z: 1 }, + dimensions: { + x: properties.dimensions.z / 2.0, + y: properties.dimensions.z / 2.0, + z: 1 + }, visible: true, }); Overlays.editOverlay(grabberPointLightCircleY, { position: position, rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(90, 0, 0)), - dimensions: { x: properties.dimensions.z / 2.0, y: properties.dimensions.z / 2.0, z: 1 }, + dimensions: { + x: properties.dimensions.z / 2.0, + y: properties.dimensions.z / 2.0, + z: 1 + }, visible: true, }); Overlays.editOverlay(grabberPointLightCircleZ, { position: position, rotation: rotation, - dimensions: { x: properties.dimensions.z / 2.0, y: properties.dimensions.z / 2.0, z: 1 }, + dimensions: { + x: properties.dimensions.z / 2.0, + y: properties.dimensions.z / 2.0, + z: 1 + }, visible: true, }); - Overlays.editOverlay(grabberSpotLightRadius, { visible: false }); - Overlays.editOverlay(grabberSpotLightL, { visible: false }); - Overlays.editOverlay(grabberSpotLightR, { visible: false }); - Overlays.editOverlay(grabberSpotLightT, { visible: false }); - Overlays.editOverlay(grabberSpotLightB, { visible: false }); - Overlays.editOverlay(grabberSpotLightCircle, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineL, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineR, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineT, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineB, { visible: false }); + Overlays.editOverlay(grabberSpotLightRadius, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightL, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightR, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightT, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightB, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightCircle, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineL, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineR, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineT, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineB, { + visible: false + }); } else { - Overlays.editOverlay(grabberSpotLightCenter, { visible: false }); - Overlays.editOverlay(grabberSpotLightRadius, { visible: false }); - Overlays.editOverlay(grabberSpotLightL, { visible: false }); - Overlays.editOverlay(grabberSpotLightR, { visible: false }); - Overlays.editOverlay(grabberSpotLightT, { visible: false }); - Overlays.editOverlay(grabberSpotLightB, { visible: false }); - Overlays.editOverlay(grabberSpotLightCircle, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineL, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineR, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineT, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineB, { visible: false }); + Overlays.editOverlay(grabberSpotLightCenter, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightRadius, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightL, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightR, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightT, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightB, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightCircle, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineL, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineR, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineT, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineB, { + visible: false + }); - Overlays.editOverlay(grabberPointLightCircleX, { visible: false }); - Overlays.editOverlay(grabberPointLightCircleY, { visible: false }); - Overlays.editOverlay(grabberPointLightCircleZ, { visible: false }); - Overlays.editOverlay(grabberPointLightT, { visible: false }); - Overlays.editOverlay(grabberPointLightB, { visible: false }); - Overlays.editOverlay(grabberPointLightL, { visible: false }); - Overlays.editOverlay(grabberPointLightR, { visible: false }); - Overlays.editOverlay(grabberPointLightF, { visible: false }); - Overlays.editOverlay(grabberPointLightN, { visible: false }); + Overlays.editOverlay(grabberPointLightCircleX, { + visible: false + }); + Overlays.editOverlay(grabberPointLightCircleY, { + visible: false + }); + Overlays.editOverlay(grabberPointLightCircleZ, { + visible: false + }); + Overlays.editOverlay(grabberPointLightT, { + visible: false + }); + Overlays.editOverlay(grabberPointLightB, { + visible: false + }); + Overlays.editOverlay(grabberPointLightL, { + visible: false + }); + Overlays.editOverlay(grabberPointLightR, { + visible: false + }); + Overlays.editOverlay(grabberPointLightF, { + visible: false + }); + Overlays.editOverlay(grabberPointLightN, { + visible: false + }); } } - Overlays.editOverlay(grabberLBN, { visible: stretchHandlesVisible, rotation: rotation, position: LBN }); - Overlays.editOverlay(grabberRBN, { visible: stretchHandlesVisible, rotation: rotation, position: RBN }); - Overlays.editOverlay(grabberLBF, { visible: stretchHandlesVisible, rotation: rotation, position: LBF }); - Overlays.editOverlay(grabberRBF, { visible: stretchHandlesVisible, rotation: rotation, position: RBF }); + Overlays.editOverlay(grabberLBN, { + visible: stretchHandlesVisible, + rotation: rotation, + position: LBN + }); + Overlays.editOverlay(grabberRBN, { + visible: stretchHandlesVisible, + rotation: rotation, + position: RBN + }); + Overlays.editOverlay(grabberLBF, { + visible: stretchHandlesVisible, + rotation: rotation, + position: LBF + }); + Overlays.editOverlay(grabberRBF, { + visible: stretchHandlesVisible, + rotation: rotation, + position: RBF + }); - Overlays.editOverlay(grabberLTN, { visible: extendedStretchHandlesVisible, rotation: rotation, position: LTN }); - Overlays.editOverlay(grabberRTN, { visible: extendedStretchHandlesVisible, rotation: rotation, position: RTN }); - Overlays.editOverlay(grabberLTF, { visible: extendedStretchHandlesVisible, rotation: rotation, position: LTF }); - Overlays.editOverlay(grabberRTF, { visible: extendedStretchHandlesVisible, rotation: rotation, position: RTF }); + Overlays.editOverlay(grabberLTN, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: LTN + }); + Overlays.editOverlay(grabberRTN, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: RTN + }); + Overlays.editOverlay(grabberLTF, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: LTF + }); + Overlays.editOverlay(grabberRTF, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: RTF + }); - Overlays.editOverlay(grabberTOP, { visible: stretchHandlesVisible, rotation: rotation, position: TOP }); - Overlays.editOverlay(grabberBOTTOM, { visible: stretchHandlesVisible, rotation: rotation, position: BOTTOM }); - Overlays.editOverlay(grabberLEFT, { visible: extendedStretchHandlesVisible, rotation: rotation, position: LEFT }); - Overlays.editOverlay(grabberRIGHT, { visible: extendedStretchHandlesVisible, rotation: rotation, position: RIGHT }); - Overlays.editOverlay(grabberNEAR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: NEAR }); - Overlays.editOverlay(grabberFAR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: FAR }); + Overlays.editOverlay(grabberTOP, { + visible: stretchHandlesVisible, + rotation: rotation, + position: TOP + }); + Overlays.editOverlay(grabberBOTTOM, { + visible: stretchHandlesVisible, + rotation: rotation, + position: BOTTOM + }); + Overlays.editOverlay(grabberLEFT, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: LEFT + }); + Overlays.editOverlay(grabberRIGHT, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: RIGHT + }); + Overlays.editOverlay(grabberNEAR, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: NEAR + }); + Overlays.editOverlay(grabberFAR, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: FAR + }); var boxPosition = Vec3.multiplyQbyV(rotation, center); boxPosition = Vec3.sum(position, boxPosition); @@ -1346,9 +2090,17 @@ SelectionDisplay = (function () { for (var i = 0; i < overlaysNeeded; i++) { selectionBoxes.push( Overlays.addOverlay("cube", { - position: { x: 0, y: 0, z: 0 }, + position: { + x: 0, + y: 0, + z: 0 + }, size: 1, - color: { red: 255, green: 153, blue: 0 }, + color: { + red: 255, + green: 153, + blue: 0 + }, alpha: 1, solid: false, visible: false, @@ -1366,7 +2118,11 @@ SelectionDisplay = (function () { // Adjust overlay position to take registrationPoint into account // centeredRP = registrationPoint with range [-0.5, 0.5] - var centeredRP = Vec3.subtract(properties.registrationPoint, { x: 0.5, y: 0.5, z: 0.5 }); + var centeredRP = Vec3.subtract(properties.registrationPoint, { + x: 0.5, + y: 0.5, + z: 0.5 + }); var offset = vec3Mult(properties.dimensions, centeredRP); offset = Vec3.multiply(-1, offset); offset = Vec3.multiplyQbyV(properties.rotation, offset); @@ -1382,25 +2138,81 @@ SelectionDisplay = (function () { } // Hide any remaining selection boxes for (; i < selectionBoxes.length; i++) { - Overlays.editOverlay(selectionBoxes[i], { visible: false }); + Overlays.editOverlay(selectionBoxes[i], { + visible: false + }); } - Overlays.editOverlay(grabberEdgeTR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeTR }); - Overlays.editOverlay(grabberEdgeTL, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeTL }); - Overlays.editOverlay(grabberEdgeTF, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeTF }); - Overlays.editOverlay(grabberEdgeTN, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeTN }); - Overlays.editOverlay(grabberEdgeBR, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeBR }); - Overlays.editOverlay(grabberEdgeBL, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeBL }); - Overlays.editOverlay(grabberEdgeBF, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeBF }); - Overlays.editOverlay(grabberEdgeBN, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeBN }); - Overlays.editOverlay(grabberEdgeNR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeNR }); - Overlays.editOverlay(grabberEdgeNL, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeNL }); - Overlays.editOverlay(grabberEdgeFR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeFR }); - Overlays.editOverlay(grabberEdgeFL, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeFL }); + Overlays.editOverlay(grabberEdgeTR, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeTR + }); + Overlays.editOverlay(grabberEdgeTL, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeTL + }); + Overlays.editOverlay(grabberEdgeTF, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeTF + }); + Overlays.editOverlay(grabberEdgeTN, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeTN + }); + Overlays.editOverlay(grabberEdgeBR, { + visible: stretchHandlesVisible, + rotation: rotation, + position: EdgeBR + }); + Overlays.editOverlay(grabberEdgeBL, { + visible: stretchHandlesVisible, + rotation: rotation, + position: EdgeBL + }); + Overlays.editOverlay(grabberEdgeBF, { + visible: stretchHandlesVisible, + rotation: rotation, + position: EdgeBF + }); + Overlays.editOverlay(grabberEdgeBN, { + visible: stretchHandlesVisible, + rotation: rotation, + position: EdgeBN + }); + Overlays.editOverlay(grabberEdgeNR, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeNR + }); + Overlays.editOverlay(grabberEdgeNL, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeNL + }); + Overlays.editOverlay(grabberEdgeFR, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeFR + }); + Overlays.editOverlay(grabberEdgeFL, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeFL + }); var grabberMoveUpOffset = 0.1; - grabberMoveUpPosition = { x: position.x, y: position.y + worldTop + grabberMoveUpOffset, z: position.z } - Overlays.editOverlay(grabberMoveUp, { visible: activeTool == null || mode == "TRANSLATE_UP_DOWN" }); + grabberMoveUpPosition = { + x: position.x, + y: position.y + worldTop + grabberMoveUpOffset, + z: position.z + } + Overlays.editOverlay(grabberMoveUp, { + visible: activeTool == null || mode == "TRANSLATE_UP_DOWN" + }); Overlays.editOverlay(baseOfEntityProjectionOverlay, { visible: mode != "ROTATE_YAW" && mode != "ROTATE_PITCH" && mode != "ROTATE_ROLL", @@ -1423,16 +2235,19 @@ SelectionDisplay = (function () { that.setOverlaysVisible = function(isVisible) { var length = allOverlays.length; for (var i = 0; i < length; i++) { - Overlays.editOverlay(allOverlays[i], { visible: isVisible }); + Overlays.editOverlay(allOverlays[i], { + visible: isVisible + }); } length = selectionBoxes.length; for (var i = 0; i < length; i++) { - Overlays.editOverlay(selectionBoxes[i], { visible: isVisible }); + Overlays.editOverlay(selectionBoxes[i], { + visible: isVisible + }); } }; - that.unselect = function (entityID) { - }; + that.unselect = function(entityID) {}; var initialXZPick = null; var isConstrained = false; @@ -1447,7 +2262,11 @@ SelectionDisplay = (function () { var dimensions = SelectionManager.worldDimensions; var pickRay = Camera.computePickRay(event.x, event.y); - initialXZPick = rayPlaneIntersection(pickRay, startPosition, { x: 0, y: 1, z: 0 }); + initialXZPick = rayPlaneIntersection(pickRay, startPosition, { + x: 0, + y: 1, + z: 0 + }); // Duplicate entities if alt is pressed. This will make a // copy of the selected entities and move the _original_ entities, not @@ -1473,13 +2292,21 @@ SelectionDisplay = (function () { onEnd: function(event, reason) { pushCommandForSelections(duplicatedEntityIDs); - Overlays.editOverlay(xRailOverlay, { visible: false }); - Overlays.editOverlay(zRailOverlay, { visible: false }); + Overlays.editOverlay(xRailOverlay, { + visible: false + }); + Overlays.editOverlay(zRailOverlay, { + visible: false + }); }, onMove: function(event) { pickRay = Camera.computePickRay(event.x, event.y); - var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { x: 0, y: 1, z: 0 }); + var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { + x: 0, + y: 1, + z: 0 + }); var vector = Vec3.subtract(pick, initialXZPick); // If shifted, constrain to one axis @@ -1490,19 +2317,49 @@ SelectionDisplay = (function () { vector.x = 0; } if (!isConstrained) { - Overlays.editOverlay(xRailOverlay, { visible: true }); - var xStart = Vec3.sum(startPosition, { x: -10000, y: 0, z: 0 }); - var xEnd = Vec3.sum(startPosition, { x: 10000, y: 0, z: 0 }); - var zStart = Vec3.sum(startPosition, { x: 0, y: 0, z: -10000 }); - var zEnd = Vec3.sum(startPosition, { x: 0, y: 0, z: 10000 }); - Overlays.editOverlay(xRailOverlay, { start: xStart, end: xEnd, visible: true }); - Overlays.editOverlay(zRailOverlay, { start: zStart, end: zEnd, visible: true }); + Overlays.editOverlay(xRailOverlay, { + visible: true + }); + var xStart = Vec3.sum(startPosition, { + x: -10000, + y: 0, + z: 0 + }); + var xEnd = Vec3.sum(startPosition, { + x: 10000, + y: 0, + z: 0 + }); + var zStart = Vec3.sum(startPosition, { + x: 0, + y: 0, + z: -10000 + }); + var zEnd = Vec3.sum(startPosition, { + x: 0, + y: 0, + z: 10000 + }); + Overlays.editOverlay(xRailOverlay, { + start: xStart, + end: xEnd, + visible: true + }); + Overlays.editOverlay(zRailOverlay, { + start: zStart, + end: zEnd, + visible: true + }); isConstrained = true; } } else { if (isConstrained) { - Overlays.editOverlay(xRailOverlay, { visible: false }); - Overlays.editOverlay(zRailOverlay, { visible: false }); + Overlays.editOverlay(xRailOverlay, { + visible: false + }); + Overlays.editOverlay(zRailOverlay, { + visible: false + }); isConstrained = false; } } @@ -1510,14 +2367,18 @@ SelectionDisplay = (function () { constrainMajorOnly = event.isControl; var cornerPosition = Vec3.sum(startPosition, Vec3.multiply(-0.5, selectionManager.worldDimensions)); vector = Vec3.subtract( - grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), - cornerPosition); + grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), + cornerPosition); var wantDebug = false; for (var i = 0; i < SelectionManager.selections.length; i++) { var properties = SelectionManager.savedProperties[SelectionManager.selections[i]]; - var newPosition = Vec3.sum(properties.position, { x: vector.x, y: 0, z: vector.z }); + var newPosition = Vec3.sum(properties.position, { + x: vector.x, + y: 0, + z: vector.z + }); Entities.editEntity(SelectionManager.selections[i], { position: newPosition, }); @@ -1533,7 +2394,7 @@ SelectionDisplay = (function () { SelectionManager._update(); } }; - + var lastXYPick = null var upDownPickNormal = null; addGrabberTool(grabberMoveUp, { @@ -1579,11 +2440,11 @@ SelectionDisplay = (function () { var vector = Vec3.subtract(newIntersection, lastXYPick); vector = grid.snapToGrid(vector); - + // we only care about the Y axis vector.x = 0; vector.z = 0; - + var wantDebug = false; if (wantDebug) { print("translateUpDown... "); @@ -1609,12 +2470,16 @@ SelectionDisplay = (function () { }); var vec3Mult = function(v1, v2) { - return { x: v1.x * v2.x, y: v1.y * v2.y, z: v1.z * v2.z }; - } - // stretchMode - name of mode - // direction - direction to stretch in - // pivot - point to use as a pivot - // offset - the position of the overlay tool relative to the selections center position + return { + x: v1.x * v2.x, + y: v1.y * v2.y, + z: v1.z * v2.z + }; + } + // stretchMode - name of mode + // direction - direction to stretch in + // pivot - point to use as a pivot + // offset - the position of the overlay tool relative to the selections center position var makeStretchTool = function(stretchMode, direction, pivot, offset, customOnMove) { var signs = { x: direction.x < 0 ? -1 : (direction.x > 0 ? 1 : 0), @@ -1659,7 +2524,11 @@ SelectionDisplay = (function () { } // Modify range of registrationPoint to be [-0.5, 0.5] - var centeredRP = Vec3.subtract(registrationPoint, { x: 0.5, y: 0.5, z: 0.5 }); + var centeredRP = Vec3.subtract(registrationPoint, { + x: 0.5, + y: 0.5, + z: 0.5 + }); // Scale pivot to be in the same range as registrationPoint var scaledPivot = Vec3.multiply(0.5, pivot) @@ -1675,9 +2544,17 @@ SelectionDisplay = (function () { pickRayPosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld)); if (numDimensions == 1 && mask.x) { - var start = Vec3.multiplyQbyV(rotation, { x: -10000, y: 0, z: 0 }); + var start = Vec3.multiplyQbyV(rotation, { + x: -10000, + y: 0, + z: 0 + }); start = Vec3.sum(start, properties.position); - var end = Vec3.multiplyQbyV(rotation, { x: 10000, y: 0, z: 0 }); + var end = Vec3.multiplyQbyV(rotation, { + x: 10000, + y: 0, + z: 0 + }); end = Vec3.sum(end, properties.position); Overlays.editOverlay(xRailOverlay, { start: start, @@ -1686,9 +2563,17 @@ SelectionDisplay = (function () { }); } if (numDimensions == 1 && mask.y) { - var start = Vec3.multiplyQbyV(rotation, { x: 0, y: -10000, z: 0 }); + var start = Vec3.multiplyQbyV(rotation, { + x: 0, + y: -10000, + z: 0 + }); start = Vec3.sum(start, properties.position); - var end = Vec3.multiplyQbyV(rotation, { x: 0, y: 10000, z: 0 }); + var end = Vec3.multiplyQbyV(rotation, { + x: 0, + y: 10000, + z: 0 + }); end = Vec3.sum(end, properties.position); Overlays.editOverlay(yRailOverlay, { start: start, @@ -1697,9 +2582,17 @@ SelectionDisplay = (function () { }); } if (numDimensions == 1 && mask.z) { - var start = Vec3.multiplyQbyV(rotation, { x: 0, y: 0, z: -10000 }); + var start = Vec3.multiplyQbyV(rotation, { + x: 0, + y: 0, + z: -10000 + }); start = Vec3.sum(start, properties.position); - var end = Vec3.multiplyQbyV(rotation, { x: 0, y: 0, z: 10000 }); + var end = Vec3.multiplyQbyV(rotation, { + x: 0, + y: 0, + z: 10000 + }); end = Vec3.sum(end, properties.position); Overlays.editOverlay(zRailOverlay, { start: start, @@ -1709,26 +2602,50 @@ SelectionDisplay = (function () { } if (numDimensions == 1) { if (mask.x == 1) { - planeNormal = { x: 0, y: 1, z: 0 }; + planeNormal = { + x: 0, + y: 1, + z: 0 + }; } else if (mask.y == 1) { - planeNormal = { x: 1, y: 0, z: 0 }; + planeNormal = { + x: 1, + y: 0, + z: 0 + }; } else { - planeNormal = { x: 0, y: 1, z: 0 }; + planeNormal = { + x: 0, + y: 1, + z: 0 + }; } } else if (numDimensions == 2) { if (mask.x == 0) { - planeNormal = { x: 1, y: 0, z: 0 }; + planeNormal = { + x: 1, + y: 0, + z: 0 + }; } else if (mask.y == 0) { - planeNormal = { x: 0, y: 1, z: 0 }; + planeNormal = { + x: 0, + y: 1, + z: 0 + }; } else { - planeNormal = { x: 0, y: 0, z: z }; + planeNormal = { + x: 0, + y: 0, + z: z + }; } } planeNormal = Vec3.multiplyQbyV(rotation, planeNormal); var pickRay = Camera.computePickRay(event.x, event.y); lastPick = rayPlaneIntersection(pickRay, - pickRayPosition, - planeNormal); + pickRayPosition, + planeNormal); // Overlays.editOverlay(normalLine, { // start: initialPosition, @@ -1739,9 +2656,15 @@ SelectionDisplay = (function () { }; var onEnd = function(event, reason) { - Overlays.editOverlay(xRailOverlay, { visible: false }); - Overlays.editOverlay(yRailOverlay, { visible: false }); - Overlays.editOverlay(zRailOverlay, { visible: false }); + Overlays.editOverlay(xRailOverlay, { + visible: false + }); + Overlays.editOverlay(yRailOverlay, { + visible: false + }); + Overlays.editOverlay(zRailOverlay, { + visible: false + }); pushCommandForSelections(); }; @@ -1762,8 +2685,8 @@ SelectionDisplay = (function () { var pickRay = Camera.computePickRay(event.x, event.y); newPick = rayPlaneIntersection(pickRay, - pickRayPosition, - planeNormal); + pickRayPosition, + planeNormal); var vector = Vec3.subtract(newPick, lastPick); vector = Vec3.multiplyQbyV(Quat.inverse(rotation), vector); @@ -1798,14 +2721,14 @@ SelectionDisplay = (function () { } else { newDimensions = Vec3.sum(initialDimensions, changeInDimensions); } - + newDimensions.x = Math.max(newDimensions.x, MINIMUM_DIMENSION); newDimensions.y = Math.max(newDimensions.y, MINIMUM_DIMENSION); newDimensions.z = Math.max(newDimensions.z, MINIMUM_DIMENSION); - + var changeInPosition = Vec3.multiplyQbyV(rotation, vec3Mult(deltaPivot, changeInDimensions)); var newPosition = Vec3.sum(initialPosition, changeInPosition); - + for (var i = 0; i < SelectionManager.selections.length; i++) { Entities.editEntity(SelectionManager.selections[i], { position: newPosition, @@ -1882,7 +2805,11 @@ SelectionDisplay = (function () { size = props.dimensions.z + change.z; } - var newDimensions = { x: size, y: size, z: size }; + var newDimensions = { + x: size, + y: size, + z: size + }; Entities.editEntity(selectionManager.selections[0], { dimensions: newDimensions, @@ -1891,47 +2818,411 @@ SelectionDisplay = (function () { SelectionManager._update(); } - addStretchTool(grabberNEAR, "STRETCH_NEAR", { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }); - addStretchTool(grabberFAR, "STRETCH_FAR", { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 }); - addStretchTool(grabberTOP, "STRETCH_TOP", { x: 0, y: -1, z: 0 }, { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }); - addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { x: 0, y: 1, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 }); - addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { x: -1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }); - addStretchTool(grabberLEFT, "STRETCH_LEFT", { x: 1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }); + addStretchTool(grabberNEAR, "STRETCH_NEAR", { + x: 0, + y: 0, + z: 1 + }, { + x: 0, + y: 0, + z: 1 + }, { + x: 0, + y: 0, + z: -1 + }); + addStretchTool(grabberFAR, "STRETCH_FAR", { + x: 0, + y: 0, + z: -1 + }, { + x: 0, + y: 0, + z: -1 + }, { + x: 0, + y: 0, + z: 1 + }); + addStretchTool(grabberTOP, "STRETCH_TOP", { + x: 0, + y: -1, + z: 0 + }, { + x: 0, + y: -1, + z: 0 + }, { + x: 0, + y: 1, + z: 0 + }); + addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { + x: 0, + y: 1, + z: 0 + }, { + x: 0, + y: 1, + z: 0 + }, { + x: 0, + y: -1, + z: 0 + }); + addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { + x: -1, + y: 0, + z: 0 + }, { + x: -1, + y: 0, + z: 0 + }, { + x: 1, + y: 0, + z: 0 + }); + addStretchTool(grabberLEFT, "STRETCH_LEFT", { + x: 1, + y: 0, + z: 0 + }, { + x: 1, + y: 0, + z: 0 + }, { + x: -1, + y: 0, + z: 0 + }); - addStretchTool(grabberSpotLightRadius, "STRETCH_RADIUS", { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }); - addStretchTool(grabberSpotLightT, "STRETCH_CUTOFF_T", { x: 0, y: 0, z: 0 }, { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }, cutoffStretchFunc); - addStretchTool(grabberSpotLightB, "STRETCH_CUTOFF_B", { x: 0, y: 0, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 }, cutoffStretchFunc); - addStretchTool(grabberSpotLightL, "STRETCH_CUTOFF_L", { x: 0, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, cutoffStretchFunc); - addStretchTool(grabberSpotLightR, "STRETCH_CUTOFF_R", { x: 0, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, cutoffStretchFunc); + addStretchTool(grabberSpotLightRadius, "STRETCH_RADIUS", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, { + x: 0, + y: 0, + z: -1 + }); + addStretchTool(grabberSpotLightT, "STRETCH_CUTOFF_T", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: -1, + z: 0 + }, { + x: 0, + y: 1, + z: 0 + }, cutoffStretchFunc); + addStretchTool(grabberSpotLightB, "STRETCH_CUTOFF_B", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 1, + z: 0 + }, { + x: 0, + y: -1, + z: 0 + }, cutoffStretchFunc); + addStretchTool(grabberSpotLightL, "STRETCH_CUTOFF_L", { + x: 0, + y: 0, + z: 0 + }, { + x: 1, + y: 0, + z: 0 + }, { + x: -1, + y: 0, + z: 0 + }, cutoffStretchFunc); + addStretchTool(grabberSpotLightR, "STRETCH_CUTOFF_R", { + x: 0, + y: 0, + z: 0 + }, { + x: -1, + y: 0, + z: 0 + }, { + x: 1, + y: 0, + z: 0 + }, cutoffStretchFunc); - addStretchTool(grabberPointLightT, "STRETCH_RADIUS_T", { x: 0, y: 0, z: 0 }, { x: 0, y: -1, z: 0 }, { x: 0, y: 0, z: 1 }, radiusStretchFunc); - addStretchTool(grabberPointLightB, "STRETCH_RADIUS_B", { x: 0, y: 0, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 0, y: 0, z: 1 }, radiusStretchFunc); - addStretchTool(grabberPointLightL, "STRETCH_RADIUS_L", { x: 0, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: 0, y: 0, z: 1 }, radiusStretchFunc); - addStretchTool(grabberPointLightR, "STRETCH_RADIUS_R", { x: 0, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 0, y: 0, z: 1 }, radiusStretchFunc); - addStretchTool(grabberPointLightF, "STRETCH_RADIUS_F", { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 }, radiusStretchFunc); - addStretchTool(grabberPointLightN, "STRETCH_RADIUS_N", { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }, radiusStretchFunc); + addStretchTool(grabberPointLightT, "STRETCH_RADIUS_T", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: -1, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, radiusStretchFunc); + addStretchTool(grabberPointLightB, "STRETCH_RADIUS_B", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 1, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, radiusStretchFunc); + addStretchTool(grabberPointLightL, "STRETCH_RADIUS_L", { + x: 0, + y: 0, + z: 0 + }, { + x: 1, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, radiusStretchFunc); + addStretchTool(grabberPointLightR, "STRETCH_RADIUS_R", { + x: 0, + y: 0, + z: 0 + }, { + x: -1, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, radiusStretchFunc); + addStretchTool(grabberPointLightF, "STRETCH_RADIUS_F", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: -1 + }, { + x: 0, + y: 0, + z: 1 + }, radiusStretchFunc); + addStretchTool(grabberPointLightN, "STRETCH_RADIUS_N", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, { + x: 0, + y: 0, + z: -1 + }, radiusStretchFunc); - addStretchTool(grabberLBN, "STRETCH_LBN", null, {x: 1, y: 0, z: 1}, { x: -1, y: -1, z: -1 }); - addStretchTool(grabberRBN, "STRETCH_RBN", null, {x: -1, y: 0, z: 1}, { x: 1, y: -1, z: -1 }); - addStretchTool(grabberLBF, "STRETCH_LBF", null, {x: 1, y: 0, z: -1}, { x: -1, y: -1, z: 1 }); - addStretchTool(grabberRBF, "STRETCH_RBF", null, {x: -1, y: 0, z: -1}, { x: 1, y: -1, z: 1 }); - addStretchTool(grabberLTN, "STRETCH_LTN", null, {x: 1, y: 0, z: 1}, { x: -1, y: 1, z: -1 }); - addStretchTool(grabberRTN, "STRETCH_RTN", null, {x: -1, y: 0, z: 1}, { x: 1, y: 1, z: -1 }); - addStretchTool(grabberLTF, "STRETCH_LTF", null, {x: 1, y: 0, z: -1}, { x: -1, y: 1, z: 1 }); - addStretchTool(grabberRTF, "STRETCH_RTF", null, {x: -1, y: 0, z: -1}, { x: 1, y: 1, z: 1 }); + addStretchTool(grabberLBN, "STRETCH_LBN", null, { + x: 1, + y: 0, + z: 1 + }, { + x: -1, + y: -1, + z: -1 + }); + addStretchTool(grabberRBN, "STRETCH_RBN", null, { + x: -1, + y: 0, + z: 1 + }, { + x: 1, + y: -1, + z: -1 + }); + addStretchTool(grabberLBF, "STRETCH_LBF", null, { + x: 1, + y: 0, + z: -1 + }, { + x: -1, + y: -1, + z: 1 + }); + addStretchTool(grabberRBF, "STRETCH_RBF", null, { + x: -1, + y: 0, + z: -1 + }, { + x: 1, + y: -1, + z: 1 + }); + addStretchTool(grabberLTN, "STRETCH_LTN", null, { + x: 1, + y: 0, + z: 1 + }, { + x: -1, + y: 1, + z: -1 + }); + addStretchTool(grabberRTN, "STRETCH_RTN", null, { + x: -1, + y: 0, + z: 1 + }, { + x: 1, + y: 1, + z: -1 + }); + addStretchTool(grabberLTF, "STRETCH_LTF", null, { + x: 1, + y: 0, + z: -1 + }, { + x: -1, + y: 1, + z: 1 + }); + addStretchTool(grabberRTF, "STRETCH_RTF", null, { + x: -1, + y: 0, + z: -1 + }, { + x: 1, + y: 1, + z: 1 + }); - addStretchTool(grabberEdgeTR, "STRETCH_EdgeTR", null, {x: 1, y: 1, z: 0}, { x: 1, y: 1, z: 0 }); - addStretchTool(grabberEdgeTL, "STRETCH_EdgeTL", null, {x: -1, y: 1, z: 0}, { x: -1, y: 1, z: 0 }); - addStretchTool(grabberEdgeTF, "STRETCH_EdgeTF", null, {x: 0, y: 1, z: -1}, { x: 0, y: 1, z: -1 }); - addStretchTool(grabberEdgeTN, "STRETCH_EdgeTN", null, {x: 0, y: 1, z: 1}, { x: 0, y: 1, z: 1 }); - addStretchTool(grabberEdgeBR, "STRETCH_EdgeBR", null, {x: -1, y: 0, z: 0}, { x: 1, y: -1, z: 0 }); - addStretchTool(grabberEdgeBL, "STRETCH_EdgeBL", null, {x: 1, y: 0, z: 0}, { x: -1, y: -1, z: 0 }); - addStretchTool(grabberEdgeBF, "STRETCH_EdgeBF", null, {x: 0, y: 0, z: -1}, { x: 0, y: -1, z: -1 }); - addStretchTool(grabberEdgeBN, "STRETCH_EdgeBN", null, {x: 0, y: 0, z: 1}, { x: 0, y: -1, z: 1 }); - addStretchTool(grabberEdgeNR, "STRETCH_EdgeNR", null, {x: -1, y: 0, z: 1}, { x: 1, y: 0, z: -1 }); - addStretchTool(grabberEdgeNL, "STRETCH_EdgeNL", null, {x: 1, y: 0, z: 1}, { x: -1, y: 0, z: -1 }); - addStretchTool(grabberEdgeFR, "STRETCH_EdgeFR", null, {x: -1, y: 0, z: -1}, { x: 1, y: 0, z: 1 }); - addStretchTool(grabberEdgeFL, "STRETCH_EdgeFL", null, {x: 1, y: 0, z: -1}, { x: -1, y: 0, z: 1 }); + addStretchTool(grabberEdgeTR, "STRETCH_EdgeTR", null, { + x: 1, + y: 1, + z: 0 + }, { + x: 1, + y: 1, + z: 0 + }); + addStretchTool(grabberEdgeTL, "STRETCH_EdgeTL", null, { + x: -1, + y: 1, + z: 0 + }, { + x: -1, + y: 1, + z: 0 + }); + addStretchTool(grabberEdgeTF, "STRETCH_EdgeTF", null, { + x: 0, + y: 1, + z: -1 + }, { + x: 0, + y: 1, + z: -1 + }); + addStretchTool(grabberEdgeTN, "STRETCH_EdgeTN", null, { + x: 0, + y: 1, + z: 1 + }, { + x: 0, + y: 1, + z: 1 + }); + addStretchTool(grabberEdgeBR, "STRETCH_EdgeBR", null, { + x: -1, + y: 0, + z: 0 + }, { + x: 1, + y: -1, + z: 0 + }); + addStretchTool(grabberEdgeBL, "STRETCH_EdgeBL", null, { + x: 1, + y: 0, + z: 0 + }, { + x: -1, + y: -1, + z: 0 + }); + addStretchTool(grabberEdgeBF, "STRETCH_EdgeBF", null, { + x: 0, + y: 0, + z: -1 + }, { + x: 0, + y: -1, + z: -1 + }); + addStretchTool(grabberEdgeBN, "STRETCH_EdgeBN", null, { + x: 0, + y: 0, + z: 1 + }, { + x: 0, + y: -1, + z: 1 + }); + addStretchTool(grabberEdgeNR, "STRETCH_EdgeNR", null, { + x: -1, + y: 0, + z: 1 + }, { + x: 1, + y: 0, + z: -1 + }); + addStretchTool(grabberEdgeNL, "STRETCH_EdgeNL", null, { + x: 1, + y: 0, + z: 1 + }, { + x: -1, + y: 0, + z: -1 + }); + addStretchTool(grabberEdgeFR, "STRETCH_EdgeFR", null, { + x: -1, + y: 0, + z: -1 + }, { + x: 1, + y: 0, + z: 1 + }); + addStretchTool(grabberEdgeFL, "STRETCH_EdgeFL", null, { + x: 1, + y: 0, + z: -1 + }, { + x: -1, + y: 0, + z: 1 + }); function updateRotationDegreesOverlay(angleFromZero, handleRotation, centerPosition) { var angle = angleFromZero * (Math.PI / 180); @@ -1967,34 +3258,31 @@ SelectionDisplay = (function () { outerRadius = diagonal * 1.15; var innerAlpha = 0.2; var outerAlpha = 0.2; - Overlays.editOverlay(rotateOverlayInner, - { - visible: true, - size: innerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: innerAlpha - }); + Overlays.editOverlay(rotateOverlayInner, { + visible: true, + size: innerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: innerAlpha + }); - Overlays.editOverlay(rotateOverlayOuter, - { - visible: true, - size: outerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: outerAlpha, - }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: true, + size: outerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: outerAlpha, + }); - Overlays.editOverlay(rotateOverlayCurrent, - { - visible: true, - size: outerRadius, - startAt: 0, - endAt: 0, - innerRadius: 0.9, - }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: true, + size: outerRadius, + startAt: 0, + endAt: 0, + innerRadius: 0.9, + }); Overlays.editOverlay(rotationDegreesDisplay, { visible: true, @@ -2003,19 +3291,35 @@ SelectionDisplay = (function () { updateRotationDegreesOverlay(0, yawHandleRotation, yawCenter); }, onEnd: function(event, reason) { - Overlays.editOverlay(rotateOverlayInner, { visible: false }); - Overlays.editOverlay(rotateOverlayOuter, { visible: false }); - Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); - Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); + Overlays.editOverlay(rotateOverlayInner, { + visible: false + }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: false + }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: false + }); + Overlays.editOverlay(rotationDegreesDisplay, { + visible: false + }); pushCommandForSelections(); }, onMove: function(event) { var pickRay = Camera.computePickRay(event.x, event.y); - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); - Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); - Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); - + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(baseOfEntityProjectionOverlay, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(rotateOverlayTarget, { + ignoreRayIntersection: false + }); + var result = Overlays.findRayIntersection(pickRay); if (result.intersects) { @@ -2028,7 +3332,11 @@ SelectionDisplay = (function () { var snapToInner = distanceFromCenter < innerRadius; var snapAngle = snapToInner ? innerSnapAngle : 1.0; angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 }); + var yawChange = Quat.fromVec3Degrees({ + x: 0, + y: angleFromZero, + z: 0 + }); // Entities should only reposition if we are rotating multiple selections around // the selections center point. Otherwise, the rotation will be around the entities @@ -2066,19 +3374,43 @@ SelectionDisplay = (function () { endAtRemainder = startAtCurrent; } if (snapToInner) { - Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius, - majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0, - majorTickMarksLength: -0.25, minorTickMarksLength: 0, }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: innerRadius, + majorTickMarksAngle: innerSnapAngle, + minorTickMarksAngle: 0, + majorTickMarksLength: -0.25, + minorTickMarksLength: 0, + }); } else { - Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius, - majorTickMarksAngle: 45.0, minorTickMarksAngle: 5, - majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: outerRadius, + majorTickMarksAngle: 45.0, + minorTickMarksAngle: 5, + majorTickMarksLength: 0.25, + minorTickMarksLength: 0.1, + }); } - + } } }); @@ -2096,34 +3428,31 @@ SelectionDisplay = (function () { outerRadius = diagonal * 1.15; var innerAlpha = 0.2; var outerAlpha = 0.2; - Overlays.editOverlay(rotateOverlayInner, - { - visible: true, - size: innerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: innerAlpha - }); + Overlays.editOverlay(rotateOverlayInner, { + visible: true, + size: innerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: innerAlpha + }); - Overlays.editOverlay(rotateOverlayOuter, - { - visible: true, - size: outerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: outerAlpha, - }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: true, + size: outerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: outerAlpha, + }); - Overlays.editOverlay(rotateOverlayCurrent, - { - visible: true, - size: outerRadius, - startAt: 0, - endAt: 0, - innerRadius: 0.9, - }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: true, + size: outerRadius, + startAt: 0, + endAt: 0, + innerRadius: 0.9, + }); Overlays.editOverlay(rotationDegreesDisplay, { visible: true, @@ -2132,18 +3461,34 @@ SelectionDisplay = (function () { updateRotationDegreesOverlay(0, pitchHandleRotation, pitchCenter); }, onEnd: function(event, reason) { - Overlays.editOverlay(rotateOverlayInner, { visible: false }); - Overlays.editOverlay(rotateOverlayOuter, { visible: false }); - Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); - Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); + Overlays.editOverlay(rotateOverlayInner, { + visible: false + }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: false + }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: false + }); + Overlays.editOverlay(rotationDegreesDisplay, { + visible: false + }); pushCommandForSelections(); }, onMove: function(event) { var pickRay = Camera.computePickRay(event.x, event.y); - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); - Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); - Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(baseOfEntityProjectionOverlay, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(rotateOverlayTarget, { + ignoreRayIntersection: false + }); var result = Overlays.findRayIntersection(pickRay); if (result.intersects) { @@ -2158,8 +3503,12 @@ SelectionDisplay = (function () { var snapToInner = distanceFromCenter < innerRadius; var snapAngle = snapToInner ? innerSnapAngle : 1.0; angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - - var pitchChange = Quat.fromVec3Degrees({ x: angleFromZero, y: 0, z: 0 }); + + var pitchChange = Quat.fromVec3Degrees({ + x: angleFromZero, + y: 0, + z: 0 + }); for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; @@ -2188,17 +3537,41 @@ SelectionDisplay = (function () { endAtRemainder = startAtCurrent; } if (snapToInner) { - Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius, - majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0, - majorTickMarksLength: -0.25, minorTickMarksLength: 0, }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: innerRadius, + majorTickMarksAngle: innerSnapAngle, + minorTickMarksAngle: 0, + majorTickMarksLength: -0.25, + minorTickMarksLength: 0, + }); } else { - Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius, - majorTickMarksAngle: 45.0, minorTickMarksAngle: 5, - majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: outerRadius, + majorTickMarksAngle: 45.0, + minorTickMarksAngle: 5, + majorTickMarksLength: 0.25, + minorTickMarksLength: 0.1, + }); } } } @@ -2217,34 +3590,31 @@ SelectionDisplay = (function () { outerRadius = diagonal * 1.15; var innerAlpha = 0.2; var outerAlpha = 0.2; - Overlays.editOverlay(rotateOverlayInner, - { - visible: true, - size: innerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: innerAlpha - }); + Overlays.editOverlay(rotateOverlayInner, { + visible: true, + size: innerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: innerAlpha + }); - Overlays.editOverlay(rotateOverlayOuter, - { - visible: true, - size: outerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: outerAlpha, - }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: true, + size: outerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: outerAlpha, + }); - Overlays.editOverlay(rotateOverlayCurrent, - { - visible: true, - size: outerRadius, - startAt: 0, - endAt: 0, - innerRadius: 0.9, - }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: true, + size: outerRadius, + startAt: 0, + endAt: 0, + innerRadius: 0.9, + }); Overlays.editOverlay(rotationDegreesDisplay, { visible: true, @@ -2253,18 +3623,34 @@ SelectionDisplay = (function () { updateRotationDegreesOverlay(0, rollHandleRotation, rollCenter); }, onEnd: function(event, reason) { - Overlays.editOverlay(rotateOverlayInner, { visible: false }); - Overlays.editOverlay(rotateOverlayOuter, { visible: false }); - Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); - Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); + Overlays.editOverlay(rotateOverlayInner, { + visible: false + }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: false + }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: false + }); + Overlays.editOverlay(rotationDegreesDisplay, { + visible: false + }); pushCommandForSelections(); }, onMove: function(event) { var pickRay = Camera.computePickRay(event.x, event.y); - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); - Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); - Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(baseOfEntityProjectionOverlay, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(rotateOverlayTarget, { + ignoreRayIntersection: false + }); var result = Overlays.findRayIntersection(pickRay); if (result.intersects) { @@ -2280,7 +3666,11 @@ SelectionDisplay = (function () { var snapAngle = snapToInner ? innerSnapAngle : 1.0; angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - var rollChange = Quat.fromVec3Degrees({ x: 0, y: 0, z: angleFromZero }); + var rollChange = Quat.fromVec3Degrees({ + x: 0, + y: 0, + z: angleFromZero + }); for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; var properties = Entities.getEntityProperties(entityID); @@ -2308,17 +3698,41 @@ SelectionDisplay = (function () { endAtRemainder = startAtCurrent; } if (snapToInner) { - Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius, - majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0, - majorTickMarksLength: -0.25, minorTickMarksLength: 0, }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: innerRadius, + majorTickMarksAngle: innerSnapAngle, + minorTickMarksAngle: 0, + majorTickMarksLength: -0.25, + minorTickMarksLength: 0, + }); } else { - Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius, - majorTickMarksAngle: 45.0, minorTickMarksAngle: 5, - majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: outerRadius, + majorTickMarksAngle: 45.0, + minorTickMarksAngle: 5, + majorTickMarksLength: 0.25, + minorTickMarksLength: 0.1, + }); } } } @@ -2329,10 +3743,10 @@ SelectionDisplay = (function () { // FIXME - this cause problems with editing in the entity properties window //SelectionManager._update(); - + if (!Vec3.equal(Camera.getPosition(), lastCameraPosition) || !Quat.equal(Camera.getOrientation(), lastCameraOrientation)) { - + that.updateRotationHandles(); } } @@ -2347,12 +3761,20 @@ SelectionDisplay = (function () { var somethingClicked = false; var pickRay = Camera.computePickRay(event.x, event.y); - + // before we do a ray test for grabbers, disable the ray intersection for our selection box - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true }); - Overlays.editOverlay(yawHandle, { ignoreRayIntersection: true }); - Overlays.editOverlay(pitchHandle, { ignoreRayIntersection: true }); - Overlays.editOverlay(rollHandle, { ignoreRayIntersection: true }); + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: true + }); + Overlays.editOverlay(yawHandle, { + ignoreRayIntersection: true + }); + Overlays.editOverlay(pitchHandle, { + ignoreRayIntersection: true + }); + Overlays.editOverlay(rollHandle, { + ignoreRayIntersection: true + }); var result = Overlays.findRayIntersection(pickRay); if (result.intersects) { @@ -2377,14 +3799,16 @@ SelectionDisplay = (function () { activeTool.onBegin(event); } } else { - switch(result.overlayID) { + switch (result.overlayID) { case grabberMoveUp: mode = "TRANSLATE_UP_DOWN"; somethingClicked = true; // in translate mode, we hide our stretch handles... for (var i = 0; i < stretchHandles.length; i++) { - Overlays.editOverlay(stretchHandles[i], { visible: false }); + Overlays.editOverlay(stretchHandles[i], { + visible: false + }); } break; @@ -2397,8 +3821,8 @@ SelectionDisplay = (function () { break; case grabberFAR: - case grabberEdgeTF: // TODO: maybe this should be TOP+FAR stretching? - case grabberEdgeBF: // TODO: maybe this should be BOTTOM+FAR stretching? + case grabberEdgeTF: // TODO: maybe this should be TOP+FAR stretching? + case grabberEdgeBF: // TODO: maybe this should be BOTTOM+FAR stretching? mode = "STRETCH_FAR"; somethingClicked = true; break; @@ -2411,14 +3835,14 @@ SelectionDisplay = (function () { somethingClicked = true; break; case grabberRIGHT: - case grabberEdgeTR: // TODO: maybe this should be TOP+RIGHT stretching? - case grabberEdgeBR: // TODO: maybe this should be BOTTOM+RIGHT stretching? + case grabberEdgeTR: // TODO: maybe this should be TOP+RIGHT stretching? + case grabberEdgeBR: // TODO: maybe this should be BOTTOM+RIGHT stretching? mode = "STRETCH_RIGHT"; somethingClicked = true; break; case grabberLEFT: - case grabberEdgeTL: // TODO: maybe this should be TOP+LEFT stretching? - case grabberEdgeBL: // TODO: maybe this should be BOTTOM+LEFT stretching? + case grabberEdgeTL: // TODO: maybe this should be TOP+LEFT stretching? + case grabberEdgeBL: // TODO: maybe this should be BOTTOM+LEFT stretching? mode = "STRETCH_LEFT"; somethingClicked = true; break; @@ -2429,29 +3853,43 @@ SelectionDisplay = (function () { } } } - + // if one of the items above was clicked, then we know we are in translate or stretch mode, and we // should hide our rotate handles... if (somethingClicked) { - Overlays.editOverlay(yawHandle, { visible: false }); - Overlays.editOverlay(pitchHandle, { visible: false }); - Overlays.editOverlay(rollHandle, { visible: false }); - + Overlays.editOverlay(yawHandle, { + visible: false + }); + Overlays.editOverlay(pitchHandle, { + visible: false + }); + Overlays.editOverlay(rollHandle, { + visible: false + }); + if (mode != "TRANSLATE_UP_DOWN") { - Overlays.editOverlay(grabberMoveUp, { visible: false }); + Overlays.editOverlay(grabberMoveUp, { + visible: false + }); } } - + if (!somethingClicked) { - + print("rotate handle case..."); - + // After testing our stretch handles, then check out rotate handles - Overlays.editOverlay(yawHandle, { ignoreRayIntersection: false }); - Overlays.editOverlay(pitchHandle, { ignoreRayIntersection: false }); - Overlays.editOverlay(rollHandle, { ignoreRayIntersection: false }); + Overlays.editOverlay(yawHandle, { + ignoreRayIntersection: false + }); + Overlays.editOverlay(pitchHandle, { + ignoreRayIntersection: false + }); + Overlays.editOverlay(rollHandle, { + ignoreRayIntersection: false + }); var result = Overlays.findRayIntersection(pickRay); - + var overlayOrientation; var overlayCenter; @@ -2460,12 +3898,12 @@ SelectionDisplay = (function () { var pitch = angles.x; var yaw = angles.y; var roll = angles.z; - + originalRotation = properties.rotation; originalPitch = pitch; originalYaw = yaw; originalRoll = roll; - + if (result.intersects) { var tool = grabberTools[result.overlayID]; if (tool) { @@ -2476,7 +3914,7 @@ SelectionDisplay = (function () { activeTool.onBegin(event); } } - switch(result.overlayID) { + switch (result.overlayID) { case yawHandle: mode = "ROTATE_YAW"; somethingClicked = true; @@ -2514,59 +3952,147 @@ SelectionDisplay = (function () { print(" somethingClicked:" + somethingClicked); print(" mode:" + mode); - + if (somethingClicked) { - - Overlays.editOverlay(rotateOverlayTarget, { visible: true, rotation: overlayOrientation, position: overlayCenter }); - Overlays.editOverlay(rotateOverlayInner, { visible: true, rotation: overlayOrientation, position: overlayCenter }); - Overlays.editOverlay(rotateOverlayOuter, { visible: true, rotation: overlayOrientation, position: overlayCenter, startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayCurrent, { visible: true, rotation: overlayOrientation, position: overlayCenter, startAt: 0, endAt: 0 }); - Overlays.editOverlay(yawHandle, { visible: false }); - Overlays.editOverlay(pitchHandle, { visible: false }); - Overlays.editOverlay(rollHandle, { visible: false }); + + Overlays.editOverlay(rotateOverlayTarget, { + visible: true, + rotation: overlayOrientation, + position: overlayCenter + }); + Overlays.editOverlay(rotateOverlayInner, { + visible: true, + rotation: overlayOrientation, + position: overlayCenter + }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: true, + rotation: overlayOrientation, + position: overlayCenter, + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: true, + rotation: overlayOrientation, + position: overlayCenter, + startAt: 0, + endAt: 0 + }); + Overlays.editOverlay(yawHandle, { + visible: false + }); + Overlays.editOverlay(pitchHandle, { + visible: false + }); + Overlays.editOverlay(rollHandle, { + visible: false + }); - Overlays.editOverlay(yawHandle, { visible: false }); - Overlays.editOverlay(pitchHandle, { visible: false }); - Overlays.editOverlay(rollHandle, { visible: false }); - Overlays.editOverlay(grabberMoveUp, { visible: false }); - Overlays.editOverlay(grabberLBN, { visible: false }); - Overlays.editOverlay(grabberLBF, { visible: false }); - Overlays.editOverlay(grabberRBN, { visible: false }); - Overlays.editOverlay(grabberRBF, { visible: false }); - Overlays.editOverlay(grabberLTN, { visible: false }); - Overlays.editOverlay(grabberLTF, { visible: false }); - Overlays.editOverlay(grabberRTN, { visible: false }); - Overlays.editOverlay(grabberRTF, { visible: false }); + Overlays.editOverlay(yawHandle, { + visible: false + }); + Overlays.editOverlay(pitchHandle, { + visible: false + }); + Overlays.editOverlay(rollHandle, { + visible: false + }); + Overlays.editOverlay(grabberMoveUp, { + visible: false + }); + Overlays.editOverlay(grabberLBN, { + visible: false + }); + Overlays.editOverlay(grabberLBF, { + visible: false + }); + Overlays.editOverlay(grabberRBN, { + visible: false + }); + Overlays.editOverlay(grabberRBF, { + visible: false + }); + Overlays.editOverlay(grabberLTN, { + visible: false + }); + Overlays.editOverlay(grabberLTF, { + visible: false + }); + Overlays.editOverlay(grabberRTN, { + visible: false + }); + Overlays.editOverlay(grabberRTF, { + visible: false + }); - Overlays.editOverlay(grabberTOP, { visible: false }); - Overlays.editOverlay(grabberBOTTOM, { visible: false }); - Overlays.editOverlay(grabberLEFT, { visible: false }); - Overlays.editOverlay(grabberRIGHT, { visible: false }); - Overlays.editOverlay(grabberNEAR, { visible: false }); - Overlays.editOverlay(grabberFAR, { visible: false }); + Overlays.editOverlay(grabberTOP, { + visible: false + }); + Overlays.editOverlay(grabberBOTTOM, { + visible: false + }); + Overlays.editOverlay(grabberLEFT, { + visible: false + }); + Overlays.editOverlay(grabberRIGHT, { + visible: false + }); + Overlays.editOverlay(grabberNEAR, { + visible: false + }); + Overlays.editOverlay(grabberFAR, { + visible: false + }); - Overlays.editOverlay(grabberEdgeTR, { visible: false }); - Overlays.editOverlay(grabberEdgeTL, { visible: false }); - Overlays.editOverlay(grabberEdgeTF, { visible: false }); - Overlays.editOverlay(grabberEdgeTN, { visible: false }); - Overlays.editOverlay(grabberEdgeBR, { visible: false }); - Overlays.editOverlay(grabberEdgeBL, { visible: false }); - Overlays.editOverlay(grabberEdgeBF, { visible: false }); - Overlays.editOverlay(grabberEdgeBN, { visible: false }); - Overlays.editOverlay(grabberEdgeNR, { visible: false }); - Overlays.editOverlay(grabberEdgeNL, { visible: false }); - Overlays.editOverlay(grabberEdgeFR, { visible: false }); - Overlays.editOverlay(grabberEdgeFL, { visible: false }); + Overlays.editOverlay(grabberEdgeTR, { + visible: false + }); + Overlays.editOverlay(grabberEdgeTL, { + visible: false + }); + Overlays.editOverlay(grabberEdgeTF, { + visible: false + }); + Overlays.editOverlay(grabberEdgeTN, { + visible: false + }); + Overlays.editOverlay(grabberEdgeBR, { + visible: false + }); + Overlays.editOverlay(grabberEdgeBL, { + visible: false + }); + Overlays.editOverlay(grabberEdgeBF, { + visible: false + }); + Overlays.editOverlay(grabberEdgeBN, { + visible: false + }); + Overlays.editOverlay(grabberEdgeNR, { + visible: false + }); + Overlays.editOverlay(grabberEdgeNL, { + visible: false + }); + Overlays.editOverlay(grabberEdgeFR, { + visible: false + }); + Overlays.editOverlay(grabberEdgeFL, { + visible: false + }); } } if (!somethingClicked) { - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: false }); + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: false + }); var result = Overlays.findRayIntersection(pickRay); if (result.intersects) { - switch(result.overlayID) { + switch (result.overlayID) { case selectionBox: activeTool = translateXZTool; mode = translateXZTool.mode; @@ -2584,17 +4110,25 @@ SelectionDisplay = (function () { if (somethingClicked) { pickRay = Camera.computePickRay(event.x, event.y); if (wantDebug) { - print("mousePressEvent()...... " + overlayNames[result.overlayID]); + print("mousePressEvent()...... " + overlayNames[result.overlayID]); } } // reset everything as intersectable... // TODO: we could optimize this since some of these were already flipped back - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: false }); - Overlays.editOverlay(yawHandle, { ignoreRayIntersection: false }); - Overlays.editOverlay(pitchHandle, { ignoreRayIntersection: false }); - Overlays.editOverlay(rollHandle, { ignoreRayIntersection: false }); - + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: false + }); + Overlays.editOverlay(yawHandle, { + ignoreRayIntersection: false + }); + Overlays.editOverlay(pitchHandle, { + ignoreRayIntersection: false + }); + Overlays.editOverlay(rollHandle, { + ignoreRayIntersection: false + }); + return somethingClicked; }; @@ -2613,7 +4147,7 @@ SelectionDisplay = (function () { var highlightNeeded = false; if (result.intersects) { - switch(result.overlayID) { + switch (result.overlayID) { case yawHandle: case pitchHandle: case rollHandle: @@ -2621,7 +4155,7 @@ SelectionDisplay = (function () { pickedAlpha = handleAlpha; highlightNeeded = true; break; - + case grabberMoveUp: pickedColor = handleColor; pickedAlpha = handleAlpha; @@ -2682,30 +4216,42 @@ SelectionDisplay = (function () { default: if (previousHandle) { - Overlays.editOverlay(previousHandle, { color: previousHandleColor, alpha: previousHandleAlpha }); + Overlays.editOverlay(previousHandle, { + color: previousHandleColor, + alpha: previousHandleAlpha + }); previousHandle = false; } break; } - + if (highlightNeeded) { if (previousHandle) { - Overlays.editOverlay(previousHandle, { color: previousHandleColor, alpha: previousHandleAlpha }); + Overlays.editOverlay(previousHandle, { + color: previousHandleColor, + alpha: previousHandleAlpha + }); previousHandle = false; } - Overlays.editOverlay(result.overlayID, { color: highlightedHandleColor, alpha: highlightedHandleAlpha }); + Overlays.editOverlay(result.overlayID, { + color: highlightedHandleColor, + alpha: highlightedHandleAlpha + }); previousHandle = result.overlayID; previousHandleColor = pickedColor; previousHandleAlpha = pickedAlpha; } - + } else { if (previousHandle) { - Overlays.editOverlay(previousHandle, { color: previousHandleColor, alpha: previousHandleAlpha }); + Overlays.editOverlay(previousHandle, { + color: previousHandleColor, + alpha: previousHandleAlpha + }); previousHandle = false; } } - + return false; }; @@ -2728,7 +4274,11 @@ SelectionDisplay = (function () { Overlays.editOverlay(rollHandle, { scale: handleSize, }); - var pos = Vec3.sum(grabberMoveUpPosition, { x: 0, y: Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 3, z: 0 }); + var pos = Vec3.sum(grabberMoveUpPosition, { + x: 0, + y: Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 3, + z: 0 + }); Overlays.editOverlay(grabberMoveUp, { position: pos, scale: handleSize / 2, @@ -2745,34 +4295,43 @@ SelectionDisplay = (function () { activeTool = null; // hide our rotation overlays..., and show our handles if (mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL") { - Overlays.editOverlay(rotateOverlayTarget, { visible: false }); - Overlays.editOverlay(rotateOverlayInner, { visible: false }); - Overlays.editOverlay(rotateOverlayOuter, { visible: false }); - Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); + Overlays.editOverlay(rotateOverlayTarget, { + visible: false + }); + Overlays.editOverlay(rotateOverlayInner, { + visible: false + }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: false + }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: false + }); showHandles = true; } if (mode != "UNKNOWN") { showHandles = true; } - + mode = "UNKNOWN"; - + // if something is selected, then reset the "original" properties for any potential next click+move operation if (SelectionManager.hasSelection()) { if (showHandles) { that.select(SelectionManager.selections[0], event); } } - + }; // NOTE: mousePressEvent and mouseMoveEvent from the main script should call us., so we don't hook these: // Controller.mousePressEvent.connect(that.mousePressEvent); // Controller.mouseMoveEvent.connect(that.mouseMoveEvent); Controller.mouseReleaseEvent.connect(that.mouseReleaseEvent); - + + + return that; -}()); - +}()); \ No newline at end of file diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 8eae5cc2a4..8f71f161a2 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -25,7 +25,7 @@ var lightOverlayManager; if (SHOW_OVERLAYS === true) { Script.include('../libraries/gridTool.js'); - Script.include('../libraries/entitySelectionTool.js'); + Script.include('../libraries/entitySelectionTool.js?'+Math.random(0-100)); Script.include('../libraries/lightOverlayManager.js'); var grid = Grid(); diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 761eb4786d..8381b9d434 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -10,6 +10,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?'+Math.random(0-100)); var basePosition, avatarRot; avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(0, Quat.getUp(avatarRot))); @@ -74,6 +75,7 @@ function createBlock() { blue: 255 }, position: position, + script:PARENT_SCRIPT_URL, userData: JSON.stringify({ handControllerKey: { disableReleaseVelocity: true diff --git a/examples/light_modifier/lightParent.js b/examples/light_modifier/lightParent.js new file mode 100644 index 0000000000..2d7cfe8042 --- /dev/null +++ b/examples/light_modifier/lightParent.js @@ -0,0 +1,42 @@ + // + // slider.js + // + // Created by James Pollack @imgntn on 12/15/2015 + // Copyright 2015 High Fidelity, Inc. + // + // Entity script that sends a scaled value to a light based on its distance from the start of its constraint axis. + // + // Distributed under the Apache License, Version 2.0. + // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + // + + (function() { + + function LightParent() { + return this; + } + + LightParent.prototype = { + preload: function(entityID) { + print('LIGHT PARENT SCRIPT GO') + this.entityID = entityID; + var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); + this.initialProperties = entityProperties + this.userData = JSON.parse(entityProperties.userData); + }, + startNearGrab: function() {}, + startDistantGrab: function() { + + }, + continueNearGrab: function() { + this.continueDistantGrab(); + }, + continueDistantGrab: function() { + print('distant grab, should send message!') + Messages.sendMessage('entityToolUpdates', 'callUpdate'); + }, + + }; + + return new LightParent(); + }); \ No newline at end of file From 6f82d680b9cb7873f091614fde07c6fd055a0ccd Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 12:38:25 -0800 Subject: [PATCH 090/209] removed unwanted file --- examples/flowArts/lightBall/particles.js | 129 ----------------------- 1 file changed, 129 deletions(-) delete mode 100644 examples/flowArts/lightBall/particles.js diff --git a/examples/flowArts/lightBall/particles.js b/examples/flowArts/lightBall/particles.js deleted file mode 100644 index 86616d5099..0000000000 --- a/examples/flowArts/lightBall/particles.js +++ /dev/null @@ -1,129 +0,0 @@ -Script.include("../../libraries/utils.js"); - -LightBall = function(spawnPosition) { - - var colorPalette = [{ - red: 25, - green: 20, - blue: 162 - }]; - - - var containerBall = Entities.addEntity({ - type: "Sphere", - position: Vec3.sum(spawnPosition, { - x: 0, - y: .5, - z: 0 - }), - dimensions: { - x: .1, - y: .1, - z: .1 - }, - color: { - red: 15, - green: 10, - blue: 150 - }, - collisionsWillMove: true, - gravity: {x: 0, y: -.5, z: 0}, - visible: false, - userData: JSON.stringify({ - grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: .1, - z: 0 - } - }, - invertSolidWhileHeld: true - } - }) - }); - - - var light = Entities.addEntity({ - type: 'Light', - parentID: containerBall, - dimensions: { - x: 30, - y: 30, - z: 30 - }, - color: colorPalette[randInt(0, colorPalette.length)], - intensity: 5 - }); - - - var lightBall = Entities.addEntity({ - type: "ParticleEffect", - position: spawnPosition, - // parentID: containerBall, - isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": { - red: 200, - green: 20, - blue: 40 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - "colorFinish": { - red: 25, - green: 20, - blue: 255 - }, - "maxParticles": 100000, - "lifespan": 2, - "emitRate": 10000, - "emitSpeed": .0, - "speedSpread": 0.0, - "emitDimensions": { - "x": 5, - "y":0 , - "z": 0 - }, - // "polarStart": 0, - // "polarFinish": Math.PI, - // "azimuthStart": -Math.PI, - // "azimuthFinish": Math.PI, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": .00, - "y": .0, - "z": .00 - }, - "particleRadius": 0.02, - "radiusSpread": 0, - "radiusStart": 0.03, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), - emitterShouldTrail: true - }) - - - - function cleanup() { - Entities.deleteEntity(lightBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(light); - } - - this.cleanup = cleanup; -} - -LightBall(); \ No newline at end of file From 92f96cbb2f403a556a62bae17326def1e90c4c8f Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 12:49:30 -0800 Subject: [PATCH 091/209] Removed un-needed libraries from particle effect entity --- libraries/entities/src/ParticleEffectEntityItem.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index da8e369841..16196aa129 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include "EntityTree.h" #include "EntityTreeElement.h" From 035ca25b485d6d712abeac8975bd9eecda455fe1 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 13:31:27 -0800 Subject: [PATCH 092/209] arc ball finds other balls --- examples/flowArts/arcBall/arcBall.js | 149 ++++++++++++++++++ .../flowArts/arcBall/arcBallEntityScript.js | 45 ++++++ examples/flowArts/flowArtsHutSpawner.js | 9 +- examples/flowArts/lightBall/lightBall.js | 10 +- 4 files changed, 206 insertions(+), 7 deletions(-) create mode 100644 examples/flowArts/arcBall/arcBall.js create mode 100644 examples/flowArts/arcBall/arcBallEntityScript.js diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js new file mode 100644 index 0000000000..3853830863 --- /dev/null +++ b/examples/flowArts/arcBall/arcBall.js @@ -0,0 +1,149 @@ +// +// arcBall.js +// examples/arcBall +// +// Created by Eric Levin on 12/17/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creats a particle light ball which makes particle trails as you move it. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include("../../libraries/utils.js"); + + +var scriptURL = Script.resolvePath("arcBallEntityScript.js"); +ArcBall = function(spawnPosition) { + + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; + + + var containerBall = Entities.addEntity({ + type: "Sphere", + name: "Arc Ball", + script: scriptURL, + position: Vec3.sum(spawnPosition, { + x: 0, + y: .5, + z: 0 + }), + dimensions: { + x: .1, + y: .1, + z: .1 + }, + color: { + red: 15, + green: 10, + blue: 150 + }, + mass: 10, + collisionsWillMove: true, + // gravity: { + // x: 0, + // y: -0.5, + // z: 0 + // }, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: .1, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + name: "ballLight", + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var arcBall = Entities.addEntity({ + type: "ParticleEffect", + parentID: containerBall, + isEmitting: true, + name: "Arc Ball Particle Effect", + colorStart: { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: { + red: 25, + green: 20, + blue: 255 + }, + maxParticles: 100000, + lifespan: 2, + emitRate: 10000, + emitSpeed: .1, + lifetime: -1, + speedSpread: 0.0, + emitDimensions: { + x: 0, + y: 0, + z: 0 + }, + polarStart: 0, + polarFinish: Math.PI, + azimuthStart: -Math.PI, + azimuthFinish: Math.PI, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + particleRadius: 0.02, + radiusSpread: 0, + radiusStart: 0.03, + radiusFinish: 0.0003, + alpha: 0, + alphaSpread: .5, + alphaStart: 0, + alphaFinish: 0.5, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + emitterShouldTrail: true + }) + + + + function cleanup() { + Entities.deleteEntity(arcBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } + + this.cleanup = cleanup; +} \ No newline at end of file diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js new file mode 100644 index 0000000000..bcdb2bc5a9 --- /dev/null +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -0,0 +1,45 @@ +// arcBallEntityScript.js +// +// Script Type: Entity +// Created by Eric Levin on 12/17/15. +// Copyright 2015 High Fidelity, Inc. +// +// This entity script handles the logic for the arcBall rave toy +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + Script.include("../../libraries/utils.js"); + var _this; + var ArcBall = function() { + _this = this; + }; + + ArcBall.prototype = { + isGrabbed: false, + startNearGrab: function() { + //Search for nearby balls and create an arc to it if one is found + var position = Entities.getEntityProperties(this.entityID, "position").position + var entities = Entities.findEntities(position, 10); + entities.forEach(function(entity) { + var props = Entities.getEntityProperties(entity, ["position", "name"]); + if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { + print ("WE FOUND ANOTHER ARC BALL"); + } + }) + + }, + + continueNearGrab: function() { + }, + + releaseGrab: function() { + }, + + preload: function(entityID) { + this.entityID = entityID; + }, + }; + return new ArcBall(); +}); diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 3762c67fe4..742b239981 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -17,6 +17,7 @@ Script.include("../../libraries/utils.js"); Script.include("lightBall/LightBall.js"); Script.include("raveStick/RaveStick.js"); Script.include("lightSaber/LightSaber.js"); +Script.include("arcBall/ArcBall.js"); @@ -24,7 +25,10 @@ var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Ca basePosition.y = MyAvatar.position.y + 1; // RAVE ITEMS -var lightBall = new LightBall(basePosition); +//var lightBall = new LightBall(basePosition); + +var arcBall = new ArcBall(basePosition); +var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0})); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); @@ -77,7 +81,8 @@ function cleanup() { Entities.deleteEntity(raveRoom); Entities.deleteEntity(lightZone) Entities.deleteEntity(floor); - lightBall.cleanup(); + arcBall.cleanup(); + arcBall2.cleanup(); raveStick.cleanup(); lightSaber.cleanup(); } diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index 1898f86eef..df62b1b786 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -42,11 +42,11 @@ LightBall = function(spawnPosition) { blue: 150 }, collisionsWillMove: true, - gravity: { - x: 0, - y: -0.5, - z: 0 - }, + // gravity: { + // x: 0, + // y: -0.5, + // z: 0 + // }, userData: JSON.stringify({ grabbableKey: { spatialKey: { From 3e6ae7c5710e99f2508022bb80082b4fcc73911b Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 15:02:25 -0800 Subject: [PATCH 093/209] added lightball back --- examples/flowArts/arcBall/arcBall.js | 8 +- .../flowArts/arcBall/arcBallEntityScript.js | 80 +++++++++++++++++-- examples/flowArts/flowArtsHutSpawner.js | 13 +-- .../lightSaber/lightSaberEntityScript.js | 3 +- 4 files changed, 88 insertions(+), 16 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 3853830863..34578cce76 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -35,9 +35,9 @@ ArcBall = function(spawnPosition) { z: 0 }), dimensions: { - x: .1, - y: .1, - z: .1 + x: .2, + y: .2, + z: .2 }, color: { red: 15, @@ -102,7 +102,7 @@ ArcBall = function(spawnPosition) { }, maxParticles: 100000, lifespan: 2, - emitRate: 10000, + emitRate: 1000, emitSpeed: .1, lifetime: -1, speedSpread: 0.0, diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index bcdb2bc5a9..f1ba9aeb95 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -25,16 +25,86 @@ entities.forEach(function(entity) { var props = Entities.getEntityProperties(entity, ["position", "name"]); if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { - print ("WE FOUND ANOTHER ARC BALL"); + _this.createBeam(position, props.position); } - }) + }); }, - continueNearGrab: function() { + createBeam: function(startPosition, endPosition) { + print("CREATE BEAM") + // Creates particle arc from start position to end position + var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + + testBox = Entities.addEntity({ + type: "Box", + dimensions: {x: .1, y: .1, z: 1}, + color: {red: 200, green: 10, blue: 10}, + position: startPosition, + rotation: emitOrientation + }); + var color = { + red: 200, + green: 10, + blue: 10 + }; + var props = { + type: "ParticleEffect", + name: "Particle Arc", + parentID: this.entityID, + isEmitting: true, + colorStart: color, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 2, + emitRate: 1000, + emitOrientation: emitOrientation, + emitSpeed: .4, + speedSpread: 0.0, + emitDimensions: { + x: 0, + y: 0, + z: 0 + }, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.03, + adiusFinish: 0.025, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: false + } + this.particleArc = Entities.addEntity(props); }, - releaseGrab: function() { + continueNearGrab: function() {}, + + releaseGrab: function() {}, + + unload: function() { + Entities.deleteEntity(this.particleArc); + Entities.deleteEntity(testBox); }, preload: function(entityID) { @@ -42,4 +112,4 @@ }, }; return new ArcBall(); -}); +}); \ No newline at end of file diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 742b239981..e03d2bf0e8 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -25,10 +25,10 @@ var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Ca basePosition.y = MyAvatar.position.y + 1; // RAVE ITEMS -//var lightBall = new LightBall(basePosition); +var lightBall = new LightBall(basePosition); -var arcBall = new ArcBall(basePosition); -var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0})); +// var arcBall = new ArcBall(basePosition); +// var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0})); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); @@ -79,10 +79,11 @@ var lightZone = Entities.addEntity({ function cleanup() { Entities.deleteEntity(raveRoom); - Entities.deleteEntity(lightZone) + Entities.deleteEntity(lightZone); Entities.deleteEntity(floor); - arcBall.cleanup(); - arcBall2.cleanup(); + lightBall.cleanup(); + // arcBall.cleanup(); + // arcBall2.cleanup(); raveStick.cleanup(); lightSaber.cleanup(); } diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index 6f396bf6e3..794e241924 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -56,7 +56,8 @@ this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); // forwardVec = Vec3.normalize(forwardVec); - var forwardQuat = orientationOf(forwardVec); + // var forwardQuat = orientationOf(forwardVec); + var forwardQuat = Quat.rotationBetween(Vec3.UNIT_Z, forwardVec); var position = Vec3.sum(this.props.position, Vec3.multiply(Quat.getFront(this.props.rotation), 0.1)); position.z += 0.1; position.x += -0.035; From aa1f77ab1c6e0294983e2f8f4c18bfa7dbef2772 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 15:42:52 -0800 Subject: [PATCH 094/209] adding ravestick to toybox demo room --- examples/flowArts/raveStick/RaveStick.js | 62 +++++++++ .../raveStick/raveStickEntityScript.js | 62 --------- unpublishedScripts/hiddenEntityReset.js | 115 ++++++++++++++++- unpublishedScripts/masterReset.js | 118 +++++++++++++++++- 4 files changed, 292 insertions(+), 65 deletions(-) diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js index fd3c98b6e5..3e4cf16136 100644 --- a/examples/flowArts/raveStick/RaveStick.js +++ b/examples/flowArts/raveStick/RaveStick.js @@ -64,11 +64,73 @@ RaveStick = function(spawnPosition) { intensity: 5 }); + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0) + var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + var position = Vec3.sum(spawnPosition, Vec3.multiply(Quat.getFront(rotation), 0.1)); + position.z += 0.1; + position.x += -0.035; + var color = { + red: 0, + green: 200, + blue: 40 + }; + var props = { + type: "ParticleEffect", + position: position, + parentID: stick, + isEmitting: true, + name: "raveBeam", + colorStart: color, + colorSpread: { + red: 200, + green: 10, + blue: 10 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 1, + emitRate: 1000, + emitOrientation: forwardQuat, + emitSpeed: .2, + speedSpread: 0.0, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.03, + radiusFinish: 0.025, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: false, + } + var beam = Entities.addEntity(props); + function cleanup() { Entities.deleteEntity(stick); Entities.deleteEntity(light); + Entities.deleteEntity(beam); } this.cleanup = cleanup; diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 171b53e0cf..2e174c78f0 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -58,7 +58,6 @@ isGrabbed: false, startNearGrab: function() { - // this.createBeam(); this.trailBasePosition = Entities.getEntityProperties(this.entityID, "position").position; Entities.editEntity(this.trail, { position: this.trailBasePosition @@ -125,7 +124,6 @@ preload: function(entityID) { this.entityID = entityID; - this.createBeam(); }, unload: function() { @@ -134,66 +132,6 @@ if (this.trailEraseInterval) { Script.clearInterval(this.trailEraseInterval); } - }, - - createBeam: function() { - - var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); - var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); - forwardVec = Vec3.normalize(forwardVec); - var forwardQuat = orientationOf(forwardVec); - var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); - position.z += 0.1; - position.x += -0.035; - var color = this.colorPalette[randInt(0, this.colorPalette.length)]; - var props = { - type: "ParticleEffect", - position: position, - parentID: this.entityID, - isEmitting: true, - name: "raveBeam", - colorStart: color, - colorSpread: { - red: 200, - green: 10, - blue: 10 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 1, - emitRate: 1000, - emitOrientation: forwardQuat, - emitSpeed: .2, - speedSpread: 0.0, - polarStart: 0, - polarFinish: .0, - azimuthStart: .1, - azimuthFinish: .01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - radiusStart: 0.03, - radiusFinish: 0.025, - alpha: 0.7, - alphaSpread: .1, - alphaStart: 0.5, - alphaFinish: 0.5, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: false - } - this.beam = Entities.addEntity(props); } }; return new RaveStick(); diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index ee53e36f9e..e4cf434bf8 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -24,6 +24,7 @@ var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js"); var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js'); var bowScriptURL = Script.resolvePath('../examples/toybox/bow/bow.js'); + var raveStickEntityScriptURL = Script.resolvePath("../examples/flowarts/raveStick/raveStickEntityScript.js"); var basketballResetterScriptURL = Script.resolvePath('basketballsResetter.js'); var targetsResetterScriptURL = Script.resolvePath('targetsResetter.js'); @@ -106,6 +107,13 @@ z: 505.78 }); + createRaveStick({ + x: 547.4, + y: 495.4, + z: 504.5 + }); + + createCombinedArmChair({ x: 549.29, y: 494.9, @@ -160,6 +168,111 @@ }); } + function createRaveStick(position) { + var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx"; + var stick = Entities.addEntity({ + type: "Model", + name: "raveStick", + modelURL: modelURL, + position: position, + shapeType: 'box', + collisionsWillMove: true, + script: raveStickEntityScriptURL, + dimensions: { + x: 0.06, + y: 0.06, + z: 0.31 + }, + gravity: { + x: 0, + y: -3, + z: 0 + }, + userData: JSON.stringify({ + resetMe: { + resetMe: true + }, + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.1 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) + }, + invertSolidWhileHeld: true + } + }) + }); + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0) + var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + position = Vec3.sum(position, Vec3.multiply(Quat.getFront(rotation), 0.1)); + position.z += 0.1; + position.x += -0.035; + var color = { + red: 0, + green: 200, + blue: 40 + }; + var props = { + type: "ParticleEffect", + position: position, + parentID: stick, + isEmitting: true, + name: "raveBeam", + colorStart: color, + colorSpread: { + red: 200, + green: 10, + blue: 10 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 1, + emitRate: 1000, + emitOrientation: forwardQuat, + emitSpeed: .2, + speedSpread: 0.0, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.03, + radiusFinish: 0.025, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: false, + userData: JSON.stringify({ + resetMe: { + resetMe: true + } + }) + } + var beam = Entities.addEntity(props); + + } + function createGun(position) { var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/gun.fbx"; @@ -1391,4 +1504,4 @@ }; // entity scripts always need to return a newly constructed object of our type return new ResetSwitch(); -}); +}); \ No newline at end of file diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 1837f4d656..66c8c74edd 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -23,10 +23,12 @@ var wandScriptURL = Script.resolvePath("../examples/toybox/bubblewand/wand.js"); var dollScriptURL = Script.resolvePath("../examples/toybox/doll/doll.js"); var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js"); var bowScriptURL = Script.resolvePath("../examples/toybox/bow/bow.js"); +var raveStickEntityScriptURL = Script.resolvePath("../examples/flowarts/raveStick/raveStickEntityScript.js"); var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js'); var basketballResetterScriptURL = Script.resolvePath('basketballsResetter.js'); var targetsResetterScriptURL = Script.resolvePath('targetsResetter.js'); + MasterReset = function() { var resetKey = "resetMe"; @@ -80,6 +82,12 @@ MasterReset = function() { z: 505.78 }); + createRaveStick({ + x: 547.4, + y: 495.4, + z: 504.5 + }); + createCombinedArmChair({ @@ -94,6 +102,8 @@ MasterReset = function() { z: 504.53 }); + + createPingPongBallGun(); createTargets(); createTargetResetter(); @@ -137,6 +147,110 @@ MasterReset = function() { }); } + function createRaveStick(position) { + var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx"; + var stick = Entities.addEntity({ + type: "Model", + name: "raveStick", + modelURL: modelURL, + position: position, + shapeType: 'box', + collisionsWillMove: true, + script: raveStickEntityScriptURL, + dimensions: { + x: 0.06, + y: 0.06, + z: 0.31 + }, + gravity: { + x: 0, + y: -3, + z: 0 + }, + userData: JSON.stringify({ + resetMe: { + resetMe: true + }, + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.1 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) + }, + invertSolidWhileHeld: true + } + }) + }); + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0) + var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + position = Vec3.sum(position, Vec3.multiply(Quat.getFront(rotation), 0.1)); + position.z += 0.1; + position.x += -0.035; + var color = { + red: 0, + green: 200, + blue: 40 + }; + var props = { + type: "ParticleEffect", + position: position, + parentID: stick, + isEmitting: true, + name: "raveBeam", + colorStart: color, + colorSpread: { + red: 200, + green: 10, + blue: 10 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 1, + emitRate: 1000, + emitOrientation: forwardQuat, + emitSpeed: .2, + speedSpread: 0.0, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.03, + radiusFinish: 0.025, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: false, + userData: JSON.stringify({ + resetMe: { + resetMe: true + } + }) + } + var beam = Entities.addEntity(props); + + } function createGun(position) { var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/gun.fbx"; @@ -1349,7 +1463,7 @@ MasterReset = function() { resetMe: true }, grabbableKey: { - invertSolidWhileHeld: true + invertSolidWhileHeld: true } }) }); @@ -1366,4 +1480,4 @@ MasterReset = function() { Script.scriptEnding.connect(cleanup); } -}; +}; \ No newline at end of file From 17af34a3be36fdc30ae832f602d5f260358e5cb4 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 15:48:05 -0800 Subject: [PATCH 095/209] fixed spelling error --- unpublishedScripts/hiddenEntityReset.js | 2 +- unpublishedScripts/masterReset.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index e4cf434bf8..cc4037beb4 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -24,7 +24,7 @@ var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js"); var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js'); var bowScriptURL = Script.resolvePath('../examples/toybox/bow/bow.js'); - var raveStickEntityScriptURL = Script.resolvePath("../examples/flowarts/raveStick/raveStickEntityScript.js"); + var raveStickEntityScriptURL = Script.resolvePath("../examples/flowArts/raveStick/raveStickEntityScript.js"); var basketballResetterScriptURL = Script.resolvePath('basketballsResetter.js'); var targetsResetterScriptURL = Script.resolvePath('targetsResetter.js'); diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 66c8c74edd..a1545a3b67 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -23,7 +23,7 @@ var wandScriptURL = Script.resolvePath("../examples/toybox/bubblewand/wand.js"); var dollScriptURL = Script.resolvePath("../examples/toybox/doll/doll.js"); var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js"); var bowScriptURL = Script.resolvePath("../examples/toybox/bow/bow.js"); -var raveStickEntityScriptURL = Script.resolvePath("../examples/flowarts/raveStick/raveStickEntityScript.js"); +var raveStickEntityScriptURL = Script.resolvePath("../examples/flowArts/raveStick/raveStickEntityScript.js"); var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js'); var basketballResetterScriptURL = Script.resolvePath('basketballsResetter.js'); var targetsResetterScriptURL = Script.resolvePath('targetsResetter.js'); From a25feb5578adfb989824aa6d2e723564a317c6bf Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 16:58:38 -0800 Subject: [PATCH 096/209] switching branches --- examples/controllers/handControllerGrab.js | 2 +- examples/libraries/entitySelectionTool.js | 1 - examples/light_modifier/lightModifier.js | 179 ++++++++++++------ .../light_modifier/lightModifierTestScene.js | 13 +- examples/light_modifier/lightParent.js | 2 - 5 files changed, 131 insertions(+), 66 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f53a66444f..0f927f39c8 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -517,7 +517,7 @@ function MyController(hand) { } var intersection = Entities.findRayIntersection(pickRayBacked, true); - + Messages.sendMessage('Hifi-Light-Overlay-Ray-Check', JSON.stringify(pickRayBacked)); if (intersection.intersects) { // the ray is intersecting something we can move. var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 9b213760c2..94ffb48a71 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -20,7 +20,6 @@ SPACE_WORLD = "world"; SelectionManager = (function() { var that = {}; - function subscribeToUpdateMessages() { Messages.subscribe('entityToolUpdates'); Messages.messageReceived.connect(handleEntitySelectionToolUpdates); diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 8f71f161a2..26fb7b7f36 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -22,10 +22,13 @@ var selectionDisplay; var selectionManager; var lightOverlayManager; +//for when we make a block parent for the light +var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?' + Math.random(0 - 100)); + if (SHOW_OVERLAYS === true) { Script.include('../libraries/gridTool.js'); - Script.include('../libraries/entitySelectionTool.js?'+Math.random(0-100)); + Script.include('../libraries/entitySelectionTool.js?' + Math.random(0 - 100)); Script.include('../libraries/lightOverlayManager.js'); var grid = Grid(); @@ -90,8 +93,8 @@ var WHITE = { var ORANGE = { red: 255, - green: 0, - blue: 128 + green: 165, + blue: 0 } var SLIDER_DIMENSIONS = { @@ -100,6 +103,18 @@ var SLIDER_DIMENSIONS = { z: 0.075 }; +var CLOSE_BUTTON_DIMENSIONS ={ + x:0.1, + y:0.1, + z:0.1 +} + +var LIGHT_MODEL_DIMENSIONS={ + x:0.04, + y:0.04, + z:0.09 +} + var PER_ROW_OFFSET = { x: 0, y: -0.2, @@ -348,7 +363,6 @@ var light = null; function makeSliders(light) { // selectionManager.setSelections([entityID]); - if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -383,9 +397,25 @@ function makeSliders(light) { // selectionManager.setSelections([entityID]); slidersRef.exponent = new entitySlider(light, ORANGE, 'exponent', 6); sliders.push(slidersRef.exponent); } + + var closeButtonPosition; + + createCloseButton(closeButtonPosition); subscribeToSliderMessages(); }; +function createCloseButton(position){ + var buttonProperties = { + type:'Model', + modelURL:CLOSE_BUTTON_MODEL_URL, + dimensions:CLOSE_BUTTON_DIMENSIONS, + position:position, + rotation:Quat.fromPitchYawRollDegrees(90,0,0); + } + + var button = Entities.addEntity(buttonProperties); +} + function subScribeToNewLights() { Messages.subscribe('Hifi-Light-Mod-Receiver'); Messages.messageReceived.connect(handleLightModMessages); @@ -396,6 +426,12 @@ function subscribeToSliderMessages() { Messages.messageReceived.connect(handleValueMessages); } +function subscribeToLightOverlayRayCheckMessages() { + Messages.subscribe('Hifi-Light-Overlay-Ray-Check'); + Messages.messageReceived.connect(handleLightOverlayRayCheckMessages); +} + + function handleLightModMessages(channel, message, sender) { if (channel !== 'Hifi-Light-Mod-Receiver') { return; @@ -425,6 +461,86 @@ function handleValueMessages(channel, message, sender) { slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage); } +var currentLight; + +function handleLightOverlayRayCheckMessages(channel, message, sender) { + if (channel !== 'Hifi-Light-Overlay-Ray-Check') { + return; + } + if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) { + return; + } + + print('RAY CHECK GOT MESSAGE::' + message); + var pickRay = JSON.parse(message); + + var doesIntersect = lightOverlayManager.findRayIntersection(pickRay); + print('DOES INTERSECT A LIGHT WE HAVE???' + doesIntersect.intersects); + if (doesIntersect.intersects === true) { + print('FULL MESSAGE:::' + JSON.stringify(doesIntersect)) + + var lightID = doesIntersect.entityID; + if (currentLight === lightID) { + print('ALREADY HAVE A BLOCK, EXIT') + return; + } + print('LIGHT ID::' + lightID); + currentLight = lightID; + var lightProperties = Entities.getEntityProperties(lightID); + var block = createBlock(lightProperties.position); + + var light = { + id: lightID, + type: 'spotlight', + initialProperties: lightProperties + } + + makeSliders(light); + print('AFTER MAKE SLIDERS') + if (SHOW_LIGHT_VOLUME === true) { + selectionManager.setSelections([lightID]); + print('SET SELECTIOIO MANAGER TO::: '+ lightID); + print('hasSelection???' + selectionManager.hasSelection()) + } + print('BLOCK IS:::' + block); + Entities.editEntity(lightID, { + parentID: block + }); + + + } +} +function createBlock(position) { + print('CREATE BLOCK') + + var blockProperties = { + name: 'Hifi-Spotlight-Block', + type: 'Box', + dimensions: { + x: 1, + y: 1, + z: 1 + }, + collisionsWillMove: true, + color: { + red: 0, + green: 0, + blue: 255 + }, + position: position, + script: PARENT_SCRIPT_URL, + userData: JSON.stringify({ + handControllerKey: { + disableReleaseVelocity: true + } + }) + }; + + var block = Entities.addEntity(blockProperties); + + return block +} + function cleanup() { var i; for (i = 0; i < sliders.length; i++) { @@ -440,7 +556,6 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -subScribeToNewLights(); function deleteEntity(entityID) { if (entityID === light) { @@ -448,60 +563,10 @@ function deleteEntity(entityID) { } } - - Entities.deletingEntity.connect(deleteEntity); -// search for lights to make grabbable - -// var USE_DEBOUNCE = true; -// var sinceLastUpdate = 0; - -// function searchForLightsToVisualize() { - -// var deltaTime = interval(); - -// if (USE_DEBOUNCE === true) { -// sinceLastUpdate = sinceLastUpdate + deltaTime; - -// if (sinceLastUpdate > 60) { -// sinceLastUpdate = 0; -// } else { -// return; -// } -// } - -// print('SEARCHING FOR LIGHTS'); - -// var entitites = Entities.findEntities(MyAvatar.position, 50); -// for (i = 0; i < entities.length; i++) { -// var entityProperties = Entities.getEntityProperties(entities[i], ['type', 'parentID']) -// var parentID = entityProperties.parentID; -// var type = entityProperties.type; - -// if (type !== 'Light') { -// return; -// } - -// if (type === "Light" && parentID !== DEFAULT_PARENT_ID && parentID !== null) { -// var light = entities[i]; -// //do something with the light. -// } - -// } - -// } - -// function interval() { -// var lastTime = new Date().getTime(); - -// return function getInterval() { -// var newTime = new Date().getTime(); -// var delta = newTime - lastTime; -// lastTime = newTime; -// return delta; -// }; -// } +subscribeToLightOverlayRayCheckMessages(); +subScribeToNewLights(); diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 8381b9d434..4b78484a31 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -19,7 +19,10 @@ var light, block; function createLight() { var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); - var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); + var position = basePosition; + position.y += 3; + var lightTransform = evalLightWorldTransform(position,avatarRot); + // var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); var lightProperties = { name: 'Hifi-Spotlight', type: "Light", @@ -29,7 +32,7 @@ function createLight() { y: 2, z: 8 }, - parentID: block, + // parentID: block, color: { red: 255, green: 0, @@ -53,7 +56,7 @@ function createLight() { } }; - Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); +// Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); } @@ -104,11 +107,11 @@ function evalLightWorldTransform(modelPos, modelRot) { } function cleanup() { - Entities.deleteEntity(block); + //Entities.deleteEntity(block); Entities.deleteEntity(light); } Script.scriptEnding.connect(cleanup); -createBlock(); +//createBlock(); createLight(); \ No newline at end of file diff --git a/examples/light_modifier/lightParent.js b/examples/light_modifier/lightParent.js index 2d7cfe8042..0d91b93f93 100644 --- a/examples/light_modifier/lightParent.js +++ b/examples/light_modifier/lightParent.js @@ -18,7 +18,6 @@ LightParent.prototype = { preload: function(entityID) { - print('LIGHT PARENT SCRIPT GO') this.entityID = entityID; var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); this.initialProperties = entityProperties @@ -32,7 +31,6 @@ this.continueDistantGrab(); }, continueDistantGrab: function() { - print('distant grab, should send message!') Messages.sendMessage('entityToolUpdates', 'callUpdate'); }, From 7a542a678b709d5a68ce0f75cb9a9c874c94c480 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 17:17:04 -0800 Subject: [PATCH 097/209] prep for close button --- examples/light_modifier/closeButton.js | 41 +++++++++++++ examples/light_modifier/lightModifier.js | 76 +++++++++++++++++------- examples/light_modifier/lightParent.js | 22 +++---- 3 files changed, 106 insertions(+), 33 deletions(-) create mode 100644 examples/light_modifier/closeButton.js diff --git a/examples/light_modifier/closeButton.js b/examples/light_modifier/closeButton.js new file mode 100644 index 0000000000..045882fd33 --- /dev/null +++ b/examples/light_modifier/closeButton.js @@ -0,0 +1,41 @@ +// +// closeButton.js +// +// Created by James Pollack @imgntn on 12/15/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Entity script that closes sliders when interacted with. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + + function CloseButton() { + return this; + } + + CloseButton.prototype = { + preload: function(entityID) { + this.entityID = entityID; + var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); + this.initialProperties = entityProperties + this.userData = JSON.parse(entityProperties.userData); + }, + startNearGrab: function() { + + }, + startDistantGrab: function() { + + }, + continueNearGrab: function() { + this.continueDistantGrab(); + }, + continueDistantGrab: function() { + }, + + }; + + return new CloseButton(); +}); \ No newline at end of file diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 26fb7b7f36..29d66ca821 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -60,6 +60,8 @@ var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); +var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx'; +var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100)); var RED = { red: 255, @@ -103,16 +105,16 @@ var SLIDER_DIMENSIONS = { z: 0.075 }; -var CLOSE_BUTTON_DIMENSIONS ={ - x:0.1, - y:0.1, - z:0.1 +var CLOSE_BUTTON_DIMENSIONS = { + x: 0.1, + y: 0.1, + z: 0.1 } -var LIGHT_MODEL_DIMENSIONS={ - x:0.04, - y:0.04, - z:0.09 +var LIGHT_MODEL_DIMENSIONS = { + x: 0.04, + y: 0.04, + z: 0.09 } var PER_ROW_OFFSET = { @@ -361,7 +363,7 @@ var slidersRef = { } var light = null; -function makeSliders(light) { // selectionManager.setSelections([entityID]); +function makeSliders(light) { if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; @@ -398,22 +400,50 @@ function makeSliders(light) { // selectionManager.setSelections([entityID]); sliders.push(slidersRef.exponent); } - var closeButtonPosition; + createCloseButton(7); - createCloseButton(closeButtonPosition); subscribeToSliderMessages(); }; -function createCloseButton(position){ +var closeButtons = []; + +function createCloseButton(row) { + var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); + var verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); + var downPosition = Vec3.sum(basePosition, verticalOffset); + var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); + var rightVector = Quat.getRight(avatarRot); + var extension = Vec3.multiply(AXIS_SCALE, rightVector); + var position = Vec3.sum(downPosition, extension); + var buttonProperties = { - type:'Model', - modelURL:CLOSE_BUTTON_MODEL_URL, - dimensions:CLOSE_BUTTON_DIMENSIONS, - position:position, - rotation:Quat.fromPitchYawRollDegrees(90,0,0); + type: 'Model', + modelURL: CLOSE_BUTTON_MODEL_URL, + dimensions: CLOSE_BUTTON_DIMENSIONS, + position: position, + rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + collisionsWillMove: false + //need to add wantsTrigger stuff so we can interact with it with our beamz } var button = Entities.addEntity(buttonProperties); + + closeButtons.push(button); + + Script.update.connect(rotateCloseButtons); +} + +function rotateCloseButtons() { + closeButtons.forEach(function(button) { + Entities.editEntity(button, { + angularVelocity: { + x: 0, + y: 0.25, + z: 0 + } + }) + + }) } function subScribeToNewLights() { @@ -471,7 +501,6 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { return; } - print('RAY CHECK GOT MESSAGE::' + message); var pickRay = JSON.parse(message); var doesIntersect = lightOverlayManager.findRayIntersection(pickRay); @@ -484,7 +513,7 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { print('ALREADY HAVE A BLOCK, EXIT') return; } - print('LIGHT ID::' + lightID); + currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); var block = createBlock(lightProperties.position); @@ -496,13 +525,13 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { } makeSliders(light); - print('AFTER MAKE SLIDERS') + if (SHOW_LIGHT_VOLUME === true) { selectionManager.setSelections([lightID]); - print('SET SELECTIOIO MANAGER TO::: '+ lightID); + print('SET SELECTIOIO MANAGER TO::: ' + lightID); print('hasSelection???' + selectionManager.hasSelection()) } - print('BLOCK IS:::' + block); + Entities.editEntity(lightID, { parentID: block }); @@ -510,6 +539,7 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { } } + function createBlock(position) { print('CREATE BLOCK') @@ -553,6 +583,8 @@ function cleanup() { Entities.deletingEntity.disconnect(deleteEntity); lightOverlayManager.setVisible(false); + Script.update.disconnect(rotateCloseButtons); + } Script.scriptEnding.connect(cleanup); diff --git a/examples/light_modifier/lightParent.js b/examples/light_modifier/lightParent.js index 0d91b93f93..2b53c05d0a 100644 --- a/examples/light_modifier/lightParent.js +++ b/examples/light_modifier/lightParent.js @@ -1,14 +1,14 @@ - // - // slider.js - // - // Created by James Pollack @imgntn on 12/15/2015 - // Copyright 2015 High Fidelity, Inc. - // - // Entity script that sends a scaled value to a light based on its distance from the start of its constraint axis. - // - // Distributed under the Apache License, Version 2.0. - // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - // +// +// lightParent.js +// +// Created by James Pollack @imgntn on 12/15/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Entity script that tells the light parent to update the selection tool when we move it. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// (function() { From f84a441c7daeb09c54acef636791986df0353609 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 18:33:17 -0800 Subject: [PATCH 098/209] close button --- examples/light_modifier/lightModifier.js | 44 ++++++++++++++++++++---- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 29d66ca821..d82afc09bb 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -60,6 +60,7 @@ var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); +var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_good.fbx'; var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx'; var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100)); @@ -112,9 +113,9 @@ var CLOSE_BUTTON_DIMENSIONS = { } var LIGHT_MODEL_DIMENSIONS = { - x: 0.04, - y: 0.04, - z: 0.09 + x: 0.68, + y: 0.68, + z: 1.54 } var PER_ROW_OFFSET = { @@ -408,15 +409,16 @@ function makeSliders(light) { var closeButtons = []; function createCloseButton(row) { - var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); + var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); + var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(avatarRot))); var verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); var downPosition = Vec3.sum(basePosition, verticalOffset); - var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); var rightVector = Quat.getRight(avatarRot); var extension = Vec3.multiply(AXIS_SCALE, rightVector); var position = Vec3.sum(downPosition, extension); var buttonProperties = { + name:'Hifi-Close-Button', type: 'Model', modelURL: CLOSE_BUTTON_MODEL_URL, dimensions: CLOSE_BUTTON_DIMENSIONS, @@ -492,6 +494,7 @@ function handleValueMessages(channel, message, sender) { } var currentLight; +var block; function handleLightOverlayRayCheckMessages(channel, message, sender) { if (channel !== 'Hifi-Light-Overlay-Ray-Check') { @@ -516,7 +519,8 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); - var block = createBlock(lightProperties.position); + block = createBlock(lightProperties.position); + // block = createLightModel(lightProperties.position); var light = { id: lightID, @@ -540,6 +544,30 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { } } +function createLightModel(position) { + print('CREATE MODEL') + var blockProperties = { + name: 'Hifi-Spotlight-Model', + type: 'Model', + shapeType: 'box', + modelURL: LIGHT_MODEL_URL, + dimensions: LIGHT_MODEL_DIMENSIONS, + collisionsWillMove: true, + position: position, + rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + script: PARENT_SCRIPT_URL, + userData: JSON.stringify({ + handControllerKey: { + disableReleaseVelocity: true + } + }) + }; + + var block = Entities.addEntity(blockProperties); + + return block +} + function createBlock(position) { print('CREATE BLOCK') @@ -551,12 +579,12 @@ function createBlock(position) { y: 1, z: 1 }, - collisionsWillMove: true, color: { red: 0, green: 0, blue: 255 }, + collisionsWillMove: true, position: position, script: PARENT_SCRIPT_URL, userData: JSON.stringify({ @@ -578,11 +606,13 @@ function cleanup() { Entities.deleteEntity(sliders[i].sliderIndicator); } + Entities.deleteEntity(block); Messages.messageReceived.disconnect(handleLightModMessages); Messages.messageReceived.disconnect(handleValueMessages); Entities.deletingEntity.disconnect(deleteEntity); lightOverlayManager.setVisible(false); + selectionManager.clearSelections(); Script.update.disconnect(rotateCloseButtons); } From 77264b3f99283694ef126d859680760a10e39032 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 14:52:39 -0800 Subject: [PATCH 099/209] Ping pong gun lines up with hand --- examples/flowArts/lightSaber/LightSaber.js | 13 +++++++++++++ unpublishedScripts/hiddenEntityReset.js | 8 ++++++++ unpublishedScripts/masterReset.js | 8 ++++++++ 3 files changed, 29 insertions(+) diff --git a/examples/flowArts/lightSaber/LightSaber.js b/examples/flowArts/lightSaber/LightSaber.js index 8a4f3f2902..50984110bc 100644 --- a/examples/flowArts/lightSaber/LightSaber.js +++ b/examples/flowArts/lightSaber/LightSaber.js @@ -44,6 +44,19 @@ LightSaber = function(spawnPosition) { }) }); + var light = Entities.addEntity({ + type: 'Light', + name: "raveLight", + parentID: saberHandle, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: {red: 200, green: 10, blue: 200}, + intensity: 5 + }); + function cleanup() { Entities.deleteEntity(saberHandle); diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index cc4037beb4..c8a2c97b0f 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1153,6 +1153,14 @@ resetMe: true }, grabbableKey: { + spatialKey: { + relativePosition: { + x: -0.05, + y: 0, + z: 0.0 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) + }, invertSolidWhileHeld: true } diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index a1545a3b67..3d985e9a92 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -1134,6 +1134,14 @@ MasterReset = function() { resetMe: true }, grabbableKey: { + spatialKey: { + relativePosition: { + x: -0.05, + y: 0, + z: 0.0 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0,-90, -90) + }, invertSolidWhileHeld: true } From 387c30d83fa1abe3fa2a97ed512918ac7ad073ea Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 15:04:13 -0800 Subject: [PATCH 100/209] close button --- examples/controllers/handControllerGrab.js | 2 +- examples/light_modifier/README.md | 6 +- examples/light_modifier/lightModifier.js | 58 +++++++++++-------- .../light_modifier/lightModifierTestScene.js | 2 +- 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 0f927f39c8..1b256f67c0 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -842,7 +842,7 @@ function MyController(hand) { this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } } else { - print('should not head move!'); + // print('should not head move!'); } diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index d978c73b5b..3bd456d525 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -3,11 +3,15 @@ This PR demonstrates one way in-world editing of objects might work. We start w To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js To reset, I recommend stopping all scripts then re-loading lightLoader.js -When you run the lightLoader.js script, 4 scripts will be loaded: +When you run the lightLoader.js script, several scripts will be loaded: - handControllerGrab.js (custom) - lightModifier.js (listens for message to create sliders for a given light) - lightModifierTestScene.js (creates a light and parents it to a block, then sends a message ^^) - slider.js (attached to each slider entity) +- lightParent.js (attached to the entity to which a light is parented, so you can move it around) +- closeButton.js (for closing the ui) +- ../libraries/lightOverlayManager.js (custom) +- ../libraries/entitySelectionTool.js diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index d82afc09bb..76c1cdc873 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -60,7 +60,7 @@ var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); -var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_good.fbx'; +var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_rotated.fbx'; var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx'; var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100)); @@ -108,14 +108,14 @@ var SLIDER_DIMENSIONS = { var CLOSE_BUTTON_DIMENSIONS = { x: 0.1, - y: 0.1, + y: 0.025, z: 0.1 } var LIGHT_MODEL_DIMENSIONS = { - x: 0.68, - y: 0.68, - z: 1.54 + x: 0.58, + y: 1.21, + z: 0.57 } var PER_ROW_OFFSET = { @@ -262,6 +262,7 @@ entitySlider.prototype = { color: this.color, position: sliderPosition, script: SLIDER_SCRIPT_URL, + ignoreForCollisions:true, userData: JSON.stringify({ lightModifierKey: { lightID: this.lightID, @@ -401,29 +402,34 @@ function makeSliders(light) { sliders.push(slidersRef.exponent); } - createCloseButton(7); + createCloseButton(slidersRef.exponent.endOfAxis); subscribeToSliderMessages(); }; var closeButtons = []; -function createCloseButton(row) { - var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); - var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(avatarRot))); - var verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); - var downPosition = Vec3.sum(basePosition, verticalOffset); - var rightVector = Quat.getRight(avatarRot); - var extension = Vec3.multiply(AXIS_SCALE, rightVector); - var position = Vec3.sum(downPosition, extension); +function createCloseButton(endOfAxis) { + // var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); + // var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(avatarRot))); + // var verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); + // var verticalOffset = lastRowVerticalOffset; + // var downPosition = Vec3.sum(basePosition, verticalOffset); + // var rightVector = Quat.getRight(avatarRot); + // var extension = Vec3.multiply(AXIS_SCALE, rightVector); + // var position = Vec3.sum(downPosition, extension); var buttonProperties = { name:'Hifi-Close-Button', type: 'Model', modelURL: CLOSE_BUTTON_MODEL_URL, dimensions: CLOSE_BUTTON_DIMENSIONS, - position: position, - rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + position: Vec3.sum(endOfAxis,{ + x:0, + y:-0.15, + z:0 + }), + rotation: Quat.fromPitchYawRollDegrees(0, 45, 90), collisionsWillMove: false //need to add wantsTrigger stuff so we can interact with it with our beamz } @@ -440,7 +446,7 @@ function rotateCloseButtons() { Entities.editEntity(button, { angularVelocity: { x: 0, - y: 0.25, + y: 0.5, z: 0 } }) @@ -519,8 +525,8 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); - block = createBlock(lightProperties.position); - // block = createLightModel(lightProperties.position); + // block = createBlock(lightProperties.position); + block = createLightModel(lightProperties.position); var light = { id: lightID, @@ -532,12 +538,11 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { if (SHOW_LIGHT_VOLUME === true) { selectionManager.setSelections([lightID]); - print('SET SELECTIOIO MANAGER TO::: ' + lightID); - print('hasSelection???' + selectionManager.hasSelection()) } Entities.editEntity(lightID, { - parentID: block + parentID: block, + parentJointIndex:-1 }); @@ -551,10 +556,11 @@ function createLightModel(position) { type: 'Model', shapeType: 'box', modelURL: LIGHT_MODEL_URL, + // modelURL:"http://hifi-content.s3.amazonaws.com/james/light_modifier/box4.fbx", dimensions: LIGHT_MODEL_DIMENSIONS, collisionsWillMove: true, position: position, - rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + // rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), script: PARENT_SCRIPT_URL, userData: JSON.stringify({ handControllerKey: { @@ -576,7 +582,7 @@ function createBlock(position) { type: 'Box', dimensions: { x: 1, - y: 1, + y: 4, z: 1 }, color: { @@ -606,6 +612,10 @@ function cleanup() { Entities.deleteEntity(sliders[i].sliderIndicator); } + while(closeButtons.length>0){ + Entities.deleteEntity(closeButtons.pop()); + } + Entities.deleteEntity(block); Messages.messageReceived.disconnect(handleLightModMessages); Messages.messageReceived.disconnect(handleValueMessages); diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 4b78484a31..8df83b09bf 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -20,7 +20,7 @@ var light, block; function createLight() { var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); var position = basePosition; - position.y += 3; + position.y += 2; var lightTransform = evalLightWorldTransform(position,avatarRot); // var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); var lightProperties = { From 2dbb3bd84abf25e2d5d6f0fc0f90ae3d02682012 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 15:12:46 -0800 Subject: [PATCH 101/209] Added grab offsets to createPingPongGun.js --- examples/toybox/ping_pong_gun/createPingPongGun.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/toybox/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js index 4b93842896..7835dbf7f9 100644 --- a/examples/toybox/ping_pong_gun/createPingPongGun.js +++ b/examples/toybox/ping_pong_gun/createPingPongGun.js @@ -38,6 +38,14 @@ var pingPongGun = Entities.addEntity({ collisionSoundURL: COLLISION_SOUND_URL, userData: JSON.stringify({ grabbableKey: { + spatialKey: { + relativePosition: { + x: -0.05, + y: 0, + z: 0.0 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) + }, invertSolidWhileHeld: true } }) From 2c02e7ad631ddec997bbcca99a462b701554d92b Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 15:22:23 -0800 Subject: [PATCH 102/209] grabbing works with left hand for ping pong gun now --- unpublishedScripts/hiddenEntityReset.js | 2 +- unpublishedScripts/masterReset.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index c8a2c97b0f..21971a18ad 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1125,7 +1125,7 @@ z: 503.39 }; - var rotation = Quat.fromPitchYawRollDegrees(0, 36, 0); + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0); var pingPongGun = Entities.addEntity({ type: "Model", diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 3d985e9a92..3d0773ca10 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -1106,7 +1106,7 @@ MasterReset = function() { z: 503.39 }; - var rotation = Quat.fromPitchYawRollDegrees(0, 36, 0); + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0); var pingPongGun = Entities.addEntity({ type: "Model", From 514cb7a329b835c282cdf448807a221143796eb0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 15:26:21 -0800 Subject: [PATCH 103/209] Beams arc to each other. BAM --- examples/flowArts/arcBall/arcBall.js | 11 ++--------- examples/flowArts/arcBall/arcBallEntityScript.js | 5 ++++- examples/flowArts/flowArtsHutSpawner.js | 12 ++++++------ 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 34578cce76..e39a9af2d6 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -26,7 +26,7 @@ ArcBall = function(spawnPosition) { var containerBall = Entities.addEntity({ - type: "Sphere", + type: "Box", name: "Arc Ball", script: scriptURL, position: Vec3.sum(spawnPosition, { @@ -37,7 +37,7 @@ ArcBall = function(spawnPosition) { dimensions: { x: .2, y: .2, - z: .2 + z: .5 }, color: { red: 15, @@ -53,13 +53,6 @@ ArcBall = function(spawnPosition) { // }, userData: JSON.stringify({ grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: .1, - z: 0 - } - }, invertSolidWhileHeld: true } }) diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index f1ba9aeb95..8c37f170bb 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -42,7 +42,8 @@ dimensions: {x: .1, y: .1, z: 1}, color: {red: 200, green: 10, blue: 10}, position: startPosition, - rotation: emitOrientation + rotation: emitOrientation, + visible: false }); var color = { red: 200, @@ -53,6 +54,8 @@ type: "ParticleEffect", name: "Particle Arc", parentID: this.entityID, + parentJointIndex: -1, + position: startPosition, isEmitting: true, colorStart: color, color: { diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index e03d2bf0e8..39dcf15698 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -25,10 +25,10 @@ var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Ca basePosition.y = MyAvatar.position.y + 1; // RAVE ITEMS -var lightBall = new LightBall(basePosition); +// var lightBall = new LightBall(basePosition); -// var arcBall = new ArcBall(basePosition); -// var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0})); +var arcBall = new ArcBall(basePosition); +var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0})); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); @@ -81,9 +81,9 @@ function cleanup() { Entities.deleteEntity(raveRoom); Entities.deleteEntity(lightZone); Entities.deleteEntity(floor); - lightBall.cleanup(); - // arcBall.cleanup(); - // arcBall2.cleanup(); + // lightBall.cleanup(); + arcBall.cleanup(); + arcBall2.cleanup(); raveStick.cleanup(); lightSaber.cleanup(); } From fffe6dbb9bd32ec6dcb7ce71a8c787dcbc00df66 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 15:38:01 -0800 Subject: [PATCH 104/209] relative rotation --- examples/flowArts/arcBall/arcBall.js | 13 ++++--------- examples/flowArts/arcBall/arcBallEntityScript.js | 4 +++- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index e39a9af2d6..736920ddd5 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -35,22 +35,17 @@ ArcBall = function(spawnPosition) { z: 0 }), dimensions: { - x: .2, - y: .2, - z: .5 + x: .1, + y: .1, + z: .2 }, color: { red: 15, green: 10, blue: 150 }, - mass: 10, + damping: 0.8, collisionsWillMove: true, - // gravity: { - // x: 0, - // y: -0.5, - // z: 0 - // }, userData: JSON.stringify({ grabbableKey: { invertSolidWhileHeld: true diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 8c37f170bb..4ad0d66257 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -34,8 +34,10 @@ createBeam: function(startPosition, endPosition) { print("CREATE BEAM") // Creates particle arc from start position to end position + var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); testBox = Entities.addEntity({ type: "Box", @@ -65,7 +67,7 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 2, + lifespan: 6, emitRate: 1000, emitOrientation: emitOrientation, emitSpeed: .4, From 0e530900d4a40bbe7c741db2812bb1ca4160637e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 16:22:20 -0800 Subject: [PATCH 105/209] sequential editing --- examples/light_modifier/closeButton.js | 12 +- examples/light_modifier/lightModifier.js | 161 +++++++++++------------ 2 files changed, 81 insertions(+), 92 deletions(-) diff --git a/examples/light_modifier/closeButton.js b/examples/light_modifier/closeButton.js index 045882fd33..7b2869cc8e 100644 --- a/examples/light_modifier/closeButton.js +++ b/examples/light_modifier/closeButton.js @@ -24,16 +24,12 @@ this.userData = JSON.parse(entityProperties.userData); }, startNearGrab: function() { - - }, - startDistantGrab: function() { }, - continueNearGrab: function() { - this.continueDistantGrab(); - }, - continueDistantGrab: function() { - }, + startFarTrigger: function() { + print('START FAR TRIGGER ON CLOSE BUTTON!!!') + Messages.sendMessage('Hifi-Light-Modifier-Cleanup', 'callCleanup') + } }; diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 76c1cdc873..5aa367dbbc 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -262,7 +262,7 @@ entitySlider.prototype = { color: this.color, position: sliderPosition, script: SLIDER_SCRIPT_URL, - ignoreForCollisions:true, + ignoreForCollisions: true, userData: JSON.stringify({ lightModifierKey: { lightID: this.lightID, @@ -407,30 +407,52 @@ function makeSliders(light) { subscribeToSliderMessages(); }; + +function createLightModel(position) { + var blockProperties = { + name: 'Hifi-Spotlight-Model', + type: 'Model', + shapeType: 'box', + modelURL: LIGHT_MODEL_URL, + dimensions: LIGHT_MODEL_DIMENSIONS, + collisionsWillMove: true, + position: position, + script: PARENT_SCRIPT_URL, + userData: JSON.stringify({ + handControllerKey: { + disableReleaseVelocity: true + } + }) + }; + + var block = Entities.addEntity(blockProperties); + + return block +} + var closeButtons = []; function createCloseButton(endOfAxis) { - // var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); - // var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(avatarRot))); - // var verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); - // var verticalOffset = lastRowVerticalOffset; - // var downPosition = Vec3.sum(basePosition, verticalOffset); - // var rightVector = Quat.getRight(avatarRot); - // var extension = Vec3.multiply(AXIS_SCALE, rightVector); - // var position = Vec3.sum(downPosition, extension); var buttonProperties = { - name:'Hifi-Close-Button', + name: 'Hifi-Close-Button', type: 'Model', modelURL: CLOSE_BUTTON_MODEL_URL, dimensions: CLOSE_BUTTON_DIMENSIONS, - position: Vec3.sum(endOfAxis,{ - x:0, - y:-0.15, - z:0 + position: Vec3.sum(endOfAxis, { + x: 0, + y: -0.15, + z: 0 }), rotation: Quat.fromPitchYawRollDegrees(0, 45, 90), - collisionsWillMove: false + collisionsWillMove: false, + ignoreForCollisions: true, + script: CLOSE_BUTTON_SCRIPT_URL, + userData: JSON.stringify({ + grabbableKey: { + wantsTrigger: true + } + }) //need to add wantsTrigger stuff so we can interact with it with our beamz } @@ -469,6 +491,11 @@ function subscribeToLightOverlayRayCheckMessages() { Messages.messageReceived.connect(handleLightOverlayRayCheckMessages); } +function subscribeToCleanupMessages() { + Messages.subscribe('Hifi-Light-Modifier-Cleanup'); + Messages.messageReceived.connect(handleCleanupMessages); +} + function handleLightModMessages(channel, message, sender) { if (channel !== 'Hifi-Light-Mod-Receiver') { @@ -513,9 +540,9 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { var pickRay = JSON.parse(message); var doesIntersect = lightOverlayManager.findRayIntersection(pickRay); - print('DOES INTERSECT A LIGHT WE HAVE???' + doesIntersect.intersects); + // print('DOES INTERSECT A LIGHT WE HAVE???' + doesIntersect.intersects); if (doesIntersect.intersects === true) { - print('FULL MESSAGE:::' + JSON.stringify(doesIntersect)) + // print('FULL MESSAGE:::' + JSON.stringify(doesIntersect)) var lightID = doesIntersect.entityID; if (currentLight === lightID) { @@ -525,7 +552,6 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); - // block = createBlock(lightProperties.position); block = createLightModel(lightProperties.position); var light = { @@ -542,103 +568,70 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { Entities.editEntity(lightID, { parentID: block, - parentJointIndex:-1 + parentJointIndex: -1 }); - } } -function createLightModel(position) { - print('CREATE MODEL') - var blockProperties = { - name: 'Hifi-Spotlight-Model', - type: 'Model', - shapeType: 'box', - modelURL: LIGHT_MODEL_URL, - // modelURL:"http://hifi-content.s3.amazonaws.com/james/light_modifier/box4.fbx", - dimensions: LIGHT_MODEL_DIMENSIONS, - collisionsWillMove: true, - position: position, - // rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), - script: PARENT_SCRIPT_URL, - userData: JSON.stringify({ - handControllerKey: { - disableReleaseVelocity: true - } - }) - }; +function handleCleanupMessages(channel, message, sender) { - var block = Entities.addEntity(blockProperties); - - return block + if (channel !== 'Hifi-Light-Modifier-Cleanup') { + return; + } + if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) { + return; + } + if (message === 'callCleanup') { + print('GOT CLEANUP CALL!!!'); + cleanup(true); + } } -function createBlock(position) { - print('CREATE BLOCK') - - var blockProperties = { - name: 'Hifi-Spotlight-Block', - type: 'Box', - dimensions: { - x: 1, - y: 4, - z: 1 - }, - color: { - red: 0, - green: 0, - blue: 255 - }, - collisionsWillMove: true, - position: position, - script: PARENT_SCRIPT_URL, - userData: JSON.stringify({ - handControllerKey: { - disableReleaseVelocity: true - } - }) - }; - - var block = Entities.addEntity(blockProperties); - - return block -} - -function cleanup() { +function cleanup(fromMessage) { var i; for (i = 0; i < sliders.length; i++) { Entities.deleteEntity(sliders[i].axis); Entities.deleteEntity(sliders[i].sliderIndicator); } - while(closeButtons.length>0){ + while (closeButtons.length > 0) { Entities.deleteEntity(closeButtons.pop()); } - Entities.deleteEntity(block); + //if the light was already parented to something we will want to restore that. or come up with groups or something clever. + Entities.editEntity(currentLight, { + parentID: null, + }); + + if(fromMessage!==true){ Messages.messageReceived.disconnect(handleLightModMessages); Messages.messageReceived.disconnect(handleValueMessages); - Entities.deletingEntity.disconnect(deleteEntity); - + Messages.messageReceived.disconnect(handleLightOverlayRayCheckMessages); lightOverlayManager.setVisible(false); + } + + selectionManager.clearSelections(); Script.update.disconnect(rotateCloseButtons); + print('DELETE LIGHT MODEL::: ' + block); + Entities.deleteEntity(block); + currentLight = null; + + } Script.scriptEnding.connect(cleanup); -function deleteEntity(entityID) { - if (entityID === light) { - // cleanup(); - } -} +Script.scriptEnding.connect(function() { + lightOverlayManager.setVisible(false); +}) -Entities.deletingEntity.connect(deleteEntity); subscribeToLightOverlayRayCheckMessages(); subScribeToNewLights(); +subscribeToCleanupMessages(); From e405311cc8018fc870cf3291a2082174cec89ec1 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 16:35:06 -0800 Subject: [PATCH 106/209] cleanup --- examples/light_modifier/closeButton.js | 1 - examples/light_modifier/lightModifier.js | 2 -- 2 files changed, 3 deletions(-) diff --git a/examples/light_modifier/closeButton.js b/examples/light_modifier/closeButton.js index 7b2869cc8e..72fcfbc382 100644 --- a/examples/light_modifier/closeButton.js +++ b/examples/light_modifier/closeButton.js @@ -27,7 +27,6 @@ }, startFarTrigger: function() { - print('START FAR TRIGGER ON CLOSE BUTTON!!!') Messages.sendMessage('Hifi-Light-Modifier-Cleanup', 'callCleanup') } diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 5aa367dbbc..d813216be5 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -583,7 +583,6 @@ function handleCleanupMessages(channel, message, sender) { return; } if (message === 'callCleanup') { - print('GOT CLEANUP CALL!!!'); cleanup(true); } } @@ -615,7 +614,6 @@ function cleanup(fromMessage) { selectionManager.clearSelections(); Script.update.disconnect(rotateCloseButtons); - print('DELETE LIGHT MODEL::: ' + block); Entities.deleteEntity(block); currentLight = null; From f83476599090eef8ae08488283ebe898e5d0e0da Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 16:39:21 -0800 Subject: [PATCH 107/209] readme --- examples/light_modifier/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index 3bd456d525..73c2199ec9 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -1,5 +1,7 @@ This PR demonstrates one way in-world editing of objects might work. We start with a spotlight. When you distant grab the sliders, you can move them along their axis to change their values. You may also rotate / move the block to which the spotlight is attached. +Enter edit mode by running your distance beam through a light overlay. Exit using the red X. + To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js To reset, I recommend stopping all scripts then re-loading lightLoader.js @@ -23,6 +25,4 @@ intensity cutoff exponent -To-Do: Determine how to enter / exit edit mode , support near grab, add other input types (checkbox, etc), prevent velocity drift on slider release,button to hide entity - -![capture](https://cloud.githubusercontent.com/assets/843228/11830366/2f2dfe70-a359-11e5-84f0-33a380ebeac7.PNG) +![capture](https://cloud.githubusercontent.com/assets/843228/11910139/afaaf1ae-a5a5-11e5-8b66-0eb3fc6976df.PNG) From 4afdd0242bfaf907b4dbdf4a6c707e1ca2aebd24 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 16:44:20 -0800 Subject: [PATCH 108/209] cleanup --- .../light_modifier/lightModifierTestScene.js | 52 ++----------------- 1 file changed, 4 insertions(+), 48 deletions(-) diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 8df83b09bf..58956850f2 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -10,19 +10,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?'+Math.random(0-100)); +var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?' + Math.random(0 - 100)); var basePosition, avatarRot; avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(0, Quat.getUp(avatarRot))); -var light, block; +var light; function createLight() { - var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); - var position = basePosition; + var position = basePosition; position.y += 2; - var lightTransform = evalLightWorldTransform(position,avatarRot); - // var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); + var lightTransform = evalLightWorldTransform(position, avatarRot); var lightProperties = { name: 'Hifi-Spotlight', type: "Light", @@ -32,7 +30,6 @@ function createLight() { y: 2, z: 8 }, - // parentID: block, color: { red: 255, green: 0, @@ -48,45 +45,6 @@ function createLight() { light = Entities.addEntity(lightProperties); - var message = { - light: { - id: light, - type: 'spotlight', - initialProperties: lightProperties - } - }; - -// Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); - -} - -function createBlock() { - var position = basePosition; - position.y += 3; - var blockProperties = { - name: 'Hifi-Spotlight-Block', - type: 'Box', - dimensions: { - x: 1, - y: 1, - z: 1 - }, - collisionsWillMove: true, - color: { - red: 0, - green: 0, - blue: 255 - }, - position: position, - script:PARENT_SCRIPT_URL, - userData: JSON.stringify({ - handControllerKey: { - disableReleaseVelocity: true - } - }) - }; - - block = Entities.addEntity(blockProperties); } function evalLightWorldTransform(modelPos, modelRot) { @@ -107,11 +65,9 @@ function evalLightWorldTransform(modelPos, modelRot) { } function cleanup() { - //Entities.deleteEntity(block); Entities.deleteEntity(light); } Script.scriptEnding.connect(cleanup); -//createBlock(); createLight(); \ No newline at end of file From b0da1773c246f4d619824355c336c2dac1c2869e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 16:53:41 -0800 Subject: [PATCH 109/209] have right rotation on sequential edits --- examples/light_modifier/lightModifier.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index d813216be5..0d07f2c011 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -60,7 +60,7 @@ var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); -var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_rotated.fbx'; +var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_very_good.fbx'; var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx'; var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100)); @@ -408,7 +408,7 @@ function makeSliders(light) { }; -function createLightModel(position) { +function createLightModel(position,rotation) { var blockProperties = { name: 'Hifi-Spotlight-Model', type: 'Model', @@ -417,6 +417,7 @@ function createLightModel(position) { dimensions: LIGHT_MODEL_DIMENSIONS, collisionsWillMove: true, position: position, + rotation:rotation, script: PARENT_SCRIPT_URL, userData: JSON.stringify({ handControllerKey: { @@ -552,7 +553,7 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); - block = createLightModel(lightProperties.position); + block = createLightModel(lightProperties.position,lightProperties.rotation); var light = { id: lightID, From 1beec0dbe7c46327bc0553734fa5871bbf3fc90d Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 18:15:05 -0800 Subject: [PATCH 110/209] balls --- examples/controllers/handControllerGrab.js | 21 ++++++---- examples/flowArts/arcBall/arcBall.js | 11 ++++- .../flowArts/arcBall/arcBallEntityScript.js | 42 ++++++++++++------- 3 files changed, 49 insertions(+), 25 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 07894b46d1..fb7ba8a4f6 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -861,20 +861,25 @@ function MyController(hand) { var handPosition = this.getHandPosition(); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - + var objectRotation = grabbedProperties.rotation; + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { // if an object is "equipped" and has a spatialKey, use it. this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + if (grabbableData.spatialKey.relativePosition) { + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + } else { + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + if (grabbableData.spatialKey.relativeRotation) { + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + } } else { this.ignoreIK = false; - - var objectRotation = grabbedProperties.rotation; this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var currentObjectPosition = grabbedProperties.position; - var offset = Vec3.subtract(currentObjectPosition, handPosition); this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); } diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 736920ddd5..f779f65643 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -26,7 +26,7 @@ ArcBall = function(spawnPosition) { var containerBall = Entities.addEntity({ - type: "Box", + type: "Sphere", name: "Arc Ball", script: scriptURL, position: Vec3.sum(spawnPosition, { @@ -37,7 +37,7 @@ ArcBall = function(spawnPosition) { dimensions: { x: .1, y: .1, - z: .2 + z: .1 }, color: { red: 15, @@ -48,6 +48,13 @@ ArcBall = function(spawnPosition) { collisionsWillMove: true, userData: JSON.stringify({ grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.5 + }, + }, invertSolidWhileHeld: true } }) diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 4ad0d66257..7cae0a9cb0 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -25,6 +25,7 @@ entities.forEach(function(entity) { var props = Entities.getEntityProperties(entity, ["position", "name"]); if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { + _this.target = entity; _this.createBeam(position, props.position); } }); @@ -32,21 +33,13 @@ }, createBeam: function(startPosition, endPosition) { - print("CREATE BEAM") // Creates particle arc from start position to end position var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - testBox = Entities.addEntity({ - type: "Box", - dimensions: {x: .1, y: .1, z: 1}, - color: {red: 200, green: 10, blue: 10}, - position: startPosition, - rotation: emitOrientation, - visible: false - }); + var color = { red: 200, green: 10, @@ -57,7 +50,7 @@ name: "Particle Arc", parentID: this.entityID, parentJointIndex: -1, - position: startPosition, + // position: startPosition, isEmitting: true, colorStart: color, color: { @@ -67,7 +60,7 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 6, + lifespan: 5, emitRate: 1000, emitOrientation: emitOrientation, emitSpeed: .4, @@ -103,13 +96,32 @@ this.particleArc = Entities.addEntity(props); }, - continueNearGrab: function() {}, + updateBeam: function(startPosition) { + var targetPosition = Entities.getEntityProperties(this.target, "position").position; + print("TARGET position " + JSON.stringify(this.target)); + var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; + var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); + Entities.editEntity(this.particleArc, {emitOrientation: emitOrientation}); + Entities.editEntity(this.testBox, {rotation: emitOrientation}); + }, - releaseGrab: function() {}, + continueNearGrab: function() { + var startPosition = Entities.getEntityProperties(this.entityID, "position").position; + this.updateBeam(startPosition); + }, + + releaseGrab: function() { + Entities.editEntity(this.particleArc, { + isEmitting: false + }); + }, unload: function() { - Entities.deleteEntity(this.particleArc); - Entities.deleteEntity(testBox); + if (this.particleArc) { + Entities.deleteEntity(this.particleArc); + } }, preload: function(entityID) { From eb03dcd8215aa92737b10ae5371eb181795ebe92 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 12:47:44 -0800 Subject: [PATCH 111/209] keep parent of lights that already have parents --- examples/light_modifier/lightModifier.js | 36 +++++++++++++++--------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 0d07f2c011..e82897e049 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -47,10 +47,6 @@ if (SHOW_OVERLAYS === true) { lightOverlayManager.setVisible(true); } -// var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking -// var pickRay = Camera.computePickRay(event.x, event.y); -// var lightResult = lightOverlayManager.findRayIntersection(pickRay) - var DEFAULT_PARENT_ID = '{00000000-0000-0000-0000-000000000000}' var AXIS_SCALE = 1; @@ -408,7 +404,7 @@ function makeSliders(light) { }; -function createLightModel(position,rotation) { +function createLightModel(position, rotation) { var blockProperties = { name: 'Hifi-Spotlight-Model', type: 'Model', @@ -417,7 +413,7 @@ function createLightModel(position,rotation) { dimensions: LIGHT_MODEL_DIMENSIONS, collisionsWillMove: true, position: position, - rotation:rotation, + rotation: rotation, script: PARENT_SCRIPT_URL, userData: JSON.stringify({ handControllerKey: { @@ -529,6 +525,7 @@ function handleValueMessages(channel, message, sender) { var currentLight; var block; +var hasParent = false; function handleLightOverlayRayCheckMessages(channel, message, sender) { if (channel !== 'Hifi-Light-Overlay-Ray-Check') { @@ -553,7 +550,16 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); - block = createLightModel(lightProperties.position,lightProperties.rotation); + if (lightProperties.parentID !== DEFAULT_PARENT_ID) { + //this light has a parent already. so lets call our block the parent and then make sure not to delete it at the end; + hasParent = true; + block = lightProperties.parentID; + if (lightProperties.parentJointIndex !== -1) { + //should make sure to retain the parent too. but i don't actually know what the + } + } else { + block = createLightModel(lightProperties.position, lightProperties.rotation); + } var light = { id: lightID, @@ -604,18 +610,20 @@ function cleanup(fromMessage) { parentID: null, }); - if(fromMessage!==true){ - Messages.messageReceived.disconnect(handleLightModMessages); - Messages.messageReceived.disconnect(handleValueMessages); - Messages.messageReceived.disconnect(handleLightOverlayRayCheckMessages); - lightOverlayManager.setVisible(false); + if (fromMessage !== true) { + Messages.messageReceived.disconnect(handleLightModMessages); + Messages.messageReceived.disconnect(handleValueMessages); + Messages.messageReceived.disconnect(handleLightOverlayRayCheckMessages); + lightOverlayManager.setVisible(false); } selectionManager.clearSelections(); Script.update.disconnect(rotateCloseButtons); - - Entities.deleteEntity(block); + if (hasParent === false) { + Entities.deleteEntity(block); + } + hasParent = false; currentLight = null; From 378d50d8a3174086ae451e3a048ff3aa96e7ac62 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 12:49:42 -0800 Subject: [PATCH 112/209] update overlays when cutoff slider is used --- examples/light_modifier/slider.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/light_modifier/slider.js b/examples/light_modifier/slider.js index dc02e0bdba..6c67d35204 100644 --- a/examples/light_modifier/slider.js +++ b/examples/light_modifier/slider.js @@ -95,6 +95,9 @@ sliderValue: _t.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); + if (_t.userData.sliderType === 'cutoff') { + Messages.sendMessage('entityToolUpdates', 'callUpdate'); + } } }; From 05467bd5e1a356afca087c151f0c77f29aa5e238 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 18:19:00 -0800 Subject: [PATCH 113/209] create panel entity and parent panel to it --- examples/light_modifier/lightModifier.js | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index e82897e049..14053c7974 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -363,6 +363,10 @@ var light = null; function makeSliders(light) { + if (USE_PARENTED_PANEL === true) { + createPanelEntity(MyAvatar.position); + } + if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -398,12 +402,55 @@ function makeSliders(light) { sliders.push(slidersRef.exponent); } + + createCloseButton(slidersRef.exponent.endOfAxis); subscribeToSliderMessages(); + + if (USE_PARENTED_PANEL === true) { + parentEntitiesToPanel(); + } }; +function parentEntitiesToPanel(panel) { + slidersRef.forEach(function(slider) { + Entities.editEntity(slider.axis, { + parentID: panel + }) + Entities.editEntity(slider.sliderIndicator, { + parentID: panel + }) + }) + + closeButtons.forEach(function(button) { + Entities.editEntity(slider.sliderIndicator, { + parentID: panel + }) + }) +} + +function createPanelEntity(position) { + + var panelProperties = { + name: 'Hifi-Slider-Panel', + type: 'Box', + dimensions: { + x: 0.1, + y: 0.1, + z: 0.1 + }, + visible: false, + collisionsWillMove: false, + ignoreForCollisions: true + } + + var panel = Entities.addEntity(panelProperties); + return panel +} + + function createLightModel(position, rotation) { var blockProperties = { name: 'Hifi-Spotlight-Model', From 9f0d254739df2a9a158c01a138a85717dcad0812 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 19:11:17 -0800 Subject: [PATCH 114/209] panel entity, readme --- examples/light_modifier/README.md | 16 ++++++------- examples/light_modifier/lightModifier.js | 29 ++++++++++++++++-------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index 73c2199ec9..b12ff7550b 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -1,6 +1,8 @@ -This PR demonstrates one way in-world editing of objects might work. We start with a spotlight. When you distant grab the sliders, you can move them along their axis to change their values. You may also rotate / move the block to which the spotlight is attached. +This PR demonstrates one way in-world editing of objects might work. -Enter edit mode by running your distance beam through a light overlay. Exit using the red X. +Running this script will show light overlay icons in-world. Enter edit mode by running your distance beam through a light overlay. Exit using the red X. + +When you distant grab the sliders, you can move them along their axis to change their values. You may also rotate / move the block to which the spotlight is attached. To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js To reset, I recommend stopping all scripts then re-loading lightLoader.js @@ -8,14 +10,12 @@ To reset, I recommend stopping all scripts then re-loading lightLoader.js When you run the lightLoader.js script, several scripts will be loaded: - handControllerGrab.js (custom) - lightModifier.js (listens for message to create sliders for a given light) -- lightModifierTestScene.js (creates a light and parents it to a block, then sends a message ^^) +- lightModifierTestScene.js (creates a light) - slider.js (attached to each slider entity) -- lightParent.js (attached to the entity to which a light is parented, so you can move it around) +- lightParent.js (attached to a 3d model of a light, to which a light is parented, so you can move it around. or keep the current parent if a light already has a parent) - closeButton.js (for closing the ui) -- ../libraries/lightOverlayManager.js (custom) -- ../libraries/entitySelectionTool.js - - +- ../libraries/lightOverlayManager.js (shows 2d overlays for lights in the world) +- ../libraries/entitySelectionTool.js (visualizes volume of the lights) Current sliders are (top to bottom): red diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 14053c7974..30f004c922 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -16,13 +16,14 @@ var SLIDERS_SHOULD_STAY_WITH_AVATAR = false; var VERTICAL_SLIDERS = false; var SHOW_OVERLAYS = true; var SHOW_LIGHT_VOLUME = true; +var USE_PARENTED_PANEL = false; //variables for managing overlays var selectionDisplay; var selectionManager; var lightOverlayManager; -//for when we make a block parent for the light +//for when we make a 3d model of a light a parent for the light var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?' + Math.random(0 - 100)); if (SHOW_OVERLAYS === true) { @@ -362,9 +363,9 @@ var slidersRef = { var light = null; function makeSliders(light) { - + var panel; if (USE_PARENTED_PANEL === true) { - createPanelEntity(MyAvatar.position); + panel = createPanelEntity(MyAvatar.position); } if (light.type === 'spotlight') { @@ -409,10 +410,21 @@ function makeSliders(light) { subscribeToSliderMessages(); if (USE_PARENTED_PANEL === true) { - parentEntitiesToPanel(); + parentEntitiesToPanel(panel); + } + + if () { + parentPanelToAvatar(panel) } }; +function parentPanelToAvatar(panel) { + Entities.editEntity(panel, { + parentID: MyAvatar.sessionUUID, + //actually figure out which one to parent it to -- probably a spine or something. + parentJointIndex: 1, + }) +} function parentEntitiesToPanel(panel) { slidersRef.forEach(function(slider) { @@ -493,11 +505,10 @@ function createCloseButton(endOfAxis) { ignoreForCollisions: true, script: CLOSE_BUTTON_SCRIPT_URL, userData: JSON.stringify({ - grabbableKey: { - wantsTrigger: true - } - }) - //need to add wantsTrigger stuff so we can interact with it with our beamz + grabbableKey: { + wantsTrigger: true + } + }) } var button = Entities.addEntity(buttonProperties); From daa262af7d33d18866d304a5c3b9d1c5e33aeb55 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 19:14:19 -0800 Subject: [PATCH 115/209] readme --- examples/light_modifier/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index b12ff7550b..4a2690cd91 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -8,7 +8,7 @@ To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js To reset, I recommend stopping all scripts then re-loading lightLoader.js When you run the lightLoader.js script, several scripts will be loaded: -- handControllerGrab.js (custom) +- handControllerGrab.js (will not impart velocity when you move the parent or a slider, will not move sliders with head movement,will constrain movement for a slider to a given axis start and end) - lightModifier.js (listens for message to create sliders for a given light) - lightModifierTestScene.js (creates a light) - slider.js (attached to each slider entity) From 485bb4ee3f3948f505fdffda30bc67bafa1c3428 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 19:14:56 -0800 Subject: [PATCH 116/209] slider should stay with avatr --- examples/light_modifier/lightModifier.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 30f004c922..02d764e7e2 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -413,7 +413,7 @@ function makeSliders(light) { parentEntitiesToPanel(panel); } - if () { + if (SLIDERS_SHOULD_STAY_WITH_AVATAR) { parentPanelToAvatar(panel) } }; From da57e29096069c06f841aa4e6d6fdbed27989e71 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sun, 20 Dec 2015 16:40:41 -0800 Subject: [PATCH 117/209] start options, cleanup --- examples/light_modifier/README.md | 2 +- examples/light_modifier/slider.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index 4a2690cd91..1358fbe917 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -9,7 +9,7 @@ To reset, I recommend stopping all scripts then re-loading lightLoader.js When you run the lightLoader.js script, several scripts will be loaded: - handControllerGrab.js (will not impart velocity when you move the parent or a slider, will not move sliders with head movement,will constrain movement for a slider to a given axis start and end) -- lightModifier.js (listens for message to create sliders for a given light) +- lightModifier.js (listens for message to create sliders for a given light. will start with slider set to the light's initial properties) - lightModifierTestScene.js (creates a light) - slider.js (attached to each slider entity) - lightParent.js (attached to a 3d model of a light, to which a light is parented, so you can move it around. or keep the current parent if a light already has a parent) diff --git a/examples/light_modifier/slider.js b/examples/light_modifier/slider.js index 6c67d35204..e1dfea4e87 100644 --- a/examples/light_modifier/slider.js +++ b/examples/light_modifier/slider.js @@ -50,16 +50,16 @@ var distance = Vec3.distance(this.userData.axisStart, currentPosition); if (this.userData.sliderType === 'color_red' || this.userData.sliderType === 'color_green' || this.userData.sliderType === 'color_blue') { - this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, COLOR_MAX); + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, COLOR_MAX); } if (this.userData.sliderType === 'intensity') { - this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, INTENSITY_MAX); + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, INTENSITY_MAX); } if (this.userData.sliderType === 'cutoff') { - this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, CUTOFF_MAX); + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, CUTOFF_MAX); } if (this.userData.sliderType === 'exponent') { - this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, EXPONENT_MAX); }; this.sendValueToSlider(); @@ -80,10 +80,10 @@ this.sendValueToSlider(); }, - scaleValueBasedOnDistanceFromStart: function(value, max2) { + scaleValueBasedOnDistanceFromStart: function(value, min2, max2) { var min1 = 0; var max1 = AXIS_SCALE; - var min2 = 0; + var min2 = min2; var max2 = max2; return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); }, From dcde640acdde332a861b6d8d9117855bf1685360 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 18 Dec 2015 19:13:59 -0800 Subject: [PATCH 118/209] Stub Perception Neuron input plugin --- interface/resources/controllers/neuron.json | 7 ++ plugins/neuron/CMakeLists.txt | 13 ++++ plugins/neuron/src/NeuronPlugin.cpp | 75 +++++++++++++++++++++ plugins/neuron/src/NeuronPlugin.h | 57 ++++++++++++++++ plugins/neuron/src/NeuronProvider.cpp | 45 +++++++++++++ plugins/neuron/src/plugin.json | 1 + 6 files changed, 198 insertions(+) create mode 100644 interface/resources/controllers/neuron.json create mode 100644 plugins/neuron/CMakeLists.txt create mode 100644 plugins/neuron/src/NeuronPlugin.cpp create mode 100644 plugins/neuron/src/NeuronPlugin.h create mode 100644 plugins/neuron/src/NeuronProvider.cpp create mode 100644 plugins/neuron/src/plugin.json diff --git a/interface/resources/controllers/neuron.json b/interface/resources/controllers/neuron.json new file mode 100644 index 0000000000..2d61f80c35 --- /dev/null +++ b/interface/resources/controllers/neuron.json @@ -0,0 +1,7 @@ +{ + "name": "Neuron to Standard", + "channels": [ + { "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, + { "from": "Hydra.RightHand", "to": "Standard.RightHand" } + ] +} diff --git a/plugins/neuron/CMakeLists.txt b/plugins/neuron/CMakeLists.txt new file mode 100644 index 0000000000..b86d310ab7 --- /dev/null +++ b/plugins/neuron/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Created by Anthony Thibault on 2015/12/18 +# Copyright 2015 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html +# + +set(TARGET_NAME neuron) +setup_hifi_plugin(Script Qml Widgets) +link_hifi_libraries(shared controllers plugins input-plugins) +# target_neuron() + diff --git a/plugins/neuron/src/NeuronPlugin.cpp b/plugins/neuron/src/NeuronPlugin.cpp new file mode 100644 index 0000000000..735b81a1ef --- /dev/null +++ b/plugins/neuron/src/NeuronPlugin.cpp @@ -0,0 +1,75 @@ +// +// NeuronPlugin.h +// input-plugins/src/input-plugins +// +// Created by Anthony Thibault on 12/18/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "NeuronPlugin.h" + +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(inputplugins) +Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") + +const QString NeuronPlugin::NAME = "Neuron"; +const QString NeuronPlugin::NEURON_ID_STRING = "Perception Neuron"; + +bool NeuronPlugin::isSupported() const { + // TODO: + return true; +} + +void NeuronPlugin::activate() { + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::activate"; +} + +void NeuronPlugin::deactivate() { + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::deactivate"; +} + +void NeuronPlugin::pluginUpdate(float deltaTime, bool jointsCaptured) { + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::pluginUpdate"; +} + +void NeuronPlugin::saveSettings() const { + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::saveSettings"; +} + +void NeuronPlugin::loadSettings() { + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::loadSettings"; +} + +controller::Input::NamedVector NeuronPlugin::InputDevice::getAvailableInputs() const { + // TODO: + static const controller::Input::NamedVector availableInputs { + makePair(controller::LEFT_HAND, "LeftHand"), + makePair(controller::RIGHT_HAND, "RightHand") + }; + return availableInputs; +} + +QString NeuronPlugin::InputDevice::getDefaultMappingConfig() const { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/neuron.json"; + return MAPPING_JSON; +} + +void NeuronPlugin::InputDevice::update(float deltaTime, bool jointsCaptured) { + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::InputDevice::update"; +} + +void NeuronPlugin::InputDevice::focusOutEvent() { + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::InputDevice::focusOutEvent"; +} diff --git a/plugins/neuron/src/NeuronPlugin.h b/plugins/neuron/src/NeuronPlugin.h new file mode 100644 index 0000000000..59e0f0a393 --- /dev/null +++ b/plugins/neuron/src/NeuronPlugin.h @@ -0,0 +1,57 @@ +// +// NeuronPlugin.h +// input-plugins/src/input-plugins +// +// Created by Anthony Thibault on 12/18/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_NeuronPlugin_h +#define hifi_NeuronPlugin_h + +#include +#include +#include + +// Handles interaction with the Neuron SDK +class NeuronPlugin : public InputPlugin { + Q_OBJECT +public: + // Plugin functions + virtual bool isSupported() const override; + virtual bool isJointController() const override { return true; } + const QString& getName() const override { return NAME; } + const QString& getID() const override { return NEURON_ID_STRING; } + + virtual void activate() override; + virtual void deactivate() override; + + virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } + virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override; + + virtual void saveSettings() const override; + virtual void loadSettings() override; + +private: + class InputDevice : public controller::InputDevice { + public: + InputDevice() : controller::InputDevice("Neuron") {} + + // Device functions + virtual controller::Input::NamedVector getAvailableInputs() const override; + virtual QString getDefaultMappingConfig() const override; + virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void focusOutEvent() override; + }; + + std::shared_ptr _inputDevice { std::make_shared() }; + + static const QString NAME; + static const QString NEURON_ID_STRING; +}; + +#endif // hifi_NeuronPlugin_h + diff --git a/plugins/neuron/src/NeuronProvider.cpp b/plugins/neuron/src/NeuronProvider.cpp new file mode 100644 index 0000000000..b171c5150d --- /dev/null +++ b/plugins/neuron/src/NeuronProvider.cpp @@ -0,0 +1,45 @@ +// +// Created by Anthony Thibault on 2015/12/18 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include +#include +#include + +#include +#include + +#include "NeuronPlugin.h" + +class NeuronProvider : public QObject, public InputProvider +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID InputProvider_iid FILE "plugin.json") + Q_INTERFACES(InputProvider) + +public: + NeuronProvider(QObject* parent = nullptr) : QObject(parent) {} + virtual ~NeuronProvider() {} + + virtual InputPluginList getInputPlugins() override { + static std::once_flag once; + std::call_once(once, [&] { + InputPluginPointer plugin(new NeuronPlugin()); + if (plugin->isSupported()) { + _inputPlugins.push_back(plugin); + } + }); + return _inputPlugins; + } + +private: + InputPluginList _inputPlugins; +}; + +#include "NeuronProvider.moc" diff --git a/plugins/neuron/src/plugin.json b/plugins/neuron/src/plugin.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/plugins/neuron/src/plugin.json @@ -0,0 +1 @@ +{} From 7a7befafb9e4afc78039d4a4f99da1b53763ea5f Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 10:43:59 -0800 Subject: [PATCH 119/209] arc balls working --- examples/controllers/handControllerGrab.js | 54 ++++++++++++------- examples/flowArts/arcBall/arcBall.js | 27 ++++++---- .../flowArts/arcBall/arcBallEntityScript.js | 47 ++++++++++------ 3 files changed, 81 insertions(+), 47 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 07894b46d1..6cacc2e80a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -218,6 +218,7 @@ function getSpatialOffsetPosition(hand, spatialKey) { } var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + function getSpatialOffsetRotation(hand, spatialKey) { var rotation = Quat.IDENTITY; @@ -261,9 +262,9 @@ function MyController(hand) { this.triggerValue = 0; // rolling average of trigger value this.rawTriggerValue = 0; this.rawBumperValue = 0; - + this.overlayLine = null; - + this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; @@ -819,8 +820,16 @@ function MyController(hand) { // mix in head motion if (MOVE_WITH_HEAD) { var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { x: 0.0, y: 0.0, z: objDistance }); - var after = Vec3.multiplyQbyV(Camera.orientation, { x: 0.0, y: 0.0, z: objDistance }); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); var change = Vec3.subtract(before, after); this.currentCameraOrientation = Camera.orientation; this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); @@ -861,20 +870,25 @@ function MyController(hand) { var handPosition = this.getHandPosition(); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - + var objectRotation = grabbedProperties.rotation; + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { // if an object is "equipped" and has a spatialKey, use it. this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + if (grabbableData.spatialKey.relativePosition) { + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + } else { + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + if (grabbableData.spatialKey.relativeRotation) { + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + } } else { this.ignoreIK = false; - - var objectRotation = grabbedProperties.rotation; this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var currentObjectPosition = grabbedProperties.position; - var offset = Vec3.subtract(currentObjectPosition, handPosition); this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); } @@ -1304,10 +1318,10 @@ Controller.enableMapping(MAPPING_NAME); var handToDisable = 'none'; function update() { - if (handToDisable !== LEFT_HAND && handToDisable!=='both') { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { leftController.update(); } - if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { rightController.update(); } } @@ -1315,7 +1329,7 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { - + if (sender === MyAvatar.sessionUUID) { if (message === 'left') { handToDisable = LEFT_HAND; @@ -1323,11 +1337,11 @@ handleHandDisablerMessages = function(channel, message, sender) { if (message === 'right') { handToDisable = RIGHT_HAND; } - if(message==='both'){ - handToDisable='both'; + if (message === 'both') { + handToDisable = 'both'; } - if(message==='none'){ - handToDisable='none'; + if (message === 'none') { + handToDisable = 'none'; } } @@ -1342,4 +1356,4 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -Script.update.connect(update); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 736920ddd5..54cb16fe15 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -26,7 +26,7 @@ ArcBall = function(spawnPosition) { var containerBall = Entities.addEntity({ - type: "Box", + type: "Sphere", name: "Arc Ball", script: scriptURL, position: Vec3.sum(spawnPosition, { @@ -35,12 +35,12 @@ ArcBall = function(spawnPosition) { z: 0 }), dimensions: { - x: .1, - y: .1, - z: .2 + x: .05, + y: .05, + z: .05 }, color: { - red: 15, + red: 100, green: 10, blue: 150 }, @@ -48,6 +48,13 @@ ArcBall = function(spawnPosition) { collisionsWillMove: true, userData: JSON.stringify({ grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.5 + }, + }, invertSolidWhileHeld: true } }) @@ -127,11 +134,11 @@ ArcBall = function(spawnPosition) { - function cleanup() { - Entities.deleteEntity(arcBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(light); - } + function cleanup() { + Entities.deleteEntity(arcBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } this.cleanup = cleanup; } \ No newline at end of file diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 4ad0d66257..7bb8472ce9 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -25,6 +25,7 @@ entities.forEach(function(entity) { var props = Entities.getEntityProperties(entity, ["position", "name"]); if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { + _this.target = entity; _this.createBeam(position, props.position); } }); @@ -32,21 +33,13 @@ }, createBeam: function(startPosition, endPosition) { - print("CREATE BEAM") - // Creates particle arc from start position to end position + // Creates particle arc from start position to end position var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - testBox = Entities.addEntity({ - type: "Box", - dimensions: {x: .1, y: .1, z: 1}, - color: {red: 200, green: 10, blue: 10}, - position: startPosition, - rotation: emitOrientation, - visible: false - }); + var color = { red: 200, green: 10, @@ -57,7 +50,7 @@ name: "Particle Arc", parentID: this.entityID, parentJointIndex: -1, - position: startPosition, + // position: startPosition, isEmitting: true, colorStart: color, color: { @@ -67,7 +60,7 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 6, + lifespan: 5, emitRate: 1000, emitOrientation: emitOrientation, emitSpeed: .4, @@ -98,18 +91,38 @@ alphaStart: 0.5, alphaFinish: 0.5, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: false + emitterShouldTrail: true } this.particleArc = Entities.addEntity(props); }, - continueNearGrab: function() {}, + updateBeam: function(startPosition) { + var targetPosition = Entities.getEntityProperties(this.target, "position").position; + print("TARGET position " + JSON.stringify(this.target)); + var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; + var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + // emitOrientation = Quat.multiply(emitOrientation,Quat.inverse(rotation)); + Entities.editEntity(this.particleArc, { + emitOrientation: emitOrientation + }); + }, - releaseGrab: function() {}, + continueNearGrab: function() { + var startPosition = Entities.getEntityProperties(this.entityID, "position").position; + this.updateBeam(startPosition); + }, + + releaseGrab: function() { + Entities.editEntity(this.particleArc, { + isEmitting: false + }); + }, unload: function() { - Entities.deleteEntity(this.particleArc); - Entities.deleteEntity(testBox); + if (this.particleArc) { + Entities.deleteEntity(this.particleArc); + } }, preload: function(entityID) { From 45ba7a3d35c12e55207acbee615757f022e655e1 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 10:46:54 -0800 Subject: [PATCH 120/209] merged --- examples/controllers/handControllerGrab.js | 10 --------- .../flowArts/arcBall/arcBallEntityScript.js | 21 ------------------- 2 files changed, 31 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 6337079dc5..6cacc2e80a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -877,24 +877,14 @@ function MyController(hand) { // if an object is "equipped" and has a spatialKey, use it. this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; if (grabbableData.spatialKey.relativePosition) { -<<<<<<< HEAD this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); -======= - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); ->>>>>>> origin/polylineOptimizations } else { this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); } if (grabbableData.spatialKey.relativeRotation) { -<<<<<<< HEAD this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); } else { this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); -======= - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - } else { - this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); ->>>>>>> origin/polylineOptimizations } } else { this.ignoreIK = false; diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 539bdd7cf0..7bb8472ce9 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -33,21 +33,13 @@ }, createBeam: function(startPosition, endPosition) { -<<<<<<< HEAD // Creates particle arc from start position to end position -======= - // Creates particle arc from start position to end position ->>>>>>> origin/polylineOptimizations var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); -<<<<<<< HEAD -======= - ->>>>>>> origin/polylineOptimizations var color = { red: 200, green: 10, @@ -110,7 +102,6 @@ var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); -<<<<<<< HEAD // emitOrientation = Quat.multiply(emitOrientation,Quat.inverse(rotation)); Entities.editEntity(this.particleArc, { emitOrientation: emitOrientation @@ -122,18 +113,6 @@ this.updateBeam(startPosition); }, -======= - emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - Entities.editEntity(this.particleArc, {emitOrientation: emitOrientation}); - Entities.editEntity(this.testBox, {rotation: emitOrientation}); - }, - - continueNearGrab: function() { - var startPosition = Entities.getEntityProperties(this.entityID, "position").position; - this.updateBeam(startPosition); - }, - ->>>>>>> origin/polylineOptimizations releaseGrab: function() { Entities.editEntity(this.particleArc, { isEmitting: false From 48ab99c34864f5ecd2734900e4d89b29f964288d Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 11:00:10 -0800 Subject: [PATCH 121/209] rotation fix --- examples/flowArts/arcBall/arcBall.js | 8 +- .../flowArts/arcBall/arcBallEntityScript.js | 112 +++++++++--------- 2 files changed, 63 insertions(+), 57 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 54cb16fe15..f6860b54c6 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -31,7 +31,7 @@ ArcBall = function(spawnPosition) { script: scriptURL, position: Vec3.sum(spawnPosition, { x: 0, - y: .5, + y: .7, z: 0 }), dimensions: { @@ -51,8 +51,8 @@ ArcBall = function(spawnPosition) { spatialKey: { relativePosition: { x: 0, - y: 0, - z: -0.5 + y: -0.5, + z: 0.0 }, }, invertSolidWhileHeld: true @@ -97,7 +97,7 @@ ArcBall = function(spawnPosition) { }, maxParticles: 100000, lifespan: 2, - emitRate: 1000, + emitRate: 400, emitSpeed: .1, lifetime: -1, speedSpread: 0.0, diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 7bb8472ce9..7edf22ecdb 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -14,6 +14,15 @@ var _this; var ArcBall = function() { _this = this; + this.colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }, { + red: 200, + green: 10, + blue: 10 + }]; }; ArcBall.prototype = { @@ -40,59 +49,56 @@ emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - var color = { - red: 200, - green: 10, - blue: 10 - }; - var props = { - type: "ParticleEffect", - name: "Particle Arc", - parentID: this.entityID, - parentJointIndex: -1, - // position: startPosition, - isEmitting: true, - colorStart: color, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 5, - emitRate: 1000, - emitOrientation: emitOrientation, - emitSpeed: .4, - speedSpread: 0.0, - emitDimensions: { - x: 0, - y: 0, - z: 0 - }, - polarStart: 0, - polarFinish: .0, - azimuthStart: .1, - azimuthFinish: .01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - radiusStart: 0.03, - adiusFinish: 0.025, - alpha: 0.7, - alphaSpread: .1, - alphaStart: 0.5, - alphaFinish: 0.5, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: true - } + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; + var props = { + type: "ParticleEffect", + name: "Particle Arc", + parentID: this.entityID, + parentJointIndex: -1, + // position: startPosition, + isEmitting: true, + colorStart: color, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 2, + emitRate: 500, + emitOrientation: emitOrientation, + emitSpeed: .4, + speedSpread: 0.1, + emitDimensions: { + x: 0, + y: 0, + z: 0 + }, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.03, + radiusFinish: 0.025, + radiusSpread: .01, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: true + } this.particleArc = Entities.addEntity(props); }, From 3c66e3826830a2f9bc84697da5e4d7b61dc77423 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 11:12:59 -0800 Subject: [PATCH 122/209] test --- examples/flowArts/arcBall/arcBall.js | 7 +++--- .../flowArts/arcBall/arcBallEntityScript.js | 22 +++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index f6860b54c6..e67dffddff 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -44,6 +44,7 @@ ArcBall = function(spawnPosition) { green: 10, blue: 150 }, + ignoreForCollisions: true, damping: 0.8, collisionsWillMove: true, userData: JSON.stringify({ @@ -51,11 +52,11 @@ ArcBall = function(spawnPosition) { spatialKey: { relativePosition: { x: 0, - y: -0.5, - z: 0.0 + y: 0.0, + z: -0.5 }, }, - invertSolidWhileHeld: true + // invertSolidWhileHeld: true } }) }); diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 7edf22ecdb..0906b90b53 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -65,15 +65,15 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 2, - emitRate: 500, + lifespan: 1, + emitRate: 1000, emitOrientation: emitOrientation, - emitSpeed: .4, + emitSpeed: .2, speedSpread: 0.1, emitDimensions: { - x: 0, - y: 0, - z: 0 + x: .1, + y: .1, + z: .1 }, polarStart: 0, polarFinish: .0, @@ -89,13 +89,13 @@ y: .00, z: .00 }, - radiusStart: 0.03, - radiusFinish: 0.025, - radiusSpread: .01, - alpha: 0.7, + radiusStart: 0.01, + radiusFinish: 0.005, + radiusSpread: .005, + alpha: 0.5, alphaSpread: .1, alphaStart: 0.5, - alphaFinish: 0.5, + alphaFinish: 0.0, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", emitterShouldTrail: true } From ba3633710a9dfb0663f386a8f532fd5bd83e1c5f Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 11:29:59 -0800 Subject: [PATCH 123/209] name fixes --- examples/flowArts/arcBall/arcBall.js | 258 +++++++++--------- examples/flowArts/flowArtsHutSpawner.js | 8 +- .../{LightSaber.js => lightSaber.js} | 0 .../raveStick/{RaveStick.js => raveStick.js} | 0 4 files changed, 130 insertions(+), 136 deletions(-) rename examples/flowArts/lightSaber/{LightSaber.js => lightSaber.js} (100%) rename examples/flowArts/raveStick/{RaveStick.js => raveStick.js} (100%) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index e67dffddff..0906b90b53 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -1,145 +1,139 @@ -// -// arcBall.js -// examples/arcBall -// +// arcBallEntityScript.js +// +// Script Type: Entity // Created by Eric Levin on 12/17/15. -// Copyright 2014 High Fidelity, Inc. -// -// This script creats a particle light ball which makes particle trails as you move it. -// +// Copyright 2015 High Fidelity, Inc. // +// This entity script handles the logic for the arcBall rave toy // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("../../libraries/utils.js"); - - -var scriptURL = Script.resolvePath("arcBallEntityScript.js"); -ArcBall = function(spawnPosition) { - - var colorPalette = [{ - red: 25, - green: 20, - blue: 162 - }]; - - - var containerBall = Entities.addEntity({ - type: "Sphere", - name: "Arc Ball", - script: scriptURL, - position: Vec3.sum(spawnPosition, { - x: 0, - y: .7, - z: 0 - }), - dimensions: { - x: .05, - y: .05, - z: .05 - }, - color: { - red: 100, - green: 10, - blue: 150 - }, - ignoreForCollisions: true, - damping: 0.8, - collisionsWillMove: true, - userData: JSON.stringify({ - grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: 0.0, - z: -0.5 - }, - }, - // invertSolidWhileHeld: true - } - }) - }); - - - var light = Entities.addEntity({ - type: 'Light', - name: "ballLight", - parentID: containerBall, - dimensions: { - x: 30, - y: 30, - z: 30 - }, - color: colorPalette[randInt(0, colorPalette.length)], - intensity: 5 - }); - - - var arcBall = Entities.addEntity({ - type: "ParticleEffect", - parentID: containerBall, - isEmitting: true, - name: "Arc Ball Particle Effect", - colorStart: { - red: 200, - green: 20, - blue: 40 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: { +(function() { + Script.include("../../libraries/utils.js"); + var _this; + var ArcBall = function() { + _this = this; + this.colorPalette = [{ red: 25, green: 20, - blue: 255 + blue: 162 + }, { + red: 200, + green: 10, + blue: 10 + }]; + }; + + ArcBall.prototype = { + isGrabbed: false, + startNearGrab: function() { + //Search for nearby balls and create an arc to it if one is found + var position = Entities.getEntityProperties(this.entityID, "position").position + var entities = Entities.findEntities(position, 10); + entities.forEach(function(entity) { + var props = Entities.getEntityProperties(entity, ["position", "name"]); + if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { + _this.target = entity; + _this.createBeam(position, props.position); + } + }); + }, - maxParticles: 100000, - lifespan: 2, - emitRate: 400, - emitSpeed: .1, - lifetime: -1, - speedSpread: 0.0, - emitDimensions: { - x: 0, - y: 0, - z: 0 - }, - polarStart: 0, - polarFinish: Math.PI, - azimuthStart: -Math.PI, - azimuthFinish: Math.PI, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - particleRadius: 0.02, - radiusSpread: 0, - radiusStart: 0.03, - radiusFinish: 0.0003, - alpha: 0, - alphaSpread: .5, - alphaStart: 0, - alphaFinish: 0.5, - textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - emitterShouldTrail: true - }) + + createBeam: function(startPosition, endPosition) { + // Creates particle arc from start position to end position + var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; + var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; + var props = { + type: "ParticleEffect", + name: "Particle Arc", + parentID: this.entityID, + parentJointIndex: -1, + // position: startPosition, + isEmitting: true, + colorStart: color, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 1, + emitRate: 1000, + emitOrientation: emitOrientation, + emitSpeed: .2, + speedSpread: 0.1, + emitDimensions: { + x: .1, + y: .1, + z: .1 + }, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.01, + radiusFinish: 0.005, + radiusSpread: .005, + alpha: 0.5, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.0, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: true + } + this.particleArc = Entities.addEntity(props); + }, - function cleanup() { - Entities.deleteEntity(arcBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(light); - } + updateBeam: function(startPosition) { + var targetPosition = Entities.getEntityProperties(this.target, "position").position; + print("TARGET position " + JSON.stringify(this.target)); + var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; + var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + // emitOrientation = Quat.multiply(emitOrientation,Quat.inverse(rotation)); + Entities.editEntity(this.particleArc, { + emitOrientation: emitOrientation + }); + }, - this.cleanup = cleanup; -} \ No newline at end of file + continueNearGrab: function() { + var startPosition = Entities.getEntityProperties(this.entityID, "position").position; + this.updateBeam(startPosition); + }, + + releaseGrab: function() { + Entities.editEntity(this.particleArc, { + isEmitting: false + }); + }, + + unload: function() { + if (this.particleArc) { + Entities.deleteEntity(this.particleArc); + } + }, + + preload: function(entityID) { + this.entityID = entityID; + }, + }; + return new ArcBall(); +}); \ No newline at end of file diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 39dcf15698..2c87a27c15 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -14,10 +14,10 @@ Script.include("../../libraries/utils.js"); -Script.include("lightBall/LightBall.js"); -Script.include("raveStick/RaveStick.js"); -Script.include("lightSaber/LightSaber.js"); -Script.include("arcBall/ArcBall.js"); +Script.include("lightBall/lightBall.js"); +Script.include("raveStick/raveStick.js"); +Script.include("lightSaber/lightSaber.js"); +Script.include("arcBall/arcBall.js"); diff --git a/examples/flowArts/lightSaber/LightSaber.js b/examples/flowArts/lightSaber/lightSaber.js similarity index 100% rename from examples/flowArts/lightSaber/LightSaber.js rename to examples/flowArts/lightSaber/lightSaber.js diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/raveStick.js similarity index 100% rename from examples/flowArts/raveStick/RaveStick.js rename to examples/flowArts/raveStick/raveStick.js From b89e25f8f7f6fe1138c9521c9b309111f164838d Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 11:35:57 -0800 Subject: [PATCH 124/209] correct file --- examples/flowArts/arcBall/arcBall.js | 256 ++++++++++++++------------- 1 file changed, 131 insertions(+), 125 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 0906b90b53..e67dffddff 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -1,139 +1,145 @@ -// arcBallEntityScript.js -// -// Script Type: Entity -// Created by Eric Levin on 12/17/15. -// Copyright 2015 High Fidelity, Inc. // -// This entity script handles the logic for the arcBall rave toy +// arcBall.js +// examples/arcBall +// +// Created by Eric Levin on 12/17/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creats a particle light ball which makes particle trails as you move it. +// +// // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -(function() { - Script.include("../../libraries/utils.js"); - var _this; - var ArcBall = function() { - _this = this; - this.colorPalette = [{ +Script.include("../../libraries/utils.js"); + + +var scriptURL = Script.resolvePath("arcBallEntityScript.js"); +ArcBall = function(spawnPosition) { + + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; + + + var containerBall = Entities.addEntity({ + type: "Sphere", + name: "Arc Ball", + script: scriptURL, + position: Vec3.sum(spawnPosition, { + x: 0, + y: .7, + z: 0 + }), + dimensions: { + x: .05, + y: .05, + z: .05 + }, + color: { + red: 100, + green: 10, + blue: 150 + }, + ignoreForCollisions: true, + damping: 0.8, + collisionsWillMove: true, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0.0, + z: -0.5 + }, + }, + // invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + name: "ballLight", + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var arcBall = Entities.addEntity({ + type: "ParticleEffect", + parentID: containerBall, + isEmitting: true, + name: "Arc Ball Particle Effect", + colorStart: { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: { red: 25, green: 20, - blue: 162 - }, { - red: 200, - green: 10, - blue: 10 - }]; - }; - - ArcBall.prototype = { - isGrabbed: false, - startNearGrab: function() { - //Search for nearby balls and create an arc to it if one is found - var position = Entities.getEntityProperties(this.entityID, "position").position - var entities = Entities.findEntities(position, 10); - entities.forEach(function(entity) { - var props = Entities.getEntityProperties(entity, ["position", "name"]); - if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { - _this.target = entity; - _this.createBeam(position, props.position); - } - }); - + blue: 255 }, - - createBeam: function(startPosition, endPosition) { - // Creates particle arc from start position to end position - var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; - var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); - var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); - emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - - - var color = this.colorPalette[randInt(0, this.colorPalette.length)]; - var props = { - type: "ParticleEffect", - name: "Particle Arc", - parentID: this.entityID, - parentJointIndex: -1, - // position: startPosition, - isEmitting: true, - colorStart: color, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 1, - emitRate: 1000, - emitOrientation: emitOrientation, - emitSpeed: .2, - speedSpread: 0.1, - emitDimensions: { - x: .1, - y: .1, - z: .1 - }, - polarStart: 0, - polarFinish: .0, - azimuthStart: .1, - azimuthFinish: .01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - radiusStart: 0.01, - radiusFinish: 0.005, - radiusSpread: .005, - alpha: 0.5, - alphaSpread: .1, - alphaStart: 0.5, - alphaFinish: 0.0, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: true - } - this.particleArc = Entities.addEntity(props); + maxParticles: 100000, + lifespan: 2, + emitRate: 400, + emitSpeed: .1, + lifetime: -1, + speedSpread: 0.0, + emitDimensions: { + x: 0, + y: 0, + z: 0 }, - - updateBeam: function(startPosition) { - var targetPosition = Entities.getEntityProperties(this.target, "position").position; - print("TARGET position " + JSON.stringify(this.target)); - var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; - var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); - var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); - // emitOrientation = Quat.multiply(emitOrientation,Quat.inverse(rotation)); - Entities.editEntity(this.particleArc, { - emitOrientation: emitOrientation - }); + polarStart: 0, + polarFinish: Math.PI, + azimuthStart: -Math.PI, + azimuthFinish: Math.PI, + emitAcceleration: { + x: 0, + y: 0, + z: 0 }, - - continueNearGrab: function() { - var startPosition = Entities.getEntityProperties(this.entityID, "position").position; - this.updateBeam(startPosition); + accelerationSpread: { + x: .00, + y: .00, + z: .00 }, + particleRadius: 0.02, + radiusSpread: 0, + radiusStart: 0.03, + radiusFinish: 0.0003, + alpha: 0, + alphaSpread: .5, + alphaStart: 0, + alphaFinish: 0.5, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + emitterShouldTrail: true + }) - releaseGrab: function() { - Entities.editEntity(this.particleArc, { - isEmitting: false - }); - }, - unload: function() { - if (this.particleArc) { - Entities.deleteEntity(this.particleArc); - } - }, - preload: function(entityID) { - this.entityID = entityID; - }, - }; - return new ArcBall(); -}); \ No newline at end of file + function cleanup() { + Entities.deleteEntity(arcBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } + + this.cleanup = cleanup; +} \ No newline at end of file From b59b8db5c935884238d6c5f269cbc922ccbf2322 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 21 Dec 2015 12:09:18 -0800 Subject: [PATCH 125/209] set defaults --- examples/light_modifier/lightModifier.js | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 02d764e7e2..e8a9f39903 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -120,6 +120,17 @@ var PER_ROW_OFFSET = { y: -0.2, z: 0 }; +var sliders = []; +var slidersRef = { + 'color_red': null, + 'color_green': null, + 'color_blue': null, + intensity: null, + cutoff: null, + exponent: null +}; +var light = null; + function entitySlider(light, color, sliderType, row) { this.light = light; @@ -351,17 +362,6 @@ entitySlider.prototype = { }; -var sliders = []; -var slidersRef = { - 'color_red': null, - 'color_green': null, - 'color_blue': null, - intensity: null, - cutoff: null, - exponent: null -} -var light = null; - function makeSliders(light) { var panel; if (USE_PARENTED_PANEL === true) { @@ -403,8 +403,6 @@ function makeSliders(light) { sliders.push(slidersRef.exponent); } - - createCloseButton(slidersRef.exponent.endOfAxis); subscribeToSliderMessages(); @@ -413,12 +411,13 @@ function makeSliders(light) { parentEntitiesToPanel(panel); } - if (SLIDERS_SHOULD_STAY_WITH_AVATAR) { - parentPanelToAvatar(panel) + if (SLIDERS_SHOULD_STAY_WITH_AVATAR === true) { + parentPanelToAvatar(panel); } }; function parentPanelToAvatar(panel) { + //this is going to need some more work re: the sliders actually being grabbable. probably something to do with updating axis movement Entities.editEntity(panel, { parentID: MyAvatar.sessionUUID, //actually figure out which one to parent it to -- probably a spine or something. @@ -427,7 +426,8 @@ function parentPanelToAvatar(panel) { } function parentEntitiesToPanel(panel) { - slidersRef.forEach(function(slider) { + + sliders.forEach(function(slider) { Entities.editEntity(slider.axis, { parentID: panel }) @@ -437,14 +437,14 @@ function parentEntitiesToPanel(panel) { }) closeButtons.forEach(function(button) { - Entities.editEntity(slider.sliderIndicator, { + Entities.editEntity(button, { parentID: panel }) }) } function createPanelEntity(position) { - + print('CREATING PANEL at ' + JSON.stringify(position)); var panelProperties = { name: 'Hifi-Slider-Panel', type: 'Box', From 4b4fe96b64808321652b4ca0e2a8d9ea056d5331 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 12:47:31 -0800 Subject: [PATCH 126/209] tweaks --- examples/flowArts/arcBall/arcBallEntityScript.js | 14 +++++++------- examples/flowArts/lightSaber/lightSaber.js | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 0906b90b53..84208bf559 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -65,19 +65,19 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 1, + lifespan: 2, emitRate: 1000, emitOrientation: emitOrientation, - emitSpeed: .2, - speedSpread: 0.1, + emitSpeed: .1, + speedSpread: 0.02, emitDimensions: { - x: .1, - y: .1, - z: .1 + x: .01, + y: .01, + z: .01 }, polarStart: 0, polarFinish: .0, - azimuthStart: .1, + azimuthStart: .02, azimuthFinish: .01, emitAcceleration: { x: 0, diff --git a/examples/flowArts/lightSaber/lightSaber.js b/examples/flowArts/lightSaber/lightSaber.js index 50984110bc..a42f81d196 100644 --- a/examples/flowArts/lightSaber/lightSaber.js +++ b/examples/flowArts/lightSaber/lightSaber.js @@ -23,6 +23,7 @@ LightSaber = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', + collisionsWillMove: true, script: scriptURL, dimensions: { x: 0.06, From 4110630d1f074fdf4c710f804d10d14539424a00 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 13:15:37 -0800 Subject: [PATCH 127/209] fixed ravestick fargrab --- examples/flowArts/raveStick/raveStick.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/flowArts/raveStick/raveStick.js b/examples/flowArts/raveStick/raveStick.js index 3e4cf16136..bcbe44168c 100644 --- a/examples/flowArts/raveStick/raveStick.js +++ b/examples/flowArts/raveStick/raveStick.js @@ -30,7 +30,8 @@ RaveStick = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', - script: scriptURL, + collisionsWillMove: true, + // script: scriptURL, dimensions: { x: 0.06, y: 0.06, From cabc47e7a9914e9e2985e932de6f74310d3bb71f Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 13:30:52 -0800 Subject: [PATCH 128/209] lightsaber immediately turns off on release --- .../flowArts/arcBall/arcBallEntityScript.js | 128 ++++++++++-------- .../lightSaber/lightSaberEntityScript.js | 4 +- 2 files changed, 76 insertions(+), 56 deletions(-) diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 84208bf559..1952209c95 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -27,7 +27,16 @@ ArcBall.prototype = { isGrabbed: false, - startNearGrab: function() { + startDistanceGrab: function() { + this.searchForNearbyArcBalls(); + + }, + + startFarGrab: function() { + this.searchForNearbyArcBalls(); + }, + + searchForNearbyArcBalls: function() { //Search for nearby balls and create an arc to it if one is found var position = Entities.getEntityProperties(this.entityID, "position").position var entities = Entities.findEntities(position, 10); @@ -36,12 +45,13 @@ if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { _this.target = entity; _this.createBeam(position, props.position); + } }); - }, createBeam: function(startPosition, endPosition) { + // Creates particle arc from start position to end position var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); @@ -50,61 +60,65 @@ var color = this.colorPalette[randInt(0, this.colorPalette.length)]; - var props = { - type: "ParticleEffect", - name: "Particle Arc", - parentID: this.entityID, - parentJointIndex: -1, - // position: startPosition, - isEmitting: true, - colorStart: color, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 2, - emitRate: 1000, - emitOrientation: emitOrientation, - emitSpeed: .1, - speedSpread: 0.02, - emitDimensions: { - x: .01, - y: .01, - z: .01 - }, - polarStart: 0, - polarFinish: .0, - azimuthStart: .02, - azimuthFinish: .01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - radiusStart: 0.01, - radiusFinish: 0.005, - radiusSpread: .005, - alpha: 0.5, - alphaSpread: .1, - alphaStart: 0.5, - alphaFinish: 0.0, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: true - } + var props = { + type: "ParticleEffect", + name: "Particle Arc", + parentID: this.entityID, + parentJointIndex: -1, + // position: startPosition, + isEmitting: true, + colorStart: color, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 2, + emitRate: 1000, + emitOrientation: emitOrientation, + emitSpeed: .1, + speedSpread: 0.02, + emitDimensions: { + x: .01, + y: .01, + z: .01 + }, + polarStart: 0, + polarFinish: .0, + azimuthStart: .02, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.01, + radiusFinish: 0.005, + radiusSpread: .005, + alpha: 0.5, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.0, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: true + } this.particleArc = Entities.addEntity(props); }, - updateBeam: function(startPosition) { + updateBeam: function() { + if(!this.target) { + return; + } + var startPosition = Entities.getEntityProperties(this.entityID, "position").position; + var targetPosition = Entities.getEntityProperties(this.target, "position").position; - print("TARGET position " + JSON.stringify(this.target)); var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); @@ -115,14 +129,18 @@ }, continueNearGrab: function() { - var startPosition = Entities.getEntityProperties(this.entityID, "position").position; - this.updateBeam(startPosition); + this.updateBeam(); + }, + + continueDistanceGrab: function() { + this.updateBeam(); }, releaseGrab: function() { Entities.editEntity(this.particleArc, { isEmitting: false }); + this.target = null; }, unload: function() { diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index 794e241924..cbbcd8a0bf 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -31,12 +31,14 @@ startNearGrab: function() { Entities.editEntity(this.beam, { - isEmitting: true + isEmitting: true, + visible: true }); }, releaseGrab: function() { Entities.editEntity(this.beam, { + visible: false, isEmitting: false }); }, From 876d8ab6b25a427ae16acbe459ea3e4f01b05348 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 13:59:00 -0800 Subject: [PATCH 129/209] far grabbing arc balls --- examples/flowArts/arcBall/arcBall.js | 12 ++++++------ examples/flowArts/arcBall/arcBallEntityScript.js | 16 ++++++---------- .../lightSaber/lightSaberEntityScript.js | 1 - 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index e67dffddff..5a6b1b47f3 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -15,7 +15,7 @@ Script.include("../../libraries/utils.js"); -var scriptURL = Script.resolvePath("arcBallEntityScript.js"); +var scriptURL = Script.resolvePath("arcBallEntityScript.js?v1" + Math.random()); ArcBall = function(spawnPosition) { var colorPalette = [{ @@ -50,11 +50,11 @@ ArcBall = function(spawnPosition) { userData: JSON.stringify({ grabbableKey: { spatialKey: { - relativePosition: { - x: 0, - y: 0.0, - z: -0.5 - }, + // relativePosition: { + // x: 0, + // y: -0.5, + // z: 0.0 + // }, }, // invertSolidWhileHeld: true } diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 1952209c95..102ceca40c 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -27,12 +27,11 @@ ArcBall.prototype = { isGrabbed: false, - startDistanceGrab: function() { + startDistantGrab: function() { this.searchForNearbyArcBalls(); - }, - startFarGrab: function() { + startNearGrab: function() { this.searchForNearbyArcBalls(); }, @@ -58,7 +57,6 @@ var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", @@ -75,10 +73,10 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 2, + lifespan: 1, emitRate: 1000, emitOrientation: emitOrientation, - emitSpeed: .1, + emitSpeed: 1, speedSpread: 0.02, emitDimensions: { x: .01, @@ -105,7 +103,7 @@ alpha: 0.5, alphaSpread: .1, alphaStart: 0.5, - alphaFinish: 0.0, + alphaFinish: 0.5, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", emitterShouldTrail: true } @@ -117,12 +115,10 @@ return; } var startPosition = Entities.getEntityProperties(this.entityID, "position").position; - var targetPosition = Entities.getEntityProperties(this.target, "position").position; var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); - // emitOrientation = Quat.multiply(emitOrientation,Quat.inverse(rotation)); Entities.editEntity(this.particleArc, { emitOrientation: emitOrientation }); @@ -132,7 +128,7 @@ this.updateBeam(); }, - continueDistanceGrab: function() { + continueDistantGrab: function() { this.updateBeam(); }, diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index cbbcd8a0bf..fd55916cc6 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -54,7 +54,6 @@ createBeam: function() { - this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); // forwardVec = Vec3.normalize(forwardVec); From f19d1a3067ccf7e586c17ac59d8e45092db1a907 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 15:20:36 -0800 Subject: [PATCH 130/209] cleanup --- .../flowArts/arcBall/arcBallEntityScript.js | 18 ++++++++++-------- examples/flowArts/flowArtsHutSpawner.js | 2 +- examples/flowArts/lightSaber/lightSaber.js | 2 +- .../lightSaber/lightSaberEntityScript.js | 10 +++++----- examples/flowArts/raveStick/raveStick.js | 14 +++++++------- .../raveStick/raveStickEntityScript.js | 2 -- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 102ceca40c..987ddc7a31 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -23,6 +23,8 @@ green: 10, blue: 10 }]; + + this.searchRadius = 10; }; ArcBall.prototype = { @@ -38,7 +40,7 @@ searchForNearbyArcBalls: function() { //Search for nearby balls and create an arc to it if one is found var position = Entities.getEntityProperties(this.entityID, "position").position - var entities = Entities.findEntities(position, 10); + var entities = Entities.findEntities(position, this.searchRadius); entities.forEach(function(entity) { var props = Entities.getEntityProperties(entity, ["position", "name"]); if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { @@ -84,8 +86,8 @@ z: .01 }, polarStart: 0, - polarFinish: .0, - azimuthStart: .02, + polarFinish: 0, + azimuthStart: 0.02, azimuthFinish: .01, emitAcceleration: { x: 0, @@ -93,15 +95,15 @@ z: 0 }, accelerationSpread: { - x: .00, - y: .00, - z: .00 + x: 0, + y: 0, + z: 0 }, radiusStart: 0.01, radiusFinish: 0.005, - radiusSpread: .005, + radiusSpread: 0.005, alpha: 0.5, - alphaSpread: .1, + alphaSpread: 0.1, alphaStart: 0.5, alphaFinish: 0.5, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 2c87a27c15..59f4e70858 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -33,7 +33,7 @@ var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); -var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/RaveRoom.fbx"; +var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/RaveRoom.fbx"; var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; diff --git a/examples/flowArts/lightSaber/lightSaber.js b/examples/flowArts/lightSaber/lightSaber.js index a42f81d196..f582798546 100644 --- a/examples/flowArts/lightSaber/lightSaber.js +++ b/examples/flowArts/lightSaber/lightSaber.js @@ -13,7 +13,7 @@ // Script.include("../../libraries/utils.js"); -var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/lightSaber.fbx"; +var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/lightSaber.fbx"; var scriptURL = Script.resolvePath("lightSaberEntityScript.js"); LightSaber = function(spawnPosition) { diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index fd55916cc6..fd53eb4c87 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -80,7 +80,7 @@ lifespan: 2, emitRate: 1000, emitOrientation: forwardQuat, - emitSpeed: .4, + emitSpeed: 0.7, speedSpread: 0.0, emitDimensions: { x: 0, @@ -88,9 +88,9 @@ z: 0 }, polarStart: 0, - polarFinish: .0, - azimuthStart: .1, - azimuthFinish: .01, + polarFinish: 0, + azimuthStart: 0.1, + azimuthFinish: 0.01, emitAcceleration: { x: 0, y: 0, @@ -104,7 +104,7 @@ radiusStart: 0.03, adiusFinish: 0.025, alpha: 0.7, - alphaSpread: .1, + alphaSpread: 0.1, alphaStart: 0.5, alphaFinish: 0.5, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", diff --git a/examples/flowArts/raveStick/raveStick.js b/examples/flowArts/raveStick/raveStick.js index bcbe44168c..79c281de47 100644 --- a/examples/flowArts/raveStick/raveStick.js +++ b/examples/flowArts/raveStick/raveStick.js @@ -12,7 +12,7 @@ // Script.include("../../libraries/utils.js"); -var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx"; +var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/raveStick.fbx"; var scriptURL = Script.resolvePath("raveStickEntityScript.js"); RaveStick = function(spawnPosition) { var colorPalette = [{ @@ -31,7 +31,7 @@ RaveStick = function(spawnPosition) { position: spawnPosition, shapeType: 'box', collisionsWillMove: true, - // script: scriptURL, + script: scriptURL, dimensions: { x: 0.06, y: 0.06, @@ -99,12 +99,12 @@ RaveStick = function(spawnPosition) { lifespan: 1, emitRate: 1000, emitOrientation: forwardQuat, - emitSpeed: .2, + emitSpeed: 0.2, speedSpread: 0.0, polarStart: 0, - polarFinish: .0, + polarFinish: 0.0, azimuthStart: .1, - azimuthFinish: .01, + azimuthFinish: 0.01, emitAcceleration: { x: 0, y: 0, @@ -118,10 +118,10 @@ RaveStick = function(spawnPosition) { radiusStart: 0.03, radiusFinish: 0.025, alpha: 0.7, - alphaSpread: .1, + alphaSpread: 0.1, alphaStart: 0.5, alphaFinish: 0.5, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + textures: "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/beamParticle.png", emitterShouldTrail: false, } var beam = Entities.addEntity(props); diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 2e174c78f0..2fc51f6821 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -74,8 +74,6 @@ forwardVec = Vec3.normalize(forwardVec); var forwardQuat = orientationOf(forwardVec); var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.2)); - // position.z += 0.1; - // position.x += -0.035; var localPoint = Vec3.subtract(position, this.trailBasePosition); if (this.points.length >= 1 && Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { //Need a minimum distance to avoid binormal NANs From 025e769a9f90d80a3c9c8eff956991d8cc18d53b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 21 Dec 2015 18:25:30 -0800 Subject: [PATCH 131/209] average both hands, enabled both mouse clicks, and detect base station resting hand --- .../controllers/reticleHandRotationTest.js | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/examples/controllers/reticleHandRotationTest.js b/examples/controllers/reticleHandRotationTest.js index 781dbf66ab..3d903217ef 100644 --- a/examples/controllers/reticleHandRotationTest.js +++ b/examples/controllers/reticleHandRotationTest.js @@ -9,8 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var whichHand = Controller.Standard.RightHand; -var whichTrigger = Controller.Standard.RT; var DEBUGGING = false; Math.clamp=function(a,b,c) { @@ -53,14 +51,49 @@ function moveReticleAbsolute(x, y) { var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation"; var mapping = Controller.newMapping(MAPPING_NAME); -mapping.from(whichTrigger).peek().constrainToInteger().to(Controller.Actions.ReticleClick); -mapping.from(whichHand).peek().to(function(pose) { +mapping.from(Controller.Standard.LT).peek().constrainToInteger().to(Controller.Actions.ReticleClick); +mapping.from(Controller.Standard.RT).peek().constrainToInteger().to(Controller.Actions.ReticleClick); +mapping.enable(); + + +var lastRotatedLeft = Vec3.UNIT_NEG_Y; +var lastRotatedRight = Vec3.UNIT_NEG_Y; + +Script.update.connect(function(deltaTime) { + + var poseRight = Controller.getPoseValue(Controller.Standard.RightHand); + var poseLeft = Controller.getPoseValue(Controller.Standard.LeftHand); // NOTE: hack for now var screenSizeX = 1920; var screenSizeY = 1080; - var rotated = Vec3.multiplyQbyV(pose.rotation, Vec3.UNIT_NEG_Y); // + var rotatedRight = Vec3.multiplyQbyV(poseRight.rotation, Vec3.UNIT_NEG_Y); + var rotatedLeft = Vec3.multiplyQbyV(poseLeft.rotation, Vec3.UNIT_NEG_Y); + + // check to see if hand is on base station + if (Vec3.equal(rotatedLeft, Vec3.UNIT_NEG_Y)) { + rotatedLeft = rotatedRight; + } + if (Vec3.equal(rotatedRight, Vec3.UNIT_NEG_Y)) { + rotatedRight = rotatedLeft; + } + + // Keep track of last rotations, to potentially detect resting (but not on + // base station hands) in the future + lastRotatedLeft = rotatedLeft; + lastRotatedRight = rotatedRight; + + // Average the two hand positions, if either hand is on base station, the + // other hand becomes the only used hand and the average is the hand in use + var rotated = Vec3.multiply(Vec3.sum(rotatedRight,rotatedLeft), 0.5); + + if (DEBUGGING) { + Vec3.print("rotatedRight:", rotatedRight); + Vec3.print("rotatedLeft:", rotatedLeft); + Vec3.print("rotated:", rotated); + } + var absolutePitch = rotated.y; // from 1 down to -1 up ... but note: if you rotate down "too far" it starts to go up again... var absoluteYaw = -rotated.x; // from -1 left to 1 right @@ -97,7 +130,6 @@ mapping.from(whichHand).peek().to(function(pose) { moveReticleAbsolute(x, y); } }); -mapping.enable(); Script.scriptEnding.connect(function(){ mapping.disable(); From 8d80c06f02eedad5c5d7a9395152a87d902d3739 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 18:26:28 -0800 Subject: [PATCH 132/209] updated ravestick model --- examples/flowArts/raveStick/raveStick.js | 50 +------------------ .../raveStick/raveStickEntityScript.js | 5 +- 2 files changed, 5 insertions(+), 50 deletions(-) diff --git a/examples/flowArts/raveStick/raveStick.js b/examples/flowArts/raveStick/raveStick.js index 79c281de47..1e49c525f2 100644 --- a/examples/flowArts/raveStick/raveStick.js +++ b/examples/flowArts/raveStick/raveStick.js @@ -77,61 +77,13 @@ RaveStick = function(spawnPosition) { green: 200, blue: 40 }; - var props = { - type: "ParticleEffect", - position: position, - parentID: stick, - isEmitting: true, - name: "raveBeam", - colorStart: color, - colorSpread: { - red: 200, - green: 10, - blue: 10 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 1, - emitRate: 1000, - emitOrientation: forwardQuat, - emitSpeed: 0.2, - speedSpread: 0.0, - polarStart: 0, - polarFinish: 0.0, - azimuthStart: .1, - azimuthFinish: 0.01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - radiusStart: 0.03, - radiusFinish: 0.025, - alpha: 0.7, - alphaSpread: 0.1, - alphaStart: 0.5, - alphaFinish: 0.5, - textures: "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/beamParticle.png", - emitterShouldTrail: false, - } - var beam = Entities.addEntity(props); + function cleanup() { Entities.deleteEntity(stick); Entities.deleteEntity(light); - Entities.deleteEntity(beam); } this.cleanup = cleanup; diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 2fc51f6821..5a37a9b313 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -73,7 +73,7 @@ var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); forwardVec = Vec3.normalize(forwardVec); var forwardQuat = orientationOf(forwardVec); - var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.2)); + var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.04)); var localPoint = Vec3.subtract(position, this.trailBasePosition); if (this.points.length >= 1 && Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { //Need a minimum distance to avoid binormal NANs @@ -114,6 +114,9 @@ }, releaseGrab: function() { + if(!this.trailEraseInterval) { + return; + } Script.setTimeout(function() { Script.clearInterval(_this.trailEraseInterval); _this.trailEraseInterval = null; From 0459479c2b1a8130beecee5771d40aac490d1a9f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 21 Dec 2015 18:30:15 -0800 Subject: [PATCH 133/209] NeuronPlugin: Added external project for Neuron SDK Now builds on windows with actual Neuron SDK. Can to TCP server on localhost, and receive joint data. Will debug draw joint 6, (left foot?) --- cmake/externals/neuron/CMakeLists.txt | 49 ++++ cmake/macros/TargetNeuron.cmake | 14 ++ cmake/modules/FindNeuron.cmake | 28 +++ interface/CMakeLists.txt | 4 +- plugins/{neuron => hifiNeuron}/CMakeLists.txt | 4 +- plugins/hifiNeuron/src/NeuronPlugin.cpp | 222 ++++++++++++++++++ .../{neuron => hifiNeuron}/src/NeuronPlugin.h | 19 +- .../src/NeuronProvider.cpp | 0 .../{neuron => hifiNeuron}/src/plugin.json | 0 plugins/neuron/src/NeuronPlugin.cpp | 75 ------ 10 files changed, 336 insertions(+), 79 deletions(-) create mode 100644 cmake/externals/neuron/CMakeLists.txt create mode 100644 cmake/macros/TargetNeuron.cmake create mode 100644 cmake/modules/FindNeuron.cmake rename plugins/{neuron => hifiNeuron}/CMakeLists.txt (88%) create mode 100644 plugins/hifiNeuron/src/NeuronPlugin.cpp rename plugins/{neuron => hifiNeuron}/src/NeuronPlugin.h (79%) rename plugins/{neuron => hifiNeuron}/src/NeuronProvider.cpp (100%) rename plugins/{neuron => hifiNeuron}/src/plugin.json (100%) delete mode 100644 plugins/neuron/src/NeuronPlugin.cpp diff --git a/cmake/externals/neuron/CMakeLists.txt b/cmake/externals/neuron/CMakeLists.txt new file mode 100644 index 0000000000..324b3fb917 --- /dev/null +++ b/cmake/externals/neuron/CMakeLists.txt @@ -0,0 +1,49 @@ +include(ExternalProject) + +set(EXTERNAL_NAME neuron) + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +set(NEURON_URL "https://s3.amazonaws.com/hifi-public/dependencies/neuron_datareader_b.12.zip") +set(NEURON_URL_MD5 "0ab54ca04c9cc8094e0fa046c226e574") + +ExternalProject_Add(${EXTERNAL_NAME} + URL ${NEURON_URL} + URL_MD5 ${NEURON_URL_MD5} + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1) + +ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +# set include dir +if(WIN32) + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS "${SOURCE_DIR}/NeuronDataReader_Windows/include" CACHE TYPE INTERNAL) +elseif(APPLE) + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS "${SOURCE_DIR}/NeuronDataReader_Mac/include" CACHE TYPE INTERNAL) +else() + # Unsupported +endif() + +if(WIN32) + + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(ARCH_DIR "x64") + else() + set(ARCH_DIR "x86") + endif() + + set(${EXTERNAL_NAME_UPPER}_LIB_PATH "${SOURCE_DIR}/NeuronDataReader_Windows/lib/${ARCH_DIR}") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE "${${EXTERNAL_NAME_UPPER}_LIB_PATH}/NeuronDataReader.lib" CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${${EXTERNAL_NAME_UPPER}_LIB_PATH}/NeuronDataReader.lib" CACHE TYPE INTERNAL) + + add_paths_to_fixup_libs("${${EXTERNAL_NAME_UPPER}_LIB_PATH}") +elseif(APPLE) + # TODO +else() + # UNSUPPORTED +endif() + diff --git a/cmake/macros/TargetNeuron.cmake b/cmake/macros/TargetNeuron.cmake new file mode 100644 index 0000000000..01891ef525 --- /dev/null +++ b/cmake/macros/TargetNeuron.cmake @@ -0,0 +1,14 @@ +# +# Copyright 2015 High Fidelity, Inc. +# Created by Anthony J. Thibault on 2015/12/21 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_NEURON) + add_dependency_external_projects(neuron) + find_package(Neuron REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${NEURON_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${NEURON_LIBRARIES}) + add_definitions(-DHAVE_NEURON) +endmacro() diff --git a/cmake/modules/FindNeuron.cmake b/cmake/modules/FindNeuron.cmake new file mode 100644 index 0000000000..6a93b3a016 --- /dev/null +++ b/cmake/modules/FindNeuron.cmake @@ -0,0 +1,28 @@ +# +# FindNeuron.cmake +# +# Try to find the Perception Neuron SDK +# +# You must provide a NEURON_ROOT_DIR which contains lib and include directories +# +# Once done this will define +# +# NEURON_FOUND - system found Neuron SDK +# NEURON_INCLUDE_DIRS - the Neuron SDK include directory +# NEURON_LIBRARIES - Link this to use Neuron +# +# Created on 12/21/2015 by Anthony J. Thibault +# Copyright 2015 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +include(SelectLibraryConfigurations) +select_library_configurations(NEURON) + +set(NEURON_REQUIREMENTS NEURON_INCLUDE_DIRS NEURON_LIBRARIES) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Neuron DEFAULT_MSG NEURON_INCLUDE_DIRS NEURON_LIBRARIES) +mark_as_advanced(NEURON_LIBRARIES NEURON_INCLUDE_DIRS NEURON_SEARCH_DIRS) + diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1d9557a835..5d96b95624 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -109,7 +109,9 @@ add_dependency_external_projects(sdl2) if (WIN32) add_dependency_external_projects(OpenVR) endif() - +if(WIN32 OR APPLE) + add_dependency_external_projects(neuron) +endif() # disable /OPT:REF and /OPT:ICF for the Debug builds # This will prevent the following linker warnings diff --git a/plugins/neuron/CMakeLists.txt b/plugins/hifiNeuron/CMakeLists.txt similarity index 88% rename from plugins/neuron/CMakeLists.txt rename to plugins/hifiNeuron/CMakeLists.txt index b86d310ab7..9c512fc877 100644 --- a/plugins/neuron/CMakeLists.txt +++ b/plugins/hifiNeuron/CMakeLists.txt @@ -6,8 +6,8 @@ # See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # -set(TARGET_NAME neuron) +set(TARGET_NAME hifiNeuron) setup_hifi_plugin(Script Qml Widgets) link_hifi_libraries(shared controllers plugins input-plugins) -# target_neuron() +target_neuron() diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp new file mode 100644 index 0000000000..c3f764da05 --- /dev/null +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -0,0 +1,222 @@ +// +// NeuronPlugin.h +// input-plugins/src/input-plugins +// +// Created by Anthony Thibault on 12/18/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "NeuronPlugin.h" + +#include +#include +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(inputplugins) +Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") + +#define __OS_XUN__ 1 +#define BOOL int +#include + +const QString NeuronPlugin::NAME = "Neuron"; +const QString NeuronPlugin::NEURON_ID_STRING = "Perception Neuron"; + +enum JointIndex { + HipsPosition = 0, + Hips, + RightUpLeg, + RightLeg, + RightFoot, + LeftUpLeg, + LeftLeg, + LeftFoot, + Spine, + Spine1, + Spine2, + Spine3, + Neck, + Head, + RightShoulder, + RightArm, + RightForeArm, + RightHand, + RightHandThumb1, + RightHandThumb2, + RightHandThumb3, + RightInHandIndex, + RightHandIndex1, + RightHandIndex2, + RightHandIndex3, + RightInHandMiddle, + RightHandMiddle1, + RightHandMiddle2, + RightHandMiddle3, + RightInHandRing, + RightHandRing1, + RightHandRing2, + RightHandRing3, + RightInHandPinky, + RightHandPinky1, + RightHandPinky2, + RightHandPinky3, + LeftShoulder, + LeftArm, + LeftForeArm, + LeftHand, + LeftHandThumb1, + LeftHandThumb2, + LeftHandThumb3, + LeftInHandIndex, + LeftHandIndex1, + LeftHandIndex2, + LeftHandIndex3, + LeftInHandMiddle, + LeftHandMiddle1, + LeftHandMiddle2, + LeftHandMiddle3, + LeftInHandRing, + LeftHandRing1, + LeftHandRing2, + LeftHandRing3, + LeftInHandPinky, + LeftHandPinky1, + LeftHandPinky2, + LeftHandPinky3 +}; + +bool NeuronPlugin::isSupported() const { + // Because it's a client/server network architecture, we can't tell + // if the neuron is actually connected until we connect to the server. + return true; +} + +// NOTE: must be thread-safe +void FrameDataReceivedCallback(void* context, SOCKET_REF sender, BvhDataHeaderEx* header, float* data) { + qCDebug(inputplugins) << "NeuronPlugin: received frame data, DataCount = " << header->DataCount; + + auto neuronPlugin = reinterpret_cast(context); + std::lock_guard guard(neuronPlugin->_jointsMutex); + + // Data is 6 floats: 3 position values, 3 rotation euler angles (degrees) + + // resize vector if necessary + const size_t NUM_FLOATS_PER_JOINT = 6; + const size_t NUM_JOINTS = header->DataCount / NUM_FLOATS_PER_JOINT; + if (neuronPlugin->_joints.size() != NUM_JOINTS) { + neuronPlugin->_joints.resize(NUM_JOINTS, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); + } + + assert(sizeof(NeuronPlugin::NeuronJoint) == (NUM_FLOATS_PER_JOINT * sizeof(float))); + + // copy the data + memcpy(&(neuronPlugin->_joints[0]), data, sizeof(NeuronPlugin::NeuronJoint) * NUM_JOINTS); +} + +// NOTE: must be thread-safe +static void CommandDataReceivedCallback(void* context, SOCKET_REF sender, CommandPack* pack, void* data) { + +} + +// NOTE: must be thread-safe +static void SocketStatusChangedCallback(void* context, SOCKET_REF sender, SocketStatus status, char* message) { + qCDebug(inputplugins) << "NeuronPlugin: socket status = " << message; +} + +void NeuronPlugin::activate() { + InputPlugin::activate(); + qCDebug(inputplugins) << "NeuronPlugin::activate"; + + // register c-style callbacks + BRRegisterFrameDataCallback((void*)this, FrameDataReceivedCallback); + BRRegisterCommandDataCallback((void*)this, CommandDataReceivedCallback); + BRRegisterSocketStatusCallback((void*)this, SocketStatusChangedCallback); + + // TODO: pull these from prefs! + _serverAddress = "localhost"; + _serverPort = 7001; + _socketRef = BRConnectTo((char*)_serverAddress.c_str(), _serverPort); + if (!_socketRef) { + // error + qCCritical(inputplugins) << "NeuronPlugin: error connecting to " << _serverAddress.c_str() << ":" << _serverPort << "error = " << BRGetLastErrorMessage(); + } + qCDebug(inputplugins) << "NeuronPlugin: success connecting to " << _serverAddress.c_str() << ":" << _serverPort; +} + +void NeuronPlugin::deactivate() { + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::deactivate"; + + if (_socketRef) { + BRCloseSocket(_socketRef); + } + InputPlugin::deactivate(); +} + +// convert between euler in degrees to quaternion +static quat eulerToQuat(vec3 euler) { + return (glm::angleAxis(euler.y * RADIANS_PER_DEGREE, Vectors::UNIT_Y) * + glm::angleAxis(euler.x * RADIANS_PER_DEGREE, Vectors::UNIT_X) * + glm::angleAxis(euler.z * RADIANS_PER_DEGREE, Vectors::UNIT_Z)); +} + +void NeuronPlugin::pluginUpdate(float deltaTime, bool jointsCaptured) { + + std::vector joints; + // copy the shared data + { + std::lock_guard guard(_jointsMutex); + joints = _joints; + } + + DebugDraw::getInstance().addMyAvatarMarker("LEFT_FOOT", + eulerToQuat(joints[6].rot), + joints[6].pos / 100.0f, + glm::vec4(1)); + + _inputDevice->update(deltaTime, jointsCaptured); +} + +void NeuronPlugin::saveSettings() const { + InputPlugin::saveSettings(); + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::saveSettings"; +} + +void NeuronPlugin::loadSettings() { + InputPlugin::loadSettings(); + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::loadSettings"; +} + +// +// InputDevice +// + +controller::Input::NamedVector NeuronPlugin::InputDevice::getAvailableInputs() const { + // TODO: + static const controller::Input::NamedVector availableInputs { + makePair(controller::LEFT_HAND, "LeftHand"), + makePair(controller::RIGHT_HAND, "RightHand") + }; + return availableInputs; +} + +QString NeuronPlugin::InputDevice::getDefaultMappingConfig() const { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/neuron.json"; + return MAPPING_JSON; +} + +void NeuronPlugin::InputDevice::update(float deltaTime, bool jointsCaptured) { + +} + +void NeuronPlugin::InputDevice::focusOutEvent() { + // TODO: + qCDebug(inputplugins) << "NeuronPlugin::InputDevice::focusOutEvent"; +} diff --git a/plugins/neuron/src/NeuronPlugin.h b/plugins/hifiNeuron/src/NeuronPlugin.h similarity index 79% rename from plugins/neuron/src/NeuronPlugin.h rename to plugins/hifiNeuron/src/NeuronPlugin.h index 59e0f0a393..5f67502e04 100644 --- a/plugins/neuron/src/NeuronPlugin.h +++ b/plugins/hifiNeuron/src/NeuronPlugin.h @@ -16,10 +16,15 @@ #include #include +struct _BvhDataHeaderEx; +void FrameDataReceivedCallback(void* context, void* sender, _BvhDataHeaderEx* header, float* data); + // Handles interaction with the Neuron SDK class NeuronPlugin : public InputPlugin { Q_OBJECT public: + friend void FrameDataReceivedCallback(void* context, void* sender, _BvhDataHeaderEx* header, float* data); + // Plugin functions virtual bool isSupported() const override; virtual bool isJointController() const override { return true; } @@ -35,7 +40,7 @@ public: virtual void saveSettings() const override; virtual void loadSettings() override; -private: +protected: class InputDevice : public controller::InputDevice { public: InputDevice() : controller::InputDevice("Neuron") {} @@ -51,6 +56,18 @@ private: static const QString NAME; static const QString NEURON_ID_STRING; + + std::string _serverAddress; + int _serverPort; + void* _socketRef; + + struct NeuronJoint { + glm::vec3 pos; + glm::vec3 rot; + }; + + std::vector _joints; + std::mutex _jointsMutex; }; #endif // hifi_NeuronPlugin_h diff --git a/plugins/neuron/src/NeuronProvider.cpp b/plugins/hifiNeuron/src/NeuronProvider.cpp similarity index 100% rename from plugins/neuron/src/NeuronProvider.cpp rename to plugins/hifiNeuron/src/NeuronProvider.cpp diff --git a/plugins/neuron/src/plugin.json b/plugins/hifiNeuron/src/plugin.json similarity index 100% rename from plugins/neuron/src/plugin.json rename to plugins/hifiNeuron/src/plugin.json diff --git a/plugins/neuron/src/NeuronPlugin.cpp b/plugins/neuron/src/NeuronPlugin.cpp deleted file mode 100644 index 735b81a1ef..0000000000 --- a/plugins/neuron/src/NeuronPlugin.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// -// NeuronPlugin.h -// input-plugins/src/input-plugins -// -// Created by Anthony Thibault on 12/18/2015. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "NeuronPlugin.h" - -#include -#include - -Q_DECLARE_LOGGING_CATEGORY(inputplugins) -Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") - -const QString NeuronPlugin::NAME = "Neuron"; -const QString NeuronPlugin::NEURON_ID_STRING = "Perception Neuron"; - -bool NeuronPlugin::isSupported() const { - // TODO: - return true; -} - -void NeuronPlugin::activate() { - // TODO: - qCDebug(inputplugins) << "NeuronPlugin::activate"; -} - -void NeuronPlugin::deactivate() { - // TODO: - qCDebug(inputplugins) << "NeuronPlugin::deactivate"; -} - -void NeuronPlugin::pluginUpdate(float deltaTime, bool jointsCaptured) { - // TODO: - qCDebug(inputplugins) << "NeuronPlugin::pluginUpdate"; -} - -void NeuronPlugin::saveSettings() const { - // TODO: - qCDebug(inputplugins) << "NeuronPlugin::saveSettings"; -} - -void NeuronPlugin::loadSettings() { - // TODO: - qCDebug(inputplugins) << "NeuronPlugin::loadSettings"; -} - -controller::Input::NamedVector NeuronPlugin::InputDevice::getAvailableInputs() const { - // TODO: - static const controller::Input::NamedVector availableInputs { - makePair(controller::LEFT_HAND, "LeftHand"), - makePair(controller::RIGHT_HAND, "RightHand") - }; - return availableInputs; -} - -QString NeuronPlugin::InputDevice::getDefaultMappingConfig() const { - static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/neuron.json"; - return MAPPING_JSON; -} - -void NeuronPlugin::InputDevice::update(float deltaTime, bool jointsCaptured) { - // TODO: - qCDebug(inputplugins) << "NeuronPlugin::InputDevice::update"; -} - -void NeuronPlugin::InputDevice::focusOutEvent() { - // TODO: - qCDebug(inputplugins) << "NeuronPlugin::InputDevice::focusOutEvent"; -} From ba993eccd4686e5c60b8e636dd3e7b378ee232a7 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 18:32:07 -0800 Subject: [PATCH 134/209] cleanup --- examples/flowArts/lightSaber/lightSaberEntityScript.js | 2 -- examples/flowArts/raveStick/raveStickEntityScript.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index fd53eb4c87..fc67015ffb 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -56,8 +56,6 @@ this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); - // forwardVec = Vec3.normalize(forwardVec); - // var forwardQuat = orientationOf(forwardVec); var forwardQuat = Quat.rotationBetween(Vec3.UNIT_Z, forwardVec); var position = Vec3.sum(this.props.position, Vec3.multiply(Quat.getFront(this.props.rotation), 0.1)); position.z += 0.1; diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 5a37a9b313..3f571817d2 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -12,7 +12,6 @@ (function() { Script.include("../../libraries/utils.js"); var _this; - // this is the "constructor" for the entity as a JS object we don't do much here var LIFETIME = 6000; var DRAWING_DEPTH = 0.8; var LINE_DIMENSIONS = 100; @@ -48,7 +47,6 @@ lifetime: LIFETIME }); - this.points = []; this.normals = []; this.strokeWidths = []; From 1031489ada2b4053f388823f923d531c0de65e25 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 19:08:34 -0800 Subject: [PATCH 135/209] changed dates --- examples/flowArts/arcBall/arcBall.js | 2 +- examples/flowArts/flowArtsHutSpawner.js | 2 +- examples/flowArts/lightSaber/lightSaber.js | 2 +- examples/flowArts/lightTrails.js | 2 +- examples/flowArts/raveStick/raveStick.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 5a6b1b47f3..12ef2df48a 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -3,7 +3,7 @@ // examples/arcBall // // Created by Eric Levin on 12/17/15. -// Copyright 2014 High Fidelity, Inc. +// Copyright 2015 High Fidelity, Inc. // // This script creats a particle light ball which makes particle trails as you move it. // diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 59f4e70858..faa07c186d 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -3,7 +3,7 @@ // examples/flowArts // // Created by Eric Levin on 12/17/15. -// Copyright 2014 High Fidelity, Inc. +// Copyright 2015 High Fidelity, Inc. // // This script creates a special flow arts hut with a bunch of flow art toys people can go in and play with // diff --git a/examples/flowArts/lightSaber/lightSaber.js b/examples/flowArts/lightSaber/lightSaber.js index f582798546..3af5b65d16 100644 --- a/examples/flowArts/lightSaber/lightSaber.js +++ b/examples/flowArts/lightSaber/lightSaber.js @@ -3,7 +3,7 @@ // examples // // Created by Eric Levin on 12/17/15. -// Copyright 2014 High Fidelity, Inc. +// Copyright 2015 High Fidelity, Inc. // // This script creates a lightsaber which activates on grab // diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 522ecce851..bb936d55c2 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -3,7 +3,7 @@ // examples // // Created by Eric Levin on 5/14/15. -// Copyright 2014 High Fidelity, Inc. +// Copyright 2015 High Fidelity, Inc. // // This script creates light trails as you move your hydra hands // diff --git a/examples/flowArts/raveStick/raveStick.js b/examples/flowArts/raveStick/raveStick.js index 1e49c525f2..c51e8b5d89 100644 --- a/examples/flowArts/raveStick/raveStick.js +++ b/examples/flowArts/raveStick/raveStick.js @@ -3,7 +3,7 @@ // examples/flowArats/raveStick // // Created by Eric Levin on 12/17/15. -// Copyright 2014 High Fidelity, Inc. +// Copyright 2015 High Fidelity, Inc. // // This script creates a rave stick which makes pretty light trails as you paint // From 60e1c74fe942bd2da82acf0a074cf7bd7868e1f0 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 22 Dec 2015 13:58:18 +0100 Subject: [PATCH 136/209] winter games target Practice scripts --- .../targetPractice/shooterPlatform.js | 73 ++++++ .../targetPractice/startTargetPractice.js | 93 +++++++ .../targetPractice/targetPracticeGame.js | 227 ++++++++++++++++++ 3 files changed, 393 insertions(+) create mode 100644 examples/winterSmashUp/targetPractice/shooterPlatform.js create mode 100644 examples/winterSmashUp/targetPractice/startTargetPractice.js create mode 100644 examples/winterSmashUp/targetPractice/targetPracticeGame.js diff --git a/examples/winterSmashUp/targetPractice/shooterPlatform.js b/examples/winterSmashUp/targetPractice/shooterPlatform.js new file mode 100644 index 0000000000..4e40dbeaa5 --- /dev/null +++ b/examples/winterSmashUp/targetPractice/shooterPlatform.js @@ -0,0 +1,73 @@ +// +// shooterPlatform.js +// examples +// +// Created by Thijs Wenker on 12/21/15. +// Copyright 2015 High Fidelity, Inc. +// +// The Winter Smash Up Target Practice Game using a bow. +// This is the platform that spawns the bow and attaches it to the avatars hand, +// then de-rez the bow on leaving to prevent walking up to the targets with the bow. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + var _this = this; + + const GAME_CHANNEL = 'winterSmashUpGame'; + const SCRIPT_URL = Script.resolvePath('../../toybox/bow/bow.js'); + const MODEL_URL = "https://hifi-public.s3.amazonaws.com/models/bow/new/bow-deadly.fbx"; + const COLLISION_HULL_URL = "https://hifi-public.s3.amazonaws.com/models/bow/new/bow_collision_hull.obj"; + const RIGHT_HAND = 1; + const LEFT_HAND = 0; + + var bowEntity = undefined; + + _this.enterEntity = function(entityID) { + print('entered bow game entity'); + + // Triggers a recording on an assignment client: + Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameExplaination'); + + bowEntity = Entities.addEntity({ + name: 'Hifi-Bow-For-Game', + type: 'Model', + modelURL: MODEL_URL, + position: MyAvatar.position, + dimensions: {x: 0.04, y: 1.3, z: 0.21}, + collisionsWillMove: true, + gravity: {x: 0, y: 0, z: 0}, + shapeType: 'compound', + compoundShapeURL: COLLISION_HULL_URL, + script: SCRIPT_URL, + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true, + spatialKey: { + leftRelativePosition: { + x: 0.05, + y: 0.06, + z: -0.05 + }, + rightRelativePosition: { + x: -0.05, + y: 0.06, + z: -0.05 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90) + } + } + }) + }); + Messages.sendMessage('Hifi-Hand-Grab', JSON.stringify({hand: 'left', entityID: bowEntity})); + }; + + _this.leaveEntity = function(entityID) { + if (bowEntity !== undefined) { + Entities.deleteEntity(bowEntity); + bowEntity = undefined; + } + }; +}); diff --git a/examples/winterSmashUp/targetPractice/startTargetPractice.js b/examples/winterSmashUp/targetPractice/startTargetPractice.js new file mode 100644 index 0000000000..b4b8685df7 --- /dev/null +++ b/examples/winterSmashUp/targetPractice/startTargetPractice.js @@ -0,0 +1,93 @@ +// +// startTargetPractice.js +// examples +// +// Created by Thijs Wenker on 12/21/15. +// Copyright 2015 High Fidelity, Inc. +// +// The Winter Smash Up Target Practice Game using a bow. +// This script starts the game, when the entity that contains the script gets shot. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + var _this = this; + var waitForScriptLoad = false; + + const MAX_GAME_TIME = 60; //seconds + const SCRIPT_URL = 'http://s3.amazonaws.com/hifi-public/scripts/winterSmashUp/targetPractice/targetPracticeGame.js'; + const GAME_CHANNEL = 'winterSmashUpGame'; + + var isScriptRunning = function(script) { + script = script.toLowerCase().trim(); + var runningScripts = ScriptDiscoveryService.getRunning(); + for (i in runningScripts) { + if (runningScripts[i].url.toLowerCase().trim() == script) { + return true; + } + } + return false; + }; + + var sendStartSignal = function() { + Messages.sendMessage(GAME_CHANNEL, JSON.stringify({ + action: 'start', + gameEntityID: _this.entityID, + playerSessionUUID: MyAvatar.sessionUUID + })); + } + + var startGame = function() { + //TODO: check here if someone is already playing this game instance by verifying the userData for playerSessionID + // and startTime with a maximum timeout of X seconds (30?) + + + if (!isScriptRunning(SCRIPT_URL)) { + // Loads the script for the player if this isn't yet loaded + Script.load(SCRIPT_URL); + waitForScriptLoad = true; + return; + } + sendStartSignal(); + }; + + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == GAME_CHANNEL) { + var data = JSON.parse(message); + switch (data.action) { + case 'scriptLoaded': + if (waitForPing) { + sendStartSignal(); + waitForPing = false; + } + break; + } + } + }); + + _this.preload = function(entityID) { + _this.entityID = entityID; + }; + + _this.collisionWithEntity = function(entityA, entityB, collisionInfo) { + if (entityA == _this.entityID) { + try { + var data = JSON.parse(Entities.getEntityProperties(entityB).userData); + if (data.creatorSessionUUID === MyAvatar.sessionUUID) { + print('attempting to startGame by collisionWithEntity.'); + startGame(); + } + } catch(e) { + } + } + }; + + _this.onShot = function(forceDirection) { + print('attempting to startGame by onShot.'); + startGame(); + }; + + Messages.subscribe(GAME_CHANNEL); +}); diff --git a/examples/winterSmashUp/targetPractice/targetPracticeGame.js b/examples/winterSmashUp/targetPractice/targetPracticeGame.js new file mode 100644 index 0000000000..c5080863ab --- /dev/null +++ b/examples/winterSmashUp/targetPractice/targetPracticeGame.js @@ -0,0 +1,227 @@ +// +// targetPracticeGame.js +// examples +// +// Created by Thijs Wenker on 12/21/15. +// Copyright 2015 High Fidelity, Inc. +// +// The Winter Smash Up Target Practice Game using a bow. +// This script runs on the client side (it is loaded through the platform trigger entity) +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +const GAME_CHANNEL = 'winterSmashUpGame'; +const SCORE_POST_URL = 'https://script.google.com/macros/s/AKfycbwZAMx6cMBx6-8NGEhR8ELUA-dldtpa_4P55z38Q4vYHW6kneg/exec'; +const MODEL_URL = 'http://cdn.highfidelity.com/chris/production/winter/game/'; +const MAX_GAME_TIME = 120; //seconds +const TARGET_CLOSE_OFFSET = 0.5; +const MILLISECS_IN_SEC = 1000; +const HIT_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Clay_Pigeon_02.L.wav'; +const GRAVITY = -9.8; +const MESSAGE_WIDTH = 100; +const MESSAGE_HEIGHT = 50; + +const TARGETS = [ + {pitch: -1, yaw: -20, maxDistance: 17}, + {pitch: -1, yaw: -15, maxDistance: 17}, + {pitch: -1, yaw: -10, maxDistance: 17}, + {pitch: -2, yaw: -5, maxDistance: 17}, + {pitch: -1, yaw: 0, maxDistance: 17}, + {pitch: 3, yaw: 10, maxDistance: 17}, + {pitch: -1, yaw: 15, maxDistance: 17}, + {pitch: -1, yaw: 20, maxDistance: 17}, + {pitch: 2, yaw: 25, maxDistance: 17}, + {pitch: 0, yaw: 30, maxDistance: 17} +]; + +var gameRunning = false; +var gameStartTime; +var gameEntityID; +var gameTimeoutTimer; +var targetEntities = []; +var hitSound = SoundCache.getSound(HIT_SOUND_URL); +var messageOverlay = undefined; +var messageExpire = 0; + +var clearMessage = function() { + if (messageOverlay !== undefined) { + Overlays.deleteOverlay(messageOverlay); + messageOverlay = undefined; + } +}; + +var displayMessage = function(message, timeout) { + clearMessage(); + messageExpire = Date.now() + timeout; + messageOverlay = Overlays.addOverlay('text', { + text: message, + x: (Window.innerWidth / 2) - (MESSAGE_WIDTH / 2), + y: (Window.innerHeight / 2) - (MESSAGE_HEIGHT / 2), + width: MESSAGE_WIDTH, + height: MESSAGE_HEIGHT, + alpha: 1, + backgroundAlpha: 0.0, + font: {size: 20} + }); +}; + +var getStatsText = function() { + var timeLeft = MAX_GAME_TIME - ((Date.now() - gameStartTime) / MILLISECS_IN_SEC); + return 'Time remaining: ' + timeLeft.toFixed(1) + 's\nTargets hit: ' + (TARGETS.length - targetEntities.length) + '/' + TARGETS.length; +}; + +const timerOverlayWidth = 50; +var timerOverlay = Overlays.addOverlay('text', { + text: '', + x: Window.innerWidth / 2 - (timerOverlayWidth / 2), + y: 100, + width: timerOverlayWidth, + alpha: 1, + backgroundAlpha: 0.0, + visible: false, + font: {size: 20} +}); + +var cleanRemainingTargets = function() { + while (targetEntities.length > 0) { + Entities.deleteEntity(targetEntities.pop()); + } +}; + +var createTarget = function(position, rotation, scale) { + var initialDimensions = {x: 1.8437, y: 0.1614, z: 1.8438}; + var dimensions = Vec3.multiply(initialDimensions, scale); + return Entities.addEntity({ + type: 'Model', + rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(90, 0, 0)), + lifetime: MAX_GAME_TIME, + modelURL: MODEL_URL + 'target.fbx', + shapeType: 'compound', + compoundShapeURL: MODEL_URL + 'targetCollision.obj', + dimensions: dimensions, + position: position + }); +}; + +var createTargetInDirection = function(startPosition, startRotation, pitch, yaw, maxDistance, scale) { + var directionQuat = Quat.multiply(startRotation, Quat.fromPitchYawRollDegrees(pitch, yaw, 0.0)); + var directionVec = Vec3.multiplyQbyV(directionQuat, Vec3.FRONT); + var intersection = Entities.findRayIntersection({direction: directionVec, origin: startPosition}, true); + var distance = maxDistance; + if (intersection.intersects && intersection.distance <= maxDistance) { + distance = intersection.distance - TARGET_CLOSE_OFFSET; + } + return createTarget(Vec3.sum(startPosition, Vec3.multiplyQbyV(directionQuat, Vec3.multiply(Vec3.FRONT, distance))), startRotation, scale); +}; + +var killTimer = function() { + if (gameTimeoutTimer !== undefined) { + Script.clearTimeout(gameTimeoutTimer); + gameTimeoutTimer = undefined; + } +}; + +var submitScore = function() { + gameRunning = false; + killTimer(); + Overlays.editOverlay(timerOverlay, {visible: false}); + if (!GlobalServices.username) { + displayMessage('Could not submit score, you are not logged in.', 5000); + return; + } + var timeItTook = Date.now() - gameStartTime; + var req = new XMLHttpRequest(); + req.open('POST', SCORE_POST_URL, false); + req.send(JSON.stringify({ + username: GlobalServices.username, + time: timeItTook / MILLISECS_IN_SEC + })); + displayMessage('Your score has been submitted!', 5000); +}; + +var onTargetHit = function(targetEntity, projectileEntity, collision) { + var targetIndex = targetEntities.indexOf(targetEntity); + if (targetIndex !== -1) { + try { + var data = JSON.parse(Entities.getEntityProperties(projectileEntity).userData); + if (data.creatorSessionUUID === MyAvatar.sessionUUID) { + this.audioInjector = Audio.playSound(hitSound, { + position: collision.contactPoint, + volume: 0.5 + }); + // Attach arrow to target for the nice effect + Entities.editEntity(projectileEntity, { + ignoreForCollisions: true, + parentID: targetEntity + }); + Entities.editEntity(targetEntity, { + collisionsWillMove: true, + gravity: {x: 0, y: GRAVITY, z: 0}, + velocity: {x: 0, y: -0.01, z: 0} + }); + targetEntities.splice(targetIndex, 1); + if (targetEntities.length === 0) { + submitScore(); + } + } + } catch(e) { + } + } +}; + +var startGame = function(entityID) { + cleanRemainingTargets(); + killTimer(); + gameEntityID = entityID; + targetEntities = []; + var parentEntity = Entities.getEntityProperties(gameEntityID); + for (var i in TARGETS) { + var target = TARGETS[i]; + var targetEntity = createTargetInDirection(parentEntity.position, parentEntity.rotation, target.pitch, target.yaw, target.maxDistance, 0.67); + Script.addEventHandler(targetEntity, 'collisionWithEntity', onTargetHit); + targetEntities.push(targetEntity); + } + gameStartTime = Date.now(); + gameTimeoutTimer = Script.setTimeout(function() { + cleanRemainingTargets(); + Overlays.editOverlay(timerOverlay, {visible: false}); + gameRunning = false; + displayMessage('Game timed out.', 5000); + }, MAX_GAME_TIME * MILLISECS_IN_SEC); + gameRunning = true; + Overlays.editOverlay(timerOverlay, {visible: true, text: getStatsText()}); + displayMessage('Game started! GO GO GO!', 3000); +}; + +Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == GAME_CHANNEL) { + var data = JSON.parse(message); + switch (data.action) { + case 'start': + if (data.playerSessionUUID === MyAvatar.sessionUUID) { + startGame(data.gameEntityID); + } + break; + } + } +}); + +Messages.subscribe(GAME_CHANNEL); +Messages.sendMessage(GAME_CHANNEL, JSON.stringify({action: 'scriptLoaded'})); + +Script.update.connect(function(deltaTime) { + if (gameRunning) { + Overlays.editOverlay(timerOverlay, {text: getStatsText()}); + } + if (messageOverlay !== undefined && Date.now() > messageExpire) { + clearMessage(); + } +}); + +Script.scriptEnding.connect(function() { + Overlays.deleteOverlay(timerOverlay); + cleanRemainingTargets(); + clearMessage(); +}); From aefff1a59b582ffece0d83e9a9558a1aa957ad7d Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 22 Dec 2015 14:08:12 +0100 Subject: [PATCH 137/209] script to trigger recording with an assignment-client using messages-mixer --- examples/acScripts/triggeredRecordingOnAC.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/acScripts/triggeredRecordingOnAC.js diff --git a/examples/acScripts/triggeredRecordingOnAC.js b/examples/acScripts/triggeredRecordingOnAC.js new file mode 100644 index 0000000000..e69de29bb2 From b97f7ace66f1d8b449faaaec6cb9d59c746ce2ca Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 22 Dec 2015 14:09:25 +0100 Subject: [PATCH 138/209] path fix --- examples/winterSmashUp/targetPractice/shooterPlatform.js | 2 +- examples/winterSmashUp/targetPractice/startTargetPractice.js | 2 +- examples/winterSmashUp/targetPractice/targetPracticeGame.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/winterSmashUp/targetPractice/shooterPlatform.js b/examples/winterSmashUp/targetPractice/shooterPlatform.js index 4e40dbeaa5..4fae47a415 100644 --- a/examples/winterSmashUp/targetPractice/shooterPlatform.js +++ b/examples/winterSmashUp/targetPractice/shooterPlatform.js @@ -1,6 +1,6 @@ // // shooterPlatform.js -// examples +// examples/winterSmashUp/targetPractice // // Created by Thijs Wenker on 12/21/15. // Copyright 2015 High Fidelity, Inc. diff --git a/examples/winterSmashUp/targetPractice/startTargetPractice.js b/examples/winterSmashUp/targetPractice/startTargetPractice.js index b4b8685df7..2e65d09fb1 100644 --- a/examples/winterSmashUp/targetPractice/startTargetPractice.js +++ b/examples/winterSmashUp/targetPractice/startTargetPractice.js @@ -1,6 +1,6 @@ // // startTargetPractice.js -// examples +// examples/winterSmashUp/targetPractice // // Created by Thijs Wenker on 12/21/15. // Copyright 2015 High Fidelity, Inc. diff --git a/examples/winterSmashUp/targetPractice/targetPracticeGame.js b/examples/winterSmashUp/targetPractice/targetPracticeGame.js index c5080863ab..d58258af5a 100644 --- a/examples/winterSmashUp/targetPractice/targetPracticeGame.js +++ b/examples/winterSmashUp/targetPractice/targetPracticeGame.js @@ -1,6 +1,6 @@ // // targetPracticeGame.js -// examples +// examples/winterSmashUp/targetPractice // // Created by Thijs Wenker on 12/21/15. // Copyright 2015 High Fidelity, Inc. From 6c34059061becc4d59a398dc34fd15af73a1adda Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 22 Dec 2015 14:24:14 +0100 Subject: [PATCH 139/209] (note to self, ctrl-s every 5 seconds in code editor) --- examples/acScripts/triggeredRecordingOnAC.js | 72 ++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/examples/acScripts/triggeredRecordingOnAC.js b/examples/acScripts/triggeredRecordingOnAC.js index e69de29bb2..9de5173615 100644 --- a/examples/acScripts/triggeredRecordingOnAC.js +++ b/examples/acScripts/triggeredRecordingOnAC.js @@ -0,0 +1,72 @@ +// +// triggeredRecordingOnAC.js +// examples/acScripts +// +// Created by Thijs Wenker on 12/21/15. +// Copyright 2015 High Fidelity, Inc. +// +// This is the triggered rocording script used in the winterSmashUp target practice game. +// Change the CLIP_URL to your asset, +// the RECORDING_CHANNEL and RECORDING_CHANNEL_MESSAGE are used to trigger it i.e.: +// Messages.sendMessage("PlayBackOnAssignment", "BowShootingGameWelcome"); +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +const CLIP_URL = "atp:3fbe82f2153c443f12f9a2b14ce2d7fa2fff81977263746d9e0885ea5aabed62.hfr"; + +const RECORDING_CHANNEL = 'PlayBackOnAssignment'; +const RECORDING_CHANNEL_MESSAGE = 'BowShootingGameWelcome'; // For each different assignment add a different message here. +const PLAY_FROM_CURRENT_LOCATION = true; +const USE_DISPLAY_NAME = true; +const USE_ATTACHMENTS = true; +const USE_AVATAR_MODEL = true; +const AUDIO_OFFSET = 0.0; +const STARTING_TIME = 0.0; +const COOLDOWN_PERIOD = 0; // The period in ms that no animations can be played after one has been played already + +var isPlaying = false; +var isPlayable = true; + +var playRecording = function() { + if (!isPlayable || isPlaying) { + return; + } + Agent.isAvatar = true; + Recording.setPlayFromCurrentLocation(PLAY_FROM_CURRENT_LOCATION); + Recording.setPlayerUseDisplayName(USE_DISPLAY_NAME); + Recording.setPlayerUseAttachments(USE_ATTACHMENTS); + Recording.setPlayerUseHeadModel(false); + Recording.setPlayerUseSkeletonModel(USE_AVATAR_MODEL); + Recording.setPlayerLoop(false); + Recording.setPlayerTime(STARTING_TIME); + Recording.setPlayerAudioOffset(AUDIO_OFFSET); + Recording.loadRecording(CLIP_URL); + Recording.startPlaying(); + isPlaying = true; + isPlayable = false; // Set this true again after the cooldown period +}; + +Script.update.connect(function(deltaTime) { + if (isPlaying && !Recording.isPlaying()) { + print('Reached the end of the recording. Resetting.'); + isPlaying = false; + Agent.isAvatar = false; + if (COOLDOWN_PERIOD === 0) { + isPlayable = true; + return; + } + Script.setTimeout(function () { + isPlayable; + }, COOLDOWN_PERIOD); + } +}); + +Messages.subscribe(RECORDING_CHANNEL); + +Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel === RECORDING_CHANNEL && message === RECORDING_CHANNEL_MESSAGE) { + playRecording(); + } +}); From 00b47cacea4b3af8f8d743f32f1db6b2d828dacc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 22 Dec 2015 09:59:57 -0800 Subject: [PATCH 140/209] Fix crash when getting MyAvatar.sessionUUID from AvatarManager The previous code inadvertently added a default constructed shared pointer to the avatar hash, causing it to crash when dereferencing it in the update loop. --- interface/src/avatar/AvatarManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 312742e778..217cd28e61 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -310,8 +310,8 @@ QVector AvatarManager::getAvatarIdentifiers() { } AvatarData* AvatarManager::getAvatar(QUuid avatarID) { - QReadLocker locker(&_hashLock); - return _avatarHash[avatarID].get(); // Non-obvious: A bogus avatarID answers your own avatar. + // Null/Default-constructed QUuids will return MyAvatar + return getAvatarBySessionID(avatarID).get(); } From 653e3ecdcc0cec85d61cf22b26ac7f6d1efc7780 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Tue, 22 Dec 2015 11:02:36 -0800 Subject: [PATCH 141/209] fixed offset issue with lightsaber --- examples/flowArts/lightSaber/lightSaberEntityScript.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index fc67015ffb..a86f471449 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -57,9 +57,8 @@ this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); var forwardQuat = Quat.rotationBetween(Vec3.UNIT_Z, forwardVec); - var position = Vec3.sum(this.props.position, Vec3.multiply(Quat.getFront(this.props.rotation), 0.1)); - position.z += 0.1; - position.x += -0.035; + var position = this.props.position; + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", @@ -114,4 +113,4 @@ }; // entity scripts always need to return a newly constructed object of our type return new LightSaber(); -}); \ No newline at end of file +}); From e8803ad9aecd6c66620ecd1de1436887f870988d Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Tue, 22 Dec 2015 11:35:04 -0800 Subject: [PATCH 142/209] Lightsaber looks way better now --- examples/flowArts/lightSaber/lightSaber.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/flowArts/lightSaber/lightSaber.js b/examples/flowArts/lightSaber/lightSaber.js index 3af5b65d16..c4ab49e8e6 100644 --- a/examples/flowArts/lightSaber/lightSaber.js +++ b/examples/flowArts/lightSaber/lightSaber.js @@ -38,7 +38,7 @@ LightSaber = function(spawnPosition) { y: 0, z: -0.1 }, - relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) + relativeRotation: Quat.fromPitchYawRollDegrees(180, 90, 0) }, invertSolidWhileHeld: true } @@ -64,4 +64,4 @@ LightSaber = function(spawnPosition) { } this.cleanup = cleanup; -} \ No newline at end of file +} From 56d654987c1f0fe91731f5671900e927814f124b Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 22 Dec 2015 11:48:56 -0800 Subject: [PATCH 143/209] changing branches --- examples/light_modifier/lightModifier.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index e8a9f39903..48efe89a6e 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -8,7 +8,9 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// +// + +// todo: text labels for property names, panel plane for visibility //some experimental options var ONLY_I_CAN_EDIT = false; @@ -16,7 +18,7 @@ var SLIDERS_SHOULD_STAY_WITH_AVATAR = false; var VERTICAL_SLIDERS = false; var SHOW_OVERLAYS = true; var SHOW_LIGHT_VOLUME = true; -var USE_PARENTED_PANEL = false; +var USE_PARENTED_PANEL = true; //variables for managing overlays var selectionDisplay; @@ -225,6 +227,9 @@ entitySlider.prototype = { }; this.axis = Entities.addEntity(properties); + }, + createLabel:function(){ + }, createSliderIndicator: function() { var extensionVector; @@ -652,6 +657,12 @@ function handleCleanupMessages(channel, message, sender) { } } +function updateSliderAxis(){ + sliders.forEach(function(slider){ + + }) +} + function cleanup(fromMessage) { var i; for (i = 0; i < sliders.length; i++) { From 7bc7bddc3aed5b4ab26abe1f1e8a9a2bb60112d2 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 22 Dec 2015 12:00:45 -0800 Subject: [PATCH 144/209] set defaults --- .../handControllerGrab-all-overlays.js | 1656 ----------------- .../handControllerGrab-particles.js | 1656 ----------------- .../handControllerGrab-pointlight.js | 1656 ----------------- .../handControllerGrab-spotlight.js | 1656 ----------------- examples/controllers/handControllerGrab.js | 8 +- 5 files changed, 4 insertions(+), 6628 deletions(-) delete mode 100644 examples/controllers/handControllerGrab-all-overlays.js delete mode 100644 examples/controllers/handControllerGrab-particles.js delete mode 100644 examples/controllers/handControllerGrab-pointlight.js delete mode 100644 examples/controllers/handControllerGrab-spotlight.js diff --git a/examples/controllers/handControllerGrab-all-overlays.js b/examples/controllers/handControllerGrab-all-overlays.js deleted file mode 100644 index 67e2b1f0a7..0000000000 --- a/examples/controllers/handControllerGrab-all-overlays.js +++ /dev/null @@ -1,1656 +0,0 @@ -// handControllerGrab.js -// -// Created by Eric Levin on 9/2/15 -// Additions by James B. Pollack @imgntn on 9/24/2015 -// Additions By Seth Alves on 10/20/2015 -// Copyright 2015 High Fidelity, Inc. -// -// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. -// Also supports touch and equipping objects. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ - -Script.include("../libraries/utils.js"); - -// -// add lines where the hand ray picking is happening -// -var WANT_DEBUG = false; - -// -// these tune time-averaging and "on" value for analog trigger -// - -var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value -var TRIGGER_ON_VALUE = 0.4; -var TRIGGER_OFF_VALUE = 0.15; - -var BUMPER_ON_VALUE = 0.5; - -// -// distant manipulation -// - -var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object -var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position -var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did -var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects - -var NO_INTERSECT_COLOR = { - red: 10, - green: 10, - blue: 255 -}; // line color when pick misses -var INTERSECT_COLOR = { - red: 250, - green: 10, - blue: 10 -}; // line color when pick hits -var LINE_ENTITY_DIMENSIONS = { - x: 1000, - y: 1000, - z: 1000 -}; - -var LINE_LENGTH = 500; -var PICK_MAX_DISTANCE = 500; // max length of pick-ray - -// -// near grabbing -// - -var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected -var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position -var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. -var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected -var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things -var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object -var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed - -// -// equip -// - -var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; -var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position - -// -// other constants -// - -var RIGHT_HAND = 1; -var LEFT_HAND = 0; - -var ZERO_VEC = { - x: 0, - y: 0, - z: 0 -}; - -var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; -var MSEC_PER_SEC = 1000.0; - -// these control how long an abandoned pointer line or action will hang around -var LIFETIME = 10; -var ACTION_TTL = 15; // seconds -var ACTION_TTL_REFRESH = 5; -var PICKS_PER_SECOND_PER_HAND = 5; -var MSECS_PER_SEC = 1000.0; -var GRABBABLE_PROPERTIES = [ - "position", - "rotation", - "gravity", - "ignoreForCollisions", - "collisionsWillMove", - "locked", - "name" -]; - -var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js -var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js - -var DEFAULT_GRABBABLE_DATA = { - grabbable: true, - invertSolidWhileHeld: false -}; - -//we've created various ways of visualizing looking for and moving distant objects -var USE_ENTITY_LINES_FOR_SEARCHING = false; -var USE_OVERLAY_LINES_FOR_SEARCHING = true; -var USE_PARTICLE_BEAM_FOR_SEARCHING = false; - -var USE_ENTITY_LINES_FOR_MOVING = false; -var USE_OVERLAY_LINES_FOR_MOVING = true; -var USE_PARTICLE_BEAM_FOR_MOVING = false; - -var USE_SPOTLIGHT = false; -var USE_POINTLIGHT = false; - -// states for the state machine -var STATE_OFF = 0; -var STATE_SEARCHING = 1; -var STATE_DISTANCE_HOLDING = 2; -var STATE_CONTINUE_DISTANCE_HOLDING = 3; -var STATE_NEAR_GRABBING = 4; -var STATE_CONTINUE_NEAR_GRABBING = 5; -var STATE_NEAR_TRIGGER = 6; -var STATE_CONTINUE_NEAR_TRIGGER = 7; -var STATE_FAR_TRIGGER = 8; -var STATE_CONTINUE_FAR_TRIGGER = 9; -var STATE_RELEASE = 10; -var STATE_EQUIP_SEARCHING = 11; -var STATE_EQUIP = 12 -var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down -var STATE_CONTINUE_EQUIP = 14; -var STATE_WAITING_FOR_BUMPER_RELEASE = 15; -var STATE_EQUIP_SPRING = 16; - - - -function stateToName(state) { - switch (state) { - case STATE_OFF: - return "off"; - case STATE_SEARCHING: - return "searching"; - case STATE_DISTANCE_HOLDING: - return "distance_holding"; - case STATE_CONTINUE_DISTANCE_HOLDING: - return "continue_distance_holding"; - case STATE_NEAR_GRABBING: - return "near_grabbing"; - case STATE_CONTINUE_NEAR_GRABBING: - return "continue_near_grabbing"; - case STATE_NEAR_TRIGGER: - return "near_trigger"; - case STATE_CONTINUE_NEAR_TRIGGER: - return "continue_near_trigger"; - case STATE_FAR_TRIGGER: - return "far_trigger"; - case STATE_CONTINUE_FAR_TRIGGER: - return "continue_far_trigger"; - case STATE_RELEASE: - return "release"; - case STATE_EQUIP_SEARCHING: - return "equip_searching"; - case STATE_EQUIP: - return "equip"; - case STATE_CONTINUE_EQUIP_BD: - return "continue_equip_bd"; - case STATE_CONTINUE_EQUIP: - return "continue_equip"; - case STATE_WAITING_FOR_BUMPER_RELEASE: - return "waiting_for_bumper_release"; - case STATE_EQUIP_SPRING: - return "state_equip_spring"; - } - - return "unknown"; -} - -function getTag() { - return "grab-" + MyAvatar.sessionUUID; -} - -function entityIsGrabbedByOther(entityID) { - // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. - var actionIDs = Entities.getActionIDs(entityID); - for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { - var actionID = actionIDs[actionIndex]; - var actionArguments = Entities.getActionArguments(entityID, actionID); - var tag = actionArguments["tag"]; - if (tag == getTag()) { - // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. - continue; - } - if (tag.slice(0, 5) == "grab-") { - // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. - return true; - } - } - return false; -} - -function getSpatialOffsetPosition(hand, spatialKey) { - var position = Vec3.ZERO; - - if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { - position = spatialKey.leftRelativePosition; - } - if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { - position = spatialKey.rightRelativePosition; - } - if (spatialKey.relativePosition) { - position = spatialKey.relativePosition; - } - - return position; -} - -var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); - -function getSpatialOffsetRotation(hand, spatialKey) { - var rotation = Quat.IDENTITY; - - if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { - rotation = spatialKey.leftRelativeRotation; - } - if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { - rotation = spatialKey.rightRelativeRotation; - } - if (spatialKey.relativeRotation) { - rotation = spatialKey.relativeRotation; - } - - // Flip left hand - if (hand !== RIGHT_HAND) { - rotation = Quat.multiply(yFlip, rotation); - } - - return rotation; -} - -function MyController(hand) { - this.hand = hand; - if (this.hand === RIGHT_HAND) { - this.getHandPosition = MyAvatar.getRightPalmPosition; - this.getHandRotation = MyAvatar.getRightPalmRotation; - } else { - this.getHandPosition = MyAvatar.getLeftPalmPosition; - this.getHandRotation = MyAvatar.getLeftPalmRotation; - } - - var SPATIAL_CONTROLLERS_PER_PALM = 2; - var TIP_CONTROLLER_OFFSET = 1; - this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; - this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; - - this.actionID = null; // action this script created... - this.grabbedEntity = null; // on this entity. - this.state = STATE_OFF; - this.pointer = null; // entity-id of line object - this.triggerValue = 0; // rolling average of trigger value - this.rawTriggerValue = 0; - this.rawBumperValue = 0; - - //for visualizations - this.overlayLine = null; - this.particleBeam = null; - - //for lights - this.spotlight = null; - this.pointlight = null; - - this.ignoreIK = false; - this.offsetPosition = Vec3.ZERO; - this.offsetRotation = Quat.IDENTITY; - - var _this = this; - - this.update = function() { - - this.updateSmoothedTrigger(); - - switch (this.state) { - case STATE_OFF: - this.off(); - this.touchTest(); - break; - case STATE_SEARCHING: - this.search(); - break; - case STATE_EQUIP_SEARCHING: - this.search(); - break; - case STATE_DISTANCE_HOLDING: - this.distanceHolding(); - break; - case STATE_CONTINUE_DISTANCE_HOLDING: - this.continueDistanceHolding(); - break; - case STATE_NEAR_GRABBING: - case STATE_EQUIP: - this.nearGrabbing(); - break; - case STATE_WAITING_FOR_BUMPER_RELEASE: - this.waitingForBumperRelease(); - break; - case STATE_EQUIP_SPRING: - this.pullTowardEquipPosition() - break; - case STATE_CONTINUE_NEAR_GRABBING: - case STATE_CONTINUE_EQUIP_BD: - case STATE_CONTINUE_EQUIP: - this.continueNearGrabbing(); - break; - case STATE_NEAR_TRIGGER: - this.nearTrigger(); - break; - case STATE_CONTINUE_NEAR_TRIGGER: - this.continueNearTrigger(); - break; - case STATE_FAR_TRIGGER: - this.farTrigger(); - break; - case STATE_CONTINUE_FAR_TRIGGER: - this.continueFarTrigger(); - break; - case STATE_RELEASE: - this.release(); - break; - } - }; - - this.setState = function(newState) { - if (WANT_DEBUG) { - print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); - } - this.state = newState; - }; - - this.debugLine = function(closePoint, farPoint, color) { - Entities.addEntity({ - type: "Line", - name: "Grab Debug Entity", - dimensions: LINE_ENTITY_DIMENSIONS, - visible: true, - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: 0.1, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - }; - - this.lineOn = function(closePoint, farPoint, color) { - // draw a line - if (this.pointer === null) { - this.pointer = Entities.addEntity({ - type: "Line", - name: "grab pointer", - dimensions: LINE_ENTITY_DIMENSIONS, - visible: true, - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: LIFETIME, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - } else { - var age = Entities.getEntityProperties(this.pointer, "age").age; - this.pointer = Entities.editEntity(this.pointer, { - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: age + LIFETIME - }); - } - }; - - this.overlayLineOn = function(closePoint, farPoint, color) { - if (this.overlayLine === null) { - var lineProperties = { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - ignoreRayIntersection: true, // always ignore this - visible: true, - alpha: 1 - }; - - this.overlayLine = Overlays.addOverlay("line3d", lineProperties); - - } else { - var success = Overlays.editOverlay(this.overlayLine, { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - visible: true, - ignoreRayIntersection: true, // always ignore this - alpha: 1 - }); - } - }; - - this.handleParticleBeam = function(position, orientation, color) { - - var rotation = Quat.angleAxis(0, { - x: 1, - y: 0, - z: 0 - }); - - var finalRotation = Quat.multiply(orientation, rotation); - var lifespan = LINE_LENGTH / 10; - var speed = 5; - var spread = 2; - if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); - } else { - this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); - } - }; - - this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { - - var handToObject = Vec3.subtract(objectPosition, handPosition); - var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); - - var distance = Vec3.distance(handPosition, objectPosition); - var speed = 5; - var spread = 0; - - var lifespan = distance / speed; - - - if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); - } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); - } - }; - - this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { - - var particleBeamProperties = { - type: "ParticleEffect", - isEmitting: true, - position: position, - visible: false, - "name": "Particle Beam", - "color": color, - "maxParticles": 2000, - "lifespan": lifespan, - "emitRate": 50, - "emitSpeed": speed, - "speedSpread": spread, - "emitOrientation": { - "x": -1, - "y": 0, - "z": 0, - "w": 1 - }, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "emitRadiusStart": 0.5, - "polarStart": 0, - "polarFinish": 0, - "azimuthStart": -3.1415927410125732, - "azimuthFinish": 3.1415927410125732, - "emitAcceleration": { - x: 0, - y: 0, - z: 0 - }, - "accelerationSpread": { - "x": 0, - "y": 0, - "z": 0 - }, - "particleRadius": 0.01, - "radiusSpread": 0, - // "radiusStart": 0.01, - // "radiusFinish": 0.01, - // "colorSpread": { - // "red": 0, - // "green": 0, - // "blue": 0 - // }, - // "colorStart": color, - // "colorFinish": color, - "alpha": 1, - "alphaSpread": 0, - "alphaStart": 1, - "alphaFinish": 1, - "additiveBlending": 0, - "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" - } - - this.particleBeam = Entities.addEntity(particleBeamProperties); - }; - - this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { - print('lifespan::' + lifespan); - Entities.editEntity(this.particleBeam, { - rotation: orientation, - position: position, - visible: true, - color: color, - emitSpeed: speed, - speedSpread:spread, - lifespan: lifespan - - }) - - }; - - this.evalLightWorldTransform = function(modelPos, modelRot) { - - var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 - }; - - var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 - }); - - return { - p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), - q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) - }; - }; - - this.handleSpotlight = function(parentID, position) { - var LIFETIME = 100; - - var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); - - var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - var lightProperties = { - type: "Light", - isSpotlight: true, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - parentID: parentID, - color: { - red: 255, - green: 255, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: LIFETIME, - position: lightTransform.p, - }; - - if (this.spotlight === null) { - this.spotlight = Entities.addEntity(lightProperties); - } else { - Entities.editEntity(this.spotlight, { - //without this, this light would maintain rotation with its parent - rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), - }) - } - }; - - this.handlePointLight = function(parentID, position) { - var LIFETIME = 100; - - var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); - var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - - var lightProperties = { - type: "Light", - isSpotlight: false, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - parentID: parentID, - color: { - red: 255, - green: 255, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: LIFETIME, - position: lightTransform.p, - }; - - if (this.pointlight === null) { - this.pointlight = Entities.addEntity(lightProperties); - } else { - - } - }; - - this.lineOff = function() { - if (this.pointer !== null) { - Entities.deleteEntity(this.pointer); - } - this.pointer = null; - }; - - this.overlayLineOff = function() { - if (this.overlayLine !== null) { - Overlays.deleteOverlay(this.overlayLine); - } - this.overlayLine = null; - }; - - this.particleBeamOff = function() { - if (this.particleBeam !== null) { - Entities.editEntity(this.particleBeam, { - visible: false - }) - } - } - - this.turnLightsOff = function() { - if (this.spotlight !== null) { - Entities.deleteEntity(this.spotlight); - this.spotlight = null; - } - - if (this.pointlight !== null) { - Entities.deleteEntity(this.pointlight); - this.pointlight = null; - } - }; - - - this.turnOffVisualizations = function() { - if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOff(); - } - - if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { - this.overlayLineOff(); - } - - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.particleBeamOff(); - } - }; - - this.triggerPress = function(value) { - _this.rawTriggerValue = value; - }; - - this.bumperPress = function(value) { - _this.rawBumperValue = value; - }; - - this.updateSmoothedTrigger = function() { - var triggerValue = this.rawTriggerValue; - // smooth out trigger value - this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + - (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); - }; - - this.triggerSmoothedSqueezed = function() { - return this.triggerValue > TRIGGER_ON_VALUE; - }; - - this.triggerSmoothedReleased = function() { - return this.triggerValue < TRIGGER_OFF_VALUE; - }; - - this.triggerSqueezed = function() { - var triggerValue = this.rawTriggerValue; - return triggerValue > TRIGGER_ON_VALUE; - }; - - this.bumperSqueezed = function() { - return _this.rawBumperValue > BUMPER_ON_VALUE; - }; - - this.bumperReleased = function() { - return _this.rawBumperValue < BUMPER_ON_VALUE; - }; - - this.off = function() { - if (this.triggerSmoothedSqueezed()) { - this.lastPickTime = 0; - this.setState(STATE_SEARCHING); - return; - } - if (this.bumperSqueezed()) { - this.lastPickTime = 0; - this.setState(STATE_EQUIP_SEARCHING); - return; - } - }; - - this.search = function() { - this.grabbedEntity = null; - - if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { - this.setState(STATE_RELEASE); - return; - } - - // the trigger is being pressed, do a ray test - var handPosition = this.getHandPosition(); - var distantPickRay = { - origin: handPosition, - direction: Quat.getUp(this.getHandRotation()), - length: PICK_MAX_DISTANCE - }; - - // don't pick 60x per second. - var pickRays = []; - var now = Date.now(); - if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - pickRays = [distantPickRay]; - this.lastPickTime = now; - } - - for (var index = 0; index < pickRays.length; ++index) { - var pickRay = pickRays[index]; - var directionNormalized = Vec3.normalize(pickRay.direction); - var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); - var pickRayBacked = { - origin: Vec3.subtract(pickRay.origin, directionBacked), - direction: pickRay.direction - }; - - if (WANT_DEBUG) { - this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { - red: 0, - green: 255, - blue: 0 - }) - } - - var intersection = Entities.findRayIntersection(pickRayBacked, true); - - if (intersection.intersects) { - // the ray is intersecting something we can move. - var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); - - if (intersection.properties.name == "Grab Debug Entity") { - continue; - } - - if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { - continue; - } - if (intersectionDistance > pickRay.length) { - // too far away for this ray. - continue; - } - if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { - // the hand is very close to the intersected object. go into close-grabbing mode. - if (grabbableData.wantsTrigger) { - this.grabbedEntity = intersection.entityID; - this.setState(STATE_NEAR_TRIGGER); - return; - } else if (!intersection.properties.locked) { - this.grabbedEntity = intersection.entityID; - if (this.state == STATE_SEARCHING) { - this.setState(STATE_NEAR_GRABBING); - } else { // equipping - if (typeof grabbableData.spatialKey !== 'undefined') { - // TODO - // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch - // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. - // this.setState(STATE_EQUIP_SPRING); - this.setState(STATE_EQUIP); - } else { - this.setState(STATE_EQUIP); - } - } - return; - } - } else if (!entityIsGrabbedByOther(intersection.entityID)) { - // don't allow two people to distance grab the same object - if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { - // the hand is far from the intersected object. go into distance-holding mode - this.grabbedEntity = intersection.entityID; - if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { - // if a distance pick in equip mode hits something with a spatialKey, equip it - // TODO use STATE_EQUIP_SPRING here once it works right. - // this.setState(STATE_EQUIP_SPRING); - this.setState(STATE_EQUIP); - return; - } else if (this.state == STATE_SEARCHING) { - this.setState(STATE_DISTANCE_HOLDING); - return; - } - } else if (grabbableData.wantsTrigger) { - this.grabbedEntity = intersection.entityID; - this.setState(STATE_FAR_TRIGGER); - return; - } - } - } - } - - // forward ray test failed, try sphere test. - if (WANT_DEBUG) { - Entities.addEntity({ - type: "Sphere", - name: "Grab Debug Entity", - dimensions: { - x: GRAB_RADIUS, - y: GRAB_RADIUS, - z: GRAB_RADIUS - }, - visible: true, - position: handPosition, - color: { - red: 0, - green: 255, - blue: 0 - }, - lifetime: 0.1, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - } - - var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); - var minDistance = PICK_MAX_DISTANCE; - var i, props, distance, grabbableData; - this.grabbedEntity = null; - for (i = 0; i < nearbyEntities.length; i++) { - var grabbableDataForCandidate = - getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); - if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { - continue; - } - var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); - - if (propsForCandidate.type == 'Unknown') { - continue; - } - - if (propsForCandidate.type == 'Light') { - continue; - } - - if (propsForCandidate.type == 'ParticleEffect') { - continue; - } - - if (propsForCandidate.type == 'PolyLine') { - continue; - } - - if (propsForCandidate.type == 'Zone') { - continue; - } - - if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { - continue; - } - - if (propsForCandidate.name == "Grab Debug Entity") { - continue; - } - - if (propsForCandidate.name == "grab pointer") { - continue; - } - - distance = Vec3.distance(propsForCandidate.position, handPosition); - if (distance < minDistance) { - this.grabbedEntity = nearbyEntities[i]; - minDistance = distance; - props = propsForCandidate; - grabbableData = grabbableDataForCandidate; - } - } - if (this.grabbedEntity !== null) { - if (grabbableData.wantsTrigger) { - this.setState(STATE_NEAR_TRIGGER); - return; - } else if (!props.locked && props.collisionsWillMove) { - this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) - return; - } - } - - //search line visualizations - if (USE_ENTITY_LINES_FOR_SEARCHING === true) { - this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - } - - if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); - } - - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { - this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); - } - - }; - - this.distanceHolding = function() { - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var now = Date.now(); - - // add the action and initialize some variables - this.currentObjectPosition = grabbedProperties.position; - this.currentObjectRotation = grabbedProperties.rotation; - this.currentObjectTime = now; - this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); - this.handPreviousRotation = handRotation; - this.currentCameraOrientation = Camera.orientation; - - // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object - this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); - if (this.radiusScalar < 1.0) { - this.radiusScalar = 1.0; - } - - this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("spring", this.grabbedEntity, { - targetPosition: this.currentObjectPosition, - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - tag: getTag(), - ttl: ACTION_TTL - }); - if (this.actionID === NULL_ACTION_ID) { - this.actionID = null; - } - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - - if (this.actionID !== null) { - this.setState(STATE_CONTINUE_DISTANCE_HOLDING); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); - } - - this.currentAvatarPosition = MyAvatar.position; - this.currentAvatarOrientation = MyAvatar.orientation; - - this.turnOffVisualizations(); - }; - - this.continueDistanceHolding = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - - var handPosition = this.getHandPosition(); - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && - typeof grabbableData.spatialKey !== 'undefined') { - var saveGrabbedID = this.grabbedEntity; - this.release(); - this.setState(STATE_EQUIP); - this.grabbedEntity = saveGrabbedID; - return; - } - - - // the action was set up on a previous call. update the targets. - var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * - this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; - if (radius < 1.0) { - radius = 1.0; - } - - // how far did avatar move this timestep? - var currentPosition = MyAvatar.position; - var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); - this.currentAvatarPosition = currentPosition; - - // How far did the avatar turn this timestep? - // Note: The following code is too long because we need a Quat.quatBetween() function - // that returns the minimum quaternion between two quaternions. - var currentOrientation = MyAvatar.orientation; - if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) { - var negativeCurrentOrientation = { - x: -currentOrientation.x, - y: -currentOrientation.y, - z: -currentOrientation.z, - w: -currentOrientation.w - }; - var avatarDeltaOrientation = Quat.multiply(negativeCurrentOrientation, Quat.inverse(this.currentAvatarOrientation)); - } else { - var avatarDeltaOrientation = Quat.multiply(currentOrientation, Quat.inverse(this.currentAvatarOrientation)); - } - var handToAvatar = Vec3.subtract(handControllerPosition, this.currentAvatarPosition); - var objectToAvatar = Vec3.subtract(this.currentObjectPosition, this.currentAvatarPosition); - var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar); - var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar); - this.currentAvatarOrientation = currentOrientation; - - // how far did hand move this timestep? - var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); - this.handRelativePreviousPosition = handToAvatar; - - // magnify the hand movement but not the change from avatar movement & rotation - handMoved = Vec3.subtract(handMoved, handMovementFromTurning); - var superHandMoved = Vec3.multiply(handMoved, radius); - - // Move the object by the magnified amount and then by amount from avatar movement & rotation - var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); - newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); - newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); - - var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters - var now = Date.now(); - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - - this.currentObjectPosition = newObjectPosition; - this.currentObjectTime = now; - - // this doubles hand rotation - var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, - handRotation, - DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), - Quat.inverse(this.handPreviousRotation)); - this.handPreviousRotation = handRotation; - this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); - - Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); - - // mix in head motion - if (MOVE_WITH_HEAD) { - var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var after = Vec3.multiplyQbyV(Camera.orientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var change = Vec3.subtract(before, after); - this.currentCameraOrientation = Camera.orientation; - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); - } - - - //visualizations - if (USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); - } - if (USE_OVERLAY_LINES_FOR_MOVING === true) { - this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); - } - if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) - // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) - } - if (USE_POINTLIGHT === true) { - this.handlePointLight(this.grabbedEntity); - } - if (USE_SPOTLIGHT === true) { - this.handleSpotlight(this.grabbedEntity); - } - - Entities.updateAction(this.grabbedEntity, this.actionID, { - targetPosition: this.currentObjectPosition, - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - ttl: ACTION_TTL - }); - - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - }; - - this.nearGrabbing = function() { - var now = Date.now(); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - - this.turnOffVisualizations(); - - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { - Entities.editEntity(this.grabbedEntity, { - collisionsWillMove: false - }); - } - - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { - // if an object is "equipped" and has a spatialKey, use it. - this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - } else { - this.ignoreIK = false; - - var objectRotation = grabbedProperties.rotation; - this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var currentObjectPosition = grabbedProperties.position; - var offset = Vec3.subtract(currentObjectPosition, handPosition); - this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); - } - - this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("hold", this.grabbedEntity, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, - ignoreIK: this.ignoreIK - }); - if (this.actionID === NULL_ACTION_ID) { - this.actionID = null; - } else { - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - if (this.state == STATE_NEAR_GRABBING) { - this.setState(STATE_CONTINUE_NEAR_GRABBING); - } else { - // equipping - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - this.startHandGrasp(); - - this.setState(STATE_CONTINUE_EQUIP_BD); - } - - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); - - } - - this.currentHandControllerTipPosition = - (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; - - this.currentObjectTime = Date.now(); - }; - - this.continueNearGrabbing = function() { - if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { - this.setState(STATE_CONTINUE_EQUIP); - return; - } - if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { - this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); - return; - } - if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { - this.setState(STATE_CONTINUE_EQUIP_BD); - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - return; - } - - // Keep track of the fingertip velocity to impart when we release the object. - // Note that the idea of using a constant 'tip' velocity regardless of the - // object's actual held offset is an idea intended to make it easier to throw things: - // Because we might catch something or transfer it between hands without a good idea - // of it's actual offset, let's try imparting a velocity which is at a fixed radius - // from the palm. - - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var now = Date.now(); - - var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - - this.currentHandControllerTipPosition = handControllerPosition; - this.currentObjectTime = now; - Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); - - if (this.state === STATE_CONTINUE_EQUIP_BD) { - Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); - } - - if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { - // if less than a 5 seconds left, refresh the actions ttl - Entities.updateAction(this.grabbedEntity, this.actionID, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, - ignoreIK: this.ignoreIK - }); - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - } - }; - - this.waitingForBumperRelease = function() { - if (this.bumperReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - Entities.callEntityMethod(this.grabbedEntity, "unequip"); - this.endHandGrasp(); - - } - }; - - this.pullTowardEquipPosition = function() { - - this.turnOffVisualizations(); - - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - // use a spring to pull the object to where it will be when equipped - var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - var targetRotation = Quat.multiply(handRotation, relativeRotation); - var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); - var targetPosition = Vec3.sum(handPosition, offset); - - if (typeof this.equipSpringID === 'undefined' || - this.equipSpringID === null || - this.equipSpringID === NULL_ACTION_ID) { - this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { - targetPosition: targetPosition, - linearTimeScale: EQUIP_SPRING_TIMEFRAME, - targetRotation: targetRotation, - angularTimeScale: EQUIP_SPRING_TIMEFRAME, - ttl: ACTION_TTL, - ignoreIK: ignoreIK - }); - if (this.equipSpringID === NULL_ACTION_ID) { - this.equipSpringID = null; - this.setState(STATE_OFF); - return; - } - } else { - Entities.updateAction(this.grabbedEntity, this.equipSpringID, { - targetPosition: targetPosition, - linearTimeScale: EQUIP_SPRING_TIMEFRAME, - targetRotation: targetRotation, - angularTimeScale: EQUIP_SPRING_TIMEFRAME, - ttl: ACTION_TTL, - ignoreIK: ignoreIK - }); - } - - if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { - Entities.deleteAction(this.grabbedEntity, this.equipSpringID); - this.equipSpringID = null; - this.setState(STATE_EQUIP); - } - }; - - this.nearTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); - this.setState(STATE_CONTINUE_NEAR_TRIGGER); - }; - - this.farTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); - return; - } - - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); - this.setState(STATE_CONTINUE_FAR_TRIGGER); - }; - - this.continueNearTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - - Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); - }; - - this.continueFarTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - - var handPosition = this.getHandPosition(); - var pickRay = { - origin: handPosition, - direction: Quat.getUp(this.getHandRotation()) - }; - - var now = Date.now(); - if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - var intersection = Entities.findRayIntersection(pickRay, true); - this.lastPickTime = now; - if (intersection.entityID != this.grabbedEntity) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); - return; - } - } - - if (USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - } - - Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); - }; - - _this.allTouchedIDs = {}; - - this.touchTest = function() { - var maxDistance = 0.05; - var leftHandPosition = MyAvatar.getLeftPalmPosition(); - var rightHandPosition = MyAvatar.getRightPalmPosition(); - var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); - var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); - var ids = []; - - if (leftEntities.length !== 0) { - leftEntities.forEach(function(entity) { - ids.push(entity); - }); - - } - - if (rightEntities.length !== 0) { - rightEntities.forEach(function(entity) { - ids.push(entity); - }); - } - - ids.forEach(function(id) { - - var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); - if (props.name === 'pointer') { - return; - } else { - var entityMinPoint = props.boundingBox.brn; - var entityMaxPoint = props.boundingBox.tfl; - var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); - var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); - - if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { - // we haven't been touched before, but either right or left is touching us now - _this.allTouchedIDs[id] = true; - _this.startTouch(id); - } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { - // we have been touched before and are still being touched - // continue touch - _this.continueTouch(id); - } else if (_this.allTouchedIDs[id]) { - delete _this.allTouchedIDs[id]; - _this.stopTouch(id); - - } else { - //we are in another state - return; - } - } - - }); - - }; - - this.startTouch = function(entityID) { - Entities.callEntityMethod(entityID, "startTouch"); - }; - - this.continueTouch = function(entityID) { - Entities.callEntityMethod(entityID, "continueTouch"); - }; - - this.stopTouch = function(entityID) { - Entities.callEntityMethod(entityID, "stopTouch"); - }; - - this.release = function() { - - this.turnLightsOff(); - this.turnOffVisualizations(); - - if (this.grabbedEntity !== null) { - if (this.actionID !== null) { - Entities.deleteAction(this.grabbedEntity, this.actionID); - } - } - - this.deactivateEntity(this.grabbedEntity); - - this.grabbedEntity = null; - this.actionID = null; - this.setState(STATE_OFF); - }; - - this.cleanup = function() { - this.release(); - this.endHandGrasp(); - Entities.deleteEntity(this.particleBeam); - Entities.deleteEntity(this.spotLight); - Entities.deleteEntity(this.pointLight); - }; - - this.activateEntity = function(entityID, grabbedProperties) { - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); - var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; - var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); - data["activated"] = true; - data["avatarId"] = MyAvatar.sessionUUID; - data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; - // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done - if (data["refCount"] == 1) { - data["gravity"] = grabbedProperties.gravity; - data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; - data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; - var whileHeldProperties = { - gravity: { - x: 0, - y: 0, - z: 0 - } - }; - if (invertSolidWhileHeld) { - whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; - } - Entities.editEntity(entityID, whileHeldProperties); - } - - setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); - return data; - }; - - this.deactivateEntity = function(entityID) { - var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); - if (data && data["refCount"]) { - data["refCount"] = data["refCount"] - 1; - if (data["refCount"] < 1) { - Entities.editEntity(entityID, { - gravity: data["gravity"], - ignoreForCollisions: data["ignoreForCollisions"], - collisionsWillMove: data["collisionsWillMove"] - }); - data = null; - } - } else { - data = null; - } - setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); - }; - - - //this is our handler, where we do the actual work of changing animation settings - this.graspHand = function(animationProperties) { - var result = {}; - //full alpha on overlay for this hand - //set grab to true - //set idle to false - //full alpha on the blend btw open and grab - if (_this.hand === RIGHT_HAND) { - result['rightHandOverlayAlpha'] = 1.0; - result['isRightHandGrab'] = true; - result['isRightHandIdle'] = false; - result['rightHandGrabBlend'] = 1.0; - } else if (_this.hand === LEFT_HAND) { - result['leftHandOverlayAlpha'] = 1.0; - result['isLeftHandGrab'] = true; - result['isLeftHandIdle'] = false; - result['leftHandGrabBlend'] = 1.0; - } - //return an object with our updated settings - return result; - }; - - this.graspHandler = null - - this.startHandGrasp = function() { - if (this.hand === RIGHT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); - } else if (this.hand === LEFT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); - } - }; - - this.endHandGrasp = function() { - // Tell the animation system we don't need any more callbacks. - MyAvatar.removeAnimationStateHandler(this.graspHandler); - }; - -}; - -var rightController = new MyController(RIGHT_HAND); -var leftController = new MyController(LEFT_HAND); - -//preload the particle beams so that they are full length when you start searching -if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { - rightController.createParticleBeam(); - leftController.createParticleBeam(); -} - -var MAPPING_NAME = "com.highfidelity.handControllerGrab"; - -var mapping = Controller.newMapping(MAPPING_NAME); -mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); -mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); - -mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); -mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); - -Controller.enableMapping(MAPPING_NAME); - -//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items -var handToDisable = 'none'; - -function update() { - if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { - leftController.update(); - } - if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { - rightController.update(); - } -} - -Messages.subscribe('Hifi-Hand-Disabler'); - -handleHandDisablerMessages = function(channel, message, sender) { - - if (sender === MyAvatar.sessionUUID) { - if (message === 'left') { - handToDisable = LEFT_HAND; - } - if (message === 'right') { - handToDisable = RIGHT_HAND; - } - if (message === 'both') { - handToDisable = 'both'; - } - if (message === 'none') { - handToDisable = 'none'; - } - } - -} - -Messages.messageReceived.connect(handleHandDisablerMessages); - -function cleanup() { - rightController.cleanup(); - leftController.cleanup(); - Controller.disableMapping(MAPPING_NAME); -} - -Script.scriptEnding.connect(cleanup); -Script.update.connect(update); \ No newline at end of file diff --git a/examples/controllers/handControllerGrab-particles.js b/examples/controllers/handControllerGrab-particles.js deleted file mode 100644 index bfe51927d0..0000000000 --- a/examples/controllers/handControllerGrab-particles.js +++ /dev/null @@ -1,1656 +0,0 @@ -// handControllerGrab.js -// -// Created by Eric Levin on 9/2/15 -// Additions by James B. Pollack @imgntn on 9/24/2015 -// Additions By Seth Alves on 10/20/2015 -// Copyright 2015 High Fidelity, Inc. -// -// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. -// Also supports touch and equipping objects. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ - -Script.include("../libraries/utils.js"); - -// -// add lines where the hand ray picking is happening -// -var WANT_DEBUG = false; - -// -// these tune time-averaging and "on" value for analog trigger -// - -var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value -var TRIGGER_ON_VALUE = 0.4; -var TRIGGER_OFF_VALUE = 0.15; - -var BUMPER_ON_VALUE = 0.5; - -// -// distant manipulation -// - -var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object -var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position -var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did -var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects - -var NO_INTERSECT_COLOR = { - red: 10, - green: 10, - blue: 255 -}; // line color when pick misses -var INTERSECT_COLOR = { - red: 250, - green: 10, - blue: 10 -}; // line color when pick hits -var LINE_ENTITY_DIMENSIONS = { - x: 1000, - y: 1000, - z: 1000 -}; - -var LINE_LENGTH = 500; -var PICK_MAX_DISTANCE = 500; // max length of pick-ray - -// -// near grabbing -// - -var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected -var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position -var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. -var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected -var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things -var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object -var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed - -// -// equip -// - -var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; -var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position - -// -// other constants -// - -var RIGHT_HAND = 1; -var LEFT_HAND = 0; - -var ZERO_VEC = { - x: 0, - y: 0, - z: 0 -}; - -var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; -var MSEC_PER_SEC = 1000.0; - -// these control how long an abandoned pointer line or action will hang around -var LIFETIME = 10; -var ACTION_TTL = 15; // seconds -var ACTION_TTL_REFRESH = 5; -var PICKS_PER_SECOND_PER_HAND = 5; -var MSECS_PER_SEC = 1000.0; -var GRABBABLE_PROPERTIES = [ - "position", - "rotation", - "gravity", - "ignoreForCollisions", - "collisionsWillMove", - "locked", - "name" -]; - -var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js -var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js - -var DEFAULT_GRABBABLE_DATA = { - grabbable: true, - invertSolidWhileHeld: false -}; - -//we've created various ways of visualizing looking for and moving distant objects -var USE_ENTITY_LINES_FOR_SEARCHING = false; -var USE_OVERLAY_LINES_FOR_SEARCHING = false; -var USE_PARTICLE_BEAM_FOR_SEARCHING = true; - -var USE_ENTITY_LINES_FOR_MOVING = false; -var USE_OVERLAY_LINES_FOR_MOVING = false; -var USE_PARTICLE_BEAM_FOR_MOVING = true; - -var USE_SPOTLIGHT = false; -var USE_POINTLIGHT = false; - -// states for the state machine -var STATE_OFF = 0; -var STATE_SEARCHING = 1; -var STATE_DISTANCE_HOLDING = 2; -var STATE_CONTINUE_DISTANCE_HOLDING = 3; -var STATE_NEAR_GRABBING = 4; -var STATE_CONTINUE_NEAR_GRABBING = 5; -var STATE_NEAR_TRIGGER = 6; -var STATE_CONTINUE_NEAR_TRIGGER = 7; -var STATE_FAR_TRIGGER = 8; -var STATE_CONTINUE_FAR_TRIGGER = 9; -var STATE_RELEASE = 10; -var STATE_EQUIP_SEARCHING = 11; -var STATE_EQUIP = 12 -var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down -var STATE_CONTINUE_EQUIP = 14; -var STATE_WAITING_FOR_BUMPER_RELEASE = 15; -var STATE_EQUIP_SPRING = 16; - - - -function stateToName(state) { - switch (state) { - case STATE_OFF: - return "off"; - case STATE_SEARCHING: - return "searching"; - case STATE_DISTANCE_HOLDING: - return "distance_holding"; - case STATE_CONTINUE_DISTANCE_HOLDING: - return "continue_distance_holding"; - case STATE_NEAR_GRABBING: - return "near_grabbing"; - case STATE_CONTINUE_NEAR_GRABBING: - return "continue_near_grabbing"; - case STATE_NEAR_TRIGGER: - return "near_trigger"; - case STATE_CONTINUE_NEAR_TRIGGER: - return "continue_near_trigger"; - case STATE_FAR_TRIGGER: - return "far_trigger"; - case STATE_CONTINUE_FAR_TRIGGER: - return "continue_far_trigger"; - case STATE_RELEASE: - return "release"; - case STATE_EQUIP_SEARCHING: - return "equip_searching"; - case STATE_EQUIP: - return "equip"; - case STATE_CONTINUE_EQUIP_BD: - return "continue_equip_bd"; - case STATE_CONTINUE_EQUIP: - return "continue_equip"; - case STATE_WAITING_FOR_BUMPER_RELEASE: - return "waiting_for_bumper_release"; - case STATE_EQUIP_SPRING: - return "state_equip_spring"; - } - - return "unknown"; -} - -function getTag() { - return "grab-" + MyAvatar.sessionUUID; -} - -function entityIsGrabbedByOther(entityID) { - // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. - var actionIDs = Entities.getActionIDs(entityID); - for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { - var actionID = actionIDs[actionIndex]; - var actionArguments = Entities.getActionArguments(entityID, actionID); - var tag = actionArguments["tag"]; - if (tag == getTag()) { - // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. - continue; - } - if (tag.slice(0, 5) == "grab-") { - // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. - return true; - } - } - return false; -} - -function getSpatialOffsetPosition(hand, spatialKey) { - var position = Vec3.ZERO; - - if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { - position = spatialKey.leftRelativePosition; - } - if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { - position = spatialKey.rightRelativePosition; - } - if (spatialKey.relativePosition) { - position = spatialKey.relativePosition; - } - - return position; -} - -var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); - -function getSpatialOffsetRotation(hand, spatialKey) { - var rotation = Quat.IDENTITY; - - if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { - rotation = spatialKey.leftRelativeRotation; - } - if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { - rotation = spatialKey.rightRelativeRotation; - } - if (spatialKey.relativeRotation) { - rotation = spatialKey.relativeRotation; - } - - // Flip left hand - if (hand !== RIGHT_HAND) { - rotation = Quat.multiply(yFlip, rotation); - } - - return rotation; -} - -function MyController(hand) { - this.hand = hand; - if (this.hand === RIGHT_HAND) { - this.getHandPosition = MyAvatar.getRightPalmPosition; - this.getHandRotation = MyAvatar.getRightPalmRotation; - } else { - this.getHandPosition = MyAvatar.getLeftPalmPosition; - this.getHandRotation = MyAvatar.getLeftPalmRotation; - } - - var SPATIAL_CONTROLLERS_PER_PALM = 2; - var TIP_CONTROLLER_OFFSET = 1; - this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; - this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; - - this.actionID = null; // action this script created... - this.grabbedEntity = null; // on this entity. - this.state = STATE_OFF; - this.pointer = null; // entity-id of line object - this.triggerValue = 0; // rolling average of trigger value - this.rawTriggerValue = 0; - this.rawBumperValue = 0; - - //for visualizations - this.overlayLine = null; - this.particleBeam = null; - - //for lights - this.spotlight = null; - this.pointlight = null; - - this.ignoreIK = false; - this.offsetPosition = Vec3.ZERO; - this.offsetRotation = Quat.IDENTITY; - - var _this = this; - - this.update = function() { - - this.updateSmoothedTrigger(); - - switch (this.state) { - case STATE_OFF: - this.off(); - this.touchTest(); - break; - case STATE_SEARCHING: - this.search(); - break; - case STATE_EQUIP_SEARCHING: - this.search(); - break; - case STATE_DISTANCE_HOLDING: - this.distanceHolding(); - break; - case STATE_CONTINUE_DISTANCE_HOLDING: - this.continueDistanceHolding(); - break; - case STATE_NEAR_GRABBING: - case STATE_EQUIP: - this.nearGrabbing(); - break; - case STATE_WAITING_FOR_BUMPER_RELEASE: - this.waitingForBumperRelease(); - break; - case STATE_EQUIP_SPRING: - this.pullTowardEquipPosition() - break; - case STATE_CONTINUE_NEAR_GRABBING: - case STATE_CONTINUE_EQUIP_BD: - case STATE_CONTINUE_EQUIP: - this.continueNearGrabbing(); - break; - case STATE_NEAR_TRIGGER: - this.nearTrigger(); - break; - case STATE_CONTINUE_NEAR_TRIGGER: - this.continueNearTrigger(); - break; - case STATE_FAR_TRIGGER: - this.farTrigger(); - break; - case STATE_CONTINUE_FAR_TRIGGER: - this.continueFarTrigger(); - break; - case STATE_RELEASE: - this.release(); - break; - } - }; - - this.setState = function(newState) { - if (WANT_DEBUG) { - print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); - } - this.state = newState; - }; - - this.debugLine = function(closePoint, farPoint, color) { - Entities.addEntity({ - type: "Line", - name: "Grab Debug Entity", - dimensions: LINE_ENTITY_DIMENSIONS, - visible: true, - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: 0.1, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - }; - - this.lineOn = function(closePoint, farPoint, color) { - // draw a line - if (this.pointer === null) { - this.pointer = Entities.addEntity({ - type: "Line", - name: "grab pointer", - dimensions: LINE_ENTITY_DIMENSIONS, - visible: true, - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: LIFETIME, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - } else { - var age = Entities.getEntityProperties(this.pointer, "age").age; - this.pointer = Entities.editEntity(this.pointer, { - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: age + LIFETIME - }); - } - }; - - this.overlayLineOn = function(closePoint, farPoint, color) { - if (this.overlayLine === null) { - var lineProperties = { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - ignoreRayIntersection: true, // always ignore this - visible: true, - alpha: 1 - }; - - this.overlayLine = Overlays.addOverlay("line3d", lineProperties); - - } else { - var success = Overlays.editOverlay(this.overlayLine, { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - visible: true, - ignoreRayIntersection: true, // always ignore this - alpha: 1 - }); - } - }; - - this.handleParticleBeam = function(position, orientation, color) { - - var rotation = Quat.angleAxis(0, { - x: 1, - y: 0, - z: 0 - }); - - var finalRotation = Quat.multiply(orientation, rotation); - var lifespan = LINE_LENGTH / 10; - var speed = 5; - var spread = 2; - if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); - } else { - this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); - } - }; - - this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { - - var handToObject = Vec3.subtract(objectPosition, handPosition); - var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); - - var distance = Vec3.distance(handPosition, objectPosition); - var speed = 5; - var spread = 0; - - var lifespan = distance / speed; - - - if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); - } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); - } - }; - - this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { - - var particleBeamProperties = { - type: "ParticleEffect", - isEmitting: true, - position: position, - visible: false, - "name": "Particle Beam", - "color": color, - "maxParticles": 2000, - "lifespan": lifespan, - "emitRate": 50, - "emitSpeed": speed, - "speedSpread": spread, - "emitOrientation": { - "x": -1, - "y": 0, - "z": 0, - "w": 1 - }, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "emitRadiusStart": 0.5, - "polarStart": 0, - "polarFinish": 0, - "azimuthStart": -3.1415927410125732, - "azimuthFinish": 3.1415927410125732, - "emitAcceleration": { - x: 0, - y: 0, - z: 0 - }, - "accelerationSpread": { - "x": 0, - "y": 0, - "z": 0 - }, - "particleRadius": 0.01, - "radiusSpread": 0, - // "radiusStart": 0.01, - // "radiusFinish": 0.01, - // "colorSpread": { - // "red": 0, - // "green": 0, - // "blue": 0 - // }, - // "colorStart": color, - // "colorFinish": color, - "alpha": 1, - "alphaSpread": 0, - "alphaStart": 1, - "alphaFinish": 1, - "additiveBlending": 0, - "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" - } - - this.particleBeam = Entities.addEntity(particleBeamProperties); - }; - - this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { - print('lifespan::' + lifespan); - Entities.editEntity(this.particleBeam, { - rotation: orientation, - position: position, - visible: true, - color: color, - emitSpeed: speed, - speedSpread:spread, - lifespan: lifespan - - }) - - }; - - this.evalLightWorldTransform = function(modelPos, modelRot) { - - var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 - }; - - var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 - }); - - return { - p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), - q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) - }; - }; - - this.handleSpotlight = function(parentID, position) { - var LIFETIME = 100; - - var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); - - var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - var lightProperties = { - type: "Light", - isSpotlight: true, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - parentID: parentID, - color: { - red: 255, - green: 255, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: LIFETIME, - position: lightTransform.p, - }; - - if (this.spotlight === null) { - this.spotlight = Entities.addEntity(lightProperties); - } else { - Entities.editEntity(this.spotlight, { - //without this, this light would maintain rotation with its parent - rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), - }) - } - }; - - this.handlePointLight = function(parentID, position) { - var LIFETIME = 100; - - var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); - var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - - var lightProperties = { - type: "Light", - isSpotlight: false, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - parentID: parentID, - color: { - red: 255, - green: 255, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: LIFETIME, - position: lightTransform.p, - }; - - if (this.pointlight === null) { - this.pointlight = Entities.addEntity(lightProperties); - } else { - - } - }; - - this.lineOff = function() { - if (this.pointer !== null) { - Entities.deleteEntity(this.pointer); - } - this.pointer = null; - }; - - this.overlayLineOff = function() { - if (this.overlayLine !== null) { - Overlays.deleteOverlay(this.overlayLine); - } - this.overlayLine = null; - }; - - this.particleBeamOff = function() { - if (this.particleBeam !== null) { - Entities.editEntity(this.particleBeam, { - visible: false - }) - } - } - - this.turnLightsOff = function() { - if (this.spotlight !== null) { - Entities.deleteEntity(this.spotlight); - this.spotlight = null; - } - - if (this.pointlight !== null) { - Entities.deleteEntity(this.pointlight); - this.pointlight = null; - } - }; - - - this.turnOffVisualizations = function() { - if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOff(); - } - - if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { - this.overlayLineOff(); - } - - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.particleBeamOff(); - } - }; - - this.triggerPress = function(value) { - _this.rawTriggerValue = value; - }; - - this.bumperPress = function(value) { - _this.rawBumperValue = value; - }; - - this.updateSmoothedTrigger = function() { - var triggerValue = this.rawTriggerValue; - // smooth out trigger value - this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + - (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); - }; - - this.triggerSmoothedSqueezed = function() { - return this.triggerValue > TRIGGER_ON_VALUE; - }; - - this.triggerSmoothedReleased = function() { - return this.triggerValue < TRIGGER_OFF_VALUE; - }; - - this.triggerSqueezed = function() { - var triggerValue = this.rawTriggerValue; - return triggerValue > TRIGGER_ON_VALUE; - }; - - this.bumperSqueezed = function() { - return _this.rawBumperValue > BUMPER_ON_VALUE; - }; - - this.bumperReleased = function() { - return _this.rawBumperValue < BUMPER_ON_VALUE; - }; - - this.off = function() { - if (this.triggerSmoothedSqueezed()) { - this.lastPickTime = 0; - this.setState(STATE_SEARCHING); - return; - } - if (this.bumperSqueezed()) { - this.lastPickTime = 0; - this.setState(STATE_EQUIP_SEARCHING); - return; - } - }; - - this.search = function() { - this.grabbedEntity = null; - - if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { - this.setState(STATE_RELEASE); - return; - } - - // the trigger is being pressed, do a ray test - var handPosition = this.getHandPosition(); - var distantPickRay = { - origin: handPosition, - direction: Quat.getUp(this.getHandRotation()), - length: PICK_MAX_DISTANCE - }; - - // don't pick 60x per second. - var pickRays = []; - var now = Date.now(); - if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - pickRays = [distantPickRay]; - this.lastPickTime = now; - } - - for (var index = 0; index < pickRays.length; ++index) { - var pickRay = pickRays[index]; - var directionNormalized = Vec3.normalize(pickRay.direction); - var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); - var pickRayBacked = { - origin: Vec3.subtract(pickRay.origin, directionBacked), - direction: pickRay.direction - }; - - if (WANT_DEBUG) { - this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { - red: 0, - green: 255, - blue: 0 - }) - } - - var intersection = Entities.findRayIntersection(pickRayBacked, true); - - if (intersection.intersects) { - // the ray is intersecting something we can move. - var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); - - if (intersection.properties.name == "Grab Debug Entity") { - continue; - } - - if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { - continue; - } - if (intersectionDistance > pickRay.length) { - // too far away for this ray. - continue; - } - if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { - // the hand is very close to the intersected object. go into close-grabbing mode. - if (grabbableData.wantsTrigger) { - this.grabbedEntity = intersection.entityID; - this.setState(STATE_NEAR_TRIGGER); - return; - } else if (!intersection.properties.locked) { - this.grabbedEntity = intersection.entityID; - if (this.state == STATE_SEARCHING) { - this.setState(STATE_NEAR_GRABBING); - } else { // equipping - if (typeof grabbableData.spatialKey !== 'undefined') { - // TODO - // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch - // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. - // this.setState(STATE_EQUIP_SPRING); - this.setState(STATE_EQUIP); - } else { - this.setState(STATE_EQUIP); - } - } - return; - } - } else if (!entityIsGrabbedByOther(intersection.entityID)) { - // don't allow two people to distance grab the same object - if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { - // the hand is far from the intersected object. go into distance-holding mode - this.grabbedEntity = intersection.entityID; - if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { - // if a distance pick in equip mode hits something with a spatialKey, equip it - // TODO use STATE_EQUIP_SPRING here once it works right. - // this.setState(STATE_EQUIP_SPRING); - this.setState(STATE_EQUIP); - return; - } else if (this.state == STATE_SEARCHING) { - this.setState(STATE_DISTANCE_HOLDING); - return; - } - } else if (grabbableData.wantsTrigger) { - this.grabbedEntity = intersection.entityID; - this.setState(STATE_FAR_TRIGGER); - return; - } - } - } - } - - // forward ray test failed, try sphere test. - if (WANT_DEBUG) { - Entities.addEntity({ - type: "Sphere", - name: "Grab Debug Entity", - dimensions: { - x: GRAB_RADIUS, - y: GRAB_RADIUS, - z: GRAB_RADIUS - }, - visible: true, - position: handPosition, - color: { - red: 0, - green: 255, - blue: 0 - }, - lifetime: 0.1, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - } - - var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); - var minDistance = PICK_MAX_DISTANCE; - var i, props, distance, grabbableData; - this.grabbedEntity = null; - for (i = 0; i < nearbyEntities.length; i++) { - var grabbableDataForCandidate = - getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); - if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { - continue; - } - var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); - - if (propsForCandidate.type == 'Unknown') { - continue; - } - - if (propsForCandidate.type == 'Light') { - continue; - } - - if (propsForCandidate.type == 'ParticleEffect') { - continue; - } - - if (propsForCandidate.type == 'PolyLine') { - continue; - } - - if (propsForCandidate.type == 'Zone') { - continue; - } - - if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { - continue; - } - - if (propsForCandidate.name == "Grab Debug Entity") { - continue; - } - - if (propsForCandidate.name == "grab pointer") { - continue; - } - - distance = Vec3.distance(propsForCandidate.position, handPosition); - if (distance < minDistance) { - this.grabbedEntity = nearbyEntities[i]; - minDistance = distance; - props = propsForCandidate; - grabbableData = grabbableDataForCandidate; - } - } - if (this.grabbedEntity !== null) { - if (grabbableData.wantsTrigger) { - this.setState(STATE_NEAR_TRIGGER); - return; - } else if (!props.locked && props.collisionsWillMove) { - this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) - return; - } - } - - //search line visualizations - if (USE_ENTITY_LINES_FOR_SEARCHING === true) { - this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - } - - if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); - } - - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { - this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); - } - - }; - - this.distanceHolding = function() { - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var now = Date.now(); - - // add the action and initialize some variables - this.currentObjectPosition = grabbedProperties.position; - this.currentObjectRotation = grabbedProperties.rotation; - this.currentObjectTime = now; - this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); - this.handPreviousRotation = handRotation; - this.currentCameraOrientation = Camera.orientation; - - // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object - this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); - if (this.radiusScalar < 1.0) { - this.radiusScalar = 1.0; - } - - this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("spring", this.grabbedEntity, { - targetPosition: this.currentObjectPosition, - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - tag: getTag(), - ttl: ACTION_TTL - }); - if (this.actionID === NULL_ACTION_ID) { - this.actionID = null; - } - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - - if (this.actionID !== null) { - this.setState(STATE_CONTINUE_DISTANCE_HOLDING); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); - } - - this.currentAvatarPosition = MyAvatar.position; - this.currentAvatarOrientation = MyAvatar.orientation; - - this.turnOffVisualizations(); - }; - - this.continueDistanceHolding = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - - var handPosition = this.getHandPosition(); - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && - typeof grabbableData.spatialKey !== 'undefined') { - var saveGrabbedID = this.grabbedEntity; - this.release(); - this.setState(STATE_EQUIP); - this.grabbedEntity = saveGrabbedID; - return; - } - - - // the action was set up on a previous call. update the targets. - var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * - this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; - if (radius < 1.0) { - radius = 1.0; - } - - // how far did avatar move this timestep? - var currentPosition = MyAvatar.position; - var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); - this.currentAvatarPosition = currentPosition; - - // How far did the avatar turn this timestep? - // Note: The following code is too long because we need a Quat.quatBetween() function - // that returns the minimum quaternion between two quaternions. - var currentOrientation = MyAvatar.orientation; - if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) { - var negativeCurrentOrientation = { - x: -currentOrientation.x, - y: -currentOrientation.y, - z: -currentOrientation.z, - w: -currentOrientation.w - }; - var avatarDeltaOrientation = Quat.multiply(negativeCurrentOrientation, Quat.inverse(this.currentAvatarOrientation)); - } else { - var avatarDeltaOrientation = Quat.multiply(currentOrientation, Quat.inverse(this.currentAvatarOrientation)); - } - var handToAvatar = Vec3.subtract(handControllerPosition, this.currentAvatarPosition); - var objectToAvatar = Vec3.subtract(this.currentObjectPosition, this.currentAvatarPosition); - var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar); - var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar); - this.currentAvatarOrientation = currentOrientation; - - // how far did hand move this timestep? - var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); - this.handRelativePreviousPosition = handToAvatar; - - // magnify the hand movement but not the change from avatar movement & rotation - handMoved = Vec3.subtract(handMoved, handMovementFromTurning); - var superHandMoved = Vec3.multiply(handMoved, radius); - - // Move the object by the magnified amount and then by amount from avatar movement & rotation - var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); - newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); - newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); - - var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters - var now = Date.now(); - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - - this.currentObjectPosition = newObjectPosition; - this.currentObjectTime = now; - - // this doubles hand rotation - var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, - handRotation, - DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), - Quat.inverse(this.handPreviousRotation)); - this.handPreviousRotation = handRotation; - this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); - - Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); - - // mix in head motion - if (MOVE_WITH_HEAD) { - var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var after = Vec3.multiplyQbyV(Camera.orientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var change = Vec3.subtract(before, after); - this.currentCameraOrientation = Camera.orientation; - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); - } - - - //visualizations - if (USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); - } - if (USE_OVERLAY_LINES_FOR_MOVING === true) { - this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); - } - if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) - // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) - } - if (USE_POINTLIGHT === true) { - this.handlePointLight(this.grabbedEntity); - } - if (USE_SPOTLIGHT === true) { - this.handleSpotlight(this.grabbedEntity); - } - - Entities.updateAction(this.grabbedEntity, this.actionID, { - targetPosition: this.currentObjectPosition, - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - ttl: ACTION_TTL - }); - - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - }; - - this.nearGrabbing = function() { - var now = Date.now(); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - - this.turnOffVisualizations(); - - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { - Entities.editEntity(this.grabbedEntity, { - collisionsWillMove: false - }); - } - - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { - // if an object is "equipped" and has a spatialKey, use it. - this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - } else { - this.ignoreIK = false; - - var objectRotation = grabbedProperties.rotation; - this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var currentObjectPosition = grabbedProperties.position; - var offset = Vec3.subtract(currentObjectPosition, handPosition); - this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); - } - - this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("hold", this.grabbedEntity, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, - ignoreIK: this.ignoreIK - }); - if (this.actionID === NULL_ACTION_ID) { - this.actionID = null; - } else { - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - if (this.state == STATE_NEAR_GRABBING) { - this.setState(STATE_CONTINUE_NEAR_GRABBING); - } else { - // equipping - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - this.startHandGrasp(); - - this.setState(STATE_CONTINUE_EQUIP_BD); - } - - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); - - } - - this.currentHandControllerTipPosition = - (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; - - this.currentObjectTime = Date.now(); - }; - - this.continueNearGrabbing = function() { - if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { - this.setState(STATE_CONTINUE_EQUIP); - return; - } - if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { - this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); - return; - } - if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { - this.setState(STATE_CONTINUE_EQUIP_BD); - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - return; - } - - // Keep track of the fingertip velocity to impart when we release the object. - // Note that the idea of using a constant 'tip' velocity regardless of the - // object's actual held offset is an idea intended to make it easier to throw things: - // Because we might catch something or transfer it between hands without a good idea - // of it's actual offset, let's try imparting a velocity which is at a fixed radius - // from the palm. - - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var now = Date.now(); - - var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - - this.currentHandControllerTipPosition = handControllerPosition; - this.currentObjectTime = now; - Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); - - if (this.state === STATE_CONTINUE_EQUIP_BD) { - Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); - } - - if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { - // if less than a 5 seconds left, refresh the actions ttl - Entities.updateAction(this.grabbedEntity, this.actionID, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, - ignoreIK: this.ignoreIK - }); - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - } - }; - - this.waitingForBumperRelease = function() { - if (this.bumperReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - Entities.callEntityMethod(this.grabbedEntity, "unequip"); - this.endHandGrasp(); - - } - }; - - this.pullTowardEquipPosition = function() { - - this.turnOffVisualizations(); - - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - // use a spring to pull the object to where it will be when equipped - var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - var targetRotation = Quat.multiply(handRotation, relativeRotation); - var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); - var targetPosition = Vec3.sum(handPosition, offset); - - if (typeof this.equipSpringID === 'undefined' || - this.equipSpringID === null || - this.equipSpringID === NULL_ACTION_ID) { - this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { - targetPosition: targetPosition, - linearTimeScale: EQUIP_SPRING_TIMEFRAME, - targetRotation: targetRotation, - angularTimeScale: EQUIP_SPRING_TIMEFRAME, - ttl: ACTION_TTL, - ignoreIK: ignoreIK - }); - if (this.equipSpringID === NULL_ACTION_ID) { - this.equipSpringID = null; - this.setState(STATE_OFF); - return; - } - } else { - Entities.updateAction(this.grabbedEntity, this.equipSpringID, { - targetPosition: targetPosition, - linearTimeScale: EQUIP_SPRING_TIMEFRAME, - targetRotation: targetRotation, - angularTimeScale: EQUIP_SPRING_TIMEFRAME, - ttl: ACTION_TTL, - ignoreIK: ignoreIK - }); - } - - if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { - Entities.deleteAction(this.grabbedEntity, this.equipSpringID); - this.equipSpringID = null; - this.setState(STATE_EQUIP); - } - }; - - this.nearTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); - this.setState(STATE_CONTINUE_NEAR_TRIGGER); - }; - - this.farTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); - return; - } - - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); - this.setState(STATE_CONTINUE_FAR_TRIGGER); - }; - - this.continueNearTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - - Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); - }; - - this.continueFarTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - - var handPosition = this.getHandPosition(); - var pickRay = { - origin: handPosition, - direction: Quat.getUp(this.getHandRotation()) - }; - - var now = Date.now(); - if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - var intersection = Entities.findRayIntersection(pickRay, true); - this.lastPickTime = now; - if (intersection.entityID != this.grabbedEntity) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); - return; - } - } - - if (USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - } - - Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); - }; - - _this.allTouchedIDs = {}; - - this.touchTest = function() { - var maxDistance = 0.05; - var leftHandPosition = MyAvatar.getLeftPalmPosition(); - var rightHandPosition = MyAvatar.getRightPalmPosition(); - var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); - var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); - var ids = []; - - if (leftEntities.length !== 0) { - leftEntities.forEach(function(entity) { - ids.push(entity); - }); - - } - - if (rightEntities.length !== 0) { - rightEntities.forEach(function(entity) { - ids.push(entity); - }); - } - - ids.forEach(function(id) { - - var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); - if (props.name === 'pointer') { - return; - } else { - var entityMinPoint = props.boundingBox.brn; - var entityMaxPoint = props.boundingBox.tfl; - var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); - var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); - - if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { - // we haven't been touched before, but either right or left is touching us now - _this.allTouchedIDs[id] = true; - _this.startTouch(id); - } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { - // we have been touched before and are still being touched - // continue touch - _this.continueTouch(id); - } else if (_this.allTouchedIDs[id]) { - delete _this.allTouchedIDs[id]; - _this.stopTouch(id); - - } else { - //we are in another state - return; - } - } - - }); - - }; - - this.startTouch = function(entityID) { - Entities.callEntityMethod(entityID, "startTouch"); - }; - - this.continueTouch = function(entityID) { - Entities.callEntityMethod(entityID, "continueTouch"); - }; - - this.stopTouch = function(entityID) { - Entities.callEntityMethod(entityID, "stopTouch"); - }; - - this.release = function() { - - this.turnLightsOff(); - this.turnOffVisualizations(); - - if (this.grabbedEntity !== null) { - if (this.actionID !== null) { - Entities.deleteAction(this.grabbedEntity, this.actionID); - } - } - - this.deactivateEntity(this.grabbedEntity); - - this.grabbedEntity = null; - this.actionID = null; - this.setState(STATE_OFF); - }; - - this.cleanup = function() { - this.release(); - this.endHandGrasp(); - Entities.deleteEntity(this.particleBeam); - Entities.deleteEntity(this.spotLight); - Entities.deleteEntity(this.pointLight); - }; - - this.activateEntity = function(entityID, grabbedProperties) { - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); - var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; - var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); - data["activated"] = true; - data["avatarId"] = MyAvatar.sessionUUID; - data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; - // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done - if (data["refCount"] == 1) { - data["gravity"] = grabbedProperties.gravity; - data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; - data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; - var whileHeldProperties = { - gravity: { - x: 0, - y: 0, - z: 0 - } - }; - if (invertSolidWhileHeld) { - whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; - } - Entities.editEntity(entityID, whileHeldProperties); - } - - setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); - return data; - }; - - this.deactivateEntity = function(entityID) { - var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); - if (data && data["refCount"]) { - data["refCount"] = data["refCount"] - 1; - if (data["refCount"] < 1) { - Entities.editEntity(entityID, { - gravity: data["gravity"], - ignoreForCollisions: data["ignoreForCollisions"], - collisionsWillMove: data["collisionsWillMove"] - }); - data = null; - } - } else { - data = null; - } - setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); - }; - - - //this is our handler, where we do the actual work of changing animation settings - this.graspHand = function(animationProperties) { - var result = {}; - //full alpha on overlay for this hand - //set grab to true - //set idle to false - //full alpha on the blend btw open and grab - if (_this.hand === RIGHT_HAND) { - result['rightHandOverlayAlpha'] = 1.0; - result['isRightHandGrab'] = true; - result['isRightHandIdle'] = false; - result['rightHandGrabBlend'] = 1.0; - } else if (_this.hand === LEFT_HAND) { - result['leftHandOverlayAlpha'] = 1.0; - result['isLeftHandGrab'] = true; - result['isLeftHandIdle'] = false; - result['leftHandGrabBlend'] = 1.0; - } - //return an object with our updated settings - return result; - }; - - this.graspHandler = null - - this.startHandGrasp = function() { - if (this.hand === RIGHT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); - } else if (this.hand === LEFT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); - } - }; - - this.endHandGrasp = function() { - // Tell the animation system we don't need any more callbacks. - MyAvatar.removeAnimationStateHandler(this.graspHandler); - }; - -}; - -var rightController = new MyController(RIGHT_HAND); -var leftController = new MyController(LEFT_HAND); - -//preload the particle beams so that they are full length when you start searching -if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { - rightController.createParticleBeam(); - leftController.createParticleBeam(); -} - -var MAPPING_NAME = "com.highfidelity.handControllerGrab"; - -var mapping = Controller.newMapping(MAPPING_NAME); -mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); -mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); - -mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); -mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); - -Controller.enableMapping(MAPPING_NAME); - -//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items -var handToDisable = 'none'; - -function update() { - if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { - leftController.update(); - } - if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { - rightController.update(); - } -} - -Messages.subscribe('Hifi-Hand-Disabler'); - -handleHandDisablerMessages = function(channel, message, sender) { - - if (sender === MyAvatar.sessionUUID) { - if (message === 'left') { - handToDisable = LEFT_HAND; - } - if (message === 'right') { - handToDisable = RIGHT_HAND; - } - if (message === 'both') { - handToDisable = 'both'; - } - if (message === 'none') { - handToDisable = 'none'; - } - } - -} - -Messages.messageReceived.connect(handleHandDisablerMessages); - -function cleanup() { - rightController.cleanup(); - leftController.cleanup(); - Controller.disableMapping(MAPPING_NAME); -} - -Script.scriptEnding.connect(cleanup); -Script.update.connect(update); \ No newline at end of file diff --git a/examples/controllers/handControllerGrab-pointlight.js b/examples/controllers/handControllerGrab-pointlight.js deleted file mode 100644 index e7bb4e3e9f..0000000000 --- a/examples/controllers/handControllerGrab-pointlight.js +++ /dev/null @@ -1,1656 +0,0 @@ -// handControllerGrab.js -// -// Created by Eric Levin on 9/2/15 -// Additions by James B. Pollack @imgntn on 9/24/2015 -// Additions By Seth Alves on 10/20/2015 -// Copyright 2015 High Fidelity, Inc. -// -// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. -// Also supports touch and equipping objects. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ - -Script.include("../libraries/utils.js"); - -// -// add lines where the hand ray picking is happening -// -var WANT_DEBUG = false; - -// -// these tune time-averaging and "on" value for analog trigger -// - -var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value -var TRIGGER_ON_VALUE = 0.4; -var TRIGGER_OFF_VALUE = 0.15; - -var BUMPER_ON_VALUE = 0.5; - -// -// distant manipulation -// - -var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object -var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position -var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did -var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects - -var NO_INTERSECT_COLOR = { - red: 10, - green: 10, - blue: 255 -}; // line color when pick misses -var INTERSECT_COLOR = { - red: 250, - green: 10, - blue: 10 -}; // line color when pick hits -var LINE_ENTITY_DIMENSIONS = { - x: 1000, - y: 1000, - z: 1000 -}; - -var LINE_LENGTH = 500; -var PICK_MAX_DISTANCE = 500; // max length of pick-ray - -// -// near grabbing -// - -var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected -var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position -var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. -var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected -var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things -var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object -var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed - -// -// equip -// - -var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; -var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position - -// -// other constants -// - -var RIGHT_HAND = 1; -var LEFT_HAND = 0; - -var ZERO_VEC = { - x: 0, - y: 0, - z: 0 -}; - -var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; -var MSEC_PER_SEC = 1000.0; - -// these control how long an abandoned pointer line or action will hang around -var LIFETIME = 10; -var ACTION_TTL = 15; // seconds -var ACTION_TTL_REFRESH = 5; -var PICKS_PER_SECOND_PER_HAND = 5; -var MSECS_PER_SEC = 1000.0; -var GRABBABLE_PROPERTIES = [ - "position", - "rotation", - "gravity", - "ignoreForCollisions", - "collisionsWillMove", - "locked", - "name" -]; - -var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js -var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js - -var DEFAULT_GRABBABLE_DATA = { - grabbable: true, - invertSolidWhileHeld: false -}; - -//we've created various ways of visualizing looking for and moving distant objects -var USE_ENTITY_LINES_FOR_SEARCHING = false; -var USE_OVERLAY_LINES_FOR_SEARCHING = true; -var USE_PARTICLE_BEAM_FOR_SEARCHING = false; - -var USE_ENTITY_LINES_FOR_MOVING = true; -var USE_OVERLAY_LINES_FOR_MOVING = false; -var USE_PARTICLE_BEAM_FOR_MOVING = false; - -var USE_SPOTLIGHT = false; -var USE_POINTLIGHT = true; - -// states for the state machine -var STATE_OFF = 0; -var STATE_SEARCHING = 1; -var STATE_DISTANCE_HOLDING = 2; -var STATE_CONTINUE_DISTANCE_HOLDING = 3; -var STATE_NEAR_GRABBING = 4; -var STATE_CONTINUE_NEAR_GRABBING = 5; -var STATE_NEAR_TRIGGER = 6; -var STATE_CONTINUE_NEAR_TRIGGER = 7; -var STATE_FAR_TRIGGER = 8; -var STATE_CONTINUE_FAR_TRIGGER = 9; -var STATE_RELEASE = 10; -var STATE_EQUIP_SEARCHING = 11; -var STATE_EQUIP = 12 -var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down -var STATE_CONTINUE_EQUIP = 14; -var STATE_WAITING_FOR_BUMPER_RELEASE = 15; -var STATE_EQUIP_SPRING = 16; - - - -function stateToName(state) { - switch (state) { - case STATE_OFF: - return "off"; - case STATE_SEARCHING: - return "searching"; - case STATE_DISTANCE_HOLDING: - return "distance_holding"; - case STATE_CONTINUE_DISTANCE_HOLDING: - return "continue_distance_holding"; - case STATE_NEAR_GRABBING: - return "near_grabbing"; - case STATE_CONTINUE_NEAR_GRABBING: - return "continue_near_grabbing"; - case STATE_NEAR_TRIGGER: - return "near_trigger"; - case STATE_CONTINUE_NEAR_TRIGGER: - return "continue_near_trigger"; - case STATE_FAR_TRIGGER: - return "far_trigger"; - case STATE_CONTINUE_FAR_TRIGGER: - return "continue_far_trigger"; - case STATE_RELEASE: - return "release"; - case STATE_EQUIP_SEARCHING: - return "equip_searching"; - case STATE_EQUIP: - return "equip"; - case STATE_CONTINUE_EQUIP_BD: - return "continue_equip_bd"; - case STATE_CONTINUE_EQUIP: - return "continue_equip"; - case STATE_WAITING_FOR_BUMPER_RELEASE: - return "waiting_for_bumper_release"; - case STATE_EQUIP_SPRING: - return "state_equip_spring"; - } - - return "unknown"; -} - -function getTag() { - return "grab-" + MyAvatar.sessionUUID; -} - -function entityIsGrabbedByOther(entityID) { - // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. - var actionIDs = Entities.getActionIDs(entityID); - for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { - var actionID = actionIDs[actionIndex]; - var actionArguments = Entities.getActionArguments(entityID, actionID); - var tag = actionArguments["tag"]; - if (tag == getTag()) { - // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. - continue; - } - if (tag.slice(0, 5) == "grab-") { - // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. - return true; - } - } - return false; -} - -function getSpatialOffsetPosition(hand, spatialKey) { - var position = Vec3.ZERO; - - if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { - position = spatialKey.leftRelativePosition; - } - if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { - position = spatialKey.rightRelativePosition; - } - if (spatialKey.relativePosition) { - position = spatialKey.relativePosition; - } - - return position; -} - -var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); - -function getSpatialOffsetRotation(hand, spatialKey) { - var rotation = Quat.IDENTITY; - - if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { - rotation = spatialKey.leftRelativeRotation; - } - if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { - rotation = spatialKey.rightRelativeRotation; - } - if (spatialKey.relativeRotation) { - rotation = spatialKey.relativeRotation; - } - - // Flip left hand - if (hand !== RIGHT_HAND) { - rotation = Quat.multiply(yFlip, rotation); - } - - return rotation; -} - -function MyController(hand) { - this.hand = hand; - if (this.hand === RIGHT_HAND) { - this.getHandPosition = MyAvatar.getRightPalmPosition; - this.getHandRotation = MyAvatar.getRightPalmRotation; - } else { - this.getHandPosition = MyAvatar.getLeftPalmPosition; - this.getHandRotation = MyAvatar.getLeftPalmRotation; - } - - var SPATIAL_CONTROLLERS_PER_PALM = 2; - var TIP_CONTROLLER_OFFSET = 1; - this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; - this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; - - this.actionID = null; // action this script created... - this.grabbedEntity = null; // on this entity. - this.state = STATE_OFF; - this.pointer = null; // entity-id of line object - this.triggerValue = 0; // rolling average of trigger value - this.rawTriggerValue = 0; - this.rawBumperValue = 0; - - //for visualizations - this.overlayLine = null; - this.particleBeam = null; - - //for lights - this.spotlight = null; - this.pointlight = null; - - this.ignoreIK = false; - this.offsetPosition = Vec3.ZERO; - this.offsetRotation = Quat.IDENTITY; - - var _this = this; - - this.update = function() { - - this.updateSmoothedTrigger(); - - switch (this.state) { - case STATE_OFF: - this.off(); - this.touchTest(); - break; - case STATE_SEARCHING: - this.search(); - break; - case STATE_EQUIP_SEARCHING: - this.search(); - break; - case STATE_DISTANCE_HOLDING: - this.distanceHolding(); - break; - case STATE_CONTINUE_DISTANCE_HOLDING: - this.continueDistanceHolding(); - break; - case STATE_NEAR_GRABBING: - case STATE_EQUIP: - this.nearGrabbing(); - break; - case STATE_WAITING_FOR_BUMPER_RELEASE: - this.waitingForBumperRelease(); - break; - case STATE_EQUIP_SPRING: - this.pullTowardEquipPosition() - break; - case STATE_CONTINUE_NEAR_GRABBING: - case STATE_CONTINUE_EQUIP_BD: - case STATE_CONTINUE_EQUIP: - this.continueNearGrabbing(); - break; - case STATE_NEAR_TRIGGER: - this.nearTrigger(); - break; - case STATE_CONTINUE_NEAR_TRIGGER: - this.continueNearTrigger(); - break; - case STATE_FAR_TRIGGER: - this.farTrigger(); - break; - case STATE_CONTINUE_FAR_TRIGGER: - this.continueFarTrigger(); - break; - case STATE_RELEASE: - this.release(); - break; - } - }; - - this.setState = function(newState) { - if (WANT_DEBUG) { - print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); - } - this.state = newState; - }; - - this.debugLine = function(closePoint, farPoint, color) { - Entities.addEntity({ - type: "Line", - name: "Grab Debug Entity", - dimensions: LINE_ENTITY_DIMENSIONS, - visible: true, - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: 0.1, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - }; - - this.lineOn = function(closePoint, farPoint, color) { - // draw a line - if (this.pointer === null) { - this.pointer = Entities.addEntity({ - type: "Line", - name: "grab pointer", - dimensions: LINE_ENTITY_DIMENSIONS, - visible: true, - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: LIFETIME, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - } else { - var age = Entities.getEntityProperties(this.pointer, "age").age; - this.pointer = Entities.editEntity(this.pointer, { - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: age + LIFETIME - }); - } - }; - - this.overlayLineOn = function(closePoint, farPoint, color) { - if (this.overlayLine === null) { - var lineProperties = { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - ignoreRayIntersection: true, // always ignore this - visible: true, - alpha: 1 - }; - - this.overlayLine = Overlays.addOverlay("line3d", lineProperties); - - } else { - var success = Overlays.editOverlay(this.overlayLine, { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - visible: true, - ignoreRayIntersection: true, // always ignore this - alpha: 1 - }); - } - }; - - this.handleParticleBeam = function(position, orientation, color) { - - var rotation = Quat.angleAxis(0, { - x: 1, - y: 0, - z: 0 - }); - - var finalRotation = Quat.multiply(orientation, rotation); - var lifespan = LINE_LENGTH / 10; - var speed = 5; - var spread = 2; - if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); - } else { - this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); - } - }; - - this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { - - var handToObject = Vec3.subtract(objectPosition, handPosition); - var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); - - var distance = Vec3.distance(handPosition, objectPosition); - var speed = 5; - var spread = 0; - - var lifespan = distance / speed; - - - if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); - } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); - } - }; - - this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { - - var particleBeamProperties = { - type: "ParticleEffect", - isEmitting: true, - position: position, - visible: false, - "name": "Particle Beam", - "color": color, - "maxParticles": 2000, - "lifespan": lifespan, - "emitRate": 50, - "emitSpeed": speed, - "speedSpread": spread, - "emitOrientation": { - "x": -1, - "y": 0, - "z": 0, - "w": 1 - }, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "emitRadiusStart": 0.5, - "polarStart": 0, - "polarFinish": 0, - "azimuthStart": -3.1415927410125732, - "azimuthFinish": 3.1415927410125732, - "emitAcceleration": { - x: 0, - y: 0, - z: 0 - }, - "accelerationSpread": { - "x": 0, - "y": 0, - "z": 0 - }, - "particleRadius": 0.01, - "radiusSpread": 0, - // "radiusStart": 0.01, - // "radiusFinish": 0.01, - // "colorSpread": { - // "red": 0, - // "green": 0, - // "blue": 0 - // }, - // "colorStart": color, - // "colorFinish": color, - "alpha": 1, - "alphaSpread": 0, - "alphaStart": 1, - "alphaFinish": 1, - "additiveBlending": 0, - "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" - } - - this.particleBeam = Entities.addEntity(particleBeamProperties); - }; - - this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { - print('lifespan::' + lifespan); - Entities.editEntity(this.particleBeam, { - rotation: orientation, - position: position, - visible: true, - color: color, - emitSpeed: speed, - speedSpread:spread, - lifespan: lifespan - - }) - - }; - - this.evalLightWorldTransform = function(modelPos, modelRot) { - - var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 - }; - - var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 - }); - - return { - p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), - q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) - }; - }; - - this.handleSpotlight = function(parentID, position) { - var LIFETIME = 100; - - var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); - - var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - var lightProperties = { - type: "Light", - isSpotlight: true, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - parentID: parentID, - color: { - red: 255, - green: 255, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: LIFETIME, - position: lightTransform.p, - }; - - if (this.spotlight === null) { - this.spotlight = Entities.addEntity(lightProperties); - } else { - Entities.editEntity(this.spotlight, { - //without this, this light would maintain rotation with its parent - rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), - }) - } - }; - - this.handlePointLight = function(parentID, position) { - var LIFETIME = 100; - - var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); - var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - - var lightProperties = { - type: "Light", - isSpotlight: false, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - parentID: parentID, - color: { - red: 255, - green: 255, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: LIFETIME, - position: lightTransform.p, - }; - - if (this.pointlight === null) { - this.pointlight = Entities.addEntity(lightProperties); - } else { - - } - }; - - this.lineOff = function() { - if (this.pointer !== null) { - Entities.deleteEntity(this.pointer); - } - this.pointer = null; - }; - - this.overlayLineOff = function() { - if (this.overlayLine !== null) { - Overlays.deleteOverlay(this.overlayLine); - } - this.overlayLine = null; - }; - - this.particleBeamOff = function() { - if (this.particleBeam !== null) { - Entities.editEntity(this.particleBeam, { - visible: false - }) - } - } - - this.turnLightsOff = function() { - if (this.spotlight !== null) { - Entities.deleteEntity(this.spotlight); - this.spotlight = null; - } - - if (this.pointlight !== null) { - Entities.deleteEntity(this.pointlight); - this.pointlight = null; - } - }; - - - this.turnOffVisualizations = function() { - if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOff(); - } - - if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { - this.overlayLineOff(); - } - - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.particleBeamOff(); - } - }; - - this.triggerPress = function(value) { - _this.rawTriggerValue = value; - }; - - this.bumperPress = function(value) { - _this.rawBumperValue = value; - }; - - this.updateSmoothedTrigger = function() { - var triggerValue = this.rawTriggerValue; - // smooth out trigger value - this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + - (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); - }; - - this.triggerSmoothedSqueezed = function() { - return this.triggerValue > TRIGGER_ON_VALUE; - }; - - this.triggerSmoothedReleased = function() { - return this.triggerValue < TRIGGER_OFF_VALUE; - }; - - this.triggerSqueezed = function() { - var triggerValue = this.rawTriggerValue; - return triggerValue > TRIGGER_ON_VALUE; - }; - - this.bumperSqueezed = function() { - return _this.rawBumperValue > BUMPER_ON_VALUE; - }; - - this.bumperReleased = function() { - return _this.rawBumperValue < BUMPER_ON_VALUE; - }; - - this.off = function() { - if (this.triggerSmoothedSqueezed()) { - this.lastPickTime = 0; - this.setState(STATE_SEARCHING); - return; - } - if (this.bumperSqueezed()) { - this.lastPickTime = 0; - this.setState(STATE_EQUIP_SEARCHING); - return; - } - }; - - this.search = function() { - this.grabbedEntity = null; - - if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { - this.setState(STATE_RELEASE); - return; - } - - // the trigger is being pressed, do a ray test - var handPosition = this.getHandPosition(); - var distantPickRay = { - origin: handPosition, - direction: Quat.getUp(this.getHandRotation()), - length: PICK_MAX_DISTANCE - }; - - // don't pick 60x per second. - var pickRays = []; - var now = Date.now(); - if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - pickRays = [distantPickRay]; - this.lastPickTime = now; - } - - for (var index = 0; index < pickRays.length; ++index) { - var pickRay = pickRays[index]; - var directionNormalized = Vec3.normalize(pickRay.direction); - var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); - var pickRayBacked = { - origin: Vec3.subtract(pickRay.origin, directionBacked), - direction: pickRay.direction - }; - - if (WANT_DEBUG) { - this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { - red: 0, - green: 255, - blue: 0 - }) - } - - var intersection = Entities.findRayIntersection(pickRayBacked, true); - - if (intersection.intersects) { - // the ray is intersecting something we can move. - var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); - - if (intersection.properties.name == "Grab Debug Entity") { - continue; - } - - if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { - continue; - } - if (intersectionDistance > pickRay.length) { - // too far away for this ray. - continue; - } - if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { - // the hand is very close to the intersected object. go into close-grabbing mode. - if (grabbableData.wantsTrigger) { - this.grabbedEntity = intersection.entityID; - this.setState(STATE_NEAR_TRIGGER); - return; - } else if (!intersection.properties.locked) { - this.grabbedEntity = intersection.entityID; - if (this.state == STATE_SEARCHING) { - this.setState(STATE_NEAR_GRABBING); - } else { // equipping - if (typeof grabbableData.spatialKey !== 'undefined') { - // TODO - // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch - // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. - // this.setState(STATE_EQUIP_SPRING); - this.setState(STATE_EQUIP); - } else { - this.setState(STATE_EQUIP); - } - } - return; - } - } else if (!entityIsGrabbedByOther(intersection.entityID)) { - // don't allow two people to distance grab the same object - if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { - // the hand is far from the intersected object. go into distance-holding mode - this.grabbedEntity = intersection.entityID; - if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { - // if a distance pick in equip mode hits something with a spatialKey, equip it - // TODO use STATE_EQUIP_SPRING here once it works right. - // this.setState(STATE_EQUIP_SPRING); - this.setState(STATE_EQUIP); - return; - } else if (this.state == STATE_SEARCHING) { - this.setState(STATE_DISTANCE_HOLDING); - return; - } - } else if (grabbableData.wantsTrigger) { - this.grabbedEntity = intersection.entityID; - this.setState(STATE_FAR_TRIGGER); - return; - } - } - } - } - - // forward ray test failed, try sphere test. - if (WANT_DEBUG) { - Entities.addEntity({ - type: "Sphere", - name: "Grab Debug Entity", - dimensions: { - x: GRAB_RADIUS, - y: GRAB_RADIUS, - z: GRAB_RADIUS - }, - visible: true, - position: handPosition, - color: { - red: 0, - green: 255, - blue: 0 - }, - lifetime: 0.1, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - } - - var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); - var minDistance = PICK_MAX_DISTANCE; - var i, props, distance, grabbableData; - this.grabbedEntity = null; - for (i = 0; i < nearbyEntities.length; i++) { - var grabbableDataForCandidate = - getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); - if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { - continue; - } - var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); - - if (propsForCandidate.type == 'Unknown') { - continue; - } - - if (propsForCandidate.type == 'Light') { - continue; - } - - if (propsForCandidate.type == 'ParticleEffect') { - continue; - } - - if (propsForCandidate.type == 'PolyLine') { - continue; - } - - if (propsForCandidate.type == 'Zone') { - continue; - } - - if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { - continue; - } - - if (propsForCandidate.name == "Grab Debug Entity") { - continue; - } - - if (propsForCandidate.name == "grab pointer") { - continue; - } - - distance = Vec3.distance(propsForCandidate.position, handPosition); - if (distance < minDistance) { - this.grabbedEntity = nearbyEntities[i]; - minDistance = distance; - props = propsForCandidate; - grabbableData = grabbableDataForCandidate; - } - } - if (this.grabbedEntity !== null) { - if (grabbableData.wantsTrigger) { - this.setState(STATE_NEAR_TRIGGER); - return; - } else if (!props.locked && props.collisionsWillMove) { - this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) - return; - } - } - - //search line visualizations - if (USE_ENTITY_LINES_FOR_SEARCHING === true) { - this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - } - - if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); - } - - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { - this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); - } - - }; - - this.distanceHolding = function() { - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var now = Date.now(); - - // add the action and initialize some variables - this.currentObjectPosition = grabbedProperties.position; - this.currentObjectRotation = grabbedProperties.rotation; - this.currentObjectTime = now; - this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); - this.handPreviousRotation = handRotation; - this.currentCameraOrientation = Camera.orientation; - - // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object - this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); - if (this.radiusScalar < 1.0) { - this.radiusScalar = 1.0; - } - - this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("spring", this.grabbedEntity, { - targetPosition: this.currentObjectPosition, - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - tag: getTag(), - ttl: ACTION_TTL - }); - if (this.actionID === NULL_ACTION_ID) { - this.actionID = null; - } - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - - if (this.actionID !== null) { - this.setState(STATE_CONTINUE_DISTANCE_HOLDING); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); - } - - this.currentAvatarPosition = MyAvatar.position; - this.currentAvatarOrientation = MyAvatar.orientation; - - this.turnOffVisualizations(); - }; - - this.continueDistanceHolding = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - - var handPosition = this.getHandPosition(); - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && - typeof grabbableData.spatialKey !== 'undefined') { - var saveGrabbedID = this.grabbedEntity; - this.release(); - this.setState(STATE_EQUIP); - this.grabbedEntity = saveGrabbedID; - return; - } - - - // the action was set up on a previous call. update the targets. - var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * - this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; - if (radius < 1.0) { - radius = 1.0; - } - - // how far did avatar move this timestep? - var currentPosition = MyAvatar.position; - var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); - this.currentAvatarPosition = currentPosition; - - // How far did the avatar turn this timestep? - // Note: The following code is too long because we need a Quat.quatBetween() function - // that returns the minimum quaternion between two quaternions. - var currentOrientation = MyAvatar.orientation; - if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) { - var negativeCurrentOrientation = { - x: -currentOrientation.x, - y: -currentOrientation.y, - z: -currentOrientation.z, - w: -currentOrientation.w - }; - var avatarDeltaOrientation = Quat.multiply(negativeCurrentOrientation, Quat.inverse(this.currentAvatarOrientation)); - } else { - var avatarDeltaOrientation = Quat.multiply(currentOrientation, Quat.inverse(this.currentAvatarOrientation)); - } - var handToAvatar = Vec3.subtract(handControllerPosition, this.currentAvatarPosition); - var objectToAvatar = Vec3.subtract(this.currentObjectPosition, this.currentAvatarPosition); - var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar); - var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar); - this.currentAvatarOrientation = currentOrientation; - - // how far did hand move this timestep? - var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); - this.handRelativePreviousPosition = handToAvatar; - - // magnify the hand movement but not the change from avatar movement & rotation - handMoved = Vec3.subtract(handMoved, handMovementFromTurning); - var superHandMoved = Vec3.multiply(handMoved, radius); - - // Move the object by the magnified amount and then by amount from avatar movement & rotation - var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); - newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); - newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); - - var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters - var now = Date.now(); - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - - this.currentObjectPosition = newObjectPosition; - this.currentObjectTime = now; - - // this doubles hand rotation - var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, - handRotation, - DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), - Quat.inverse(this.handPreviousRotation)); - this.handPreviousRotation = handRotation; - this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); - - Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); - - // mix in head motion - if (MOVE_WITH_HEAD) { - var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var after = Vec3.multiplyQbyV(Camera.orientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var change = Vec3.subtract(before, after); - this.currentCameraOrientation = Camera.orientation; - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); - } - - - //visualizations - if (USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); - } - if (USE_OVERLAY_LINES_FOR_MOVING === true) { - this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); - } - if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) - // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) - } - if (USE_POINTLIGHT === true) { - this.handlePointLight(this.grabbedEntity); - } - if (USE_SPOTLIGHT === true) { - this.handleSpotlight(this.grabbedEntity); - } - - Entities.updateAction(this.grabbedEntity, this.actionID, { - targetPosition: this.currentObjectPosition, - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - ttl: ACTION_TTL - }); - - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - }; - - this.nearGrabbing = function() { - var now = Date.now(); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - - this.turnOffVisualizations(); - - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { - Entities.editEntity(this.grabbedEntity, { - collisionsWillMove: false - }); - } - - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { - // if an object is "equipped" and has a spatialKey, use it. - this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - } else { - this.ignoreIK = false; - - var objectRotation = grabbedProperties.rotation; - this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var currentObjectPosition = grabbedProperties.position; - var offset = Vec3.subtract(currentObjectPosition, handPosition); - this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); - } - - this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("hold", this.grabbedEntity, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, - ignoreIK: this.ignoreIK - }); - if (this.actionID === NULL_ACTION_ID) { - this.actionID = null; - } else { - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - if (this.state == STATE_NEAR_GRABBING) { - this.setState(STATE_CONTINUE_NEAR_GRABBING); - } else { - // equipping - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - this.startHandGrasp(); - - this.setState(STATE_CONTINUE_EQUIP_BD); - } - - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); - - } - - this.currentHandControllerTipPosition = - (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; - - this.currentObjectTime = Date.now(); - }; - - this.continueNearGrabbing = function() { - if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { - this.setState(STATE_CONTINUE_EQUIP); - return; - } - if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { - this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); - return; - } - if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { - this.setState(STATE_CONTINUE_EQUIP_BD); - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - return; - } - - // Keep track of the fingertip velocity to impart when we release the object. - // Note that the idea of using a constant 'tip' velocity regardless of the - // object's actual held offset is an idea intended to make it easier to throw things: - // Because we might catch something or transfer it between hands without a good idea - // of it's actual offset, let's try imparting a velocity which is at a fixed radius - // from the palm. - - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var now = Date.now(); - - var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - - this.currentHandControllerTipPosition = handControllerPosition; - this.currentObjectTime = now; - Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); - - if (this.state === STATE_CONTINUE_EQUIP_BD) { - Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); - } - - if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { - // if less than a 5 seconds left, refresh the actions ttl - Entities.updateAction(this.grabbedEntity, this.actionID, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, - ignoreIK: this.ignoreIK - }); - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - } - }; - - this.waitingForBumperRelease = function() { - if (this.bumperReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - Entities.callEntityMethod(this.grabbedEntity, "unequip"); - this.endHandGrasp(); - - } - }; - - this.pullTowardEquipPosition = function() { - - this.turnOffVisualizations(); - - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - // use a spring to pull the object to where it will be when equipped - var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - var targetRotation = Quat.multiply(handRotation, relativeRotation); - var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); - var targetPosition = Vec3.sum(handPosition, offset); - - if (typeof this.equipSpringID === 'undefined' || - this.equipSpringID === null || - this.equipSpringID === NULL_ACTION_ID) { - this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { - targetPosition: targetPosition, - linearTimeScale: EQUIP_SPRING_TIMEFRAME, - targetRotation: targetRotation, - angularTimeScale: EQUIP_SPRING_TIMEFRAME, - ttl: ACTION_TTL, - ignoreIK: ignoreIK - }); - if (this.equipSpringID === NULL_ACTION_ID) { - this.equipSpringID = null; - this.setState(STATE_OFF); - return; - } - } else { - Entities.updateAction(this.grabbedEntity, this.equipSpringID, { - targetPosition: targetPosition, - linearTimeScale: EQUIP_SPRING_TIMEFRAME, - targetRotation: targetRotation, - angularTimeScale: EQUIP_SPRING_TIMEFRAME, - ttl: ACTION_TTL, - ignoreIK: ignoreIK - }); - } - - if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { - Entities.deleteAction(this.grabbedEntity, this.equipSpringID); - this.equipSpringID = null; - this.setState(STATE_EQUIP); - } - }; - - this.nearTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); - this.setState(STATE_CONTINUE_NEAR_TRIGGER); - }; - - this.farTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); - return; - } - - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); - this.setState(STATE_CONTINUE_FAR_TRIGGER); - }; - - this.continueNearTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - - Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); - }; - - this.continueFarTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - - var handPosition = this.getHandPosition(); - var pickRay = { - origin: handPosition, - direction: Quat.getUp(this.getHandRotation()) - }; - - var now = Date.now(); - if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - var intersection = Entities.findRayIntersection(pickRay, true); - this.lastPickTime = now; - if (intersection.entityID != this.grabbedEntity) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); - return; - } - } - - if (USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - } - - Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); - }; - - _this.allTouchedIDs = {}; - - this.touchTest = function() { - var maxDistance = 0.05; - var leftHandPosition = MyAvatar.getLeftPalmPosition(); - var rightHandPosition = MyAvatar.getRightPalmPosition(); - var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); - var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); - var ids = []; - - if (leftEntities.length !== 0) { - leftEntities.forEach(function(entity) { - ids.push(entity); - }); - - } - - if (rightEntities.length !== 0) { - rightEntities.forEach(function(entity) { - ids.push(entity); - }); - } - - ids.forEach(function(id) { - - var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); - if (props.name === 'pointer') { - return; - } else { - var entityMinPoint = props.boundingBox.brn; - var entityMaxPoint = props.boundingBox.tfl; - var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); - var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); - - if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { - // we haven't been touched before, but either right or left is touching us now - _this.allTouchedIDs[id] = true; - _this.startTouch(id); - } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { - // we have been touched before and are still being touched - // continue touch - _this.continueTouch(id); - } else if (_this.allTouchedIDs[id]) { - delete _this.allTouchedIDs[id]; - _this.stopTouch(id); - - } else { - //we are in another state - return; - } - } - - }); - - }; - - this.startTouch = function(entityID) { - Entities.callEntityMethod(entityID, "startTouch"); - }; - - this.continueTouch = function(entityID) { - Entities.callEntityMethod(entityID, "continueTouch"); - }; - - this.stopTouch = function(entityID) { - Entities.callEntityMethod(entityID, "stopTouch"); - }; - - this.release = function() { - - this.turnLightsOff(); - this.turnOffVisualizations(); - - if (this.grabbedEntity !== null) { - if (this.actionID !== null) { - Entities.deleteAction(this.grabbedEntity, this.actionID); - } - } - - this.deactivateEntity(this.grabbedEntity); - - this.grabbedEntity = null; - this.actionID = null; - this.setState(STATE_OFF); - }; - - this.cleanup = function() { - this.release(); - this.endHandGrasp(); - Entities.deleteEntity(this.particleBeam); - Entities.deleteEntity(this.spotLight); - Entities.deleteEntity(this.pointLight); - }; - - this.activateEntity = function(entityID, grabbedProperties) { - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); - var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; - var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); - data["activated"] = true; - data["avatarId"] = MyAvatar.sessionUUID; - data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; - // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done - if (data["refCount"] == 1) { - data["gravity"] = grabbedProperties.gravity; - data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; - data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; - var whileHeldProperties = { - gravity: { - x: 0, - y: 0, - z: 0 - } - }; - if (invertSolidWhileHeld) { - whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; - } - Entities.editEntity(entityID, whileHeldProperties); - } - - setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); - return data; - }; - - this.deactivateEntity = function(entityID) { - var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); - if (data && data["refCount"]) { - data["refCount"] = data["refCount"] - 1; - if (data["refCount"] < 1) { - Entities.editEntity(entityID, { - gravity: data["gravity"], - ignoreForCollisions: data["ignoreForCollisions"], - collisionsWillMove: data["collisionsWillMove"] - }); - data = null; - } - } else { - data = null; - } - setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); - }; - - - //this is our handler, where we do the actual work of changing animation settings - this.graspHand = function(animationProperties) { - var result = {}; - //full alpha on overlay for this hand - //set grab to true - //set idle to false - //full alpha on the blend btw open and grab - if (_this.hand === RIGHT_HAND) { - result['rightHandOverlayAlpha'] = 1.0; - result['isRightHandGrab'] = true; - result['isRightHandIdle'] = false; - result['rightHandGrabBlend'] = 1.0; - } else if (_this.hand === LEFT_HAND) { - result['leftHandOverlayAlpha'] = 1.0; - result['isLeftHandGrab'] = true; - result['isLeftHandIdle'] = false; - result['leftHandGrabBlend'] = 1.0; - } - //return an object with our updated settings - return result; - }; - - this.graspHandler = null - - this.startHandGrasp = function() { - if (this.hand === RIGHT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); - } else if (this.hand === LEFT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); - } - }; - - this.endHandGrasp = function() { - // Tell the animation system we don't need any more callbacks. - MyAvatar.removeAnimationStateHandler(this.graspHandler); - }; - -}; - -var rightController = new MyController(RIGHT_HAND); -var leftController = new MyController(LEFT_HAND); - -//preload the particle beams so that they are full length when you start searching -if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { - rightController.createParticleBeam(); - leftController.createParticleBeam(); -} - -var MAPPING_NAME = "com.highfidelity.handControllerGrab"; - -var mapping = Controller.newMapping(MAPPING_NAME); -mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); -mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); - -mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); -mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); - -Controller.enableMapping(MAPPING_NAME); - -//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items -var handToDisable = 'none'; - -function update() { - if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { - leftController.update(); - } - if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { - rightController.update(); - } -} - -Messages.subscribe('Hifi-Hand-Disabler'); - -handleHandDisablerMessages = function(channel, message, sender) { - - if (sender === MyAvatar.sessionUUID) { - if (message === 'left') { - handToDisable = LEFT_HAND; - } - if (message === 'right') { - handToDisable = RIGHT_HAND; - } - if (message === 'both') { - handToDisable = 'both'; - } - if (message === 'none') { - handToDisable = 'none'; - } - } - -} - -Messages.messageReceived.connect(handleHandDisablerMessages); - -function cleanup() { - rightController.cleanup(); - leftController.cleanup(); - Controller.disableMapping(MAPPING_NAME); -} - -Script.scriptEnding.connect(cleanup); -Script.update.connect(update); \ No newline at end of file diff --git a/examples/controllers/handControllerGrab-spotlight.js b/examples/controllers/handControllerGrab-spotlight.js deleted file mode 100644 index ee6dcfa681..0000000000 --- a/examples/controllers/handControllerGrab-spotlight.js +++ /dev/null @@ -1,1656 +0,0 @@ -// handControllerGrab.js -// -// Created by Eric Levin on 9/2/15 -// Additions by James B. Pollack @imgntn on 9/24/2015 -// Additions By Seth Alves on 10/20/2015 -// Copyright 2015 High Fidelity, Inc. -// -// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. -// Also supports touch and equipping objects. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ - -Script.include("../libraries/utils.js"); - -// -// add lines where the hand ray picking is happening -// -var WANT_DEBUG = false; - -// -// these tune time-averaging and "on" value for analog trigger -// - -var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value -var TRIGGER_ON_VALUE = 0.4; -var TRIGGER_OFF_VALUE = 0.15; - -var BUMPER_ON_VALUE = 0.5; - -// -// distant manipulation -// - -var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object -var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position -var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did -var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects - -var NO_INTERSECT_COLOR = { - red: 10, - green: 10, - blue: 255 -}; // line color when pick misses -var INTERSECT_COLOR = { - red: 250, - green: 10, - blue: 10 -}; // line color when pick hits -var LINE_ENTITY_DIMENSIONS = { - x: 1000, - y: 1000, - z: 1000 -}; - -var LINE_LENGTH = 500; -var PICK_MAX_DISTANCE = 500; // max length of pick-ray - -// -// near grabbing -// - -var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected -var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position -var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. -var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected -var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things -var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object -var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed - -// -// equip -// - -var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; -var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position - -// -// other constants -// - -var RIGHT_HAND = 1; -var LEFT_HAND = 0; - -var ZERO_VEC = { - x: 0, - y: 0, - z: 0 -}; - -var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; -var MSEC_PER_SEC = 1000.0; - -// these control how long an abandoned pointer line or action will hang around -var LIFETIME = 10; -var ACTION_TTL = 15; // seconds -var ACTION_TTL_REFRESH = 5; -var PICKS_PER_SECOND_PER_HAND = 5; -var MSECS_PER_SEC = 1000.0; -var GRABBABLE_PROPERTIES = [ - "position", - "rotation", - "gravity", - "ignoreForCollisions", - "collisionsWillMove", - "locked", - "name" -]; - -var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js -var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js - -var DEFAULT_GRABBABLE_DATA = { - grabbable: true, - invertSolidWhileHeld: false -}; - -//we've created various ways of visualizing looking for and moving distant objects -var USE_ENTITY_LINES_FOR_SEARCHING = false; -var USE_OVERLAY_LINES_FOR_SEARCHING = true; -var USE_PARTICLE_BEAM_FOR_SEARCHING = false; - -var USE_ENTITY_LINES_FOR_MOVING = true; -var USE_OVERLAY_LINES_FOR_MOVING = false; -var USE_PARTICLE_BEAM_FOR_MOVING = false; - -var USE_SPOTLIGHT = true; -var USE_POINTLIGHT = false; - -// states for the state machine -var STATE_OFF = 0; -var STATE_SEARCHING = 1; -var STATE_DISTANCE_HOLDING = 2; -var STATE_CONTINUE_DISTANCE_HOLDING = 3; -var STATE_NEAR_GRABBING = 4; -var STATE_CONTINUE_NEAR_GRABBING = 5; -var STATE_NEAR_TRIGGER = 6; -var STATE_CONTINUE_NEAR_TRIGGER = 7; -var STATE_FAR_TRIGGER = 8; -var STATE_CONTINUE_FAR_TRIGGER = 9; -var STATE_RELEASE = 10; -var STATE_EQUIP_SEARCHING = 11; -var STATE_EQUIP = 12 -var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down -var STATE_CONTINUE_EQUIP = 14; -var STATE_WAITING_FOR_BUMPER_RELEASE = 15; -var STATE_EQUIP_SPRING = 16; - - - -function stateToName(state) { - switch (state) { - case STATE_OFF: - return "off"; - case STATE_SEARCHING: - return "searching"; - case STATE_DISTANCE_HOLDING: - return "distance_holding"; - case STATE_CONTINUE_DISTANCE_HOLDING: - return "continue_distance_holding"; - case STATE_NEAR_GRABBING: - return "near_grabbing"; - case STATE_CONTINUE_NEAR_GRABBING: - return "continue_near_grabbing"; - case STATE_NEAR_TRIGGER: - return "near_trigger"; - case STATE_CONTINUE_NEAR_TRIGGER: - return "continue_near_trigger"; - case STATE_FAR_TRIGGER: - return "far_trigger"; - case STATE_CONTINUE_FAR_TRIGGER: - return "continue_far_trigger"; - case STATE_RELEASE: - return "release"; - case STATE_EQUIP_SEARCHING: - return "equip_searching"; - case STATE_EQUIP: - return "equip"; - case STATE_CONTINUE_EQUIP_BD: - return "continue_equip_bd"; - case STATE_CONTINUE_EQUIP: - return "continue_equip"; - case STATE_WAITING_FOR_BUMPER_RELEASE: - return "waiting_for_bumper_release"; - case STATE_EQUIP_SPRING: - return "state_equip_spring"; - } - - return "unknown"; -} - -function getTag() { - return "grab-" + MyAvatar.sessionUUID; -} - -function entityIsGrabbedByOther(entityID) { - // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. - var actionIDs = Entities.getActionIDs(entityID); - for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { - var actionID = actionIDs[actionIndex]; - var actionArguments = Entities.getActionArguments(entityID, actionID); - var tag = actionArguments["tag"]; - if (tag == getTag()) { - // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. - continue; - } - if (tag.slice(0, 5) == "grab-") { - // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. - return true; - } - } - return false; -} - -function getSpatialOffsetPosition(hand, spatialKey) { - var position = Vec3.ZERO; - - if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { - position = spatialKey.leftRelativePosition; - } - if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { - position = spatialKey.rightRelativePosition; - } - if (spatialKey.relativePosition) { - position = spatialKey.relativePosition; - } - - return position; -} - -var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); - -function getSpatialOffsetRotation(hand, spatialKey) { - var rotation = Quat.IDENTITY; - - if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { - rotation = spatialKey.leftRelativeRotation; - } - if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { - rotation = spatialKey.rightRelativeRotation; - } - if (spatialKey.relativeRotation) { - rotation = spatialKey.relativeRotation; - } - - // Flip left hand - if (hand !== RIGHT_HAND) { - rotation = Quat.multiply(yFlip, rotation); - } - - return rotation; -} - -function MyController(hand) { - this.hand = hand; - if (this.hand === RIGHT_HAND) { - this.getHandPosition = MyAvatar.getRightPalmPosition; - this.getHandRotation = MyAvatar.getRightPalmRotation; - } else { - this.getHandPosition = MyAvatar.getLeftPalmPosition; - this.getHandRotation = MyAvatar.getLeftPalmRotation; - } - - var SPATIAL_CONTROLLERS_PER_PALM = 2; - var TIP_CONTROLLER_OFFSET = 1; - this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; - this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; - - this.actionID = null; // action this script created... - this.grabbedEntity = null; // on this entity. - this.state = STATE_OFF; - this.pointer = null; // entity-id of line object - this.triggerValue = 0; // rolling average of trigger value - this.rawTriggerValue = 0; - this.rawBumperValue = 0; - - //for visualizations - this.overlayLine = null; - this.particleBeam = null; - - //for lights - this.spotlight = null; - this.pointlight = null; - - this.ignoreIK = false; - this.offsetPosition = Vec3.ZERO; - this.offsetRotation = Quat.IDENTITY; - - var _this = this; - - this.update = function() { - - this.updateSmoothedTrigger(); - - switch (this.state) { - case STATE_OFF: - this.off(); - this.touchTest(); - break; - case STATE_SEARCHING: - this.search(); - break; - case STATE_EQUIP_SEARCHING: - this.search(); - break; - case STATE_DISTANCE_HOLDING: - this.distanceHolding(); - break; - case STATE_CONTINUE_DISTANCE_HOLDING: - this.continueDistanceHolding(); - break; - case STATE_NEAR_GRABBING: - case STATE_EQUIP: - this.nearGrabbing(); - break; - case STATE_WAITING_FOR_BUMPER_RELEASE: - this.waitingForBumperRelease(); - break; - case STATE_EQUIP_SPRING: - this.pullTowardEquipPosition() - break; - case STATE_CONTINUE_NEAR_GRABBING: - case STATE_CONTINUE_EQUIP_BD: - case STATE_CONTINUE_EQUIP: - this.continueNearGrabbing(); - break; - case STATE_NEAR_TRIGGER: - this.nearTrigger(); - break; - case STATE_CONTINUE_NEAR_TRIGGER: - this.continueNearTrigger(); - break; - case STATE_FAR_TRIGGER: - this.farTrigger(); - break; - case STATE_CONTINUE_FAR_TRIGGER: - this.continueFarTrigger(); - break; - case STATE_RELEASE: - this.release(); - break; - } - }; - - this.setState = function(newState) { - if (WANT_DEBUG) { - print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); - } - this.state = newState; - }; - - this.debugLine = function(closePoint, farPoint, color) { - Entities.addEntity({ - type: "Line", - name: "Grab Debug Entity", - dimensions: LINE_ENTITY_DIMENSIONS, - visible: true, - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: 0.1, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - }; - - this.lineOn = function(closePoint, farPoint, color) { - // draw a line - if (this.pointer === null) { - this.pointer = Entities.addEntity({ - type: "Line", - name: "grab pointer", - dimensions: LINE_ENTITY_DIMENSIONS, - visible: true, - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: LIFETIME, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - } else { - var age = Entities.getEntityProperties(this.pointer, "age").age; - this.pointer = Entities.editEntity(this.pointer, { - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: age + LIFETIME - }); - } - }; - - this.overlayLineOn = function(closePoint, farPoint, color) { - if (this.overlayLine === null) { - var lineProperties = { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - ignoreRayIntersection: true, // always ignore this - visible: true, - alpha: 1 - }; - - this.overlayLine = Overlays.addOverlay("line3d", lineProperties); - - } else { - var success = Overlays.editOverlay(this.overlayLine, { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - visible: true, - ignoreRayIntersection: true, // always ignore this - alpha: 1 - }); - } - }; - - this.handleParticleBeam = function(position, orientation, color) { - - var rotation = Quat.angleAxis(0, { - x: 1, - y: 0, - z: 0 - }); - - var finalRotation = Quat.multiply(orientation, rotation); - var lifespan = LINE_LENGTH / 10; - var speed = 5; - var spread = 2; - if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); - } else { - this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); - } - }; - - this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { - - var handToObject = Vec3.subtract(objectPosition, handPosition); - var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); - - var distance = Vec3.distance(handPosition, objectPosition); - var speed = 5; - var spread = 0; - - var lifespan = distance / speed; - - - if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); - } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); - } - }; - - this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { - - var particleBeamProperties = { - type: "ParticleEffect", - isEmitting: true, - position: position, - visible: false, - "name": "Particle Beam", - "color": color, - "maxParticles": 2000, - "lifespan": lifespan, - "emitRate": 50, - "emitSpeed": speed, - "speedSpread": spread, - "emitOrientation": { - "x": -1, - "y": 0, - "z": 0, - "w": 1 - }, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "emitRadiusStart": 0.5, - "polarStart": 0, - "polarFinish": 0, - "azimuthStart": -3.1415927410125732, - "azimuthFinish": 3.1415927410125732, - "emitAcceleration": { - x: 0, - y: 0, - z: 0 - }, - "accelerationSpread": { - "x": 0, - "y": 0, - "z": 0 - }, - "particleRadius": 0.01, - "radiusSpread": 0, - // "radiusStart": 0.01, - // "radiusFinish": 0.01, - // "colorSpread": { - // "red": 0, - // "green": 0, - // "blue": 0 - // }, - // "colorStart": color, - // "colorFinish": color, - "alpha": 1, - "alphaSpread": 0, - "alphaStart": 1, - "alphaFinish": 1, - "additiveBlending": 0, - "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" - } - - this.particleBeam = Entities.addEntity(particleBeamProperties); - }; - - this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { - print('lifespan::' + lifespan); - Entities.editEntity(this.particleBeam, { - rotation: orientation, - position: position, - visible: true, - color: color, - emitSpeed: speed, - speedSpread:spread, - lifespan: lifespan - - }) - - }; - - this.evalLightWorldTransform = function(modelPos, modelRot) { - - var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 - }; - - var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 - }); - - return { - p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), - q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) - }; - }; - - this.handleSpotlight = function(parentID, position) { - var LIFETIME = 100; - - var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); - - var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - var lightProperties = { - type: "Light", - isSpotlight: true, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - parentID: parentID, - color: { - red: 255, - green: 255, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: LIFETIME, - position: lightTransform.p, - }; - - if (this.spotlight === null) { - this.spotlight = Entities.addEntity(lightProperties); - } else { - Entities.editEntity(this.spotlight, { - //without this, this light would maintain rotation with its parent - rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), - }) - } - }; - - this.handlePointLight = function(parentID, position) { - var LIFETIME = 100; - - var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); - var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - - var lightProperties = { - type: "Light", - isSpotlight: false, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - parentID: parentID, - color: { - red: 255, - green: 255, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: LIFETIME, - position: lightTransform.p, - }; - - if (this.pointlight === null) { - this.pointlight = Entities.addEntity(lightProperties); - } else { - - } - }; - - this.lineOff = function() { - if (this.pointer !== null) { - Entities.deleteEntity(this.pointer); - } - this.pointer = null; - }; - - this.overlayLineOff = function() { - if (this.overlayLine !== null) { - Overlays.deleteOverlay(this.overlayLine); - } - this.overlayLine = null; - }; - - this.particleBeamOff = function() { - if (this.particleBeam !== null) { - Entities.editEntity(this.particleBeam, { - visible: false - }) - } - } - - this.turnLightsOff = function() { - if (this.spotlight !== null) { - Entities.deleteEntity(this.spotlight); - this.spotlight = null; - } - - if (this.pointlight !== null) { - Entities.deleteEntity(this.pointlight); - this.pointlight = null; - } - }; - - - this.turnOffVisualizations = function() { - if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOff(); - } - - if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { - this.overlayLineOff(); - } - - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.particleBeamOff(); - } - }; - - this.triggerPress = function(value) { - _this.rawTriggerValue = value; - }; - - this.bumperPress = function(value) { - _this.rawBumperValue = value; - }; - - this.updateSmoothedTrigger = function() { - var triggerValue = this.rawTriggerValue; - // smooth out trigger value - this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + - (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); - }; - - this.triggerSmoothedSqueezed = function() { - return this.triggerValue > TRIGGER_ON_VALUE; - }; - - this.triggerSmoothedReleased = function() { - return this.triggerValue < TRIGGER_OFF_VALUE; - }; - - this.triggerSqueezed = function() { - var triggerValue = this.rawTriggerValue; - return triggerValue > TRIGGER_ON_VALUE; - }; - - this.bumperSqueezed = function() { - return _this.rawBumperValue > BUMPER_ON_VALUE; - }; - - this.bumperReleased = function() { - return _this.rawBumperValue < BUMPER_ON_VALUE; - }; - - this.off = function() { - if (this.triggerSmoothedSqueezed()) { - this.lastPickTime = 0; - this.setState(STATE_SEARCHING); - return; - } - if (this.bumperSqueezed()) { - this.lastPickTime = 0; - this.setState(STATE_EQUIP_SEARCHING); - return; - } - }; - - this.search = function() { - this.grabbedEntity = null; - - if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { - this.setState(STATE_RELEASE); - return; - } - - // the trigger is being pressed, do a ray test - var handPosition = this.getHandPosition(); - var distantPickRay = { - origin: handPosition, - direction: Quat.getUp(this.getHandRotation()), - length: PICK_MAX_DISTANCE - }; - - // don't pick 60x per second. - var pickRays = []; - var now = Date.now(); - if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - pickRays = [distantPickRay]; - this.lastPickTime = now; - } - - for (var index = 0; index < pickRays.length; ++index) { - var pickRay = pickRays[index]; - var directionNormalized = Vec3.normalize(pickRay.direction); - var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); - var pickRayBacked = { - origin: Vec3.subtract(pickRay.origin, directionBacked), - direction: pickRay.direction - }; - - if (WANT_DEBUG) { - this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { - red: 0, - green: 255, - blue: 0 - }) - } - - var intersection = Entities.findRayIntersection(pickRayBacked, true); - - if (intersection.intersects) { - // the ray is intersecting something we can move. - var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); - - if (intersection.properties.name == "Grab Debug Entity") { - continue; - } - - if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { - continue; - } - if (intersectionDistance > pickRay.length) { - // too far away for this ray. - continue; - } - if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { - // the hand is very close to the intersected object. go into close-grabbing mode. - if (grabbableData.wantsTrigger) { - this.grabbedEntity = intersection.entityID; - this.setState(STATE_NEAR_TRIGGER); - return; - } else if (!intersection.properties.locked) { - this.grabbedEntity = intersection.entityID; - if (this.state == STATE_SEARCHING) { - this.setState(STATE_NEAR_GRABBING); - } else { // equipping - if (typeof grabbableData.spatialKey !== 'undefined') { - // TODO - // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch - // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. - // this.setState(STATE_EQUIP_SPRING); - this.setState(STATE_EQUIP); - } else { - this.setState(STATE_EQUIP); - } - } - return; - } - } else if (!entityIsGrabbedByOther(intersection.entityID)) { - // don't allow two people to distance grab the same object - if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { - // the hand is far from the intersected object. go into distance-holding mode - this.grabbedEntity = intersection.entityID; - if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { - // if a distance pick in equip mode hits something with a spatialKey, equip it - // TODO use STATE_EQUIP_SPRING here once it works right. - // this.setState(STATE_EQUIP_SPRING); - this.setState(STATE_EQUIP); - return; - } else if (this.state == STATE_SEARCHING) { - this.setState(STATE_DISTANCE_HOLDING); - return; - } - } else if (grabbableData.wantsTrigger) { - this.grabbedEntity = intersection.entityID; - this.setState(STATE_FAR_TRIGGER); - return; - } - } - } - } - - // forward ray test failed, try sphere test. - if (WANT_DEBUG) { - Entities.addEntity({ - type: "Sphere", - name: "Grab Debug Entity", - dimensions: { - x: GRAB_RADIUS, - y: GRAB_RADIUS, - z: GRAB_RADIUS - }, - visible: true, - position: handPosition, - color: { - red: 0, - green: 255, - blue: 0 - }, - lifetime: 0.1, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - } - - var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); - var minDistance = PICK_MAX_DISTANCE; - var i, props, distance, grabbableData; - this.grabbedEntity = null; - for (i = 0; i < nearbyEntities.length; i++) { - var grabbableDataForCandidate = - getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); - if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { - continue; - } - var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); - - if (propsForCandidate.type == 'Unknown') { - continue; - } - - if (propsForCandidate.type == 'Light') { - continue; - } - - if (propsForCandidate.type == 'ParticleEffect') { - continue; - } - - if (propsForCandidate.type == 'PolyLine') { - continue; - } - - if (propsForCandidate.type == 'Zone') { - continue; - } - - if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { - continue; - } - - if (propsForCandidate.name == "Grab Debug Entity") { - continue; - } - - if (propsForCandidate.name == "grab pointer") { - continue; - } - - distance = Vec3.distance(propsForCandidate.position, handPosition); - if (distance < minDistance) { - this.grabbedEntity = nearbyEntities[i]; - minDistance = distance; - props = propsForCandidate; - grabbableData = grabbableDataForCandidate; - } - } - if (this.grabbedEntity !== null) { - if (grabbableData.wantsTrigger) { - this.setState(STATE_NEAR_TRIGGER); - return; - } else if (!props.locked && props.collisionsWillMove) { - this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) - return; - } - } - - //search line visualizations - if (USE_ENTITY_LINES_FOR_SEARCHING === true) { - this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - } - - if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); - } - - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { - this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); - } - - }; - - this.distanceHolding = function() { - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var now = Date.now(); - - // add the action and initialize some variables - this.currentObjectPosition = grabbedProperties.position; - this.currentObjectRotation = grabbedProperties.rotation; - this.currentObjectTime = now; - this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); - this.handPreviousRotation = handRotation; - this.currentCameraOrientation = Camera.orientation; - - // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object - this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); - if (this.radiusScalar < 1.0) { - this.radiusScalar = 1.0; - } - - this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("spring", this.grabbedEntity, { - targetPosition: this.currentObjectPosition, - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - tag: getTag(), - ttl: ACTION_TTL - }); - if (this.actionID === NULL_ACTION_ID) { - this.actionID = null; - } - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - - if (this.actionID !== null) { - this.setState(STATE_CONTINUE_DISTANCE_HOLDING); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); - } - - this.currentAvatarPosition = MyAvatar.position; - this.currentAvatarOrientation = MyAvatar.orientation; - - this.turnOffVisualizations(); - }; - - this.continueDistanceHolding = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - - var handPosition = this.getHandPosition(); - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && - typeof grabbableData.spatialKey !== 'undefined') { - var saveGrabbedID = this.grabbedEntity; - this.release(); - this.setState(STATE_EQUIP); - this.grabbedEntity = saveGrabbedID; - return; - } - - - // the action was set up on a previous call. update the targets. - var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * - this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; - if (radius < 1.0) { - radius = 1.0; - } - - // how far did avatar move this timestep? - var currentPosition = MyAvatar.position; - var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); - this.currentAvatarPosition = currentPosition; - - // How far did the avatar turn this timestep? - // Note: The following code is too long because we need a Quat.quatBetween() function - // that returns the minimum quaternion between two quaternions. - var currentOrientation = MyAvatar.orientation; - if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) { - var negativeCurrentOrientation = { - x: -currentOrientation.x, - y: -currentOrientation.y, - z: -currentOrientation.z, - w: -currentOrientation.w - }; - var avatarDeltaOrientation = Quat.multiply(negativeCurrentOrientation, Quat.inverse(this.currentAvatarOrientation)); - } else { - var avatarDeltaOrientation = Quat.multiply(currentOrientation, Quat.inverse(this.currentAvatarOrientation)); - } - var handToAvatar = Vec3.subtract(handControllerPosition, this.currentAvatarPosition); - var objectToAvatar = Vec3.subtract(this.currentObjectPosition, this.currentAvatarPosition); - var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar); - var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar); - this.currentAvatarOrientation = currentOrientation; - - // how far did hand move this timestep? - var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); - this.handRelativePreviousPosition = handToAvatar; - - // magnify the hand movement but not the change from avatar movement & rotation - handMoved = Vec3.subtract(handMoved, handMovementFromTurning); - var superHandMoved = Vec3.multiply(handMoved, radius); - - // Move the object by the magnified amount and then by amount from avatar movement & rotation - var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); - newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); - newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); - - var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters - var now = Date.now(); - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - - this.currentObjectPosition = newObjectPosition; - this.currentObjectTime = now; - - // this doubles hand rotation - var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, - handRotation, - DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), - Quat.inverse(this.handPreviousRotation)); - this.handPreviousRotation = handRotation; - this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); - - Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); - - // mix in head motion - if (MOVE_WITH_HEAD) { - var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var after = Vec3.multiplyQbyV(Camera.orientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var change = Vec3.subtract(before, after); - this.currentCameraOrientation = Camera.orientation; - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); - } - - - //visualizations - if (USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); - } - if (USE_OVERLAY_LINES_FOR_MOVING === true) { - this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); - } - if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) - // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) - } - if (USE_POINTLIGHT === true) { - this.handlePointLight(this.grabbedEntity); - } - if (USE_SPOTLIGHT === true) { - this.handleSpotlight(this.grabbedEntity); - } - - Entities.updateAction(this.grabbedEntity, this.actionID, { - targetPosition: this.currentObjectPosition, - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - ttl: ACTION_TTL - }); - - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - }; - - this.nearGrabbing = function() { - var now = Date.now(); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - - this.turnOffVisualizations(); - - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { - Entities.editEntity(this.grabbedEntity, { - collisionsWillMove: false - }); - } - - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { - // if an object is "equipped" and has a spatialKey, use it. - this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - } else { - this.ignoreIK = false; - - var objectRotation = grabbedProperties.rotation; - this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var currentObjectPosition = grabbedProperties.position; - var offset = Vec3.subtract(currentObjectPosition, handPosition); - this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); - } - - this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("hold", this.grabbedEntity, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, - ignoreIK: this.ignoreIK - }); - if (this.actionID === NULL_ACTION_ID) { - this.actionID = null; - } else { - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - if (this.state == STATE_NEAR_GRABBING) { - this.setState(STATE_CONTINUE_NEAR_GRABBING); - } else { - // equipping - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - this.startHandGrasp(); - - this.setState(STATE_CONTINUE_EQUIP_BD); - } - - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); - - } - - this.currentHandControllerTipPosition = - (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; - - this.currentObjectTime = Date.now(); - }; - - this.continueNearGrabbing = function() { - if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } - if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { - this.setState(STATE_CONTINUE_EQUIP); - return; - } - if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { - this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); - return; - } - if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { - this.setState(STATE_CONTINUE_EQUIP_BD); - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - return; - } - - // Keep track of the fingertip velocity to impart when we release the object. - // Note that the idea of using a constant 'tip' velocity regardless of the - // object's actual held offset is an idea intended to make it easier to throw things: - // Because we might catch something or transfer it between hands without a good idea - // of it's actual offset, let's try imparting a velocity which is at a fixed radius - // from the palm. - - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var now = Date.now(); - - var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - - this.currentHandControllerTipPosition = handControllerPosition; - this.currentObjectTime = now; - Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); - - if (this.state === STATE_CONTINUE_EQUIP_BD) { - Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); - } - - if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { - // if less than a 5 seconds left, refresh the actions ttl - Entities.updateAction(this.grabbedEntity, this.actionID, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, - ignoreIK: this.ignoreIK - }); - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - } - }; - - this.waitingForBumperRelease = function() { - if (this.bumperReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - Entities.callEntityMethod(this.grabbedEntity, "unequip"); - this.endHandGrasp(); - - } - }; - - this.pullTowardEquipPosition = function() { - - this.turnOffVisualizations(); - - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - // use a spring to pull the object to where it will be when equipped - var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - var targetRotation = Quat.multiply(handRotation, relativeRotation); - var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); - var targetPosition = Vec3.sum(handPosition, offset); - - if (typeof this.equipSpringID === 'undefined' || - this.equipSpringID === null || - this.equipSpringID === NULL_ACTION_ID) { - this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { - targetPosition: targetPosition, - linearTimeScale: EQUIP_SPRING_TIMEFRAME, - targetRotation: targetRotation, - angularTimeScale: EQUIP_SPRING_TIMEFRAME, - ttl: ACTION_TTL, - ignoreIK: ignoreIK - }); - if (this.equipSpringID === NULL_ACTION_ID) { - this.equipSpringID = null; - this.setState(STATE_OFF); - return; - } - } else { - Entities.updateAction(this.grabbedEntity, this.equipSpringID, { - targetPosition: targetPosition, - linearTimeScale: EQUIP_SPRING_TIMEFRAME, - targetRotation: targetRotation, - angularTimeScale: EQUIP_SPRING_TIMEFRAME, - ttl: ACTION_TTL, - ignoreIK: ignoreIK - }); - } - - if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { - Entities.deleteAction(this.grabbedEntity, this.equipSpringID); - this.equipSpringID = null; - this.setState(STATE_EQUIP); - } - }; - - this.nearTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); - this.setState(STATE_CONTINUE_NEAR_TRIGGER); - }; - - this.farTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); - return; - } - - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); - this.setState(STATE_CONTINUE_FAR_TRIGGER); - }; - - this.continueNearTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - - Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); - }; - - this.continueFarTrigger = function() { - if (this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); - return; - } - - var handPosition = this.getHandPosition(); - var pickRay = { - origin: handPosition, - direction: Quat.getUp(this.getHandRotation()) - }; - - var now = Date.now(); - if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - var intersection = Entities.findRayIntersection(pickRay, true); - this.lastPickTime = now; - if (intersection.entityID != this.grabbedEntity) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); - return; - } - } - - if (USE_ENTITY_LINES_FOR_MOVING === true) { - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - } - - Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); - }; - - _this.allTouchedIDs = {}; - - this.touchTest = function() { - var maxDistance = 0.05; - var leftHandPosition = MyAvatar.getLeftPalmPosition(); - var rightHandPosition = MyAvatar.getRightPalmPosition(); - var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); - var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); - var ids = []; - - if (leftEntities.length !== 0) { - leftEntities.forEach(function(entity) { - ids.push(entity); - }); - - } - - if (rightEntities.length !== 0) { - rightEntities.forEach(function(entity) { - ids.push(entity); - }); - } - - ids.forEach(function(id) { - - var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); - if (props.name === 'pointer') { - return; - } else { - var entityMinPoint = props.boundingBox.brn; - var entityMaxPoint = props.boundingBox.tfl; - var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); - var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); - - if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { - // we haven't been touched before, but either right or left is touching us now - _this.allTouchedIDs[id] = true; - _this.startTouch(id); - } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { - // we have been touched before and are still being touched - // continue touch - _this.continueTouch(id); - } else if (_this.allTouchedIDs[id]) { - delete _this.allTouchedIDs[id]; - _this.stopTouch(id); - - } else { - //we are in another state - return; - } - } - - }); - - }; - - this.startTouch = function(entityID) { - Entities.callEntityMethod(entityID, "startTouch"); - }; - - this.continueTouch = function(entityID) { - Entities.callEntityMethod(entityID, "continueTouch"); - }; - - this.stopTouch = function(entityID) { - Entities.callEntityMethod(entityID, "stopTouch"); - }; - - this.release = function() { - - this.turnLightsOff(); - this.turnOffVisualizations(); - - if (this.grabbedEntity !== null) { - if (this.actionID !== null) { - Entities.deleteAction(this.grabbedEntity, this.actionID); - } - } - - this.deactivateEntity(this.grabbedEntity); - - this.grabbedEntity = null; - this.actionID = null; - this.setState(STATE_OFF); - }; - - this.cleanup = function() { - this.release(); - this.endHandGrasp(); - Entities.deleteEntity(this.particleBeam); - Entities.deleteEntity(this.spotLight); - Entities.deleteEntity(this.pointLight); - }; - - this.activateEntity = function(entityID, grabbedProperties) { - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); - var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; - var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); - data["activated"] = true; - data["avatarId"] = MyAvatar.sessionUUID; - data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; - // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done - if (data["refCount"] == 1) { - data["gravity"] = grabbedProperties.gravity; - data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; - data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; - var whileHeldProperties = { - gravity: { - x: 0, - y: 0, - z: 0 - } - }; - if (invertSolidWhileHeld) { - whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; - } - Entities.editEntity(entityID, whileHeldProperties); - } - - setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); - return data; - }; - - this.deactivateEntity = function(entityID) { - var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); - if (data && data["refCount"]) { - data["refCount"] = data["refCount"] - 1; - if (data["refCount"] < 1) { - Entities.editEntity(entityID, { - gravity: data["gravity"], - ignoreForCollisions: data["ignoreForCollisions"], - collisionsWillMove: data["collisionsWillMove"] - }); - data = null; - } - } else { - data = null; - } - setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); - }; - - - //this is our handler, where we do the actual work of changing animation settings - this.graspHand = function(animationProperties) { - var result = {}; - //full alpha on overlay for this hand - //set grab to true - //set idle to false - //full alpha on the blend btw open and grab - if (_this.hand === RIGHT_HAND) { - result['rightHandOverlayAlpha'] = 1.0; - result['isRightHandGrab'] = true; - result['isRightHandIdle'] = false; - result['rightHandGrabBlend'] = 1.0; - } else if (_this.hand === LEFT_HAND) { - result['leftHandOverlayAlpha'] = 1.0; - result['isLeftHandGrab'] = true; - result['isLeftHandIdle'] = false; - result['leftHandGrabBlend'] = 1.0; - } - //return an object with our updated settings - return result; - }; - - this.graspHandler = null - - this.startHandGrasp = function() { - if (this.hand === RIGHT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); - } else if (this.hand === LEFT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); - } - }; - - this.endHandGrasp = function() { - // Tell the animation system we don't need any more callbacks. - MyAvatar.removeAnimationStateHandler(this.graspHandler); - }; - -}; - -var rightController = new MyController(RIGHT_HAND); -var leftController = new MyController(LEFT_HAND); - -//preload the particle beams so that they are full length when you start searching -if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { - rightController.createParticleBeam(); - leftController.createParticleBeam(); -} - -var MAPPING_NAME = "com.highfidelity.handControllerGrab"; - -var mapping = Controller.newMapping(MAPPING_NAME); -mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); -mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); - -mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); -mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); - -Controller.enableMapping(MAPPING_NAME); - -//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items -var handToDisable = 'none'; - -function update() { - if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { - leftController.update(); - } - if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { - rightController.update(); - } -} - -Messages.subscribe('Hifi-Hand-Disabler'); - -handleHandDisablerMessages = function(channel, message, sender) { - - if (sender === MyAvatar.sessionUUID) { - if (message === 'left') { - handToDisable = LEFT_HAND; - } - if (message === 'right') { - handToDisable = RIGHT_HAND; - } - if (message === 'both') { - handToDisable = 'both'; - } - if (message === 'none') { - handToDisable = 'none'; - } - } - -} - -Messages.messageReceived.connect(handleHandDisablerMessages); - -function cleanup() { - rightController.cleanup(); - leftController.cleanup(); - Controller.disableMapping(MAPPING_NAME); -} - -Script.scriptEnding.connect(cleanup); -Script.update.connect(update); \ No newline at end of file diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index b6f1a82c3f..bfe51927d0 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -118,12 +118,12 @@ var DEFAULT_GRABBABLE_DATA = { //we've created various ways of visualizing looking for and moving distant objects var USE_ENTITY_LINES_FOR_SEARCHING = false; -var USE_OVERLAY_LINES_FOR_SEARCHING = true; -var USE_PARTICLE_BEAM_FOR_SEARCHING = false; +var USE_OVERLAY_LINES_FOR_SEARCHING = false; +var USE_PARTICLE_BEAM_FOR_SEARCHING = true; -var USE_ENTITY_LINES_FOR_MOVING = true; +var USE_ENTITY_LINES_FOR_MOVING = false; var USE_OVERLAY_LINES_FOR_MOVING = false; -var USE_PARTICLE_BEAM_FOR_MOVING = false; +var USE_PARTICLE_BEAM_FOR_MOVING = true; var USE_SPOTLIGHT = false; var USE_POINTLIGHT = false; From 6fc98bd5773d7aa93c9b29692665e59a9c577a36 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 22 Dec 2015 12:03:03 -0800 Subject: [PATCH 145/209] fixed ravestick, merged --- libraries/entities-renderer/src/paintStroke.slf | 2 ++ libraries/entities-renderer/src/paintStroke.slv | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index f6beca811b..fc659d5928 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -21,6 +21,7 @@ uniform sampler2D originalTexture; // the interpolated normal in vec3 interpolatedNormal; in vec2 varTexcoord; +in vec4 varColor; struct PolyLineUniforms { vec3 color; @@ -35,6 +36,7 @@ void main(void) { vec4 texel = texture(originalTexture, varTexcoord); int frontCondition = 1 -int(gl_FrontFacing) * 2; + vec3 color = varColor.rgb; packDeferredFragmentTranslucent( interpolatedNormal * frontCondition, texel.a, diff --git a/libraries/entities-renderer/src/paintStroke.slv b/libraries/entities-renderer/src/paintStroke.slv index 43eac49e3d..769b87f2a9 100644 --- a/libraries/entities-renderer/src/paintStroke.slv +++ b/libraries/entities-renderer/src/paintStroke.slv @@ -23,9 +23,13 @@ out vec3 interpolatedNormal; //the diffuse texture out vec2 varTexcoord; +out vec4 varColor; + void main(void) { varTexcoord = inTexCoord0.st; + + // pass along the diffuse color varColor = colorToLinearRGBA(inColor); From 51630734dfac1a9c992df67e6d83b9a2cde42a1e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 22 Dec 2015 12:07:02 -0800 Subject: [PATCH 146/209] Update masterReset.js add initial zeroes --- unpublishedScripts/masterReset.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 3d0773ca10..9afbd0a68b 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -218,26 +218,26 @@ MasterReset = function() { lifespan: 1, emitRate: 1000, emitOrientation: forwardQuat, - emitSpeed: .2, + emitSpeed: 0.2, speedSpread: 0.0, polarStart: 0, - polarFinish: .0, - azimuthStart: .1, - azimuthFinish: .01, + polarFinish: 0.0, + azimuthStart: 0.1, + azimuthFinish: 0.01, emitAcceleration: { x: 0, y: 0, z: 0 }, accelerationSpread: { - x: .00, - y: .00, - z: .00 + x: 0.00, + y: 0.00, + z: 0.00 }, radiusStart: 0.03, radiusFinish: 0.025, alpha: 0.7, - alphaSpread: .1, + alphaSpread: 0.1, alphaStart: 0.5, alphaFinish: 0.5, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", @@ -1488,4 +1488,4 @@ MasterReset = function() { Script.scriptEnding.connect(cleanup); } -}; \ No newline at end of file +}; From 5e0a428dec71bc493736587b73784a1f6abae0d7 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 22 Dec 2015 12:07:57 -0800 Subject: [PATCH 147/209] Update hiddenEntityReset.js add zeroes --- unpublishedScripts/hiddenEntityReset.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 21971a18ad..94d815796b 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -239,26 +239,26 @@ lifespan: 1, emitRate: 1000, emitOrientation: forwardQuat, - emitSpeed: .2, + emitSpeed: 0.2, speedSpread: 0.0, polarStart: 0, - polarFinish: .0, - azimuthStart: .1, - azimuthFinish: .01, + polarFinish: 0.0, + azimuthStart: 0.1, + azimuthFinish: 0.01, emitAcceleration: { x: 0, y: 0, z: 0 }, accelerationSpread: { - x: .00, - y: .00, - z: .00 + x: 0.00, + y: 0.00, + z: 0.00 }, radiusStart: 0.03, radiusFinish: 0.025, alpha: 0.7, - alphaSpread: .1, + alphaSpread:0.1, alphaStart: 0.5, alphaFinish: 0.5, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", @@ -1512,4 +1512,4 @@ }; // entity scripts always need to return a newly constructed object of our type return new ResetSwitch(); -}); \ No newline at end of file +}); From 52e6b849684f2f1766687c534061570faa63d364 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 22 Dec 2015 12:09:16 -0800 Subject: [PATCH 148/209] Update lightBall.js zeroes --- examples/flowArts/lightBall/lightBall.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index df62b1b786..b2ed00f326 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -28,13 +28,13 @@ LightBall = function(spawnPosition) { name: "containerBall", position: Vec3.sum(spawnPosition, { x: 0, - y: .5, + y: 0.5, z: 0 }), dimensions: { - x: .1, - y: .1, - z: .1 + x: 0.1, + y: 0.1, + z: 0.1 }, color: { red: 15, @@ -52,7 +52,7 @@ LightBall = function(spawnPosition) { spatialKey: { relativePosition: { x: 0, - y: .1, + y: 0.1, z: 0 } }, @@ -99,7 +99,7 @@ LightBall = function(spawnPosition) { maxParticles: 100000, lifespan: 2, emitRate: 10000, - emitSpeed: .1, + emitSpeed: 0.1, lifetime: -1, speedSpread: 0.0, emitDimensions: { @@ -117,16 +117,16 @@ LightBall = function(spawnPosition) { z: 0 }, accelerationSpread: { - x: .00, - y: .00, - z: .00 + x: 0.00, + y: 0.00, + z: 0.00 }, particleRadius: 0.02, radiusSpread: 0, radiusStart: 0.03, radiusFinish: 0.0003, alpha: 0, - alphaSpread: .5, + alphaSpread: 0.5, alphaStart: 0, alphaFinish: 0.5, textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", @@ -142,4 +142,4 @@ LightBall = function(spawnPosition) { } this.cleanup = cleanup; -} \ No newline at end of file +} From f9070ee9894e166a590487eead143ac49a24944d Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 22 Dec 2015 12:41:31 -0800 Subject: [PATCH 149/209] Cleanup cruft in the shaders, glowIntensity and alphaThreshold not needed anymore --- .../src/RenderableProceduralItemShader.h | 6 ++---- .../render-utils/src/DebugDeferredBuffer.cpp | 2 +- .../render-utils/src/DeferredBufferWrite.slh | 17 +++++++---------- .../render-utils/src/DeferredLightingEffect.cpp | 4 ---- libraries/render-utils/src/MeshPartPayload.cpp | 10 +++------- libraries/render-utils/src/ModelRender.cpp | 15 ++------------- libraries/render-utils/src/ModelRender.h | 8 +++----- .../render-utils/src/RenderDeferredTask.cpp | 15 +-------------- libraries/render-utils/src/SkyFromSpace.slf | 3 ++- libraries/render-utils/src/simple.slf | 4 ++-- libraries/render-utils/src/simple_textured.slf | 2 +- .../src/simple_textured_emisive.slf | 2 +- libraries/shared/src/RenderArgs.h | 2 -- tests/gpu-test/src/unlit.slf | 2 +- 14 files changed, 26 insertions(+), 66 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableProceduralItemShader.h b/libraries/entities-renderer/src/RenderableProceduralItemShader.h index 8c9e7c77dd..a01a6b8571 100644 --- a/libraries/entities-renderer/src/RenderableProceduralItemShader.h +++ b/libraries/entities-renderer/src/RenderableProceduralItemShader.h @@ -23,8 +23,6 @@ layout(location = 0) out vec4 _fragColor0; layout(location = 1) out vec4 _fragColor1; layout(location = 2) out vec4 _fragColor2; -// the glow intensity -uniform float glowIntensity; // the alpha threshold uniform float alphaThreshold; uniform sampler2D normalFittingMap; @@ -318,8 +316,8 @@ const QString SHADER_TEMPLATE_V1 = SHADER_COMMON + R"SCRIBE( void main(void) { vec4 emissive = getProceduralColor(); - float alpha = glowIntensity * emissive.a; - if (alpha != glowIntensity) { + float alpha = emissive.a; + if (alpha != 1.0) { discard; } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 23150a1779..ca678770fb 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -56,7 +56,7 @@ static const std::string DEEFAULT_ROUGHNESS_SHADER { }; static const std::string DEEFAULT_NORMAL_SHADER { "vec4 getFragmentColor() {" - " return vec4(texture(normalMap, uv).xyz, 1.0);" + " return vec4(normalize(texture(normalMap, uv).xyz), 1.0);" " }" }; static const std::string DEEFAULT_DEPTH_SHADER { diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index d3a5ff1e31..1045c4afc7 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -15,12 +15,6 @@ layout(location = 0) out vec4 _fragColor0; layout(location = 1) out vec4 _fragColor1; layout(location = 2) out vec4 _fragColor2; -// the glow intensity -uniform float glowIntensity; - -// the alpha threshold -uniform float alphaThreshold; - uniform sampler2D normalFittingMap; vec3 bestFitNormal(vec3 normal) { @@ -39,15 +33,18 @@ vec3 bestFitNormal(vec3 normal) { return (cN * 0.5 + 0.5); } + +// the alpha threshold +const float alphaThreshold = 0.5; float evalOpaqueFinalAlpha(float alpha, float mapAlpha) { - return mix(alpha * glowIntensity, 1.0 - alpha * glowIntensity, step(mapAlpha, alphaThreshold)); + return mix(alpha, 1.0 - alpha, step(mapAlpha, alphaThreshold)); } const vec3 DEFAULT_SPECULAR = vec3(0.1); const float DEFAULT_SHININESS = 10; void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) { - if (alpha != glowIntensity) { + if (alpha != 1.0) { discard; } @@ -57,7 +54,7 @@ void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular, } void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess, vec3 emissive) { - if (alpha != glowIntensity) { + if (alpha != 1.0) { discard; } @@ -67,7 +64,7 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 s } void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) { - if (alpha <= alphaThreshold) { + if (alpha <= 0.0) { discard; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 4e4799612d..db0e47de5e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -40,8 +40,6 @@ #include "point_light_frag.h" #include "spot_light_frag.h" -static const std::string glowIntensityShaderHandle = "glowIntensity"; - struct LightLocations { int radius; int ambientSphere; @@ -134,8 +132,6 @@ gpu::PipelinePointer DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch batch.setPipeline(pipeline); gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; - int glowIntensity = program->getUniforms().findLocation("glowIntensity"); - batch._glUniform1f(glowIntensity, 1.0f); if (!config.isTextured()) { // If it is not textured, bind white texture and keep using textured pipeline diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2fae09a158..414ad9cf97 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -199,8 +199,6 @@ void MeshPartPayload::render(RenderArgs* args) const { gpu::Batch& batch = *(args->_batch); auto mode = args->_renderMode; - auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME - model::MaterialKey drawMaterialKey; if (_drawMaterial) { drawMaterialKey = _drawMaterial->getKey(); @@ -217,7 +215,7 @@ void MeshPartPayload::render(RenderArgs* args) const { } ModelRender::Locations* locations = nullptr; - ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, + ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, args, locations); @@ -395,9 +393,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { gpu::Batch& batch = *(args->_batch); auto mode = args->_renderMode; - - auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME - + const FBXGeometry& geometry = _model->_geometry->getFBXGeometry(); const std::vector>& networkMeshes = _model->_geometry->getMeshes(); @@ -467,7 +463,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { } ModelRender::Locations* locations = nullptr; - ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, + ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, args, locations); if (!locations) { // the pipeline could not be found diff --git a/libraries/render-utils/src/ModelRender.cpp b/libraries/render-utils/src/ModelRender.cpp index 10c9d738d2..312d34e41b 100644 --- a/libraries/render-utils/src/ModelRender.cpp +++ b/libraries/render-utils/src/ModelRender.cpp @@ -228,10 +228,8 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, ModelRender::Locations& locations) { - locations.alphaThreshold = program->getUniforms().findLocation("alphaThreshold"); locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); locations.emissiveParams = program->getUniforms().findLocation("emissiveParams"); - locations.glowIntensity = program->getUniforms().findLocation("glowIntensity"); locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); locations.diffuseTextureUnit = program->getTextures().findLocation("diffuseMap"); locations.normalTextureUnit = program->getTextures().findLocation("normalMap"); @@ -244,14 +242,14 @@ void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, } -void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, +void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, Locations*& locations) { PerformanceTimer perfTimer("Model::pickPrograms"); getRenderPipelineLib(); - RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); + RenderKey key(mode, translucent, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); auto pipeline = _renderPipelineLib.find(key.getRaw()); if (pipeline == _renderPipelineLib.end()) { qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw(); @@ -266,15 +264,6 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b // Setup the One pipeline batch.setPipeline((*pipeline).second._pipeline); - if ((locations->alphaThreshold > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { - batch._glUniform1f(locations->alphaThreshold, alphaThreshold); - } - - if ((locations->glowIntensity > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { - const float DEFAULT_GLOW_INTENSITY = 1.0f; // FIXME - glow is removed - batch._glUniform1f(locations->glowIntensity, DEFAULT_GLOW_INTENSITY); - } - if ((locations->normalFittingMapUnit > -1)) { batch.setResourceTexture(locations->normalFittingMapUnit, DependencyManager::get()->getNormalFittingTexture()); diff --git a/libraries/render-utils/src/ModelRender.h b/libraries/render-utils/src/ModelRender.h index 39fe05378d..8331440fb0 100644 --- a/libraries/render-utils/src/ModelRender.h +++ b/libraries/render-utils/src/ModelRender.h @@ -29,21 +29,19 @@ public: class Locations { public: - int alphaThreshold; int texcoordMatrices; int diffuseTextureUnit; int normalTextureUnit; int specularTextureUnit; int emissiveTextureUnit; int emissiveParams; - int glowIntensity; int normalFittingMapUnit; int skinClusterBufferUnit; int materialBufferUnit; int lightBufferUnit; }; - static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, + static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, Locations*& locations); @@ -111,9 +109,9 @@ public: ) {} RenderKey(RenderArgs::RenderMode mode, - bool translucent, float alphaThreshold, bool hasLightmap, + bool translucent, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) : - RenderKey(((translucent && (alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0) + RenderKey(((translucent && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0) | (hasLightmap && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_LIGHTMAP : 0) // Lightmap, tangents and specular don't matter for depthOnly | (hasTangents && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_TANGENTS : 0) | (hasSpecular && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_SPECULAR : 0) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 4dcda425a1..cf60fcfe37 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -126,12 +126,6 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new HitEffect::JobModel("HitEffect"))); _jobs.back().setEnabled(false); _drawHitEffectJobIndex = (int)_jobs.size() -1; - - // Give ourselves 3 frmaes of timer queries - _timerQueries.push_back(std::make_shared()); - _timerQueries.push_back(std::make_shared()); - _timerQueries.push_back(std::make_shared()); - _currentTimerQueryIndex = 0; } RenderDeferredTask::~RenderDeferredTask() { @@ -197,10 +191,6 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - { - const float OPAQUE_ALPHA_THRESHOLD = 0.5f; - args->_alphaThreshold = OPAQUE_ALPHA_THRESHOLD; - } renderItems(sceneContext, renderContext, inItems, opaque.maxDrawn); args->_batch = nullptr; }); @@ -226,10 +216,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - - const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; - args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD; - + renderItems(sceneContext, renderContext, inItems, transparent.maxDrawn); args->_batch = nullptr; }); diff --git a/libraries/render-utils/src/SkyFromSpace.slf b/libraries/render-utils/src/SkyFromSpace.slf index e3569a2914..42282fe08b 100755 --- a/libraries/render-utils/src/SkyFromSpace.slf +++ b/libraries/render-utils/src/SkyFromSpace.slf @@ -114,5 +114,6 @@ void main (void) vec3 finalColor = color + fMiePhase * secondaryColor; outFragColor.a = finalColor.b; - outFragColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2)); + // outFragColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2)); + outFragColor.rgb = finalColor.rgb; } diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index 8c93ee564e..b24e4f92ff 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -51,9 +51,9 @@ void main(void) { if (emissiveAmount > 0.0) { packDeferredFragmentLightmap( - normal, glowIntensity, diffuse, specular, shininess, specular); + normal, 1.0, diffuse, specular, shininess, specular); } else { packDeferredFragment( - normal, glowIntensity, diffuse, specular, shininess); + normal, 1.0, diffuse, specular, shininess); } } diff --git a/libraries/render-utils/src/simple_textured.slf b/libraries/render-utils/src/simple_textured.slf index d567b043f4..727c029bbe 100644 --- a/libraries/render-utils/src/simple_textured.slf +++ b/libraries/render-utils/src/simple_textured.slf @@ -29,7 +29,7 @@ void main(void) { packDeferredFragment( normalize(_normal.xyz), - glowIntensity * texel.a, + texel.a, _color.rgb * texel.rgb, DEFAULT_SPECULAR, DEFAULT_SHININESS); } \ No newline at end of file diff --git a/libraries/render-utils/src/simple_textured_emisive.slf b/libraries/render-utils/src/simple_textured_emisive.slf index 96119e98f0..1dd3d667a6 100644 --- a/libraries/render-utils/src/simple_textured_emisive.slf +++ b/libraries/render-utils/src/simple_textured_emisive.slf @@ -27,7 +27,7 @@ void main(void) { packDeferredFragmentLightmap( normalize(_normal), - glowIntensity * texel.a, + texel.a, _color.rgb, DEFAULT_SPECULAR, DEFAULT_SHININESS, texel.rgb); diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 061e07c600..399b94bcef 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -115,8 +115,6 @@ public: std::shared_ptr _whiteTexture; RenderDetails _details; - - float _alphaThreshold = 0.5f; }; #endif // hifi_RenderArgs_h diff --git a/tests/gpu-test/src/unlit.slf b/tests/gpu-test/src/unlit.slf index 350190180a..77d28aa7e9 100644 --- a/tests/gpu-test/src/unlit.slf +++ b/tests/gpu-test/src/unlit.slf @@ -22,7 +22,7 @@ in vec3 _color; void main(void) { packDeferredFragment( normalize(_normal.xyz), - glowIntensity, + 1.0, _color.rgb, DEFAULT_SPECULAR, DEFAULT_SHININESS); } From 119f3e9895e46ff412bb83a9c03b06f245c6c84e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 22 Dec 2015 13:35:16 -0800 Subject: [PATCH 150/209] make both hands and mouse work --- .../controllers/reticleHandRotationTest.js | 136 ++++++++++++++++-- 1 file changed, 126 insertions(+), 10 deletions(-) diff --git a/examples/controllers/reticleHandRotationTest.js b/examples/controllers/reticleHandRotationTest.js index 3d903217ef..9ca1aa661d 100644 --- a/examples/controllers/reticleHandRotationTest.js +++ b/examples/controllers/reticleHandRotationTest.js @@ -32,14 +32,14 @@ function moveReticleAbsolute(x, y) { // some debugging to see if position is jumping around on us... var distanceSinceLastMove = length(lastPos, globalPos); if (distanceSinceLastMove > EXPECTED_CHANGE) { - print("------------------ distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------"); + debugPrint("------------------ distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------"); } if (Math.abs(dX) > EXPECTED_CHANGE) { - print("surpressing unexpectedly large change dX:" + dX + "----------------------------"); + debugPrint("surpressing unexpectedly large change dX:" + dX + "----------------------------"); } if (Math.abs(dY) > EXPECTED_CHANGE) { - print("surpressing unexpectedly large change dY:" + dY + "----------------------------"); + debugPrint("surpressing unexpectedly large change dY:" + dY + "----------------------------"); } globalPos.x = x; @@ -59,6 +59,31 @@ mapping.enable(); var lastRotatedLeft = Vec3.UNIT_NEG_Y; var lastRotatedRight = Vec3.UNIT_NEG_Y; +function debugPrint(message) { + if (DEBUGGING) { + print(message); + } +} + +var MAX_WAKE_UP_DISTANCE = 0.005; +var MIN_WAKE_UP_DISTANCE = 0.001; +var INITIAL_WAKE_UP_DISTANCE = MIN_WAKE_UP_DISTANCE; +var INCREMENTAL_WAKE_UP_DISTANCE = 0.001; + +var MAX_SLEEP_DISTANCE = 0.0004; +var MIN_SLEEP_DISTANCE = 0.00002; +var INITIAL_SLEEP_DISTANCE = MIN_SLEEP_DISTANCE; +var INCREMENTAL_SLEEP_DISTANCE = 0.00002; + +var leftAsleep = true; +var rightAsleep = true; + +var leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; +var rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; + +var leftSleepDistance = INITIAL_SLEEP_DISTANCE; +var rightSleepDistance = INITIAL_SLEEP_DISTANCE; + Script.update.connect(function(deltaTime) { var poseRight = Controller.getPoseValue(Controller.Standard.RightHand); @@ -71,19 +96,110 @@ Script.update.connect(function(deltaTime) { var rotatedRight = Vec3.multiplyQbyV(poseRight.rotation, Vec3.UNIT_NEG_Y); var rotatedLeft = Vec3.multiplyQbyV(poseLeft.rotation, Vec3.UNIT_NEG_Y); - // check to see if hand is on base station - if (Vec3.equal(rotatedLeft, Vec3.UNIT_NEG_Y)) { - rotatedLeft = rotatedRight; + var suppressRight = false; + var suppressLeft = false; + + // What I really want to do is to slowly increase the epsilon you have to move it + // to wake up, the longer you go without moving it + var leftDistance = Vec3.distance(rotatedLeft, lastRotatedLeft); + var rightDistance = Vec3.distance(rotatedRight, lastRotatedRight); + + // check to see if hand should wakeup or sleep + if (leftAsleep) { + if (leftDistance > leftWakeUpDistance) { + leftAsleep = false; + leftSleepDistance = INITIAL_SLEEP_DISTANCE; + leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; + } else { + // grow the wake up distance to make it harder to wake up + leftWakeUpDistance = Math.min(leftWakeUpDistance + INCREMENTAL_WAKE_UP_DISTANCE, MAX_WAKE_UP_DISTANCE); + } + } else { + // we are awake, determine if we should fall asleep, if we haven't moved + // at least as much as our sleep distance then we sleep + if (leftDistance < leftSleepDistance) { + leftAsleep = true; + leftSleepDistance = INITIAL_SLEEP_DISTANCE; + leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; + } else { + // if we moved more than the sleep amount, but we moved less than the max sleep + // amount, then increase our liklihood of sleep. + if (leftDistance < MAX_SLEEP_DISTANCE) { + print("growing sleep...."); + leftSleepDistance = Math.max(leftSleepDistance + INCREMENTAL_SLEEP_DISTANCE, MAX_SLEEP_DISTANCE); + } else { + // otherwise reset it to initial + leftSleepDistance = INITIAL_SLEEP_DISTANCE; + } + } } - if (Vec3.equal(rotatedRight, Vec3.UNIT_NEG_Y)) { - rotatedRight = rotatedLeft; + if (leftAsleep) { + suppressLeft = true; + debugPrint("suppressing left not moving enough"); } - // Keep track of last rotations, to potentially detect resting (but not on - // base station hands) in the future + // check to see if hand should wakeup or sleep + if (rightAsleep) { + if (rightDistance > rightWakeUpDistance) { + rightAsleep = false; + rightSleepDistance = INITIAL_SLEEP_DISTANCE; + rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; + } else { + // grow the wake up distance to make it harder to wake up + rightWakeUpDistance = Math.min(rightWakeUpDistance + INCREMENTAL_WAKE_UP_DISTANCE, MAX_WAKE_UP_DISTANCE); + } + } else { + // we are awake, determine if we should fall asleep, if we haven't moved + // at least as much as our sleep distance then we sleep + if (rightDistance < rightSleepDistance) { + rightAsleep = true; + rightSleepDistance = INITIAL_SLEEP_DISTANCE; + rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; + } else { + // if we moved more than the sleep amount, but we moved less than the max sleep + // amount, then increase our liklihood of sleep. + if (rightDistance < MAX_SLEEP_DISTANCE) { + print("growing sleep...."); + rightSleepDistance = Math.max(rightSleepDistance + INCREMENTAL_SLEEP_DISTANCE, MAX_SLEEP_DISTANCE); + } else { + // otherwise reset it to initial + rightSleepDistance = INITIAL_SLEEP_DISTANCE; + } + } + } + if (rightAsleep) { + suppressRight = true; + debugPrint("suppressing right not moving enough"); + } + + // check to see if hand is on base station + if (Vec3.equal(rotatedLeft, Vec3.UNIT_NEG_Y)) { + suppressLeft = true; + debugPrint("suppressing left on base station"); + } + if (Vec3.equal(rotatedRight, Vec3.UNIT_NEG_Y)) { + suppressRight = true; + debugPrint("suppressing right on base station"); + } + + // Keep track of last rotations, to detect resting (but not on base station hands) in the future lastRotatedLeft = rotatedLeft; lastRotatedRight = rotatedRight; + if (suppressLeft && suppressRight) { + debugPrint("both hands suppressed bail out early"); + return; + } + + if (suppressLeft) { + debugPrint("right only"); + rotatedLeft = rotatedRight; + } + if (suppressRight) { + debugPrint("left only"); + rotatedRight = rotatedLeft; + } + // Average the two hand positions, if either hand is on base station, the // other hand becomes the only used hand and the average is the hand in use var rotated = Vec3.multiply(Vec3.sum(rotatedRight,rotatedLeft), 0.5); From 9a3d72c7b61674f12558a9e796cc3662d6a35b03 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 22 Dec 2015 13:55:01 -0800 Subject: [PATCH 151/209] tweak sleep cycle slightly --- examples/controllers/reticleHandRotationTest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/controllers/reticleHandRotationTest.js b/examples/controllers/reticleHandRotationTest.js index 9ca1aa661d..ece9283deb 100644 --- a/examples/controllers/reticleHandRotationTest.js +++ b/examples/controllers/reticleHandRotationTest.js @@ -71,9 +71,9 @@ var INITIAL_WAKE_UP_DISTANCE = MIN_WAKE_UP_DISTANCE; var INCREMENTAL_WAKE_UP_DISTANCE = 0.001; var MAX_SLEEP_DISTANCE = 0.0004; -var MIN_SLEEP_DISTANCE = 0.00002; +var MIN_SLEEP_DISTANCE = 0.00001; //0.00002; var INITIAL_SLEEP_DISTANCE = MIN_SLEEP_DISTANCE; -var INCREMENTAL_SLEEP_DISTANCE = 0.00002; +var INCREMENTAL_SLEEP_DISTANCE = 0.000002; // 0.00002; var leftAsleep = true; var rightAsleep = true; From 60f2314469db50a6ca06c9f1b3a163d5dbf5d28a Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 22 Dec 2015 14:38:05 -0800 Subject: [PATCH 152/209] remove debugging print --- examples/controllers/handControllerGrab.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index bfe51927d0..61e7e1d16a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -529,7 +529,6 @@ function MyController(hand) { }; this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { - print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, @@ -538,7 +537,6 @@ function MyController(hand) { emitSpeed: speed, speedSpread:spread, lifespan: lifespan - }) }; From edd11a670a8d48688a4b545d90793a3ee5bc2584 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 22 Dec 2015 14:38:53 -0800 Subject: [PATCH 153/209] minor adjustments to particles --- examples/controllers/handControllerGrab.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 61e7e1d16a..8f291b509a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -506,8 +506,8 @@ function MyController(hand) { "y": 0, "z": 0 }, - "particleRadius": 0.01, - "radiusSpread": 0, + "particleRadius": 0.015, + "radiusSpread": 0.005, // "radiusStart": 0.01, // "radiusFinish": 0.01, // "colorSpread": { From df78f895a67f810357766082ff103c912c39110a Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 22 Dec 2015 14:53:18 -0800 Subject: [PATCH 154/209] Reorder RenderContext initializer to avoid -Wreorder --- libraries/render/src/render/Engine.cpp | 7 ++++--- libraries/render/src/render/Engine.h | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index c38ceda034..907c836347 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -14,9 +14,10 @@ using namespace render; RenderContext::RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode) - : _args{ nullptr }, _items{ items }, _tone{ tone }, - _drawStatus{ drawStatus }, _drawHitEffect{ drawHitEffect }, - _deferredDebugSize{ deferredDebugSize }, _deferredDebugMode{ deferredDebugMode } {}; + : _deferredDebugMode{ deferredDebugMode }, _deferredDebugSize{ deferredDebugSize }, + _args{ nullptr }, + _drawStatus{ drawStatus }, _drawHitEffect{ drawHitEffect }, + _items{ items }, _tone{ tone } {} void RenderContext::setOptions(bool occlusion, bool fxaa, bool showOwned) { _occlusionStatus = occlusion; diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 02f3bf3b2c..4192dd3ed9 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -91,15 +91,15 @@ public: void setOptions(bool occlusion, bool fxaa, bool showOwned); // Debugging - int _deferredDebugMode = -1; - glm::vec4 _deferredDebugSize { 0.0f, -1.0f, 1.0f, 1.0f }; + int _deferredDebugMode; + glm::vec4 _deferredDebugSize; protected: RenderArgs* _args; // Options - int _drawStatus = 0; // bitflag - bool _drawHitEffect = false; + int _drawStatus; // bitflag + bool _drawHitEffect; bool _occlusionStatus = false; bool _fxaaStatus = false; From c39f26ad72c340fb09a5e4e4e91c45ca7f9dd1c5 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 22 Dec 2015 16:31:49 -0800 Subject: [PATCH 155/209] new features --- examples/light_modifier/lightModifier.js | 113 ++++++++++++++++++++--- 1 file changed, 98 insertions(+), 15 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 48efe89a6e..4e0507b69f 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -19,6 +19,8 @@ var VERTICAL_SLIDERS = false; var SHOW_OVERLAYS = true; var SHOW_LIGHT_VOLUME = true; var USE_PARENTED_PANEL = true; +var VISIBLE_PANEL = true; +var USE_LABELS = true; //variables for managing overlays var selectionDisplay; @@ -62,6 +64,7 @@ var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_very_good.fbx'; var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx'; var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100)); +var TRANSPARENT_PANEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/transparent_box_alpha_15.fbx'; var RED = { red: 255, @@ -134,12 +137,13 @@ var slidersRef = { var light = null; -function entitySlider(light, color, sliderType, row) { +function entitySlider(light, color, sliderType, displayText, row) { this.light = light; this.lightID = light.id.replace(/[{}]/g, ""); this.initialProperties = light.initialProperties; this.color = color; this.sliderType = sliderType; + this.displayText = displayText; this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); @@ -182,6 +186,9 @@ function entitySlider(light, color, sliderType, row) { this.setInitialSliderPositions(); this.createAxis(); this.createSliderIndicator(); + if (USE_LABELS === true) { + this.createLabel() + } return this; } @@ -205,6 +212,8 @@ entitySlider.prototype = { extension = Vec3.multiply(AXIS_SCALE, rightVector); } + + this.axisStart = position; this.endOfAxis = Vec3.sum(position, extension); var properties = { type: 'Line', @@ -228,8 +237,35 @@ entitySlider.prototype = { this.axis = Entities.addEntity(properties); }, - createLabel:function(){ - + createLabel: function() { + var LABEL_WIDTH = 0.25 + var leftVector = Vec.multiply(-1, Quat.getRight(this.avatarRot)); + var extension = Vec3.multiply(LABEL_WIDTH, leftVector); + var position = Vec3.sum(this.axisStart, extension); + var labelProperties = { + name: 'Hifi-Slider-Label-' + this.sliderType, + type: 'Text', + dimensions: { + x: LABEL_WIDTH, + y: 0.2, + z: 0.1 + }, + textColor: { + red: 255, + green: 255, + blue: 255 + }, + text: this.displayText, + lineHeight: 0.14, + backgroundColor: { + red: 0, + green: 0, + blue: 0 + }, + + } + + this.label = Entities.addEntity(labelProperties); }, createSliderIndicator: function() { var extensionVector; @@ -367,8 +403,12 @@ entitySlider.prototype = { }; + +var panel; +var visiblePanel; + function makeSliders(light) { - var panel; + if (USE_PARENTED_PANEL === true) { panel = createPanelEntity(MyAvatar.position); } @@ -386,9 +426,9 @@ function makeSliders(light) { var USE_EXPONENT_SLIDER = false; } if (USE_COLOR_SLIDER === true) { - slidersRef.color_red = new entitySlider(light, RED, 'color_red', 1); - slidersRef.color_green = new entitySlider(light, GREEN, 'color_green', 2); - slidersRef.color_blue = new entitySlider(light, BLUE, 'color_blue', 3); + slidersRef.color_red = new entitySlider(light, RED, 'color_red', 'Red', 1); + slidersRef.color_green = new entitySlider(light, GREEN, 'color_green', 'Green', 2); + slidersRef.color_blue = new entitySlider(light, BLUE, 'color_blue', 'Blue', 3); sliders.push(slidersRef.color_red); sliders.push(slidersRef.color_green); @@ -396,15 +436,15 @@ function makeSliders(light) { } if (USE_INTENSITY_SLIDER === true) { - slidersRef.intensity = new entitySlider(light, WHITE, 'intensity', 4); + slidersRef.intensity = new entitySlider(light, WHITE, 'intensity', 'Intensity', 4); sliders.push(slidersRef.intensity); } if (USE_CUTOFF_SLIDER === true) { - slidersRef.cutoff = new entitySlider(light, PURPLE, 'cutoff', 5); + slidersRef.cutoff = new entitySlider(light, PURPLE, 'cutoff', 'Cutoff', 5); sliders.push(slidersRef.cutoff); } if (USE_EXPONENT_SLIDER === true) { - slidersRef.exponent = new entitySlider(light, ORANGE, 'exponent', 6); + slidersRef.exponent = new entitySlider(light, ORANGE, 'exponent', 'Exponent', 6); sliders.push(slidersRef.exponent); } @@ -419,6 +459,10 @@ function makeSliders(light) { if (SLIDERS_SHOULD_STAY_WITH_AVATAR === true) { parentPanelToAvatar(panel); } + + if (VISIBLE_PANEL === true) { + visiblePanel = createVisiblePanel(); + } }; function parentPanelToAvatar(panel) { @@ -430,6 +474,9 @@ function parentPanelToAvatar(panel) { }) } + +function updateAxisWhe + function parentEntitiesToPanel(panel) { sliders.forEach(function(slider) { @@ -467,6 +514,29 @@ function createPanelEntity(position) { return panel } +function createVisiblePanel(position) { + print('CREATING VISIBLE PANEL at ' + JSON.stringify(position)); + + var totalOffset = Vec3.multiply(sliders.length, PER_ROW_OFFSET); + var panelProperties = { + name: 'Hifi-Visible-Transparent-Panel', + type: 'Model', + modelURL: TRANSPARENT_PANEL_URL, + dimensions: { + x: 1, + y: 1.4, + z: 0.1 + }, + visible: true, + collisionsWillMove: false, + ignoreForCollisions: true, + position: position + } + + var panel = Entities.addEntity(panelProperties); + return panel +} + function createLightModel(position, rotation) { var blockProperties = { @@ -588,6 +658,7 @@ function handleValueMessages(channel, message, sender) { var currentLight; var block; +var oldParent = null; var hasParent = false; function handleLightOverlayRayCheckMessages(channel, message, sender) { @@ -615,6 +686,7 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { var lightProperties = Entities.getEntityProperties(lightID); if (lightProperties.parentID !== DEFAULT_PARENT_ID) { //this light has a parent already. so lets call our block the parent and then make sure not to delete it at the end; + oldParent = lightProperties.parentID; hasParent = true; block = lightProperties.parentID; if (lightProperties.parentJointIndex !== -1) { @@ -657,8 +729,8 @@ function handleCleanupMessages(channel, message, sender) { } } -function updateSliderAxis(){ - sliders.forEach(function(slider){ +function updateSliderAxis() { + sliders.forEach(function(slider) { }) } @@ -675,9 +747,16 @@ function cleanup(fromMessage) { } //if the light was already parented to something we will want to restore that. or come up with groups or something clever. - Entities.editEntity(currentLight, { - parentID: null, - }); + if (oldParent !== null) { + Entities.editEntity(currentLight, { + parentID: oldParent, + }); + } else { + Entities.editEntity(currentLight, { + parentID: null, + }); + } + if (fromMessage !== true) { Messages.messageReceived.disconnect(handleLightModMessages); @@ -687,11 +766,15 @@ function cleanup(fromMessage) { } + Entities.deleteEntity(panel); + Entities.deleteEntity(visiblePanel); + selectionManager.clearSelections(); Script.update.disconnect(rotateCloseButtons); if (hasParent === false) { Entities.deleteEntity(block); } + oldParent = null; hasParent = false; currentLight = null; From aa0d1f0c29a0ae6e14b0bac03307ed218cd84b6e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 22 Dec 2015 17:15:23 -0800 Subject: [PATCH 156/209] temp --- examples/light_modifier/lightModifier.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 4e0507b69f..a347aeadb0 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -10,8 +10,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// todo: text labels for property names, panel plane for visibility - //some experimental options var ONLY_I_CAN_EDIT = false; var SLIDERS_SHOULD_STAY_WITH_AVATAR = false; @@ -514,23 +512,23 @@ function createPanelEntity(position) { return panel } -function createVisiblePanel(position) { +function createVisiblePanel() { print('CREATING VISIBLE PANEL at ' + JSON.stringify(position)); - var totalOffset = Vec3.multiply(sliders.length, PER_ROW_OFFSET); + var totalOffset = -PER_ROW_OFFSET.y * sliders.length; var panelProperties = { name: 'Hifi-Visible-Transparent-Panel', type: 'Model', modelURL: TRANSPARENT_PANEL_URL, dimensions: { x: 1, - y: 1.4, + y: totalOffset, z: 0.1 }, visible: true, collisionsWillMove: false, ignoreForCollisions: true, - position: position + position: this.basePosition } var panel = Entities.addEntity(panelProperties); From 68c6cae4f3069fe3680f6bccb1865afd958fa5fe Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 22 Dec 2015 17:21:25 -0800 Subject: [PATCH 157/209] fix warning --- plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h index bc474634e5..cd1177b581 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h @@ -56,9 +56,9 @@ private: mat4 _eyeProjections[3]; mat4 _compositeEyeProjections[2]; uvec2 _desiredFramebufferSize; - ovrTexture _eyeTextures[2]; - mutable int _hmdScreen{ -1 }; - bool _hswDismissed{ false }; + //ovrTexture _eyeTextures[2]; // FIXME - not currently in use + mutable int _hmdScreen { -1 }; + bool _hswDismissed { false }; }; From 6afe3bae5ecfe0bb7096391a29e8d7ce26326591 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 22 Dec 2015 17:21:33 -0800 Subject: [PATCH 158/209] Copy Neuron joints into controller poses This makes the accessible for controller mapping and to JavaScript. Added 'neuronAvatar.js' as an example of reading joints from the neuron and setting them on the avatar. NOTE: the rotations are currently in the wrong coordinate frame. --- examples/controllers/neuron/neuronAvatar.js | 141 ++++++++++++ libraries/animation/src/Rig.cpp | 6 +- .../src/controllers/StandardControls.h | 61 +++++- plugins/hifiNeuron/src/NeuronPlugin.cpp | 205 ++++++++++++++++-- plugins/hifiNeuron/src/NeuronPlugin.h | 21 +- 5 files changed, 400 insertions(+), 34 deletions(-) create mode 100644 examples/controllers/neuron/neuronAvatar.js diff --git a/examples/controllers/neuron/neuronAvatar.js b/examples/controllers/neuron/neuronAvatar.js new file mode 100644 index 0000000000..a7146e0759 --- /dev/null +++ b/examples/controllers/neuron/neuronAvatar.js @@ -0,0 +1,141 @@ +// maps controller joint names to avatar joint names +var JOINT_NAME_MAP = { + HipsPosition: "", + Hips: "Hips", + RightUpLeg: "RightUpLeg", + RightLeg: "RightLeg", + RightFoot: "RightFoot", + LeftUpLeg: "LeftUpLeg", + LeftLeg: "LeftLeg", + LeftFoot: "LeftFoot", + Spine: "Spine", + Spine1: "Spine1", + Spine2: "Spine2", + Spine3: "Spine3", + Neck: "Neck", + Head: "Head", + RightShoulder: "RightShoulder", + RightArm: "RightArm", + RightForeArm: "RightForeArm", + RightHand: "RightHand", + RightHandThumb1: "RightHandThumb2", + RightHandThumb2: "RightHandThumb3", + RightHandThumb3: "RightHandThumb4", + RightInHandIndex: "RightHandIndex1", + RightHandIndex1: "RightHandIndex2", + RightHandIndex2: "RightHandIndex3", + RightHandIndex3: "RightHandIndex4", + RightInHandMiddle: "RightHandMiddle1", + RightHandMiddle1: "RightHandMiddle2", + RightHandMiddle2: "RightHandMiddle3", + RightHandMiddle3: "RightHandMiddle4", + RightInHandRing: "RightHandRing1", + RightHandRing1: "RightHandRing2", + RightHandRing2: "RightHandRing3", + RightHandRing3: "RightHandRing4", + RightInHandPinky: "RightHandPinky1", + RightHandPinky1: "RightHandPinky2", + RightHandPinky2: "RightHandPinky3", + RightHandPinky3: "RightHandPinky4", + LeftShoulder: "LeftShoulder", + LeftArm: "LeftArm", + LeftForeArm: "LeftForeArm", + LeftHand: "LeftHand", + LeftHandThumb1: "LeftHandThumb2", + LeftHandThumb2: "LeftHandThumb3", + LeftHandThumb3: "LeftHandThumb4", + LeftInHandIndex: "LeftHandIndex1", + LeftHandIndex1: "LeftHandIndex2", + LeftHandIndex2: "LeftHandIndex3", + LeftHandIndex3: "LeftHandIndex4", + LeftInHandMiddle: "LeftHandMiddle1", + LeftHandMiddle1: "LeftHandMiddle2", + LeftHandMiddle2: "LeftHandMiddle3", + LeftHandMiddle3: "LeftHandMiddle4", + LeftInHandRing: "LeftHandRing1", + LeftHandRing1: "LeftHandRing2", + LeftHandRing2: "LeftHandRing3", + LeftHandRing3: "LeftHandRing4", + LeftInHandPinky: "LeftHandPinky1", + LeftHandPinky1: "LeftHandPinky2", + LeftHandPinky2: "LeftHandPinky3", + LeftHandPinky3: "LeftHandPinky4" +}; + +function dumpHardwareMapping() { + Object.keys(Controller.Hardware).forEach(function (deviceName) { + Object.keys(Controller.Hardware[deviceName]).forEach(function (input) { + print("Controller.Hardware." + deviceName + "." + input + ":" + Controller.Hardware[deviceName][input]); + }); + }); +} + +// ctor +function NeuronAvatar() { + var self = this; + Script.scriptEnding.connect(function () { + self.shutdown(); + }); + Controller.hardwareChanged.connect(function () { + self.hardwareChanged(); + }); + + if (Controller.Hardware.Neuron) { + this.activate(); + } else { + this.deactivate(); + } +} + +NeuronAvatar.prototype.shutdown = function () { + this.deactivate(); +}; + +NeuronAvatar.prototype.hardwareChanged = function () { + if (Controller.Hardware.Neuron) { + this.activate(); + } else { + this.deactivate(); + } +}; + +NeuronAvatar.prototype.activate = function () { + if (!this._active) { + Script.update.connect(updateCallback); + } + this._active = true; +}; + +NeuronAvatar.prototype.deactivate = function () { + if (this._active) { + var self = this; + Script.update.disconnect(updateCallback); + } + this._active = false; + MyAvatar.clearJointsData(); +}; + +NeuronAvatar.prototype.update = function (deltaTime) { + var keys = Object.keys(JOINT_NAME_MAP); + var i, l = keys.length; + for (i = 0; i < l; i++) { + var channel = Controller.Hardware.Neuron[keys[i]]; + if (channel) { + var pose = Controller.getPoseValue(channel); + var j = MyAvatar.getJointIndex(JOINT_NAME_MAP[keys[i]]); + var defaultRot = MyAvatar.getDefaultJointRotation(j); + if (keys[i] == "Hips") { + MyAvatar.setJointRotation(j, Quat.multiply(pose.rotation, defaultRot)); + } else { + MyAvatar.setJointRotation(j, defaultRot); + } + } + } +}; + +var neuronAvatar = new NeuronAvatar(); + +function updateCallback(deltaTime) { + neuronAvatar.update(deltaTime); +} + diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 68f382d2d9..4dd091f1d6 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -289,8 +289,10 @@ void Rig::clearJointState(int index) { void Rig::clearJointStates() { _internalPoseSet._overrideFlags.clear(); - _internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints()); - _internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses(); + if (_animSkeleton) { + _internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints()); + _internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses(); + } } void Rig::clearJointAnimationPriority(int index) { diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h index bbd33c5cb3..feed8a0fad 100644 --- a/libraries/controllers/src/controllers/StandardControls.h +++ b/libraries/controllers/src/controllers/StandardControls.h @@ -88,9 +88,66 @@ namespace controller { // No correlation to SDL enum StandardPoseChannel { - LEFT_HAND = 0, - RIGHT_HAND, + HIPS_ROOT = 0, + HIPS, + RIGHT_UP_LEG, + RIGHT_LEG, + RIGHT_FOOT, + LEFT_UP_LEG, + LEFT_LEG, + LEFT_FOOT, + SPINE, + SPINE1, + SPINE2, + SPINE3, + NECK, HEAD, + RIGHT_SHOULDER, + RIGHT_ARM, + RIGHT_FORE_ARM, + RIGHT_HAND, + RIGHT_HAND_THUMB1, + RIGHT_HAND_THUMB2, + RIGHT_HAND_THUMB3, + RIGHT_IN_HAND_INDEX, + RIGHT_HAND_INDEX1, + RIGHT_HAND_INDEX2, + RIGHT_HAND_INDEX3, + RIGHT_IN_HAND_MIDDLE, + RIGHT_HAND_MIDDLE1, + RIGHT_HAND_MIDDLE2, + RIGHT_HAND_MIDDLE3, + RIGHT_IN_HANDRING, + RIGHT_HAND_RING1, + RIGHT_HAND_RING2, + RIGHT_HAND_RING3, + RIGHT_IN_HAND_PINKY, + RIGHT_HAND_PINKY1, + RIGHT_HAND_PINKY2, + RIGHT_HAND_PINKY3, + LEFT_SHOULDER, + LEFT_ARM, + LEFT_FORE_ARM, + LEFT_HAND, + LEFT_HAND_THUMB1, + LEFT_HAND_THUMB2, + LEFT_HAND_THUMB3, + LEFT_IN_HAND_INDEX, + LEFT_HAND_INDEX1, + LEFT_HAND_INDEX2, + LEFT_HAND_INDEX3, + LEFT_IN_HAND_MIDDLE, + LEFT_HAND_MIDDLE1, + LEFT_HAND_MIDDLE2, + LEFT_HAND_MIDDLE3, + LEFT_IN_HAND_RING, + LEFT_HAND_RING1, + LEFT_HAND_RING2, + LEFT_HAND_RING3, + LEFT_IN_HAND_PINKY, + LEFT_HAND_PINKY1, + LEFT_HAND_PINKY2, + LEFT_HAND_PINKY3, NUM_STANDARD_POSES }; diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index c3f764da05..4f52d8da98 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -1,5 +1,5 @@ // -// NeuronPlugin.h +// NeuronPlugin.cpp // input-plugins/src/input-plugins // // Created by Anthony Thibault on 12/18/2015. @@ -11,6 +11,7 @@ #include "NeuronPlugin.h" +#include #include #include #include @@ -27,6 +28,7 @@ Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") const QString NeuronPlugin::NAME = "Neuron"; const QString NeuronPlugin::NEURON_ID_STRING = "Perception Neuron"; +// This matches controller::StandardPoseChannel enum JointIndex { HipsPosition = 0, Hips, @@ -87,7 +89,8 @@ enum JointIndex { LeftInHandPinky, LeftHandPinky1, LeftHandPinky2, - LeftHandPinky3 + LeftHandPinky3, + Size }; bool NeuronPlugin::isSupported() const { @@ -98,29 +101,81 @@ bool NeuronPlugin::isSupported() const { // NOTE: must be thread-safe void FrameDataReceivedCallback(void* context, SOCKET_REF sender, BvhDataHeaderEx* header, float* data) { - qCDebug(inputplugins) << "NeuronPlugin: received frame data, DataCount = " << header->DataCount; auto neuronPlugin = reinterpret_cast(context); - std::lock_guard guard(neuronPlugin->_jointsMutex); - // Data is 6 floats: 3 position values, 3 rotation euler angles (degrees) + // version 1.0 + if (header->DataVersion.Major == 1 && header->DataVersion.Minor == 0) { - // resize vector if necessary - const size_t NUM_FLOATS_PER_JOINT = 6; - const size_t NUM_JOINTS = header->DataCount / NUM_FLOATS_PER_JOINT; - if (neuronPlugin->_joints.size() != NUM_JOINTS) { - neuronPlugin->_joints.resize(NUM_JOINTS, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); + std::lock_guard guard(neuronPlugin->_jointsMutex); + + // Data is 6 floats: 3 position values, 3 rotation euler angles (degrees) + + // resize vector if necessary + const size_t NUM_FLOATS_PER_JOINT = 6; + const size_t NUM_JOINTS = header->DataCount / NUM_FLOATS_PER_JOINT; + if (neuronPlugin->_joints.size() != NUM_JOINTS) { + neuronPlugin->_joints.resize(NUM_JOINTS, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); + } + + assert(sizeof(NeuronPlugin::NeuronJoint) == (NUM_FLOATS_PER_JOINT * sizeof(float))); + + // copy the data + memcpy(&(neuronPlugin->_joints[0]), data, sizeof(NeuronPlugin::NeuronJoint) * NUM_JOINTS); + + } else { + static bool ONCE = false; + if (!ONCE) { + qCCritical(inputplugins) << "NeuronPlugin: bad frame version number, expected 1.0"; + ONCE = true; + } } - - assert(sizeof(NeuronPlugin::NeuronJoint) == (NUM_FLOATS_PER_JOINT * sizeof(float))); - - // copy the data - memcpy(&(neuronPlugin->_joints[0]), data, sizeof(NeuronPlugin::NeuronJoint) * NUM_JOINTS); } // NOTE: must be thread-safe static void CommandDataReceivedCallback(void* context, SOCKET_REF sender, CommandPack* pack, void* data) { + DATA_VER version; + version._VersionMask = pack->DataVersion; + if (version.Major == 1 && version.Minor == 0) { + const char* str = "Unknown"; + switch (pack->CommandId) { + case Cmd_BoneSize: // Id can be used to request bone size from server or register avatar name command. + str = "BoneSize"; + break; + case Cmd_AvatarName: // Id can be used to request avatar name from server or register avatar name command. + str = "AvatarName"; + break; + case Cmd_FaceDirection: // Id used to request face direction from server + str = "FaceDirection"; + break; + case Cmd_DataFrequency: // Id can be used to request data frequency from server or register data frequency command. + str = "DataFrequency"; + break; + case Cmd_BvhInheritanceTxt: // Id can be used to request bvh header txt from server or register bvh header txt command. + str = "BvhInheritanceTxt"; + break; + case Cmd_AvatarCount: // Id can be used to request avatar count from server or register avatar count command. + str = "AvatarCount"; + break; + case Cmd_CombinationMode: // Id can be used to request combination mode from server or register combination mode command. + str = "CombinationMode"; + break; + case Cmd_RegisterEvent: // Id can be used to register event. + str = "RegisterEvent"; + break; + case Cmd_UnRegisterEvent: // Id can be used to unregister event. + str = "UnRegisterEvent"; + break; + } + qCDebug(inputplugins) << "NeuronPlugin: command data received CommandID = " << str; + } else { + static bool ONCE = false; + if (!ONCE) { + qCCritical(inputplugins) << "NeuronPlugin: bad command version number, expected 1.0"; + ONCE = true; + } + } } // NOTE: must be thread-safe @@ -130,6 +185,11 @@ static void SocketStatusChangedCallback(void* context, SOCKET_REF sender, Socket void NeuronPlugin::activate() { InputPlugin::activate(); + + // register with userInputMapper + auto userInputMapper = DependencyManager::get(); + userInputMapper->registerDevice(_inputDevice); + qCDebug(inputplugins) << "NeuronPlugin::activate"; // register c-style callbacks @@ -149,12 +209,18 @@ void NeuronPlugin::activate() { } void NeuronPlugin::deactivate() { - // TODO: qCDebug(inputplugins) << "NeuronPlugin::deactivate"; + // unregister from userInputMapper + if (_inputDevice->_deviceID != controller::Input::INVALID_DEVICE) { + auto userInputMapper = DependencyManager::get(); + userInputMapper->removeDevice(_inputDevice->_deviceID); + } + if (_socketRef) { BRCloseSocket(_socketRef); } + InputPlugin::deactivate(); } @@ -174,12 +240,14 @@ void NeuronPlugin::pluginUpdate(float deltaTime, bool jointsCaptured) { joints = _joints; } + /* DebugDraw::getInstance().addMyAvatarMarker("LEFT_FOOT", - eulerToQuat(joints[6].rot), + eulerToQuat(joints[6].euler), joints[6].pos / 100.0f, glm::vec4(1)); - - _inputDevice->update(deltaTime, jointsCaptured); + */ + _inputDevice->update(deltaTime, joints, _prevJoints); + _prevJoints = joints; } void NeuronPlugin::saveSettings() const { @@ -198,11 +266,86 @@ void NeuronPlugin::loadSettings() { // InputDevice // +static controller::StandardPoseChannel neuronJointIndexToPoseIndex(JointIndex i) { + // Currently they are the same. + // but that won't always be the case... + return (controller::StandardPoseChannel)i; +} + +static const char* neuronJointName(JointIndex i) { + switch (i) { + case HipsPosition: return "HipsPosition"; + case Hips: return "Hips"; + case RightUpLeg: return "RightUpLeg"; + case RightLeg: return "RightLeg"; + case RightFoot: return "RightFoot"; + case LeftUpLeg: return "LeftUpLeg"; + case LeftLeg: return "LeftLeg"; + case LeftFoot: return "LeftFoot"; + case Spine: return "Spine"; + case Spine1: return "Spine1"; + case Spine2: return "Spine2"; + case Spine3: return "Spine3"; + case Neck: return "Neck"; + case Head: return "Head"; + case RightShoulder: return "RightShoulder"; + case RightArm: return "RightArm"; + case RightForeArm: return "RightForeArm"; + case RightHand: return "RightHand"; + case RightHandThumb1: return "RightHandThumb1"; + case RightHandThumb2: return "RightHandThumb2"; + case RightHandThumb3: return "RightHandThumb3"; + case RightInHandIndex: return "RightInHandIndex"; + case RightHandIndex1: return "RightHandIndex1"; + case RightHandIndex2: return "RightHandIndex2"; + case RightHandIndex3: return "RightHandIndex3"; + case RightInHandMiddle: return "RightInHandMiddle"; + case RightHandMiddle1: return "RightHandMiddle1"; + case RightHandMiddle2: return "RightHandMiddle2"; + case RightHandMiddle3: return "RightHandMiddle3"; + case RightInHandRing: return "RightInHandRing"; + case RightHandRing1: return "RightHandRing1"; + case RightHandRing2: return "RightHandRing2"; + case RightHandRing3: return "RightHandRing3"; + case RightInHandPinky: return "RightInHandPinky"; + case RightHandPinky1: return "RightHandPinky1"; + case RightHandPinky2: return "RightHandPinky2"; + case RightHandPinky3: return "RightHandPinky3"; + case LeftShoulder: return "LeftShoulder"; + case LeftArm: return "LeftArm"; + case LeftForeArm: return "LeftForeArm"; + case LeftHand: return "LeftHand"; + case LeftHandThumb1: return "LeftHandThumb1"; + case LeftHandThumb2: return "LeftHandThumb2"; + case LeftHandThumb3: return "LeftHandThumb3"; + case LeftInHandIndex: return "LeftInHandIndex"; + case LeftHandIndex1: return "LeftHandIndex1"; + case LeftHandIndex2: return "LeftHandIndex2"; + case LeftHandIndex3: return "LeftHandIndex3"; + case LeftInHandMiddle: return "LeftInHandMiddle"; + case LeftHandMiddle1: return "LeftHandMiddle1"; + case LeftHandMiddle2: return "LeftHandMiddle2"; + case LeftHandMiddle3: return "LeftHandMiddle3"; + case LeftInHandRing: return "LeftInHandRing"; + case LeftHandRing1: return "LeftHandRing1"; + case LeftHandRing2: return "LeftHandRing2"; + case LeftHandRing3: return "LeftHandRing3"; + case LeftInHandPinky: return "LeftInHandPinky"; + case LeftHandPinky1: return "LeftHandPinky1"; + case LeftHandPinky2: return "LeftHandPinky2"; + case LeftHandPinky3: return "LeftHandPinky3"; + default: return "???"; + } +} + controller::Input::NamedVector NeuronPlugin::InputDevice::getAvailableInputs() const { // TODO: - static const controller::Input::NamedVector availableInputs { - makePair(controller::LEFT_HAND, "LeftHand"), - makePair(controller::RIGHT_HAND, "RightHand") + static controller::Input::NamedVector availableInputs; + + if (availableInputs.size() == 0) { + for (int i = 0; i < JointIndex::Size; i++) { + availableInputs.push_back(makePair(neuronJointIndexToPoseIndex((JointIndex)i), neuronJointName((JointIndex)i))); + } }; return availableInputs; } @@ -212,8 +355,24 @@ QString NeuronPlugin::InputDevice::getDefaultMappingConfig() const { return MAPPING_JSON; } -void NeuronPlugin::InputDevice::update(float deltaTime, bool jointsCaptured) { +void NeuronPlugin::InputDevice::update(float deltaTime, const std::vector& joints, const std::vector& prevJoints) { + for (int i = 0; i < joints.size(); i++) { + int poseIndex = neuronJointIndexToPoseIndex((JointIndex)i); + glm::vec3 linearVel, angularVel; + glm::vec3 pos = (joints[i].pos * METERS_PER_CENTIMETER); + glm::quat rot = eulerToQuat(joints[i].euler); + if (i < prevJoints.size()) { + linearVel = (pos - (prevJoints[i].pos * METERS_PER_CENTIMETER)) / deltaTime; + // quat log imag part points along the axis of rotation, and it's length will be the half angle. + glm::quat d = glm::log(rot * glm::inverse(eulerToQuat(prevJoints[i].euler))); + angularVel = glm::vec3(d.x, d.y, d.z) / (0.5f * deltaTime); + } + _poseStateMap[poseIndex] = controller::Pose(pos, rot, linearVel, angularVel); + if (glm::length(angularVel) > 0.5f) { + qCDebug(inputplugins) << "Movement in joint" << i << neuronJointName((JointIndex)i); + } + } } void NeuronPlugin::InputDevice::focusOutEvent() { diff --git a/plugins/hifiNeuron/src/NeuronPlugin.h b/plugins/hifiNeuron/src/NeuronPlugin.h index 5f67502e04..f787838ce2 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.h +++ b/plugins/hifiNeuron/src/NeuronPlugin.h @@ -41,15 +41,25 @@ public: virtual void loadSettings() override; protected: + + struct NeuronJoint { + glm::vec3 pos; + glm::vec3 euler; + }; + class InputDevice : public controller::InputDevice { public: + friend class NeuronPlugin; + InputDevice() : controller::InputDevice("Neuron") {} // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; virtual QString getDefaultMappingConfig() const override; - virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void update(float deltaTime, bool jointsCaptured) override {}; virtual void focusOutEvent() override; + + void update(float deltaTime, const std::vector& joints, const std::vector& prevJoints); }; std::shared_ptr _inputDevice { std::make_shared() }; @@ -61,13 +71,10 @@ protected: int _serverPort; void* _socketRef; - struct NeuronJoint { - glm::vec3 pos; - glm::vec3 rot; - }; - std::vector _joints; - std::mutex _jointsMutex; + std::mutex _jointsMutex; // used to guard access to _joints + + std::vector _prevJoints; }; #endif // hifi_NeuronPlugin_h From 4115138b5b9920d615420dd81cce9ee86eee82f4 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 22 Dec 2015 17:22:55 -0800 Subject: [PATCH 159/209] fix merge problems --- examples/controllers/handControllerGrab.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 04b52ebb50..9e7623b483 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -274,8 +274,6 @@ function MyController(hand) { this.triggerValue = 0; // rolling average of trigger value this.rawTriggerValue = 0; this.rawBumperValue = 0; - -<<<<<<< HEAD //for visualizations this.overlayLine = null; this.particleBeam = null; @@ -283,9 +281,7 @@ function MyController(hand) { //for lights this.spotlight = null; this.pointlight = null; -======= this.overlayLine = null; ->>>>>>> master this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; @@ -510,7 +506,7 @@ function MyController(hand) { "y": 0, "z": 0 }, - "particleRadius": 0.015, + "particleRadius": 0.015, "radiusSpread": 0.005, // "radiusStart": 0.01, // "radiusFinish": 0.01, @@ -539,7 +535,7 @@ function MyController(hand) { visible: true, color: color, emitSpeed: speed, - speedSpread:spread, + speedSpread: spread, lifespan: lifespan }) @@ -1085,7 +1081,6 @@ function MyController(hand) { this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); - // mix in head motion if (MOVE_WITH_HEAD) { var objDistance = Vec3.length(objectToAvatar); @@ -1113,8 +1108,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) - // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); From ea9f2e57cea6797bfb790344f462e0652ec00fe8 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 23 Dec 2015 13:08:46 -0800 Subject: [PATCH 160/209] Simplify renderDebug GUI --- examples/utilities/tools/cookies.js | 6 +- examples/utilities/tools/renderEngineDebug.js | 70 +++++++------------ 2 files changed, 30 insertions(+), 46 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index edb0fb4330..0e08f80d0e 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -814,12 +814,14 @@ var CHECK_MARK_COLOR = { }); }; - CollapsablePanelItem.prototype.destroy = function() { Overlays.deleteOverlay(this.title); Overlays.deleteOverlay(this.thumb); }; + CollapsablePanelItem.prototype.editTitle = function(opts) { + Overlays.editOverlay(this.title, opts); + }; CollapsablePanelItem.prototype.hide = function() { Overlays.editOverlay(this.title, { @@ -1531,4 +1533,4 @@ Controller.captureKeyEvents({ }); Controller.captureKeyEvents({ text: "right" -}); \ No newline at end of file +}); diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index cc04ddd8a2..3e619dbd5a 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -21,56 +21,34 @@ Number.prototype.clamp = function(min, max) { var panel = new Panel(10, 100); -function CounterWidget(parentPanel, name, feedGetter, drawGetter, capSetter, capGetter) { - this.subPanel = parentPanel.newSubPanel(name); +function CounterWidget(parentPanel, name, counter) { + var subPanel = parentPanel.newSubPanel(name); + var widget = parentPanel.items[name]; + widget.editTitle({ width: 270 }); - this.subPanel.newSlider("Num Feed", 0, 1, - function(value) { }, - feedGetter, - function(value) { return (value); }); - this.subPanel.newSlider("Num Drawn", 0, 1, - function(value) { }, - drawGetter, - function(value) { return (value); }); - this.subPanel.newSlider("Max Drawn", -1, 1, - capSetter, - capGetter, - function(value) { return (value); }); + subPanel.newSlider('Max Drawn', -1, 1, + function(value) { counter.maxDrawn = value; }, // setter + function() { return counter.maxDrawn; }, // getter + function(value) { return value; }); + + var slider = subPanel.getWidget('Max Drawn'); this.update = function () { - var numFeed = this.subPanel.get("Num Feed"); - var numDrawn = this.subPanel.get("Num Drawn"); - var numMax = Math.max(numFeed, 1); + var numDrawn = counter.numDrawn; // avoid double polling + var numMax = Math.max(numDrawn, 1); + var title = [ + ' ' + name, + numDrawn + ' / ' + counter.numFeed + ].join('\t'); - this.subPanel.set("Num Feed", numFeed); - this.subPanel.set("Num Drawn", numDrawn); - - this.subPanel.getWidget("Num Feed").setMaxValue(numMax); - this.subPanel.getWidget("Num Drawn").setMaxValue(numMax); - this.subPanel.getWidget("Max Drawn").setMaxValue(numMax); + widget.editTitle({ text: title }); + slider.setMaxValue(numMax); }; }; -var opaquesCounter = new CounterWidget(panel, "Opaques", - function () { return Render.opaque.numFeed; }, - function () { return Render.opaque.numDrawn; }, - function(value) { Render.opaque.maxDrawn = value; }, - function () { return Render.opaque.maxDrawn; } -); - -var transparentsCounter = new CounterWidget(panel, "Transparents", - function () { return Render.transparent.numFeed; }, - function () { return Render.transparent.numDrawn; }, - function(value) { Render.transparent.maxDrawn = value; }, - function () { return Render.transparent.maxDrawn; } -); - -var overlaysCounter = new CounterWidget(panel, "Overlays", - function () { return Render.overlay3D.numFeed; }, - function () { return Render.overlay3D.numDrawn; }, - function(value) { Render.overlay3D.maxDrawn = value; }, - function () { return Render.overlay3D.maxDrawn; } -); +var opaquesCounter = new CounterWidget(panel, "Opaques", Render.opaque); +var transparentsCounter = new CounterWidget(panel, "Transparents", Render.transparent); +var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D); var resizing = false; var previousMode = Settings.getValue(SETTINGS_KEY, -1); @@ -162,9 +140,13 @@ Menu.menuItemEvent.connect(menuItemEvent); function scriptEnding() { panel.destroy(); Menu.removeActionGroup(MENU); + // Reset Settings.setValue(SETTINGS_KEY, Render.deferredDebugMode); Render.deferredDebugMode = -1; - Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size + Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; + Render.opaque.maxDrawn = -1; + Render.transparent.maxDrawn = -1; + Render.overlay3D.maxDrawn = -1; } Script.scriptEnding.connect(scriptEnding); From 2c72e7964d4d9eb2ebdf11152ffe638582c43aa8 Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Wed, 23 Dec 2015 13:53:35 -0800 Subject: [PATCH 161/209] Fix assignment --- examples/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 8903b773c9..e0a7c55af8 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1637,7 +1637,7 @@ handleHandMessages = function(channel, message, sender) { handToDisable = RIGHT_HAND; } if (message === 'both' || message === 'none') { - handToDisable = handToDisable; + handToDisable = message; } } else if (channel === 'Hifi-Hand-Grab') { try { From 65d5e3f60a3a919fd0d0ee00357ce4e2f0e62e3f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 23 Dec 2015 14:11:42 -0800 Subject: [PATCH 162/209] add labels and transparent panel, but panel blocks pick so disable --- examples/light_modifier/lightModifier.js | 83 ++++++++++++++++++++---- 1 file changed, 69 insertions(+), 14 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index a347aeadb0..dc9332405e 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -17,8 +17,10 @@ var VERTICAL_SLIDERS = false; var SHOW_OVERLAYS = true; var SHOW_LIGHT_VOLUME = true; var USE_PARENTED_PANEL = true; -var VISIBLE_PANEL = true; +var VISIBLE_PANEL = false; var USE_LABELS = true; +var LEFT_LABELS = false; +var RIGHT_LABELS = true; //variables for managing overlays var selectionDisplay; @@ -134,6 +136,8 @@ var slidersRef = { }; var light = null; +var basePosition; +var avatarRotation; function entitySlider(light, color, sliderType, displayText, row) { this.light = light; @@ -146,6 +150,8 @@ function entitySlider(light, color, sliderType, displayText, row) { this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); this.basePosition.y += 1; + basePosition=this.basePosition; + avatarRot = this.avatarRot; var message = { lightID: this.lightID, @@ -213,6 +219,8 @@ entitySlider.prototype = { this.axisStart = position; this.endOfAxis = Vec3.sum(position, extension); + this.createEndOfAxisEntity(); + var properties = { type: 'Line', name: 'Hifi-Slider-Axis::' + this.sliderType, @@ -235,16 +243,59 @@ entitySlider.prototype = { this.axis = Entities.addEntity(properties); }, + createEndOfAxisEntity: function() { + //we use this to track the end of the axis while parented to a panel + var properties = { + name: 'Hifi-End-Of-Axis', + type: 'Box', + collisionsWillMove: false, + ignoreForCollisions: true, + dimensions: { + x: 0.01, + y: 0.01, + z: 0.01 + }, + color: { + red: 255, + green: 255, + blue: 255 + }, + position: this.endOfAxis, + parentID:this.axis, + visible: false + } + + this.endOfAxisEntity = Entities.addEntity(this.endOfAxis); + }, createLabel: function() { + var LABEL_WIDTH = 0.25 - var leftVector = Vec.multiply(-1, Quat.getRight(this.avatarRot)); - var extension = Vec3.multiply(LABEL_WIDTH, leftVector); - var position = Vec3.sum(this.axisStart, extension); + var PER_LETTER_SPACING = 0.1; + var textWidth = this.displayText.length * PER_LETTER_SPACING; + + var position; + if (LEFT_LABELS === true) { + var leftVector = Vec3.multiply(-1, Quat.getRight(this.avatarRot)); + + var extension = Vec3.multiply(textWidth, leftVector); + + position = Vec3.sum(this.axisStart, extension); + } + + if (RIGHT_LABELS === true) { + var rightVector = Quat.getRight(this.avatarRot); + + var extension = Vec3.multiply(textWidth / 1.75, rightVector); + + position = Vec3.sum(this.endOfAxis, extension); + } + + var labelProperties = { name: 'Hifi-Slider-Label-' + this.sliderType, type: 'Text', dimensions: { - x: LABEL_WIDTH, + x: textWidth, y: 0.2, z: 0.1 }, @@ -260,10 +311,12 @@ entitySlider.prototype = { green: 0, blue: 0 }, - + position: position, + rotation:this.avatarRot, } - + print('BEFORE CREATE LABEL' + JSON.stringify(labelProperties)) this.label = Entities.addEntity(labelProperties); + print('AFTER CREATE LABEL') }, createSliderIndicator: function() { var extensionVector; @@ -473,8 +526,6 @@ function parentPanelToAvatar(panel) { } -function updateAxisWhe - function parentEntitiesToPanel(panel) { sliders.forEach(function(slider) { @@ -513,22 +564,25 @@ function createPanelEntity(position) { } function createVisiblePanel() { - print('CREATING VISIBLE PANEL at ' + JSON.stringify(position)); - var totalOffset = -PER_ROW_OFFSET.y * sliders.length; + + var moveRight =Vec3.sum(basePosition,Vec3.multiply(AXIS_SCALE/2,Quat.getRight(avatarRot))); + + var moveDown = Vec3.sum(moveRight,Vec3.multiply((sliders.length+1)/2,PER_ROW_OFFSET)) var panelProperties = { name: 'Hifi-Visible-Transparent-Panel', type: 'Model', modelURL: TRANSPARENT_PANEL_URL, dimensions: { - x: 1, + x: AXIS_SCALE+0.1, y: totalOffset, - z: 0.1 + z: SLIDER_DIMENSIONS.z/4 }, visible: true, collisionsWillMove: false, ignoreForCollisions: true, - position: this.basePosition + position: moveDown, + rotation:avatarRot } var panel = Entities.addEntity(panelProperties); @@ -738,6 +792,7 @@ function cleanup(fromMessage) { for (i = 0; i < sliders.length; i++) { Entities.deleteEntity(sliders[i].axis); Entities.deleteEntity(sliders[i].sliderIndicator); + Entities.deleteEntity(sliders[i].label); } while (closeButtons.length > 0) { From f8a515de64fd51ca2297c969145aa3a68ba6a709 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 23 Dec 2015 14:46:18 -0800 Subject: [PATCH 163/209] add a test script for HMD.getHUDLookAtPositionXX() --- .../controllers/getHUDLookAtPositionTest.js | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 examples/controllers/getHUDLookAtPositionTest.js diff --git a/examples/controllers/getHUDLookAtPositionTest.js b/examples/controllers/getHUDLookAtPositionTest.js new file mode 100644 index 0000000000..348b6757b8 --- /dev/null +++ b/examples/controllers/getHUDLookAtPositionTest.js @@ -0,0 +1,54 @@ +// +// getHUDLookAtPositionTest.js +// examples/controllers +// +// Created by Brad Hefta-Gaub on 2015/12/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +// This script demonstrates the testing of the HMD.getHUDLookAtPosition--() functions. +// If these functions are working correctly, we'd expect to see a 3D cube and a 2D square +// follow around the center of the HMD view. + +var cubePosition = { x: 0, y: 0, z: 0 }; +var cubeSize = 0.03; +var cube = Overlays.addOverlay("cube", { + position: cubePosition, + size: cubeSize, + color: { red: 255, green: 0, blue: 0}, + alpha: 1, + solid: false + }); + +var square = Overlays.addOverlay("text", { + x: 0, + y: 0, + width: 20, + height: 20, + color: { red: 255, green: 255, blue: 0}, + backgroundColor: { red: 255, green: 255, blue: 0}, + alpha: 1 + }); + + +Script.update.connect(function(deltaTime) { + if (!HMD.active) { + return; + } + var lookAt3D = HMD.getHUDLookAtPosition3D(); + Overlays.editOverlay(cube, { position: lookAt3D }); + + var lookAt2D = HMD.getHUDLookAtPosition2D(); + Overlays.editOverlay(square, { x: lookAt2D.x, y: lookAt2D.y }); +}); + +Script.scriptEnding.connect(function(){ + Overlays.deleteOverlay(cube); + Overlays.deleteOverlay(square); +}); + + From b4988b0998b0f5c40962cbd5fa4817294ee13cb4 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 23 Dec 2015 15:09:10 -0800 Subject: [PATCH 164/209] Taking individual avatar hand size into consideration for grabbing objects --- examples/controllers/handControllerGrab.js | 9 ++- examples/libraries/utils.js | 27 +++++++ unpublishedScripts/hiddenEntityReset.js | 67 +-------------- unpublishedScripts/masterReset.js | 94 +++++----------------- 4 files changed, 54 insertions(+), 143 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 9e7623b483..7afb687f6d 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -226,6 +226,9 @@ function getSpatialOffsetPosition(hand, spatialKey) { position = spatialKey.relativePosition; } + // add the relative hand center offset + var handSizeRatio = calculateHandSizeRatio(); + position = Vec3.multiply(position, handSizeRatio); return position; } @@ -1159,12 +1162,14 @@ function MyController(hand) { if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { // if an object is "equipped" and has a spatialKey, use it. this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - if (grabbableData.spatialKey.relativePosition) { + if (grabbableData.spatialKey.relativePosition || grabbableData.spatialKey.rightRelativePosition + || grabbableData.spatialKey.leftRelativePosition) { this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); } else { this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); } - if (grabbableData.spatialKey.relativeRotation) { + if (grabbableData.spatialKey.relativeRotation || grabbableData.spatialKey.rightRelativeRotation + || grabbableData.spatialKey.leftRelativeRotation) { this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); } else { this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); diff --git a/examples/libraries/utils.js b/examples/libraries/utils.js index 5d14bfb7dd..37dccd5ac8 100644 --- a/examples/libraries/utils.js +++ b/examples/libraries/utils.js @@ -271,3 +271,30 @@ hexToRgb = function(hex) { } : null; } +calculateHandSizeRatio = function() { + // Get the ratio of the current avatar's hand to Owen's hand + + // var standardCenterHandPoint = 0.11288; + var standardCenterHandPoint = 0.11288; + var jointNames = MyAvatar.getJointNames(); + //get distance from handJoint up to leftHandIndex3 as a proxy for center of hand + var wristToFingertipDistance = 0;; + for (var i = 0; i < jointNames.length; i++) { + var jointName = jointNames[i]; + print(jointName) + if (jointName.indexOf("LeftHandIndex") !== -1) { + // translations are relative to parent joint, so simply add them together + // joints face down the y-axis + var translation = MyAvatar.getDefaultJointTranslation(i).y; + wristToFingertipDistance += translation; + } + } + // Right now units are in cm, so convert to meters + wristToFingertipDistance /= 100; + + var centerHandPoint = wristToFingertipDistance/2; + + // Compare against standard hand (Owen) + var handSizeRatio = centerHandPoint/standardCenterHandPoint; + return handSizeRatio; +} diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 94d815796b..e8783bbbcb 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -169,7 +169,7 @@ } function createRaveStick(position) { - var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx"; + var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/raveStick.fbx"; var stick = Entities.addEntity({ type: "Model", name: "raveStick", @@ -205,71 +205,6 @@ } }) }); - var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0) - var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); - forwardVec = Vec3.normalize(forwardVec); - var forwardQuat = orientationOf(forwardVec); - position = Vec3.sum(position, Vec3.multiply(Quat.getFront(rotation), 0.1)); - position.z += 0.1; - position.x += -0.035; - var color = { - red: 0, - green: 200, - blue: 40 - }; - var props = { - type: "ParticleEffect", - position: position, - parentID: stick, - isEmitting: true, - name: "raveBeam", - colorStart: color, - colorSpread: { - red: 200, - green: 10, - blue: 10 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 1, - emitRate: 1000, - emitOrientation: forwardQuat, - emitSpeed: 0.2, - speedSpread: 0.0, - polarStart: 0, - polarFinish: 0.0, - azimuthStart: 0.1, - azimuthFinish: 0.01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: 0.00, - y: 0.00, - z: 0.00 - }, - radiusStart: 0.03, - radiusFinish: 0.025, - alpha: 0.7, - alphaSpread:0.1, - alphaStart: 0.5, - alphaFinish: 0.5, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: false, - userData: JSON.stringify({ - resetMe: { - resetMe: true - } - }) - } - var beam = Entities.addEntity(props); } diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 9afbd0a68b..f3c38b2adf 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -148,7 +148,7 @@ MasterReset = function() { } function createRaveStick(position) { - var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx"; + var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/raveStick.fbx"; var stick = Entities.addEntity({ type: "Model", name: "raveStick", @@ -173,10 +173,15 @@ MasterReset = function() { }, grabbableKey: { spatialKey: { - relativePosition: { - x: 0, + rightRelativePosition: { + x: 0.02, y: 0, - z: -0.1 + z: 0 + }, + leftRelativePosition: { + x: -0.02, + y: 0, + z: 0 }, relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) }, @@ -184,72 +189,6 @@ MasterReset = function() { } }) }); - var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0) - var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); - forwardVec = Vec3.normalize(forwardVec); - var forwardQuat = orientationOf(forwardVec); - position = Vec3.sum(position, Vec3.multiply(Quat.getFront(rotation), 0.1)); - position.z += 0.1; - position.x += -0.035; - var color = { - red: 0, - green: 200, - blue: 40 - }; - var props = { - type: "ParticleEffect", - position: position, - parentID: stick, - isEmitting: true, - name: "raveBeam", - colorStart: color, - colorSpread: { - red: 200, - green: 10, - blue: 10 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 1, - emitRate: 1000, - emitOrientation: forwardQuat, - emitSpeed: 0.2, - speedSpread: 0.0, - polarStart: 0, - polarFinish: 0.0, - azimuthStart: 0.1, - azimuthFinish: 0.01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: 0.00, - y: 0.00, - z: 0.00 - }, - radiusStart: 0.03, - radiusFinish: 0.025, - alpha: 0.7, - alphaSpread: 0.1, - alphaStart: 0.5, - alphaFinish: 0.5, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: false, - userData: JSON.stringify({ - resetMe: { - resetMe: true - } - }) - } - var beam = Entities.addEntity(props); - } function createGun(position) { @@ -283,10 +222,15 @@ MasterReset = function() { userData: JSON.stringify({ grabbableKey: { spatialKey: { - relativePosition: { - x: 0, + rightRelativePosition: { + x: 0.02, y: 0, - z: -0.1 + z: -0.03 + }, + leftRelativePosition: { + x: -0.02, + y: 0, + z: -0.03 }, relativeRotation: Quat.fromPitchYawRollDegrees(100, 90, 0) }, @@ -1136,9 +1080,9 @@ MasterReset = function() { grabbableKey: { spatialKey: { relativePosition: { - x: -0.05, + x: 0, y: 0, - z: 0.0 + z: .06 }, relativeRotation: Quat.fromPitchYawRollDegrees(0,-90, -90) }, From c44f69b370387b06ab16b27583aaf5940f3cf59d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 23 Dec 2015 17:13:52 -0800 Subject: [PATCH 165/209] WIP checkpoint Changed euler angle compisition based on experiments in maya. Also, the neuronAvatar.js attempts to transform the neuron input quaternions into a pose relative to the avatar's default pose, but doesn't it doesn't work. --- examples/controllers/neuron/neuronAvatar.js | 9 +++----- .../src/controllers/StandardControls.h | 3 +-- plugins/hifiNeuron/src/NeuronPlugin.cpp | 22 +++++++++++++------ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/examples/controllers/neuron/neuronAvatar.js b/examples/controllers/neuron/neuronAvatar.js index a7146e0759..776cabd301 100644 --- a/examples/controllers/neuron/neuronAvatar.js +++ b/examples/controllers/neuron/neuronAvatar.js @@ -1,6 +1,5 @@ // maps controller joint names to avatar joint names var JOINT_NAME_MAP = { - HipsPosition: "", Hips: "Hips", RightUpLeg: "RightUpLeg", RightLeg: "RightLeg", @@ -124,11 +123,9 @@ NeuronAvatar.prototype.update = function (deltaTime) { var pose = Controller.getPoseValue(channel); var j = MyAvatar.getJointIndex(JOINT_NAME_MAP[keys[i]]); var defaultRot = MyAvatar.getDefaultJointRotation(j); - if (keys[i] == "Hips") { - MyAvatar.setJointRotation(j, Quat.multiply(pose.rotation, defaultRot)); - } else { - MyAvatar.setJointRotation(j, defaultRot); - } + var rot = Quat.multiply(Quat.inverse(defaultRot), Quat.multiply(pose.rotation, defaultRot)); + MyAvatar.setJointRotation(j, Quat.multiply(defaultRot, rot)); + //MyAvatar.setJointTranslation(j, Vec3.multiply(100.0, pose.translation)); } } }; diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h index feed8a0fad..4294713238 100644 --- a/libraries/controllers/src/controllers/StandardControls.h +++ b/libraries/controllers/src/controllers/StandardControls.h @@ -88,8 +88,7 @@ namespace controller { // No correlation to SDL enum StandardPoseChannel { - HIPS_ROOT = 0, - HIPS, + HIPS = 0, RIGHT_UP_LEG, RIGHT_LEG, RIGHT_FOOT, diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index 4f52d8da98..152bce913d 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -17,6 +17,7 @@ #include #include #include +#include Q_DECLARE_LOGGING_CATEGORY(inputplugins) Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") @@ -30,8 +31,7 @@ const QString NeuronPlugin::NEURON_ID_STRING = "Perception Neuron"; // This matches controller::StandardPoseChannel enum JointIndex { - HipsPosition = 0, - Hips, + Hips = 0, RightUpLeg, RightLeg, RightFoot, @@ -204,8 +204,9 @@ void NeuronPlugin::activate() { if (!_socketRef) { // error qCCritical(inputplugins) << "NeuronPlugin: error connecting to " << _serverAddress.c_str() << ":" << _serverPort << "error = " << BRGetLastErrorMessage(); + } else { + qCDebug(inputplugins) << "NeuronPlugin: success connecting to " << _serverAddress.c_str() << ":" << _serverPort; } - qCDebug(inputplugins) << "NeuronPlugin: success connecting to " << _serverAddress.c_str() << ":" << _serverPort; } void NeuronPlugin::deactivate() { @@ -226,9 +227,9 @@ void NeuronPlugin::deactivate() { // convert between euler in degrees to quaternion static quat eulerToQuat(vec3 euler) { - return (glm::angleAxis(euler.y * RADIANS_PER_DEGREE, Vectors::UNIT_Y) * - glm::angleAxis(euler.x * RADIANS_PER_DEGREE, Vectors::UNIT_X) * - glm::angleAxis(euler.z * RADIANS_PER_DEGREE, Vectors::UNIT_Z)); + // euler.x and euler.y are swaped (thanks NOMICOM!) + glm::vec3 e = glm::vec3(euler.y, euler.x, euler.z) * RADIANS_PER_DEGREE; + return (glm::angleAxis(e.y, Vectors::UNIT_Y) * glm::angleAxis(e.x, Vectors::UNIT_X) * glm::angleAxis(e.z, Vectors::UNIT_Z)); } void NeuronPlugin::pluginUpdate(float deltaTime, bool jointsCaptured) { @@ -274,7 +275,6 @@ static controller::StandardPoseChannel neuronJointIndexToPoseIndex(JointIndex i) static const char* neuronJointName(JointIndex i) { switch (i) { - case HipsPosition: return "HipsPosition"; case Hips: return "Hips"; case RightUpLeg: return "RightUpLeg"; case RightLeg: return "RightLeg"; @@ -369,9 +369,17 @@ void NeuronPlugin::InputDevice::update(float deltaTime, const std::vector Date: Wed, 23 Dec 2015 18:20:20 -0800 Subject: [PATCH 166/209] Move final blit into RenderDeferredTask - Also changes color buffer clearing, such that anything run through Blit will now clear BUFFER_COLOR0 to 0,0,1,0. - Blit will always be added to RenderDeferredTask, but will only run if renderArgs._blitFramebuffer is set. --- interface/src/Application.cpp | 79 ++----------------- .../render-utils/src/RenderDeferredTask.cpp | 73 +++++++++++++++++ .../render-utils/src/RenderDeferredTask.h | 7 ++ libraries/shared/src/RenderArgs.h | 2 + 4 files changed, 89 insertions(+), 72 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e36ad051b9..d383ee3339 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1207,23 +1207,12 @@ void Application::paintGL() { auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer(); renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; + renderArgs._blitFramebuffer = DependencyManager::get()->getSelfieFramebuffer(); + renderRearViewMirror(&renderArgs, _mirrorViewRect); + + renderArgs._blitFramebuffer.reset(); renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; - - { - float ratio = ((float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale()); - // Flip the src and destination rect horizontally to do the mirror - auto mirrorRect = glm::ivec4(0, 0, _mirrorViewRect.width() * ratio, _mirrorViewRect.height() * ratio); - auto mirrorRectDest = glm::ivec4(mirrorRect.z, mirrorRect.y, mirrorRect.x, mirrorRect.w); - - auto selfieFbo = DependencyManager::get()->getSelfieFramebuffer(); - gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { - batch.setFramebuffer(selfieFbo); - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); - batch.blit(primaryFbo, mirrorRect, selfieFbo, mirrorRectDest); - batch.setFramebuffer(nullptr); - }); - } } { @@ -1394,65 +1383,11 @@ void Application::paintGL() { renderArgs._context->setStereoProjections(eyeProjections); renderArgs._context->setStereoViews(eyeOffsets); } + renderArgs._blitFramebuffer = finalFramebuffer; displaySide(&renderArgs, _myCamera); + + renderArgs._blitFramebuffer.reset(); renderArgs._context->enableStereo(false); - - // Blit primary to final FBO - auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); - - if (renderArgs._renderMode == RenderArgs::MIRROR_RENDER_MODE) { - if (displayPlugin->isStereo()) { - gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { - gpu::Vec4i srcRectLeft; - srcRectLeft.z = size.width() / 2; - srcRectLeft.w = size.height(); - - gpu::Vec4i srcRectRight; - srcRectRight.x = size.width() / 2; - srcRectRight.z = size.width(); - srcRectRight.w = size.height(); - - gpu::Vec4i destRectLeft; - destRectLeft.x = srcRectLeft.z; - destRectLeft.z = srcRectLeft.x; - destRectLeft.y = srcRectLeft.y; - destRectLeft.w = srcRectLeft.w; - - gpu::Vec4i destRectRight; - destRectRight.x = srcRectRight.z; - destRectRight.z = srcRectRight.x; - destRectRight.y = srcRectRight.y; - destRectRight.w = srcRectRight.w; - - batch.setFramebuffer(finalFramebuffer); - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 1.0f, 0.0f)); - // BLit left to right and right to left in stereo - batch.blit(primaryFbo, srcRectRight, finalFramebuffer, destRectLeft); - batch.blit(primaryFbo, srcRectLeft, finalFramebuffer, destRectRight); - }); - } else { - gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { - gpu::Vec4i srcRect; - srcRect.z = size.width(); - srcRect.w = size.height(); - gpu::Vec4i destRect; - destRect.x = size.width(); - destRect.y = 0; - destRect.z = 0; - destRect.w = size.height(); - batch.setFramebuffer(finalFramebuffer); - batch.blit(primaryFbo, srcRect, finalFramebuffer, destRect); - }); - } - } else { - gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { - gpu::Vec4i rect; - rect.z = size.width(); - rect.w = size.height(); - batch.setFramebuffer(finalFramebuffer); - batch.blit(primaryFbo, rect, finalFramebuffer, rect); - }); - } } // Overlay Composition, needs to occur after screen space effects have completed diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index cf60fcfe37..9c99307684 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -126,6 +126,8 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new HitEffect::JobModel("HitEffect"))); _jobs.back().setEnabled(false); _drawHitEffectJobIndex = (int)_jobs.size() -1; + + _jobs.push_back(Job(new Blit::JobModel("Blit"))); } RenderDeferredTask::~RenderDeferredTask() { @@ -385,6 +387,77 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const args->_batch = nullptr; } +void Blit::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_context); + + RenderArgs* renderArgs = renderContext->getArgs(); + auto blitFbo = renderArgs->_blitFramebuffer; + + if (!blitFbo) { + return; + } + + // Determine size from viewport + int width = renderArgs->_viewport.z; + int height = renderArgs->_viewport.w; + + // Blit primary to blit FBO + auto framebufferCache = DependencyManager::get(); + auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); + + gpu::doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { + batch.setFramebuffer(blitFbo); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 1.0f, 0.0f)); + + if (renderArgs->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { + if (renderArgs->_context->isStereo()) { + gpu::Vec4i srcRectLeft; + srcRectLeft.z = width / 2; + srcRectLeft.w = height; + + gpu::Vec4i srcRectRight; + srcRectRight.x = width / 2; + srcRectRight.z = width; + srcRectRight.w = height; + + gpu::Vec4i destRectLeft; + destRectLeft.x = srcRectLeft.z; + destRectLeft.z = srcRectLeft.x; + destRectLeft.y = srcRectLeft.y; + destRectLeft.w = srcRectLeft.w; + + gpu::Vec4i destRectRight; + destRectRight.x = srcRectRight.z; + destRectRight.z = srcRectRight.x; + destRectRight.y = srcRectRight.y; + destRectRight.w = srcRectRight.w; + + // Blit left to right and right to left in stereo + batch.blit(primaryFbo, srcRectRight, blitFbo, destRectLeft); + batch.blit(primaryFbo, srcRectLeft, blitFbo, destRectRight); + } else { + gpu::Vec4i srcRect; + srcRect.z = width; + srcRect.w = height; + + gpu::Vec4i destRect; + destRect.x = width; + destRect.y = 0; + destRect.z = 0; + destRect.w = height; + + batch.blit(primaryFbo, srcRect, blitFbo, destRect); + } + } else { + gpu::Vec4i rect; + rect.z = width; + rect.w = height; + + batch.blit(primaryFbo, rect, blitFbo, rect); + } + }); +} void RenderDeferredTask::setToneMappingExposure(float exposure) { if (_toneMappingJobIndex >= 0) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index b84db31a26..051faa3238 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -90,6 +90,13 @@ public: typedef render::Job::Model JobModel; }; +class Blit { +public: + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + + typedef render::Job::Model JobModel; +}; + class RenderDeferredTask : public render::Task { public: diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 399b94bcef..640ccdcb1f 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -24,6 +24,7 @@ namespace gpu { class Batch; class Context; class Texture; +class Framebuffer; } class RenderDetails { @@ -101,6 +102,7 @@ public: } std::shared_ptr _context = nullptr; + std::shared_ptr _blitFramebuffer = nullptr; OctreeRenderer* _renderer = nullptr; ViewFrustum* _viewFrustum = nullptr; glm::ivec4 _viewport{ 0, 0, 1, 1 }; From 24796c1a1eb46cce988752634bd40ba62cf28bdd Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 24 Dec 2015 10:14:36 -0800 Subject: [PATCH 167/209] updated ravestick spawner relative position --- examples/flowArts/raveStick/raveStick.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/examples/flowArts/raveStick/raveStick.js b/examples/flowArts/raveStick/raveStick.js index c51e8b5d89..5fb019bf97 100644 --- a/examples/flowArts/raveStick/raveStick.js +++ b/examples/flowArts/raveStick/raveStick.js @@ -40,13 +40,18 @@ RaveStick = function(spawnPosition) { userData: JSON.stringify({ grabbableKey: { spatialKey: { - relativePosition: { - x: 0, - y: 0, - z: -0.1 + rightRelativePosition: { + x: 0.02, + y: 0, + z: 0 + }, + leftRelativePosition: { + x: -0.02, + y: 0, + z: 0 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) }, - relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) - }, invertSolidWhileHeld: true } }) From dfa2b8d453c06790869fa4a85819f41241d0a3c2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 24 Dec 2015 10:39:29 -0800 Subject: [PATCH 168/209] Remove redundant clearColorBuffer from Blit --- libraries/render-utils/src/RenderDeferredTask.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 9c99307684..1b1d08f353 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -408,7 +408,6 @@ void Blit::run(const SceneContextPointer& sceneContext, const RenderContextPoint gpu::doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { batch.setFramebuffer(blitFbo); - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 1.0f, 0.0f)); if (renderArgs->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { if (renderArgs->_context->isStereo()) { From e8a6fd1f054e375b2e2316009c7991b3d55d24a5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 24 Dec 2015 11:00:24 -0800 Subject: [PATCH 169/209] adding ray filters example/test --- .../painting/whiteboard/whiteboardSpawner.js | 4 +- examples/rayPickingFilterExample.js | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 examples/rayPickingFilterExample.js diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js index f3005495ec..1d0f21c026 100644 --- a/examples/painting/whiteboard/whiteboardSpawner.js +++ b/examples/painting/whiteboard/whiteboardSpawner.js @@ -15,7 +15,7 @@ /*global hexToRgb */ Script.include("../../libraries/utils.js"); -var scriptURL = Script.resolvePath("whiteboardEntityScript.js"); +var scriptURL = Script.resolvePath("whiteboardEntityScript.js?v1" + Math.random()); var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/whiteboard.fbx"; var colorIndicatorBorderModelURL = "https://s3.amazonaws.com/hifi-public/eric/models/colorIndicatorBorder.fbx"; @@ -247,4 +247,4 @@ function cleanup() { // Uncomment this line to delete whiteboard and all associated entity on script close -//Script.scriptEnding.connect(cleanup); +Script.scriptEnding.connect(cleanup); diff --git a/examples/rayPickingFilterExample.js b/examples/rayPickingFilterExample.js new file mode 100644 index 0000000000..f434d21ab9 --- /dev/null +++ b/examples/rayPickingFilterExample.js @@ -0,0 +1,50 @@ + var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation()))); + + var whiteListBox = Entities.addEntity({ + type: "Box", + color: { + red: 10, + green: 200, + blue: 10 + }, + dimensions: { + x: .2, + y: .2, + z: .2 + }, + position: center + }); + + var blackListBox = Entities.addEntity({ + type: "Box", + color: { + red: 100, + green: 10, + blue: 10 + }, + dimensions: { + x: .2, + y: .2, + z: .2 + }, + position: Vec3.sum(center, {x: 0, y: .3, z: 0}) + }); + + + function castRay(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var pickResults = Entities.findRayIntersection(pickRay, true, [whiteListBox]); + + if(pickResults.intersects) { + print("INTERSECTION"); + } + + } + + function cleanup() { + Entities.deleteEntity(whiteListBox); + Entities.deleteEntity(blackListBox); + } + + Script.scriptEnding.connect(cleanup); + Controller.mousePressEvent.connect(castRay); \ No newline at end of file From 390dce461317e36d97e2214274f6044b3b0ff526 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 24 Dec 2015 11:48:40 -0800 Subject: [PATCH 170/209] Adding blacklist --- examples/rayPickingFilterExample.js | 2 +- .../src/EntityTreeRenderer.cpp | 5 +++-- .../entities-renderer/src/EntityTreeRenderer.h | 3 ++- .../entities/src/EntityScriptingInterface.cpp | 18 ++++++++++-------- .../entities/src/EntityScriptingInterface.h | 6 +++--- libraries/entities/src/EntityTree.cpp | 7 ++++--- libraries/entities/src/EntityTree.h | 1 + libraries/entities/src/EntityTreeElement.cpp | 8 ++++---- libraries/entities/src/EntityTreeElement.h | 4 +++- 9 files changed, 31 insertions(+), 23 deletions(-) diff --git a/examples/rayPickingFilterExample.js b/examples/rayPickingFilterExample.js index f434d21ab9..aa1950c013 100644 --- a/examples/rayPickingFilterExample.js +++ b/examples/rayPickingFilterExample.js @@ -33,7 +33,7 @@ function castRay(event) { var pickRay = Camera.computePickRay(event.x, event.y); - var pickResults = Entities.findRayIntersection(pickRay, true, [whiteListBox]); + var pickResults = Entities.findRayIntersection(pickRay, true, [], [blackListBox]); if(pickResults.intersects) { print("INTERSECTION"); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 996a8f3e1d..f517c49b00 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -487,7 +487,8 @@ void EntityTreeRenderer::deleteReleasedModels() { } RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, - bool precisionPicking, const QVector& entityIdsToInclude) { + bool precisionPicking, const QVector& entityIdsToInclude, + const QVector& entityIdsToDiscard) { RayToEntityIntersectionResult result; if (_tree) { EntityTreePointer entityTree = std::static_pointer_cast(_tree); @@ -495,7 +496,7 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons OctreeElementPointer element; EntityItemPointer intersectedEntity = NULL; result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, - result.face, result.surfaceNormal, entityIdsToInclude, + result.face, result.surfaceNormal, entityIdsToInclude, entityIdsToDiscard, (void**)&intersectedEntity, lockType, &result.accurate, precisionPicking); if (result.intersects && intersectedEntity) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 076fe26d6f..2c205336c0 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -130,7 +130,8 @@ private: QList _releasedModels; RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, - bool precisionPicking, const QVector& entityIdsToInclude = QVector()); + bool precisionPicking, const QVector& entityIdsToInclude = QVector(), + const QVector& entityIdsToDiscard = QVector()); EntityItemID _currentHoverOverEntityID; EntityItemID _currentClickingOnEntityID; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index a0a6719521..0746c2a824 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -357,19 +357,21 @@ QVector EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corn return result; } -RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude) { - QVector entities = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); - return findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking, entities); +RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) { + QVector entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); + QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard); + return findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking, entitiesToInclude, entitiesToDiscard); } -RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude) { - const QVector& entities = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); - return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entities); +RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) { + const QVector& entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); + const QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard); + return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entitiesToInclude, entitiesToDiscard); } RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, - bool precisionPicking, const QVector& entityIdsToInclude) { + bool precisionPicking, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard) { RayToEntityIntersectionResult result; @@ -377,7 +379,7 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorke OctreeElementPointer element; EntityItemPointer intersectedEntity = NULL; result.intersects = _entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, - result.surfaceNormal, entityIdsToInclude, (void**)&intersectedEntity, lockType, &result.accurate, + result.surfaceNormal, entityIdsToInclude, entityIdsToDiscard, (void**)&intersectedEntity, lockType, &result.accurate, precisionPicking); if (result.intersects && intersectedEntity) { result.entityID = intersectedEntity->getEntityItemID(); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index f745b6b644..d08a1b7e36 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -112,11 +112,11 @@ public slots: /// If the scripting context has visible entities, this will determine a ray intersection, the results /// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate /// will be false. - Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false, const QScriptValue& entityIdsToInclude = QScriptValue()); + Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false, const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue()); /// If the scripting context has visible entities, this will determine a ray intersection, and will block in /// order to return an accurate result - Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking = false, const QScriptValue& entityIdsToInclude = QScriptValue()); + Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking = false, const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue()); Q_INVOKABLE void setLightsArePickable(bool value); Q_INVOKABLE bool getLightsArePickable() const; @@ -189,7 +189,7 @@ private: /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, - bool precisionPicking, const QVector& entityIdsToInclude); + bool precisionPicking, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard); EntityTreePointer _entityTree; EntitiesScriptEngineProvider* _entitiesScriptEngine = nullptr; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ba6294f8a8..f0a03623c2 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -498,6 +498,7 @@ public: BoxFace& face; glm::vec3& surfaceNormal; const QVector& entityIdsToInclude; + const QVector& entityIdsToDiscard; void** intersectedObject; bool found; bool precisionPicking; @@ -510,7 +511,7 @@ bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) { EntityTreeElementPointer entityTreeElementPointer = std::dynamic_pointer_cast(element); if (entityTreeElementPointer ->findRayIntersection(args->origin, args->direction, keepSearching, args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude, - args->intersectedObject, args->precisionPicking)) { + args->entityIdsToDiscard, args->intersectedObject, args->precisionPicking)) { args->found = true; } return keepSearching; @@ -518,9 +519,9 @@ bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) { bool EntityTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, OctreeElementPointer& element, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, void** intersectedObject, + BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard, void** intersectedObject, Octree::lockType lockType, bool* accurateResult, bool precisionPicking) { - RayArgs args = { origin, direction, element, distance, face, surfaceNormal, entityIdsToInclude, intersectedObject, false, precisionPicking }; + RayArgs args = { origin, direction, element, distance, face, surfaceNormal, entityIdsToInclude, entityIdsToDiscard, intersectedObject, false, precisionPicking }; distance = FLT_MAX; bool requireLock = lockType == Octree::Lock; diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 5e54e562a0..f68e2d59e9 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -84,6 +84,7 @@ public: virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, OctreeElementPointer& node, float& distance, BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude = QVector(), + const QVector& entityIdsToDiscard = QVector(), void** intersectedObject = NULL, Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL, diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index ff2e97e8fe..17f967fc1f 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -475,8 +475,8 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3 bool EntityTreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, - void** intersectedObject, bool precisionPicking) { + BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, + const QVector& entityIdsToDiscard, void** intersectedObject, bool precisionPicking) { keepSearching = true; // assume that we will continue searching after this. @@ -501,7 +501,7 @@ bool EntityTreeElement::findRayIntersection(const glm::vec3& origin, const glm:: if (_cube.contains(origin) || distanceToElementCube < distance) { if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, - face, localSurfaceNormal, entityIdsToInclude, intersectedObject, precisionPicking, distanceToElementCube)) { + face, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, intersectedObject, precisionPicking, distanceToElementCube)) { if (distanceToElementDetails < distance) { distance = distanceToElementDetails; @@ -516,7 +516,7 @@ bool EntityTreeElement::findRayIntersection(const glm::vec3& origin, const glm:: bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, - const QVector& entityIdsToInclude, void** intersectedObject, bool precisionPicking, float distanceToElementCube) { + const QVector& entityIdsToInclude, const QVector& entityIDsToDiscard, void** intersectedObject, bool precisionPicking, float distanceToElementCube) { // only called if we do intersect our bounding cube, but find if we actually intersect with entities... int entityNumber = 0; diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index d8a182156d..aa05438bde 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -144,11 +144,13 @@ public: virtual bool canRayIntersect() const { return hasEntities(); } virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& node, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, + BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, + const QVector& entityIdsToDiscard, void** intersectedObject = NULL, bool precisionPicking = false); virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, + const QVector& entityIdsToDiscard, void** intersectedObject, bool precisionPicking, float distanceToElementCube); virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const; From 8e7dfc07c0568616f06d66c0276337166cc03488 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 24 Dec 2015 11:59:47 -0800 Subject: [PATCH 171/209] Added logic to blacklist entities from raypicking --- examples/rayPickingFilterExample.js | 110 +++++++++++-------- libraries/entities/src/EntityTreeElement.cpp | 2 +- 2 files changed, 67 insertions(+), 45 deletions(-) diff --git a/examples/rayPickingFilterExample.js b/examples/rayPickingFilterExample.js index aa1950c013..a373840e72 100644 --- a/examples/rayPickingFilterExample.js +++ b/examples/rayPickingFilterExample.js @@ -1,50 +1,72 @@ - var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation()))); - - var whiteListBox = Entities.addEntity({ - type: "Box", - color: { - red: 10, - green: 200, - blue: 10 - }, - dimensions: { - x: .2, - y: .2, - z: .2 - }, - position: center - }); - - var blackListBox = Entities.addEntity({ - type: "Box", - color: { - red: 100, - green: 10, - blue: 10 - }, - dimensions: { - x: .2, - y: .2, - z: .2 - }, - position: Vec3.sum(center, {x: 0, y: .3, z: 0}) - }); + // + // rayPickingFilterExample.js + // examples + // + // Created by Eric Levin on 12/24/2015 + // Copyright 2015 High Fidelity, Inc. + // + // This is an example script that demonstrates the use of filtering entities for ray picking + // + // Distributed under the Apache License, Version 2.0. + // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + // - function castRay(event) { - var pickRay = Camera.computePickRay(event.x, event.y); - var pickResults = Entities.findRayIntersection(pickRay, true, [], [blackListBox]); + var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation()))); - if(pickResults.intersects) { - print("INTERSECTION"); - } + var whiteListBox = Entities.addEntity({ + type: "Box", + color: { + red: 10, + green: 200, + blue: 10 + }, + dimensions: { + x: 0.2, + y: 0.2, + z: 0.2 + }, + position: center + }); - } + var blackListBox = Entities.addEntity({ + type: "Box", + color: { + red: 100, + green: 10, + blue: 10 + }, + dimensions: { + x: 0.2, + y: 0.2, + z: 0.2 + }, + position: Vec3.sum(center, { + x: 0, + y: 0.3, + z: 0 + }) + }); - function cleanup() { - Entities.deleteEntity(whiteListBox); - Entities.deleteEntity(blackListBox); - } - Script.scriptEnding.connect(cleanup); - Controller.mousePressEvent.connect(castRay); \ No newline at end of file + function castRay(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + // In this example every entity will be pickable except the entities in the blacklist array + // the third arg is the whitelist array,a nd the fourth and final is the blacklist array + var pickResults = Entities.findRayIntersection(pickRay, true, [], [blackListBox]); + // With below example, only entities adde dto whitelist will be pickable + // var pickResults = Entities.findRayIntersection(pickRay, true, [whiteListBox], []); + + if (pickResults.intersects) { + print("INTERSECTION!"); + } + + } + + function cleanup() { + Entities.deleteEntity(whiteListBox); + Entities.deleteEntity(blackListBox); + } + + Script.scriptEnding.connect(cleanup); + Controller.mousePressEvent.connect(castRay); \ No newline at end of file diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 17f967fc1f..8944c95cbc 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -522,7 +522,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con int entityNumber = 0; bool somethingIntersected = false; forEachEntity([&](EntityItemPointer entity) { - if (entityIdsToInclude.size() > 0 && !entityIdsToInclude.contains(entity->getID())) { + if ( (entityIdsToInclude.size() > 0 && !entityIdsToInclude.contains(entity->getID())) || (entityIDsToDiscard.size() > 0 && entityIDsToDiscard.contains(entity->getID())) ) { return; } From 340c066b5ccba6a40bfd11d02604b554cb8ace2f Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 24 Dec 2015 12:04:36 -0800 Subject: [PATCH 172/209] reverted whiteboard changes --- examples/painting/whiteboard/whiteboardSpawner.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js index 1d0f21c026..e55f54e312 100644 --- a/examples/painting/whiteboard/whiteboardSpawner.js +++ b/examples/painting/whiteboard/whiteboardSpawner.js @@ -15,7 +15,7 @@ /*global hexToRgb */ Script.include("../../libraries/utils.js"); -var scriptURL = Script.resolvePath("whiteboardEntityScript.js?v1" + Math.random()); +var scriptURL = Script.resolvePath("whiteboardEntityScript.js"; var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/whiteboard.fbx"; var colorIndicatorBorderModelURL = "https://s3.amazonaws.com/hifi-public/eric/models/colorIndicatorBorder.fbx"; @@ -247,4 +247,4 @@ function cleanup() { // Uncomment this line to delete whiteboard and all associated entity on script close -Script.scriptEnding.connect(cleanup); +// Script.scriptEnding.connect(cleanup); From 2e95ca7947d54f9f99e46c44398d0fcadaf5fedc Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 24 Dec 2015 12:05:11 -0800 Subject: [PATCH 173/209] fixed syntax error --- examples/painting/whiteboard/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js index e55f54e312..f6c7aa77ca 100644 --- a/examples/painting/whiteboard/whiteboardSpawner.js +++ b/examples/painting/whiteboard/whiteboardSpawner.js @@ -15,7 +15,7 @@ /*global hexToRgb */ Script.include("../../libraries/utils.js"); -var scriptURL = Script.resolvePath("whiteboardEntityScript.js"; +var scriptURL = Script.resolvePath("whiteboardEntityScript.js"); var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/whiteboard.fbx"; var colorIndicatorBorderModelURL = "https://s3.amazonaws.com/hifi-public/eric/models/colorIndicatorBorder.fbx"; From 542d8a4b6cb292bc1e5bdd40c8b69675345c665d Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 24 Dec 2015 12:06:29 -0800 Subject: [PATCH 174/209] Fixed spelling mistakes --- examples/rayPickingFilterExample.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/rayPickingFilterExample.js b/examples/rayPickingFilterExample.js index a373840e72..73d151847b 100644 --- a/examples/rayPickingFilterExample.js +++ b/examples/rayPickingFilterExample.js @@ -52,9 +52,10 @@ function castRay(event) { var pickRay = Camera.computePickRay(event.x, event.y); // In this example every entity will be pickable except the entities in the blacklist array - // the third arg is the whitelist array,a nd the fourth and final is the blacklist array + // the third argument is the whitelist array,and the fourth and final is the blacklist array var pickResults = Entities.findRayIntersection(pickRay, true, [], [blackListBox]); - // With below example, only entities adde dto whitelist will be pickable + + // With below example, only entities added to whitelist will be pickable // var pickResults = Entities.findRayIntersection(pickRay, true, [whiteListBox], []); if (pickResults.intersects) { From 8b979b67ee2ec086a83ab55c1ec20a14134c665f Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Thu, 24 Dec 2015 17:14:17 -0800 Subject: [PATCH 175/209] neruonAvatar.js: now sets rotations in correct frame. The rotations from the neuron are effectively in world space and are deltas from the default pose. There still is an issue with the thumb, due to the missing joint from the Neuron. The Neuron only has 3 thumb joints, not 4. --- examples/controllers/neuron/neuronAvatar.js | 95 ++++++++++++++++++++- plugins/hifiNeuron/src/NeuronPlugin.cpp | 52 +++++------ 2 files changed, 119 insertions(+), 28 deletions(-) diff --git a/examples/controllers/neuron/neuronAvatar.js b/examples/controllers/neuron/neuronAvatar.js index 776cabd301..fae46330b1 100644 --- a/examples/controllers/neuron/neuronAvatar.js +++ b/examples/controllers/neuron/neuronAvatar.js @@ -61,6 +61,70 @@ var JOINT_NAME_MAP = { LeftHandPinky3: "LeftHandPinky4" }; +var JOINT_PARENT_MAP = { + Hips: "", + RightUpLeg: "Hips", + RightLeg: "RightUpLeg", + RightFoot: "RightLeg", + LeftUpLeg: "Hips", + LeftLeg: "LeftUpLeg", + LeftFoot: "LeftLeg", + Spine: "Hips", + Spine1: "Spine", + Spine2: "Spine1", + Spine3: "Spine2", + Neck: "Spine3", + Head: "Neck", + RightShoulder: "Spine3", + RightArm: "RightShoulder", + RightForeArm: "RightArm", + RightHand: "RightForeArm", + RightHandThumb1: "RightHand", + RightHandThumb2: "RightHandThumb1", + RightHandThumb3: "RightHandThumb2", + RightHandThumb4: "RightHandThumb3", + RightHandIndex1: "RightHand", + RightHandIndex2: "RightHandIndex1", + RightHandIndex3: "RightHandIndex2", + RightHandIndex4: "RightHandIndex3", + RightHandMiddle1: "RightHand", + RightHandMiddle2: "RightHandMiddle1", + RightHandMiddle3: "RightHandMiddle2", + RightHandMiddle4: "RightHandMiddle3", + RightHandRing1: "RightHand", + RightHandRing2: "RightHandRing1", + RightHandRing3: "RightHandRing2", + RightHandRing4: "RightHandRing3", + RightHandPinky1: "RightHand", + RightHandPinky2: "RightHandPinky1", + RightHandPinky3: "RightHandPinky2", + RightHandPinky4: "RightHandPinky3", + LeftShoulder: "Spine3", + LeftArm: "LeftShoulder", + LeftForeArm: "LeftArm", + LeftHand: "LeftForeArm", + LeftHandThumb1: "LeftHand", + LeftHandThumb2: "LeftHandThumb1", + LeftHandThumb3: "LeftHandThumb2", + LeftHandThumb4: "LeftHandThumb3", + LeftHandIndex1: "LeftHand", + LeftHandIndex2: "LeftHandIndex1", + LeftHandIndex3: "LeftHandIndex2", + LeftHandIndex4: "LeftHandIndex3", + LeftHandMiddle1: "LeftHand", + LeftHandMiddle2: "LeftHandMiddle1", + LeftHandMiddle3: "LeftHandMiddle2", + LeftHandMiddle4: "LeftHandMiddle3", + LeftHandRing1: "LeftHand", + LeftHandRing2: "LeftHandRing1", + LeftHandRing3: "LeftHandRing2", + LeftHandRing4: "LeftHandRing3", + LeftHandPinky1: "LeftHand", + LeftHandPinky2: "LeftHandPinky1", + LeftHandPinky3: "LeftHandPinky2", + LeftHandPinky: "LeftHandPinky3", +}; + function dumpHardwareMapping() { Object.keys(Controller.Hardware).forEach(function (deviceName) { Object.keys(Controller.Hardware[deviceName]).forEach(function (input) { @@ -103,6 +167,21 @@ NeuronAvatar.prototype.activate = function () { Script.update.connect(updateCallback); } this._active = true; + + // build absDefaultPoseMap + this._absDefaultRotMap = {}; + var keys = Object.keys(JOINT_NAME_MAP); + var i, l = keys.length; + for (i = 0; i < l; i++) { + var jointName = JOINT_NAME_MAP[keys[i]]; + var j = MyAvatar.getJointIndex(jointName); + var parentJointName = JOINT_PARENT_MAP[jointName]; + if (parentJointName === "") { + this._absDefaultRotMap[jointName] = MyAvatar.getDefaultJointRotation(j); + } else { + this._absDefaultRotMap[jointName] = Quat.multiply(this._absDefaultRotMap[parentJointName], MyAvatar.getDefaultJointRotation(j)); + } + } }; NeuronAvatar.prototype.deactivate = function () { @@ -117,14 +196,22 @@ NeuronAvatar.prototype.deactivate = function () { NeuronAvatar.prototype.update = function (deltaTime) { var keys = Object.keys(JOINT_NAME_MAP); var i, l = keys.length; + var absDefaultRot = {}; for (i = 0; i < l; i++) { var channel = Controller.Hardware.Neuron[keys[i]]; if (channel) { var pose = Controller.getPoseValue(channel); - var j = MyAvatar.getJointIndex(JOINT_NAME_MAP[keys[i]]); - var defaultRot = MyAvatar.getDefaultJointRotation(j); - var rot = Quat.multiply(Quat.inverse(defaultRot), Quat.multiply(pose.rotation, defaultRot)); - MyAvatar.setJointRotation(j, Quat.multiply(defaultRot, rot)); + var jointName = JOINT_NAME_MAP[keys[i]]; + var parentJointName = JOINT_PARENT_MAP[jointName]; + var j = MyAvatar.getJointIndex(jointName); + var defaultAbsRot = this._absDefaultRotMap[jointName]; + var parentDefaultAbsRot; + if (parentJointName === "") { + parentDefaultAbsRot = {x: 0, y: 0, z: 0, w: 1}; + } else { + parentDefaultAbsRot = this._absDefaultRotMap[parentJointName]; + } + MyAvatar.setJointRotation(j, Quat.multiply(Quat.inverse(parentDefaultAbsRot), Quat.multiply(pose.rotation, defaultAbsRot))); //MyAvatar.setJointTranslation(j, Vec3.multiply(100.0, pose.translation)); } } diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index 152bce913d..ae438c10e0 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -107,21 +107,37 @@ void FrameDataReceivedCallback(void* context, SOCKET_REF sender, BvhDataHeaderEx // version 1.0 if (header->DataVersion.Major == 1 && header->DataVersion.Minor == 0) { - std::lock_guard guard(neuronPlugin->_jointsMutex); - - // Data is 6 floats: 3 position values, 3 rotation euler angles (degrees) - - // resize vector if necessary - const size_t NUM_FLOATS_PER_JOINT = 6; - const size_t NUM_JOINTS = header->DataCount / NUM_FLOATS_PER_JOINT; - if (neuronPlugin->_joints.size() != NUM_JOINTS) { - neuronPlugin->_joints.resize(NUM_JOINTS, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); + // skip reference joint if present + if (header->WithReference && header->WithDisp) { + data += 6; + } else if (header->WithReference && !header->WithDisp) { + data += 3; } - assert(sizeof(NeuronPlugin::NeuronJoint) == (NUM_FLOATS_PER_JOINT * sizeof(float))); + if (header->WithDisp) { + // enter mutex + std::lock_guard guard(neuronPlugin->_jointsMutex); - // copy the data - memcpy(&(neuronPlugin->_joints[0]), data, sizeof(NeuronPlugin::NeuronJoint) * NUM_JOINTS); + // + // Data is 6 floats per joint: 3 position values, 3 rotation euler angles (degrees) + // + + // resize vector if necessary + const size_t NUM_FLOATS_PER_JOINT = 6; + const size_t NUM_JOINTS = header->DataCount / NUM_FLOATS_PER_JOINT; + if (neuronPlugin->_joints.size() != NUM_JOINTS) { + neuronPlugin->_joints.resize(NUM_JOINTS, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); + } + + assert(sizeof(NeuronPlugin::NeuronJoint) == (NUM_FLOATS_PER_JOINT * sizeof(float))); + + // copy the data + memcpy(&(neuronPlugin->_joints[0]), data, sizeof(NeuronPlugin::NeuronJoint) * NUM_JOINTS); + } else { + + qCCritical(inputplugins) << "NeruonPlugin: format not supported"; + + } } else { static bool ONCE = false; @@ -368,18 +384,6 @@ void NeuronPlugin::InputDevice::update(float deltaTime, const std::vector Date: Fri, 25 Dec 2015 09:57:50 -0800 Subject: [PATCH 176/209] Set up controller poses to match hifi standard skeleton Neuron plugin in fills in the gap (thumb1) with identity. Updated neuronAvatar script to work with new controller pose names. --- examples/controllers/neuron/neuronAvatar.js | 97 +----- .../src/controllers/StandardControls.h | 20 +- plugins/hifiNeuron/src/NeuronPlugin.cpp | 324 +++++++++++------- plugins/hifiNeuron/src/NeuronPlugin.h | 10 +- 4 files changed, 245 insertions(+), 206 deletions(-) diff --git a/examples/controllers/neuron/neuronAvatar.js b/examples/controllers/neuron/neuronAvatar.js index fae46330b1..cc53987f05 100644 --- a/examples/controllers/neuron/neuronAvatar.js +++ b/examples/controllers/neuron/neuronAvatar.js @@ -1,66 +1,3 @@ -// maps controller joint names to avatar joint names -var JOINT_NAME_MAP = { - Hips: "Hips", - RightUpLeg: "RightUpLeg", - RightLeg: "RightLeg", - RightFoot: "RightFoot", - LeftUpLeg: "LeftUpLeg", - LeftLeg: "LeftLeg", - LeftFoot: "LeftFoot", - Spine: "Spine", - Spine1: "Spine1", - Spine2: "Spine2", - Spine3: "Spine3", - Neck: "Neck", - Head: "Head", - RightShoulder: "RightShoulder", - RightArm: "RightArm", - RightForeArm: "RightForeArm", - RightHand: "RightHand", - RightHandThumb1: "RightHandThumb2", - RightHandThumb2: "RightHandThumb3", - RightHandThumb3: "RightHandThumb4", - RightInHandIndex: "RightHandIndex1", - RightHandIndex1: "RightHandIndex2", - RightHandIndex2: "RightHandIndex3", - RightHandIndex3: "RightHandIndex4", - RightInHandMiddle: "RightHandMiddle1", - RightHandMiddle1: "RightHandMiddle2", - RightHandMiddle2: "RightHandMiddle3", - RightHandMiddle3: "RightHandMiddle4", - RightInHandRing: "RightHandRing1", - RightHandRing1: "RightHandRing2", - RightHandRing2: "RightHandRing3", - RightHandRing3: "RightHandRing4", - RightInHandPinky: "RightHandPinky1", - RightHandPinky1: "RightHandPinky2", - RightHandPinky2: "RightHandPinky3", - RightHandPinky3: "RightHandPinky4", - LeftShoulder: "LeftShoulder", - LeftArm: "LeftArm", - LeftForeArm: "LeftForeArm", - LeftHand: "LeftHand", - LeftHandThumb1: "LeftHandThumb2", - LeftHandThumb2: "LeftHandThumb3", - LeftHandThumb3: "LeftHandThumb4", - LeftInHandIndex: "LeftHandIndex1", - LeftHandIndex1: "LeftHandIndex2", - LeftHandIndex2: "LeftHandIndex3", - LeftHandIndex3: "LeftHandIndex4", - LeftInHandMiddle: "LeftHandMiddle1", - LeftHandMiddle1: "LeftHandMiddle2", - LeftHandMiddle2: "LeftHandMiddle3", - LeftHandMiddle3: "LeftHandMiddle4", - LeftInHandRing: "LeftHandRing1", - LeftHandRing1: "LeftHandRing2", - LeftHandRing2: "LeftHandRing3", - LeftHandRing3: "LeftHandRing4", - LeftInHandPinky: "LeftHandPinky1", - LeftHandPinky1: "LeftHandPinky2", - LeftHandPinky2: "LeftHandPinky3", - LeftHandPinky3: "LeftHandPinky4" -}; - var JOINT_PARENT_MAP = { Hips: "", RightUpLeg: "Hips", @@ -170,10 +107,11 @@ NeuronAvatar.prototype.activate = function () { // build absDefaultPoseMap this._absDefaultRotMap = {}; - var keys = Object.keys(JOINT_NAME_MAP); + this._absDefaultRotMap[""] = {x: 0, y: 0, z: 0, w: 1}; + var keys = Object.keys(JOINT_PARENT_MAP); var i, l = keys.length; for (i = 0; i < l; i++) { - var jointName = JOINT_NAME_MAP[keys[i]]; + var jointName = keys[i]; var j = MyAvatar.getJointIndex(jointName); var parentJointName = JOINT_PARENT_MAP[jointName]; if (parentJointName === "") { @@ -194,24 +132,27 @@ NeuronAvatar.prototype.deactivate = function () { }; NeuronAvatar.prototype.update = function (deltaTime) { - var keys = Object.keys(JOINT_NAME_MAP); + var keys = Object.keys(JOINT_PARENT_MAP); var i, l = keys.length; var absDefaultRot = {}; + var jointName, channel, pose, parentJointName, j, parentDefaultAbsRot; for (i = 0; i < l; i++) { - var channel = Controller.Hardware.Neuron[keys[i]]; + var jointName = keys[i]; + var channel = Controller.Hardware.Neuron[jointName]; if (channel) { - var pose = Controller.getPoseValue(channel); - var jointName = JOINT_NAME_MAP[keys[i]]; - var parentJointName = JOINT_PARENT_MAP[jointName]; - var j = MyAvatar.getJointIndex(jointName); - var defaultAbsRot = this._absDefaultRotMap[jointName]; - var parentDefaultAbsRot; - if (parentJointName === "") { - parentDefaultAbsRot = {x: 0, y: 0, z: 0, w: 1}; - } else { - parentDefaultAbsRot = this._absDefaultRotMap[parentJointName]; - } + pose = Controller.getPoseValue(channel); + parentJointName = JOINT_PARENT_MAP[jointName]; + j = MyAvatar.getJointIndex(jointName); + defaultAbsRot = this._absDefaultRotMap[jointName]; + parentDefaultAbsRot = this._absDefaultRotMap[parentJointName]; + + // Rotations from the neuron controller are in world orientation but are delta's from the default pose. + // So first we build the absolute rotation of the default pose (local into world). + // Then apply the rotation from the controller, in world space. + // Then we transform back into joint local by multiplying by the inverse of the parents absolute rotation. MyAvatar.setJointRotation(j, Quat.multiply(Quat.inverse(parentDefaultAbsRot), Quat.multiply(pose.rotation, defaultAbsRot))); + + // TODO: //MyAvatar.setJointTranslation(j, Vec3.multiply(100.0, pose.translation)); } } diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h index 4294713238..2b0613321e 100644 --- a/libraries/controllers/src/controllers/StandardControls.h +++ b/libraries/controllers/src/controllers/StandardControls.h @@ -108,22 +108,23 @@ namespace controller { RIGHT_HAND_THUMB1, RIGHT_HAND_THUMB2, RIGHT_HAND_THUMB3, - RIGHT_IN_HAND_INDEX, + RIGHT_HAND_THUMB4, RIGHT_HAND_INDEX1, RIGHT_HAND_INDEX2, RIGHT_HAND_INDEX3, - RIGHT_IN_HAND_MIDDLE, + RIGHT_HAND_INDEX4, RIGHT_HAND_MIDDLE1, RIGHT_HAND_MIDDLE2, RIGHT_HAND_MIDDLE3, - RIGHT_IN_HANDRING, + RIGHT_HAND_MIDDLE4, RIGHT_HAND_RING1, RIGHT_HAND_RING2, RIGHT_HAND_RING3, - RIGHT_IN_HAND_PINKY, + RIGHT_HAND_RING4, RIGHT_HAND_PINKY1, RIGHT_HAND_PINKY2, RIGHT_HAND_PINKY3, + RIGHT_HAND_PINKY4, LEFT_SHOULDER, LEFT_ARM, LEFT_FORE_ARM, @@ -131,28 +132,29 @@ namespace controller { LEFT_HAND_THUMB1, LEFT_HAND_THUMB2, LEFT_HAND_THUMB3, - LEFT_IN_HAND_INDEX, + LEFT_HAND_THUMB4, LEFT_HAND_INDEX1, LEFT_HAND_INDEX2, LEFT_HAND_INDEX3, - LEFT_IN_HAND_MIDDLE, + LEFT_HAND_INDEX4, LEFT_HAND_MIDDLE1, LEFT_HAND_MIDDLE2, LEFT_HAND_MIDDLE3, - LEFT_IN_HAND_RING, + LEFT_HAND_MIDDLE4, LEFT_HAND_RING1, LEFT_HAND_RING2, LEFT_HAND_RING3, - LEFT_IN_HAND_PINKY, + LEFT_HAND_RING4, LEFT_HAND_PINKY1, LEFT_HAND_PINKY2, LEFT_HAND_PINKY3, + LEFT_HAND_PINKY4, NUM_STANDARD_POSES }; enum StandardCounts { TRIGGERS = 2, ANALOG_STICKS = 2, - POSES = 2, // FIXME 3? if we want to expose the head? + POSES = NUM_STANDARD_POSES }; } diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index ae438c10e0..4edda64c22 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -29,8 +29,10 @@ Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") const QString NeuronPlugin::NAME = "Neuron"; const QString NeuronPlugin::NEURON_ID_STRING = "Perception Neuron"; -// This matches controller::StandardPoseChannel -enum JointIndex { +// indices of joints of the Neuron standard skeleton. +// This is 'almost' the same as the High Fidelity standard skeleton. +// It is missing a thumb joint. +enum NeuronJointIndex { Hips = 0, RightUpLeg, RightLeg, @@ -93,12 +95,160 @@ enum JointIndex { Size }; -bool NeuronPlugin::isSupported() const { - // Because it's a client/server network architecture, we can't tell - // if the neuron is actually connected until we connect to the server. - return true; +// Almost a direct mapping except for LEFT_HAND_THUMB1 and RIGHT_HAND_THUMB1, +// which are not present in the Neuron standard skeleton. +static controller::StandardPoseChannel neuronJointIndexToPoseIndexMap[NeuronJointIndex::Size] = { + controller::HIPS, + controller::RIGHT_UP_LEG, + controller::RIGHT_LEG, + controller::RIGHT_FOOT, + controller::LEFT_UP_LEG, + controller::LEFT_LEG, + controller::LEFT_FOOT, + controller::SPINE, + controller::SPINE1, + controller::SPINE2, + controller::SPINE3, + controller::NECK, + controller::HEAD, + controller::RIGHT_SHOULDER, + controller::RIGHT_ARM, + controller::RIGHT_FORE_ARM, + controller::RIGHT_HAND, + controller::RIGHT_HAND_THUMB2, + controller::RIGHT_HAND_THUMB3, + controller::RIGHT_HAND_THUMB4, + controller::RIGHT_HAND_INDEX1, + controller::RIGHT_HAND_INDEX2, + controller::RIGHT_HAND_INDEX3, + controller::RIGHT_HAND_INDEX4, + controller::RIGHT_HAND_MIDDLE1, + controller::RIGHT_HAND_MIDDLE2, + controller::RIGHT_HAND_MIDDLE3, + controller::RIGHT_HAND_MIDDLE4, + controller::RIGHT_HAND_RING1, + controller::RIGHT_HAND_RING2, + controller::RIGHT_HAND_RING3, + controller::RIGHT_HAND_RING4, + controller::RIGHT_HAND_PINKY1, + controller::RIGHT_HAND_PINKY2, + controller::RIGHT_HAND_PINKY3, + controller::RIGHT_HAND_PINKY4, + controller::LEFT_SHOULDER, + controller::LEFT_ARM, + controller::LEFT_FORE_ARM, + controller::LEFT_HAND, + controller::LEFT_HAND_THUMB2, + controller::LEFT_HAND_THUMB3, + controller::LEFT_HAND_THUMB4, + controller::LEFT_HAND_INDEX1, + controller::LEFT_HAND_INDEX2, + controller::LEFT_HAND_INDEX3, + controller::LEFT_HAND_INDEX4, + controller::LEFT_HAND_MIDDLE1, + controller::LEFT_HAND_MIDDLE2, + controller::LEFT_HAND_MIDDLE3, + controller::LEFT_HAND_MIDDLE4, + controller::LEFT_HAND_RING1, + controller::LEFT_HAND_RING2, + controller::LEFT_HAND_RING3, + controller::LEFT_HAND_RING4, + controller::LEFT_HAND_PINKY1, + controller::LEFT_HAND_PINKY2, + controller::LEFT_HAND_PINKY3, + controller::LEFT_HAND_PINKY4 +}; + +static controller::StandardPoseChannel neuronJointIndexToPoseIndex(NeuronJointIndex i) { + assert(i >= 0 && i < NeuronJointIndex::Size); + if (i >= 0 && i < NeuronJointIndex::Size) { + return neuronJointIndexToPoseIndexMap[i]; + } else { + return (controller::StandardPoseChannel)0; // not sure what to do here, but don't crash! + } } +static const char* controllerJointName(controller::StandardPoseChannel i) { + switch (i) { + case controller::HIPS: return "Hips"; + case controller::RIGHT_UP_LEG: return "RightUpLeg"; + case controller::RIGHT_LEG: return "RightLeg"; + case controller::RIGHT_FOOT: return "RightFoot"; + case controller::LEFT_UP_LEG: return "LeftUpLeg"; + case controller::LEFT_LEG: return "LeftLeg"; + case controller::LEFT_FOOT: return "LeftFoot"; + case controller::SPINE: return "Spine"; + case controller::SPINE1: return "Spine1"; + case controller::SPINE2: return "Spine2"; + case controller::SPINE3: return "Spine3"; + case controller::NECK: return "Neck"; + case controller::HEAD: return "Head"; + case controller::RIGHT_SHOULDER: return "RightShoulder"; + case controller::RIGHT_ARM: return "RightArm"; + case controller::RIGHT_FORE_ARM: return "RightForeArm"; + case controller::RIGHT_HAND: return "RightHand"; + case controller::RIGHT_HAND_THUMB1: return "RightHandThumb1"; + case controller::RIGHT_HAND_THUMB2: return "RightHandThumb2"; + case controller::RIGHT_HAND_THUMB3: return "RightHandThumb3"; + case controller::RIGHT_HAND_THUMB4: return "RightHandThumb4"; + case controller::RIGHT_HAND_INDEX1: return "RightHandIndex1"; + case controller::RIGHT_HAND_INDEX2: return "RightHandIndex2"; + case controller::RIGHT_HAND_INDEX3: return "RightHandIndex3"; + case controller::RIGHT_HAND_INDEX4: return "RightHandIndex4"; + case controller::RIGHT_HAND_MIDDLE1: return "RightHandMiddle1"; + case controller::RIGHT_HAND_MIDDLE2: return "RightHandMiddle2"; + case controller::RIGHT_HAND_MIDDLE3: return "RightHandMiddle3"; + case controller::RIGHT_HAND_MIDDLE4: return "RightHandMiddle4"; + case controller::RIGHT_HAND_RING1: return "RightHandRing1"; + case controller::RIGHT_HAND_RING2: return "RightHandRing2"; + case controller::RIGHT_HAND_RING3: return "RightHandRing3"; + case controller::RIGHT_HAND_RING4: return "RightHandRing4"; + case controller::RIGHT_HAND_PINKY1: return "RightHandPinky1"; + case controller::RIGHT_HAND_PINKY2: return "RightHandPinky2"; + case controller::RIGHT_HAND_PINKY3: return "RightHandPinky3"; + case controller::RIGHT_HAND_PINKY4: return "RightHandPinky4"; + case controller::LEFT_SHOULDER: return "LeftShoulder"; + case controller::LEFT_ARM: return "LeftArm"; + case controller::LEFT_FORE_ARM: return "LeftForeArm"; + case controller::LEFT_HAND: return "LeftHand"; + case controller::LEFT_HAND_THUMB1: return "LeftHandThumb1"; + case controller::LEFT_HAND_THUMB2: return "LeftHandThumb2"; + case controller::LEFT_HAND_THUMB3: return "LeftHandThumb3"; + case controller::LEFT_HAND_THUMB4: return "LeftHandThumb4"; + case controller::LEFT_HAND_INDEX1: return "LeftHandIndex1"; + case controller::LEFT_HAND_INDEX2: return "LeftHandIndex2"; + case controller::LEFT_HAND_INDEX3: return "LeftHandIndex3"; + case controller::LEFT_HAND_INDEX4: return "LeftHandIndex4"; + case controller::LEFT_HAND_MIDDLE1: return "LeftHandMiddle1"; + case controller::LEFT_HAND_MIDDLE2: return "LeftHandMiddle2"; + case controller::LEFT_HAND_MIDDLE3: return "LeftHandMiddle3"; + case controller::LEFT_HAND_MIDDLE4: return "LeftHandMiddle4"; + case controller::LEFT_HAND_RING1: return "LeftHandRing1"; + case controller::LEFT_HAND_RING2: return "LeftHandRing2"; + case controller::LEFT_HAND_RING3: return "LeftHandRing3"; + case controller::LEFT_HAND_RING4: return "LeftHandRing4"; + case controller::LEFT_HAND_PINKY1: return "LeftHandPinky1"; + case controller::LEFT_HAND_PINKY2: return "LeftHandPinky2"; + case controller::LEFT_HAND_PINKY3: return "LeftHandPinky3"; + case controller::LEFT_HAND_PINKY4: return "LeftHandPinky4"; + default: return "???"; + } +} + +// convert between YXZ neuron euler angles in degrees to quaternion +// this is the default setting in the Axis Neuron server. +static quat eulerToQuat(vec3 euler) { + // euler.x and euler.y are swaped, WTF. + glm::vec3 e = glm::vec3(euler.y, euler.x, euler.z) * RADIANS_PER_DEGREE; + return (glm::angleAxis(e.y, Vectors::UNIT_Y) * + glm::angleAxis(e.x, Vectors::UNIT_X) * + glm::angleAxis(e.z, Vectors::UNIT_Z)); +} + +// +// neuronDataReader SDK callback functions +// + // NOTE: must be thread-safe void FrameDataReceivedCallback(void* context, SOCKET_REF sender, BvhDataHeaderEx* header, float* data) { @@ -133,7 +283,28 @@ void FrameDataReceivedCallback(void* context, SOCKET_REF sender, BvhDataHeaderEx // copy the data memcpy(&(neuronPlugin->_joints[0]), data, sizeof(NeuronPlugin::NeuronJoint) * NUM_JOINTS); + } else { + // enter mutex + std::lock_guard guard(neuronPlugin->_jointsMutex); + + // + // Data is 3 floats per joint: 3 rotation euler angles (degrees) + // + + // resize vector if necessary + const size_t NUM_FLOATS_PER_JOINT = 3; + const size_t NUM_JOINTS = header->DataCount / NUM_FLOATS_PER_JOINT; + if (neuronPlugin->_joints.size() != NUM_JOINTS) { + neuronPlugin->_joints.resize(NUM_JOINTS, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); + } + + assert(sizeof(NeuronPlugin::NeuronJoint) == (NUM_FLOATS_PER_JOINT * sizeof(float))); + + for (int i = 0; i < NUM_JOINTS; i++) { + // TODO: should probably just copy over default positions?! + memcpy(&(neuronPlugin->_joints[i].euler), data, sizeof(float) * NUM_FLOATS_PER_JOINT); + } qCCritical(inputplugins) << "NeruonPlugin: format not supported"; @@ -148,6 +319,9 @@ void FrameDataReceivedCallback(void* context, SOCKET_REF sender, BvhDataHeaderEx } } +// I can't even get the SDK to send me a callback. +// BRCommandFetchAvatarDataFromServer & BRRegisterAutoSyncParmeter [sic] don't seem to work. +// So this is totally untested. // NOTE: must be thread-safe static void CommandDataReceivedCallback(void* context, SOCKET_REF sender, CommandPack* pack, void* data) { @@ -196,9 +370,20 @@ static void CommandDataReceivedCallback(void* context, SOCKET_REF sender, Comman // NOTE: must be thread-safe static void SocketStatusChangedCallback(void* context, SOCKET_REF sender, SocketStatus status, char* message) { + // just dump to log, later we might want to pop up a connection lost dialog or attempt to reconnect. qCDebug(inputplugins) << "NeuronPlugin: socket status = " << message; } +// +// NeuronPlugin +// + +bool NeuronPlugin::isSupported() const { + // Because it's a client/server network architecture, we can't tell + // if the neuron is actually connected until we connect to the server. + return true; +} + void NeuronPlugin::activate() { InputPlugin::activate(); @@ -206,28 +391,26 @@ void NeuronPlugin::activate() { auto userInputMapper = DependencyManager::get(); userInputMapper->registerDevice(_inputDevice); - qCDebug(inputplugins) << "NeuronPlugin::activate"; - // register c-style callbacks BRRegisterFrameDataCallback((void*)this, FrameDataReceivedCallback); BRRegisterCommandDataCallback((void*)this, CommandDataReceivedCallback); BRRegisterSocketStatusCallback((void*)this, SocketStatusChangedCallback); - // TODO: pull these from prefs! + // TODO: Pull these from prefs dialog? + // localhost is fine for now. _serverAddress = "localhost"; - _serverPort = 7001; + _serverPort = 7001; // default port for TCP Axis Neuron server. + _socketRef = BRConnectTo((char*)_serverAddress.c_str(), _serverPort); if (!_socketRef) { // error - qCCritical(inputplugins) << "NeuronPlugin: error connecting to " << _serverAddress.c_str() << ":" << _serverPort << "error = " << BRGetLastErrorMessage(); + qCCritical(inputplugins) << "NeuronPlugin: error connecting to " << _serverAddress.c_str() << ":" << _serverPort << ", error = " << BRGetLastErrorMessage(); } else { qCDebug(inputplugins) << "NeuronPlugin: success connecting to " << _serverAddress.c_str() << ":" << _serverPort; } } void NeuronPlugin::deactivate() { - qCDebug(inputplugins) << "NeuronPlugin::deactivate"; - // unregister from userInputMapper if (_inputDevice->_deviceID != controller::Input::INVALID_DEVICE) { auto userInputMapper = DependencyManager::get(); @@ -241,126 +424,35 @@ void NeuronPlugin::deactivate() { InputPlugin::deactivate(); } -// convert between euler in degrees to quaternion -static quat eulerToQuat(vec3 euler) { - // euler.x and euler.y are swaped (thanks NOMICOM!) - glm::vec3 e = glm::vec3(euler.y, euler.x, euler.z) * RADIANS_PER_DEGREE; - return (glm::angleAxis(e.y, Vectors::UNIT_Y) * glm::angleAxis(e.x, Vectors::UNIT_X) * glm::angleAxis(e.z, Vectors::UNIT_Z)); -} - void NeuronPlugin::pluginUpdate(float deltaTime, bool jointsCaptured) { - std::vector joints; - // copy the shared data { + // lock and copy std::lock_guard guard(_jointsMutex); joints = _joints; } - - /* - DebugDraw::getInstance().addMyAvatarMarker("LEFT_FOOT", - eulerToQuat(joints[6].euler), - joints[6].pos / 100.0f, - glm::vec4(1)); - */ _inputDevice->update(deltaTime, joints, _prevJoints); _prevJoints = joints; } void NeuronPlugin::saveSettings() const { InputPlugin::saveSettings(); - // TODO: - qCDebug(inputplugins) << "NeuronPlugin::saveSettings"; } void NeuronPlugin::loadSettings() { InputPlugin::loadSettings(); - // TODO: - qCDebug(inputplugins) << "NeuronPlugin::loadSettings"; } // // InputDevice // -static controller::StandardPoseChannel neuronJointIndexToPoseIndex(JointIndex i) { - // Currently they are the same. - // but that won't always be the case... - return (controller::StandardPoseChannel)i; -} - -static const char* neuronJointName(JointIndex i) { - switch (i) { - case Hips: return "Hips"; - case RightUpLeg: return "RightUpLeg"; - case RightLeg: return "RightLeg"; - case RightFoot: return "RightFoot"; - case LeftUpLeg: return "LeftUpLeg"; - case LeftLeg: return "LeftLeg"; - case LeftFoot: return "LeftFoot"; - case Spine: return "Spine"; - case Spine1: return "Spine1"; - case Spine2: return "Spine2"; - case Spine3: return "Spine3"; - case Neck: return "Neck"; - case Head: return "Head"; - case RightShoulder: return "RightShoulder"; - case RightArm: return "RightArm"; - case RightForeArm: return "RightForeArm"; - case RightHand: return "RightHand"; - case RightHandThumb1: return "RightHandThumb1"; - case RightHandThumb2: return "RightHandThumb2"; - case RightHandThumb3: return "RightHandThumb3"; - case RightInHandIndex: return "RightInHandIndex"; - case RightHandIndex1: return "RightHandIndex1"; - case RightHandIndex2: return "RightHandIndex2"; - case RightHandIndex3: return "RightHandIndex3"; - case RightInHandMiddle: return "RightInHandMiddle"; - case RightHandMiddle1: return "RightHandMiddle1"; - case RightHandMiddle2: return "RightHandMiddle2"; - case RightHandMiddle3: return "RightHandMiddle3"; - case RightInHandRing: return "RightInHandRing"; - case RightHandRing1: return "RightHandRing1"; - case RightHandRing2: return "RightHandRing2"; - case RightHandRing3: return "RightHandRing3"; - case RightInHandPinky: return "RightInHandPinky"; - case RightHandPinky1: return "RightHandPinky1"; - case RightHandPinky2: return "RightHandPinky2"; - case RightHandPinky3: return "RightHandPinky3"; - case LeftShoulder: return "LeftShoulder"; - case LeftArm: return "LeftArm"; - case LeftForeArm: return "LeftForeArm"; - case LeftHand: return "LeftHand"; - case LeftHandThumb1: return "LeftHandThumb1"; - case LeftHandThumb2: return "LeftHandThumb2"; - case LeftHandThumb3: return "LeftHandThumb3"; - case LeftInHandIndex: return "LeftInHandIndex"; - case LeftHandIndex1: return "LeftHandIndex1"; - case LeftHandIndex2: return "LeftHandIndex2"; - case LeftHandIndex3: return "LeftHandIndex3"; - case LeftInHandMiddle: return "LeftInHandMiddle"; - case LeftHandMiddle1: return "LeftHandMiddle1"; - case LeftHandMiddle2: return "LeftHandMiddle2"; - case LeftHandMiddle3: return "LeftHandMiddle3"; - case LeftInHandRing: return "LeftInHandRing"; - case LeftHandRing1: return "LeftHandRing1"; - case LeftHandRing2: return "LeftHandRing2"; - case LeftHandRing3: return "LeftHandRing3"; - case LeftInHandPinky: return "LeftInHandPinky"; - case LeftHandPinky1: return "LeftHandPinky1"; - case LeftHandPinky2: return "LeftHandPinky2"; - case LeftHandPinky3: return "LeftHandPinky3"; - default: return "???"; - } -} - controller::Input::NamedVector NeuronPlugin::InputDevice::getAvailableInputs() const { - // TODO: static controller::Input::NamedVector availableInputs; - if (availableInputs.size() == 0) { - for (int i = 0; i < JointIndex::Size; i++) { - availableInputs.push_back(makePair(neuronJointIndexToPoseIndex((JointIndex)i), neuronJointName((JointIndex)i))); + for (int i = 0; i < controller::NUM_STANDARD_POSES; i++) { + auto channel = static_cast(i); + availableInputs.push_back(makePair(channel, controllerJointName(channel))); } }; return availableInputs; @@ -373,21 +465,21 @@ QString NeuronPlugin::InputDevice::getDefaultMappingConfig() const { void NeuronPlugin::InputDevice::update(float deltaTime, const std::vector& joints, const std::vector& prevJoints) { for (int i = 0; i < joints.size(); i++) { - int poseIndex = neuronJointIndexToPoseIndex((JointIndex)i); glm::vec3 linearVel, angularVel; glm::vec3 pos = (joints[i].pos * METERS_PER_CENTIMETER); glm::quat rot = eulerToQuat(joints[i].euler); if (i < prevJoints.size()) { - linearVel = (pos - (prevJoints[i].pos * METERS_PER_CENTIMETER)) / deltaTime; - // quat log imag part points along the axis of rotation, and it's length will be the half angle. + linearVel = (pos - (prevJoints[i].pos * METERS_PER_CENTIMETER)) / deltaTime; // m/s + // quat log imaginary part points along the axis of rotation, with length of one half the angle of rotation. glm::quat d = glm::log(rot * glm::inverse(eulerToQuat(prevJoints[i].euler))); - angularVel = glm::vec3(d.x, d.y, d.z) / (0.5f * deltaTime); + angularVel = glm::vec3(d.x, d.y, d.z) / (0.5f * deltaTime); // radians/s } + int poseIndex = neuronJointIndexToPoseIndex((NeuronJointIndex)i); _poseStateMap[poseIndex] = controller::Pose(pos, rot, linearVel, angularVel); } -} -void NeuronPlugin::InputDevice::focusOutEvent() { - // TODO: - qCDebug(inputplugins) << "NeuronPlugin::InputDevice::focusOutEvent"; + // fill in missing thumb joints with identity. + // TODO: need a standard displacement + _poseStateMap[controller::RIGHT_HAND_THUMB1] = controller::Pose(glm::vec3(), glm::quat(), glm::vec3(), glm::vec3()); + _poseStateMap[controller::LEFT_HAND_THUMB1] = controller::Pose(glm::vec3(), glm::quat(), glm::vec3(), glm::vec3()); } diff --git a/plugins/hifiNeuron/src/NeuronPlugin.h b/plugins/hifiNeuron/src/NeuronPlugin.h index f787838ce2..c85a5dd383 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.h +++ b/plugins/hifiNeuron/src/NeuronPlugin.h @@ -57,7 +57,7 @@ protected: virtual controller::Input::NamedVector getAvailableInputs() const override; virtual QString getDefaultMappingConfig() const override; virtual void update(float deltaTime, bool jointsCaptured) override {}; - virtual void focusOutEvent() override; + virtual void focusOutEvent() override {}; void update(float deltaTime, const std::vector& joints, const std::vector& prevJoints); }; @@ -71,9 +71,13 @@ protected: int _serverPort; void* _socketRef; - std::vector _joints; - std::mutex _jointsMutex; // used to guard access to _joints + // used to guard multi-threaded access to _joints + std::mutex _jointsMutex; + // copy of data directly from the NeuronDataReader SDK + std::vector _joints; + + // one frame old copy of _joints, used to caluclate angular and linear velocity. std::vector _prevJoints; }; From fd3eed3d4132e58ff5e58284ac57e1feb9ad9ae1 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sat, 26 Dec 2015 11:50:54 -0800 Subject: [PATCH 177/209] NeruonPlugin: translation support Warn if translations are not present. --- examples/controllers/neuron/neuronAvatar.js | 10 +- plugins/hifiNeuron/src/NeuronPlugin.cpp | 100 +++++++++++++++----- 2 files changed, 85 insertions(+), 25 deletions(-) diff --git a/examples/controllers/neuron/neuronAvatar.js b/examples/controllers/neuron/neuronAvatar.js index cc53987f05..a124316f24 100644 --- a/examples/controllers/neuron/neuronAvatar.js +++ b/examples/controllers/neuron/neuronAvatar.js @@ -62,6 +62,8 @@ var JOINT_PARENT_MAP = { LeftHandPinky: "LeftHandPinky3", }; +var USE_TRANSLATIONS = false; + function dumpHardwareMapping() { Object.keys(Controller.Hardware).forEach(function (deviceName) { Object.keys(Controller.Hardware[deviceName]).forEach(function (input) { @@ -152,8 +154,12 @@ NeuronAvatar.prototype.update = function (deltaTime) { // Then we transform back into joint local by multiplying by the inverse of the parents absolute rotation. MyAvatar.setJointRotation(j, Quat.multiply(Quat.inverse(parentDefaultAbsRot), Quat.multiply(pose.rotation, defaultAbsRot))); - // TODO: - //MyAvatar.setJointTranslation(j, Vec3.multiply(100.0, pose.translation)); + // translation proportions might be different from the neuron avatar and the user avatar skeleton. + // so this is disabled by default + if (USE_TRANSLATIONS) { + var localTranslation = Vec3.multiplyQbyV(Quat.inverse(parentDefaultAbsRot), pose.translation); + MyAvatar.setJointTranslation(j, localTranslation); + } } } }; diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index 4edda64c22..0e338c30f8 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -159,6 +159,73 @@ static controller::StandardPoseChannel neuronJointIndexToPoseIndexMap[NeuronJoin controller::LEFT_HAND_PINKY4 }; +// in rig frame +static glm::vec3 rightHandThumb1DefaultAbsTranslation(-2.155500650405884, -0.7610001564025879, 2.685631036758423); +static glm::vec3 leftHandThumb1DefaultAbsTranslation(2.1555817127227783, -0.7603635787963867, 2.6856393814086914); + +// default translations (cm) +static glm::vec3 neuronJointTranslations[NeuronJointIndex::Size] = { + {131.901, 95.6602, -27.9815}, + {-9.55907, -1.58772, 0.0760284}, + {0.0144232, -41.4683, -0.105322}, + {1.59348, -41.5875, -0.557237}, + {9.72077, -1.68926, -0.280643}, + {0.0886684, -43.1586, -0.0111596}, + {-2.98473, -44.0517, 0.0694456}, + {0.110967, 16.3959, 0.140463}, + {0.0500451, 10.0238, 0.0731921}, + {0.061568, 10.4352, 0.0583075}, + {0.0500606, 10.0217, 0.0711083}, + {0.0317731, 10.7176, 0.0779325}, + {-0.0204253, 9.71067, 0.131734}, + {-3.24245, 7.13584, 0.185638}, + {-13.0885, -0.0877601, 0.176065}, + {-27.2674, 0.0688724, 0.0272146}, + {-26.7673, 0.0301916, 0.0102847}, + {-2.56017, 0.195537, 3.20968}, + {-3.78796, 0, 0}, + {-2.63141, 0, 0}, + {-3.31579, 0.522947, 2.03495}, + {-5.36589, -0.0939789, 1.02771}, + {-3.72278, 0, 0}, + {-2.11074, 0, 0}, + {-3.47874, 0.532042, 0.778358}, + {-5.32194, -0.0864, 0.322863}, + {-4.06232, 0, 0}, + {-2.54653, 0, 0}, + {-3.46131, 0.553263, -0.132632}, + {-4.76716, -0.0227368, -0.492632}, + {-3.54073, 0, 0}, + {-2.45634, 0, 0}, + {-3.25137, 0.482779, -1.23613}, + {-4.25937, -0.0227368, -1.12168}, + {-2.83528, 0, 0}, + {-1.79166, 0, 0}, + {3.25624, 7.13148, -0.131575}, + {13.149, -0.052598, -0.125076}, + {27.2903, 0.00282644, -0.0181535}, + {26.6602, 0.000969969, -0.0487599}, + {2.56017, 0.195537, 3.20968}, + {3.78796, 0, 0}, + {2.63141, 0, 0}, + {3.31579, 0.522947, 2.03495}, + {5.36589, -0.0939789, 1.02771}, + {3.72278, 0, 0}, + {2.11074, 0, 0}, + {3.47874, 0.532042, 0.778358}, + {5.32194, -0.0864, 0.322863}, + {4.06232, 0, 0}, + {2.54653, 0, 0}, + {3.46131, 0.553263, -0.132632}, + {4.76716, -0.0227368, -0.492632}, + {3.54073, 0, 0}, + {2.45634, 0, 0}, + {3.25137, 0.482779, -1.23613}, + {4.25937, -0.0227368, -1.12168}, + {2.83528, 0, 0}, + {1.79166, 0, 0} +}; + static controller::StandardPoseChannel neuronJointIndexToPoseIndex(NeuronJointIndex i) { assert(i >= 0 && i < NeuronJointIndex::Size); if (i >= 0 && i < NeuronJointIndex::Size) { @@ -285,31 +352,20 @@ void FrameDataReceivedCallback(void* context, SOCKET_REF sender, BvhDataHeaderEx memcpy(&(neuronPlugin->_joints[0]), data, sizeof(NeuronPlugin::NeuronJoint) * NUM_JOINTS); } else { + qCWarning(inputplugins) << "NeuronPlugin: unsuported binary format, please enable displacements"; + // enter mutex std::lock_guard guard(neuronPlugin->_jointsMutex); - // - // Data is 3 floats per joint: 3 rotation euler angles (degrees) - // - - // resize vector if necessary - const size_t NUM_FLOATS_PER_JOINT = 3; - const size_t NUM_JOINTS = header->DataCount / NUM_FLOATS_PER_JOINT; - if (neuronPlugin->_joints.size() != NUM_JOINTS) { - neuronPlugin->_joints.resize(NUM_JOINTS, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); + if (neuronPlugin->_joints.size() != NeuronJointIndex::Size) { + neuronPlugin->_joints.resize(NeuronJointIndex::Size, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); } - assert(sizeof(NeuronPlugin::NeuronJoint) == (NUM_FLOATS_PER_JOINT * sizeof(float))); - - for (int i = 0; i < NUM_JOINTS; i++) { - // TODO: should probably just copy over default positions?! - memcpy(&(neuronPlugin->_joints[i].euler), data, sizeof(float) * NUM_FLOATS_PER_JOINT); + for (int i = 0; i < NeuronJointIndex::Size; i++) { + neuronPlugin->_joints[i].euler = glm::vec3(); + neuronPlugin->_joints[i].pos = neuronJointTranslations[i]; } - - qCCritical(inputplugins) << "NeruonPlugin: format not supported"; - } - } else { static bool ONCE = false; if (!ONCE) { @@ -466,7 +522,7 @@ QString NeuronPlugin::InputDevice::getDefaultMappingConfig() const { void NeuronPlugin::InputDevice::update(float deltaTime, const std::vector& joints, const std::vector& prevJoints) { for (int i = 0; i < joints.size(); i++) { glm::vec3 linearVel, angularVel; - glm::vec3 pos = (joints[i].pos * METERS_PER_CENTIMETER); + glm::vec3 pos = joints[i].pos; glm::quat rot = eulerToQuat(joints[i].euler); if (i < prevJoints.size()) { linearVel = (pos - (prevJoints[i].pos * METERS_PER_CENTIMETER)) / deltaTime; // m/s @@ -478,8 +534,6 @@ void NeuronPlugin::InputDevice::update(float deltaTime, const std::vector Date: Sat, 26 Dec 2015 12:13:29 -0800 Subject: [PATCH 178/209] NeuronPlugin: register for combination mode This will tell us, if user is using arms, upper-body or full body configurations. --- plugins/hifiNeuron/src/NeuronPlugin.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index 0e338c30f8..97131a0a87 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -463,6 +463,8 @@ void NeuronPlugin::activate() { qCCritical(inputplugins) << "NeuronPlugin: error connecting to " << _serverAddress.c_str() << ":" << _serverPort << ", error = " << BRGetLastErrorMessage(); } else { qCDebug(inputplugins) << "NeuronPlugin: success connecting to " << _serverAddress.c_str() << ":" << _serverPort; + + BRRegisterAutoSyncParmeter(_socketRef, Cmd_CombinationMode); } } @@ -474,6 +476,7 @@ void NeuronPlugin::deactivate() { } if (_socketRef) { + BRUnregisterAutoSyncParmeter(_socketRef, Cmd_CombinationMode); BRCloseSocket(_socketRef); } From 28c53822b15291c99f7845e3e42af285e45019f1 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sun, 27 Dec 2015 12:37:33 -0800 Subject: [PATCH 179/209] add raypick blacklisting to hand grab script --- examples/controllers/handControllerGrab.js | 33 +++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index e0a7c55af8..aa416068f2 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -116,6 +116,11 @@ var DEFAULT_GRABBABLE_DATA = { invertSolidWhileHeld: false }; + +// sometimes we want to exclude objects from being picked +var USE_BLACKLIST = true; +var blacklist = []; + //we've created various ways of visualizing looking for and moving distant objects var USE_ENTITY_LINES_FOR_SEARCHING = false; var USE_OVERLAY_LINES_FOR_SEARCHING = false; @@ -771,7 +776,14 @@ function MyController(hand) { }) } - var intersection = Entities.findRayIntersection(pickRayBacked, true); + var intersection; + + if(USE_BLACKLIST===true){ + intersection = Entities.findRayIntersection(pickRay, true, [], blacklist); + } + else{ + intersection = Entities.findRayIntersection(pickRayBacked, true); + } if (intersection.intersects) { // the ray is intersecting something we can move. @@ -1626,6 +1638,7 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); Messages.subscribe('Hifi-Hand-Grab'); +Messages.subscribe('Hifi-Hand-RayPick-Blacklist'); handleHandMessages = function(channel, message, sender) { if (sender === MyAvatar.sessionUUID) { @@ -1649,6 +1662,24 @@ handleHandMessages = function(channel, message, sender) { } catch (e) { } } + else if (channel === 'Hifi-Hand-RayPick-Blacklist') { + try { + var data = JSON.parse(message); + var action = data.action; + var id = data.id; + var index = blacklist.indexOf(id); + + if (action === 'add' && index ===-1) { + blacklist.push(id); + } + if (action === 'remove') { + if (index > -1) { + blacklist.splice(index, 1); + } + } + + } catch (e) {} + } } } From 546e908633f41206c032b114eaa3af179b5bc770 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sun, 27 Dec 2015 12:46:40 -0800 Subject: [PATCH 180/209] protect blacklisting to my id --- examples/controllers/handControllerGrab.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index aa416068f2..80fcaa3f6f 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -777,7 +777,7 @@ function MyController(hand) { } var intersection; - + if(USE_BLACKLIST===true){ intersection = Entities.findRayIntersection(pickRay, true, [], blacklist); } @@ -1662,7 +1662,7 @@ handleHandMessages = function(channel, message, sender) { } catch (e) { } } - else if (channel === 'Hifi-Hand-RayPick-Blacklist') { + else if (channel === 'Hifi-Hand-RayPick-Blacklist' && sender === MyAvatar.sessionUUID) { try { var data = JSON.parse(message); var action = data.action; From 0e30393c81b7ec1067d0fdfb5f483b68004326cd Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sun, 27 Dec 2015 12:47:56 -0800 Subject: [PATCH 181/209] make sure theres something on the blacklist --- examples/controllers/handControllerGrab.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 80fcaa3f6f..deca0aa3ba 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -778,13 +778,12 @@ function MyController(hand) { var intersection; - if(USE_BLACKLIST===true){ - intersection = Entities.findRayIntersection(pickRay, true, [], blacklist); + if (USE_BLACKLIST === true && blacklist.length !== 0) { + intersection = Entities.findRayIntersection(pickRay, true, [], blacklist); + } else { + intersection = Entities.findRayIntersection(pickRayBacked, true); } - else{ - intersection = Entities.findRayIntersection(pickRayBacked, true); - } - + if (intersection.intersects) { // the ray is intersecting something we can move. var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); From 1f834a9c01f3343368cc89f1df87c4f1e7e6c957 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 27 Dec 2015 16:29:30 -0800 Subject: [PATCH 182/209] neruonAvatar.js: attempt to adjust hips for HMD mode. It attempts to adjust the hips so that the avatar's head is at the same location & orientation as the HMD in world space, however it's fighting with the internal c++ code that also attempts to adjust the hips as well. --- examples/controllers/neuron/neuronAvatar.js | 78 ++++++++++++++++++--- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/examples/controllers/neuron/neuronAvatar.js b/examples/controllers/neuron/neuronAvatar.js index a124316f24..abd51f2990 100644 --- a/examples/controllers/neuron/neuronAvatar.js +++ b/examples/controllers/neuron/neuronAvatar.js @@ -64,6 +64,27 @@ var JOINT_PARENT_MAP = { var USE_TRANSLATIONS = false; +// ctor +function Xform(rot, pos) { + this.rot = rot; + this.pos = pos; +}; +Xform.mul = function (lhs, rhs) { + var rot = Quat.multiply(lhs.rot, rhs.rot); + var pos = Vec3.sum(lhs.pos, Vec3.multiplyQbyV(lhs.rot, rhs.pos)); + return new Xform(rot, pos); +}; +Xform.prototype.inv = function () { + var invRot = Quat.inverse(this.rot); + var invPos = Vec3.multiply(-1, this.pos); + return new Xform(invRot, Vec3.multiplyQbyV(invRot, invPos)); +}; +Xform.prototype.toString = function () { + var rot = this.rot; + var pos = this.pos; + return "Xform rot = (" + rot.x + ", " + rot.y + ", " + rot.z + ", " + rot.w + "), pos = (" + pos.x + ", " + pos.y + ", " + pos.z + ")"; +}; + function dumpHardwareMapping() { Object.keys(Controller.Hardware).forEach(function (deviceName) { Object.keys(Controller.Hardware[deviceName]).forEach(function (input) { @@ -108,19 +129,19 @@ NeuronAvatar.prototype.activate = function () { this._active = true; // build absDefaultPoseMap - this._absDefaultRotMap = {}; - this._absDefaultRotMap[""] = {x: 0, y: 0, z: 0, w: 1}; + this._defaultAbsRotMap = {}; + this._defaultAbsPosMap = {}; + this._defaultAbsRotMap[""] = {x: 0, y: 0, z: 0, w: 1}; + this._defaultAbsPosMap[""] = {x: 0, y: 0, z: 0}; var keys = Object.keys(JOINT_PARENT_MAP); var i, l = keys.length; for (i = 0; i < l; i++) { var jointName = keys[i]; var j = MyAvatar.getJointIndex(jointName); var parentJointName = JOINT_PARENT_MAP[jointName]; - if (parentJointName === "") { - this._absDefaultRotMap[jointName] = MyAvatar.getDefaultJointRotation(j); - } else { - this._absDefaultRotMap[jointName] = Quat.multiply(this._absDefaultRotMap[parentJointName], MyAvatar.getDefaultJointRotation(j)); - } + this._defaultAbsRotMap[jointName] = Quat.multiply(this._defaultAbsRotMap[parentJointName], MyAvatar.getDefaultJointRotation(j)); + this._defaultAbsPosMap[jointName] = Vec3.sum(this._defaultAbsPosMap[parentJointName], + Quat.multiply(this._defaultAbsRotMap[parentJointName], MyAvatar.getDefaultJointTranslation(j))); } }; @@ -134,10 +155,16 @@ NeuronAvatar.prototype.deactivate = function () { }; NeuronAvatar.prototype.update = function (deltaTime) { + + var hmdActive = HMD.active; + var hmdXform = new Xform(HMD.orientation, HMD.position); + var keys = Object.keys(JOINT_PARENT_MAP); var i, l = keys.length; var absDefaultRot = {}; var jointName, channel, pose, parentJointName, j, parentDefaultAbsRot; + var localRotations = {}; + var localTranslations = {}; for (i = 0; i < l; i++) { var jointName = keys[i]; var channel = Controller.Hardware.Neuron[jointName]; @@ -145,23 +172,54 @@ NeuronAvatar.prototype.update = function (deltaTime) { pose = Controller.getPoseValue(channel); parentJointName = JOINT_PARENT_MAP[jointName]; j = MyAvatar.getJointIndex(jointName); - defaultAbsRot = this._absDefaultRotMap[jointName]; - parentDefaultAbsRot = this._absDefaultRotMap[parentJointName]; + defaultAbsRot = this._defaultAbsRotMap[jointName]; + parentDefaultAbsRot = this._defaultAbsRotMap[parentJointName]; // Rotations from the neuron controller are in world orientation but are delta's from the default pose. // So first we build the absolute rotation of the default pose (local into world). // Then apply the rotation from the controller, in world space. // Then we transform back into joint local by multiplying by the inverse of the parents absolute rotation. - MyAvatar.setJointRotation(j, Quat.multiply(Quat.inverse(parentDefaultAbsRot), Quat.multiply(pose.rotation, defaultAbsRot))); + var localRotation = Quat.multiply(Quat.inverse(parentDefaultAbsRot), Quat.multiply(pose.rotation, defaultAbsRot)); + if (!hmdActive || jointName !== "Hips") { + MyAvatar.setJointRotation(j, localRotation); + } + localRotations[jointName] = localRotation; // translation proportions might be different from the neuron avatar and the user avatar skeleton. // so this is disabled by default if (USE_TRANSLATIONS) { var localTranslation = Vec3.multiplyQbyV(Quat.inverse(parentDefaultAbsRot), pose.translation); MyAvatar.setJointTranslation(j, localTranslation); + localTranslations[jointName] = localTranslation; + } else { + localTranslations[jointName] = MyAvatar.getJointTranslation(j); } } } + + // TODO: Currrently does not work. + // it attempts to adjust the hips so that the avatar's head is at the same location & oreintation as the HMD. + // however it's fighting with the internal c++ code that also attempts to adjust the hips. + if (hmdActive) { + + var y180Xform = new Xform({x: 0, y: 1, z: 0, w: 0}, {x: 0, y: 0, z: 0}); + var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position); + var headXform = new Xform(localRotations["Head"], localTranslations["Head"]); + + // transform eyes down the heirarchy chain into avatar space. + var hierarchy = ["Neck", "Spine3", "Spine2", "Spine1", "Spine"]; + var i, l = hierarchy.length; + for (i = 0; i < l; i++) { + var xform = new Xform(localRotations[hierarchy[i]], localTranslations[hierarchy[i]]); + headXform = Xform.mul(xform, headXform); + } + + // solve for the offset that will put the eyes at the hmd position & orientation. + var hipsXform = Xform.mul(y180Xform, Xform.mul(avatarXform.inv(), Xform.mul(hmdXform, Xform.mul(y180Xform, headXform.inv())))); + + MyAvatar.setJointRotation("Hips", hipsXform.rot); + MyAvatar.setJointTranslation("Hips", hipsXform.pos); + } }; var neuronAvatar = new NeuronAvatar(); From c4d7b7b9bb2afc5abd5f084c45391ef51a372fca Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 28 Dec 2015 10:21:23 -0800 Subject: [PATCH 183/209] Update utils.js --- examples/libraries/utils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/libraries/utils.js b/examples/libraries/utils.js index 37dccd5ac8..115c1bcb65 100644 --- a/examples/libraries/utils.js +++ b/examples/libraries/utils.js @@ -274,7 +274,6 @@ hexToRgb = function(hex) { calculateHandSizeRatio = function() { // Get the ratio of the current avatar's hand to Owen's hand - // var standardCenterHandPoint = 0.11288; var standardCenterHandPoint = 0.11288; var jointNames = MyAvatar.getJointNames(); //get distance from handJoint up to leftHandIndex3 as a proxy for center of hand From 679070ff6e1b155fcb8388aa3c446515499e4d8f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 28 Dec 2015 10:22:02 -0800 Subject: [PATCH 184/209] Update hiddenEntityReset.js --- unpublishedScripts/hiddenEntityReset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index e8783bbbcb..a53d6e721f 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -169,7 +169,7 @@ } function createRaveStick(position) { - var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/raveStick.fbx"; + var modelURL = "http://hifi-content.s3.amazonaws.com/eric/models/raveStick.fbx"; var stick = Entities.addEntity({ type: "Model", name: "raveStick", From 4f80753d7b0c9ec88f49cc3ea3034d5929967e9f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 28 Dec 2015 10:22:34 -0800 Subject: [PATCH 185/209] Update masterReset.js --- unpublishedScripts/masterReset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index f3c38b2adf..b82c8340e4 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -148,7 +148,7 @@ MasterReset = function() { } function createRaveStick(position) { - var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/raveStick.fbx"; + var modelURL = "http://hifi-content.s3.amazonaws.com/eric/models/raveStick.fbx"; var stick = Entities.addEntity({ type: "Model", name: "raveStick", From 4b50a030e06aeffd105abd977511e4f1932edf30 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 28 Dec 2015 10:23:08 -0800 Subject: [PATCH 186/209] Update masterReset.js --- unpublishedScripts/masterReset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index b82c8340e4..2d6d9a0d01 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -1082,7 +1082,7 @@ MasterReset = function() { relativePosition: { x: 0, y: 0, - z: .06 + z: 0.06 }, relativeRotation: Quat.fromPitchYawRollDegrees(0,-90, -90) }, From d4fd59edc0299101599959f7e7732535808f1b41 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 28 Dec 2015 13:49:00 -0800 Subject: [PATCH 187/209] send blacklist messages --- examples/light_modifier/lightModifier.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index dc9332405e..3ead989d6d 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -17,7 +17,7 @@ var VERTICAL_SLIDERS = false; var SHOW_OVERLAYS = true; var SHOW_LIGHT_VOLUME = true; var USE_PARENTED_PANEL = true; -var VISIBLE_PANEL = false; +var VISIBLE_PANEL = true; var USE_LABELS = true; var LEFT_LABELS = false; var RIGHT_LABELS = true; @@ -586,6 +586,8 @@ function createVisiblePanel() { } var panel = Entities.addEntity(panelProperties); + var data = {action:'add', id:panel}; + Messages.sendMessage ('Hifi-Hand-RayPick-Blacklist',JSON.stringify(data)) return panel } @@ -821,7 +823,12 @@ function cleanup(fromMessage) { Entities.deleteEntity(panel); Entities.deleteEntity(visiblePanel); - + var data = { + action: 'remove', + id: visiblePanel + }; + Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)) + selectionManager.clearSelections(); Script.update.disconnect(rotateCloseButtons); if (hasParent === false) { From 36beea17fabf6e0829e21ba580d84d03890df788 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 28 Dec 2015 14:59:43 -0800 Subject: [PATCH 188/209] Improved hand controller reticle movement --- .../controllers/reticleHandRotationTest.js | 192 +++--------------- 1 file changed, 24 insertions(+), 168 deletions(-) diff --git a/examples/controllers/reticleHandRotationTest.js b/examples/controllers/reticleHandRotationTest.js index ece9283deb..a303e5e7b4 100644 --- a/examples/controllers/reticleHandRotationTest.js +++ b/examples/controllers/reticleHandRotationTest.js @@ -22,33 +22,13 @@ function length(posA, posB) { return length; } -var EXPECTED_CHANGE = 50; -var lastPos = Controller.getReticlePosition(); function moveReticleAbsolute(x, y) { var globalPos = Controller.getReticlePosition(); - var dX = x - globalPos.x; - var dY = y - globalPos.y; - - // some debugging to see if position is jumping around on us... - var distanceSinceLastMove = length(lastPos, globalPos); - if (distanceSinceLastMove > EXPECTED_CHANGE) { - debugPrint("------------------ distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------"); - } - - if (Math.abs(dX) > EXPECTED_CHANGE) { - debugPrint("surpressing unexpectedly large change dX:" + dX + "----------------------------"); - } - if (Math.abs(dY) > EXPECTED_CHANGE) { - debugPrint("surpressing unexpectedly large change dY:" + dY + "----------------------------"); - } - globalPos.x = x; globalPos.y = y; Controller.setReticlePosition(globalPos); - lastPos = globalPos; } - var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation"; var mapping = Controller.newMapping(MAPPING_NAME); mapping.from(Controller.Standard.LT).peek().constrainToInteger().to(Controller.Actions.ReticleClick); @@ -56,8 +36,6 @@ mapping.from(Controller.Standard.RT).peek().constrainToInteger().to(Controller.A mapping.enable(); -var lastRotatedLeft = Vec3.UNIT_NEG_Y; -var lastRotatedRight = Vec3.UNIT_NEG_Y; function debugPrint(message) { if (DEBUGGING) { @@ -65,24 +43,9 @@ function debugPrint(message) { } } -var MAX_WAKE_UP_DISTANCE = 0.005; -var MIN_WAKE_UP_DISTANCE = 0.001; -var INITIAL_WAKE_UP_DISTANCE = MIN_WAKE_UP_DISTANCE; -var INCREMENTAL_WAKE_UP_DISTANCE = 0.001; - -var MAX_SLEEP_DISTANCE = 0.0004; -var MIN_SLEEP_DISTANCE = 0.00001; //0.00002; -var INITIAL_SLEEP_DISTANCE = MIN_SLEEP_DISTANCE; -var INCREMENTAL_SLEEP_DISTANCE = 0.000002; // 0.00002; - -var leftAsleep = true; -var rightAsleep = true; - -var leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; -var rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; - -var leftSleepDistance = INITIAL_SLEEP_DISTANCE; -var rightSleepDistance = INITIAL_SLEEP_DISTANCE; +var leftRightBias = 0.0; +var filteredRotatedLeft = Vec3.UNIT_NEG_Y; +var filteredRotatedRight = Vec3.UNIT_NEG_Y; Script.update.connect(function(deltaTime) { @@ -96,153 +59,46 @@ Script.update.connect(function(deltaTime) { var rotatedRight = Vec3.multiplyQbyV(poseRight.rotation, Vec3.UNIT_NEG_Y); var rotatedLeft = Vec3.multiplyQbyV(poseLeft.rotation, Vec3.UNIT_NEG_Y); - var suppressRight = false; - var suppressLeft = false; - - // What I really want to do is to slowly increase the epsilon you have to move it - // to wake up, the longer you go without moving it - var leftDistance = Vec3.distance(rotatedLeft, lastRotatedLeft); - var rightDistance = Vec3.distance(rotatedRight, lastRotatedRight); - - // check to see if hand should wakeup or sleep - if (leftAsleep) { - if (leftDistance > leftWakeUpDistance) { - leftAsleep = false; - leftSleepDistance = INITIAL_SLEEP_DISTANCE; - leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; - } else { - // grow the wake up distance to make it harder to wake up - leftWakeUpDistance = Math.min(leftWakeUpDistance + INCREMENTAL_WAKE_UP_DISTANCE, MAX_WAKE_UP_DISTANCE); - } - } else { - // we are awake, determine if we should fall asleep, if we haven't moved - // at least as much as our sleep distance then we sleep - if (leftDistance < leftSleepDistance) { - leftAsleep = true; - leftSleepDistance = INITIAL_SLEEP_DISTANCE; - leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; - } else { - // if we moved more than the sleep amount, but we moved less than the max sleep - // amount, then increase our liklihood of sleep. - if (leftDistance < MAX_SLEEP_DISTANCE) { - print("growing sleep...."); - leftSleepDistance = Math.max(leftSleepDistance + INCREMENTAL_SLEEP_DISTANCE, MAX_SLEEP_DISTANCE); - } else { - // otherwise reset it to initial - leftSleepDistance = INITIAL_SLEEP_DISTANCE; - } - } - } - if (leftAsleep) { - suppressLeft = true; - debugPrint("suppressing left not moving enough"); - } - - // check to see if hand should wakeup or sleep - if (rightAsleep) { - if (rightDistance > rightWakeUpDistance) { - rightAsleep = false; - rightSleepDistance = INITIAL_SLEEP_DISTANCE; - rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; - } else { - // grow the wake up distance to make it harder to wake up - rightWakeUpDistance = Math.min(rightWakeUpDistance + INCREMENTAL_WAKE_UP_DISTANCE, MAX_WAKE_UP_DISTANCE); - } - } else { - // we are awake, determine if we should fall asleep, if we haven't moved - // at least as much as our sleep distance then we sleep - if (rightDistance < rightSleepDistance) { - rightAsleep = true; - rightSleepDistance = INITIAL_SLEEP_DISTANCE; - rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; - } else { - // if we moved more than the sleep amount, but we moved less than the max sleep - // amount, then increase our liklihood of sleep. - if (rightDistance < MAX_SLEEP_DISTANCE) { - print("growing sleep...."); - rightSleepDistance = Math.max(rightSleepDistance + INCREMENTAL_SLEEP_DISTANCE, MAX_SLEEP_DISTANCE); - } else { - // otherwise reset it to initial - rightSleepDistance = INITIAL_SLEEP_DISTANCE; - } - } - } - if (rightAsleep) { - suppressRight = true; - debugPrint("suppressing right not moving enough"); - } - - // check to see if hand is on base station - if (Vec3.equal(rotatedLeft, Vec3.UNIT_NEG_Y)) { - suppressLeft = true; - debugPrint("suppressing left on base station"); - } - if (Vec3.equal(rotatedRight, Vec3.UNIT_NEG_Y)) { - suppressRight = true; - debugPrint("suppressing right on base station"); - } - - // Keep track of last rotations, to detect resting (but not on base station hands) in the future - lastRotatedLeft = rotatedLeft; lastRotatedRight = rotatedRight; - if (suppressLeft && suppressRight) { - debugPrint("both hands suppressed bail out early"); - return; + + // Decide which hand should be controlling the pointer + // by comparing which one is moving more, and by + // tending to stay with the one moving more. + var BIAS_ADJUST_RATE = 0.5; + var BIAS_ADJUST_DEADZONE = 0.05; + leftRightBias += (Vec3.length(poseRight.angularVelocity) - Vec3.length(poseLeft.angularVelocity)) * BIAS_ADJUST_RATE; + if (leftRightBias < BIAS_ADJUST_DEADZONE) { + leftRightBias = 0.0; + } else if (leftRightBias > (1.0 - BIAS_ADJUST_DEADZONE)) { + leftRightBias = 1.0; } - if (suppressLeft) { - debugPrint("right only"); - rotatedLeft = rotatedRight; - } - if (suppressRight) { - debugPrint("left only"); - rotatedRight = rotatedLeft; - } - - // Average the two hand positions, if either hand is on base station, the - // other hand becomes the only used hand and the average is the hand in use - var rotated = Vec3.multiply(Vec3.sum(rotatedRight,rotatedLeft), 0.5); - - if (DEBUGGING) { - Vec3.print("rotatedRight:", rotatedRight); - Vec3.print("rotatedLeft:", rotatedLeft); - Vec3.print("rotated:", rotated); - } + // Velocity filter the hand rotation used to position reticle so that it is easier to target small things with the hand controllers + var VELOCITY_FILTER_GAIN = 1.0; + filteredRotatedLeft = Vec3.mix(filteredRotatedLeft, rotatedLeft, Math.clamp(Vec3.length(poseLeft.angularVelocity) * VELOCITY_FILTER_GAIN, 0.0, 1.0)); + filteredRotatedRight = Vec3.mix(filteredRotatedRight, rotatedRight, Math.clamp(Vec3.length(poseRight.angularVelocity) * VELOCITY_FILTER_GAIN, 0.0, 1.0)); + var rotated = Vec3.mix(filteredRotatedLeft, filteredRotatedRight, leftRightBias); var absolutePitch = rotated.y; // from 1 down to -1 up ... but note: if you rotate down "too far" it starts to go up again... var absoluteYaw = -rotated.x; // from -1 left to 1 right - if (DEBUGGING) { - print("absolutePitch:" + absolutePitch); - print("absoluteYaw:" + absoluteYaw); - Vec3.print("rotated:", rotated); - } - var ROTATION_BOUND = 0.6; var clampYaw = Math.clamp(absoluteYaw, -ROTATION_BOUND, ROTATION_BOUND); var clampPitch = Math.clamp(absolutePitch, -ROTATION_BOUND, ROTATION_BOUND); - if (DEBUGGING) { - print("clampYaw:" + clampYaw); - print("clampPitch:" + clampPitch); - } // using only from -ROTATION_BOUND to ROTATION_BOUND var xRatio = (clampYaw + ROTATION_BOUND) / (2 * ROTATION_BOUND); var yRatio = (clampPitch + ROTATION_BOUND) / (2 * ROTATION_BOUND); - if (DEBUGGING) { - print("xRatio:" + xRatio); - print("yRatio:" + yRatio); - } - var x = screenSizeX * xRatio; var y = screenSizeY * yRatio; - if (DEBUGGING) { - print("position x:" + x + " y:" + y); - } - if (!(xRatio == 0.5 && yRatio == 0)) { + // don't move the reticle with the hand controllers unless the controllers are actually being moved + var MINIMUM_CONTROLLER_ANGULAR_VELOCITY = 0.0001; + var angularVelocityMagnitude = Vec3.length(poseLeft.angularVelocity) * (1.0 - leftRightBias) + Vec3.length(poseRight.angularVelocity) * leftRightBias; + + if (!(xRatio == 0.5 && yRatio == 0) && (angularVelocityMagnitude > MINIMUM_CONTROLLER_ANGULAR_VELOCITY)) { moveReticleAbsolute(x, y); } }); From bea18e91aa08ac3ef6fb6fb07f5db5ea88e5c05c Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 28 Dec 2015 15:09:49 -0800 Subject: [PATCH 189/209] Guard against empty polyline index out of range --- .../entities-renderer/src/RenderablePolyLineEntityItem.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index cfdcc87121..7b3bbc4c02 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -141,6 +141,11 @@ void RenderablePolyLineEntityItem::updateVertices() { _vertices << v1 << v2; } + // Guard against an empty polyline + if (finalIndex < 0) { + return; + } + // For last point we can assume binormals are the same since it represents the last two vertices of quad point = _points.at(finalIndex); v1 = point + binormal; From 5786789a665f4e271084131f1a0124b47ada99f0 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 28 Dec 2015 15:12:29 -0800 Subject: [PATCH 190/209] cleanup cleanup --- examples/light_modifier/lightModifier.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 08271fa7a8..eff373d3d7 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -636,7 +636,7 @@ function createCloseButton(axisStart) { modelURL: CLOSE_BUTTON_MODEL_URL, dimensions: CLOSE_BUTTON_DIMENSIONS, position: Vec3.sum(position, VERTICAL_OFFFSET), - rotation: Quat.multiply(avatarRot,Quat.fromPitchYawRollDegrees(90, 0, 45)), + rotation: Quat.multiply(avatarRot, Quat.fromPitchYawRollDegrees(90, 0, 45)), //rotation: Quat.fromPitchYawRollDegrees(0, 0, 90), collisionsWillMove: false, ignoreForCollisions: true, @@ -652,8 +652,8 @@ function createCloseButton(axisStart) { closeButtons.push(button); - if(ROTATE_CLOSE_BUTTON===true){ - Script.update.connect(rotateCloseButtons); + if (ROTATE_CLOSE_BUTTON === true) { + Script.update.connect(rotateCloseButtons); } } @@ -742,7 +742,7 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { var lightID = doesIntersect.entityID; if (currentLight === lightID) { - // print('ALREADY HAVE A BLOCK, EXIT') + // print('ALREADY HAVE A BLOCK, EXIT') return; } @@ -833,17 +833,17 @@ function cleanup(fromMessage) { Entities.deleteEntity(panel); Entities.deleteEntity(visiblePanel); - var data = { - action: 'remove', - id: visiblePanel - }; - Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)) selectionManager.clearSelections(); - Script.update.disconnect(rotateCloseButtons); + + if (ROTATE_CLOSE_BUTTON === true) { + Script.update.disconnect(rotateCloseButtons); + } + if (hasParent === false) { Entities.deleteEntity(block); } + oldParent = null; hasParent = false; currentLight = null; From 9f342ba8ce14661a130ed2635a31e5130057d8e7 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 28 Dec 2015 15:14:59 -0800 Subject: [PATCH 191/209] readme --- examples/light_modifier/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index 1358fbe917..f23f22148a 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -8,11 +8,12 @@ To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js To reset, I recommend stopping all scripts then re-loading lightLoader.js When you run the lightLoader.js script, several scripts will be loaded: -- handControllerGrab.js (will not impart velocity when you move the parent or a slider, will not move sliders with head movement,will constrain movement for a slider to a given axis start and end) +- handControllerGrab.js (will not impart velocity when you move the parent or a slider, will not move sliders with head movement,will constrain movement for a slider to a given axis start and end, will support blacklisting of entities for raypicking during search for objects) - lightModifier.js (listens for message to create sliders for a given light. will start with slider set to the light's initial properties) - lightModifierTestScene.js (creates a light) - slider.js (attached to each slider entity) - lightParent.js (attached to a 3d model of a light, to which a light is parented, so you can move it around. or keep the current parent if a light already has a parent) +- visiblePanel.js (the transparent panel) - closeButton.js (for closing the ui) - ../libraries/lightOverlayManager.js (shows 2d overlays for lights in the world) - ../libraries/entitySelectionTool.js (visualizes volume of the lights) From c266a093e026cf4d60cd3a98f64ffc76474e587b Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 28 Dec 2015 15:17:00 -0800 Subject: [PATCH 192/209] clear sliders at cleanup --- examples/light_modifier/lightModifier.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index eff373d3d7..52d9342464 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -847,7 +847,7 @@ function cleanup(fromMessage) { oldParent = null; hasParent = false; currentLight = null; - + sliders = []; } From 2ec712a5db30b2c847fb8da5e02f8770f99ceece Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 28 Dec 2015 15:27:17 -0800 Subject: [PATCH 193/209] disable near grabbing on sliders --- examples/controllers/handControllerGrab.js | 35 +++++++++++++++++----- examples/light_modifier/lightModifier.js | 3 +- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 50fdf3353c..9652132c08 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -788,14 +788,19 @@ function MyController(hand) { } else { intersection = Entities.findRayIntersection(pickRayBacked, true); } - + if (intersection.intersects) { - + // the ray is intersecting something we can move. var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); + var defaultDisableNearGrabData = { + disableNearGrab: false + }; + //sometimes we want things to stay right where they are when we let go. + var disableNearGrabData = getEntityCustomData('handControllerKey', intersection.entityID, defaultDisableNearGrabData); if (intersection.properties.name == "Grab Debug Entity") { continue; @@ -817,7 +822,11 @@ function MyController(hand) { } else if (!intersection.properties.locked) { this.grabbedEntity = intersection.entityID; if (this.state == STATE_SEARCHING) { - this.setState(STATE_NEAR_GRABBING); + if (disableNearGrabData.disableNearGrab !== true) { + this.setState(STATE_NEAR_GRABBING); + } else { + //disable near grab on this thing + } } else { // equipping if (typeof grabbableData.spatialKey !== 'undefined') { // TODO @@ -940,7 +949,18 @@ function MyController(hand) { this.setState(STATE_NEAR_TRIGGER); return; } else if (!props.locked && props.collisionsWillMove) { - this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) + var defaultDisableNearGrabData = { + disableNearGrab: false + }; + //sometimes we want things to stay right where they are when we let go. + var disableNearGrabData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultDisableNearGrabData); + if (disableNearGrabData.disableNearGrab === true) { + //do nothing because near grab is disabled for this object + } else { + this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) + + } + return; } } @@ -1753,15 +1773,14 @@ handleHandMessages = function(channel, message, sender) { } catch (e) {} - } - else if (channel === 'Hifi-Hand-RayPick-Blacklist') { + } else if (channel === 'Hifi-Hand-RayPick-Blacklist') { try { var data = JSON.parse(message); var action = data.action; var id = data.id; var index = blacklist.indexOf(id); - - if (action === 'add' && index ===-1) { + + if (action === 'add' && index === -1) { blacklist.push(id); } if (action === 'remove') { diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 52d9342464..b50bbe9478 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -374,7 +374,8 @@ entitySlider.prototype = { }, handControllerKey: { disableReleaseVelocity: true, - disableMoveWithHead: true + disableMoveWithHead: true, + disableNearGrab:true } }), }; From 4661152aa779c0e6dc1957e467f0fe237188816b Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 28 Dec 2015 17:57:24 -0800 Subject: [PATCH 194/209] NeuronAvatar.js: Now aligns the head with the HMD if active --- examples/controllers/neuron/neuronAvatar.js | 23 ++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/controllers/neuron/neuronAvatar.js b/examples/controllers/neuron/neuronAvatar.js index abd51f2990..7cebc13feb 100644 --- a/examples/controllers/neuron/neuronAvatar.js +++ b/examples/controllers/neuron/neuronAvatar.js @@ -157,8 +157,6 @@ NeuronAvatar.prototype.deactivate = function () { NeuronAvatar.prototype.update = function (deltaTime) { var hmdActive = HMD.active; - var hmdXform = new Xform(HMD.orientation, HMD.position); - var keys = Object.keys(JOINT_PARENT_MAP); var i, l = keys.length; var absDefaultRot = {}; @@ -192,18 +190,22 @@ NeuronAvatar.prototype.update = function (deltaTime) { MyAvatar.setJointTranslation(j, localTranslation); localTranslations[jointName] = localTranslation; } else { - localTranslations[jointName] = MyAvatar.getJointTranslation(j); + localTranslations[jointName] = MyAvatar.getDefaultJointTranslation(j); } } } - // TODO: Currrently does not work. // it attempts to adjust the hips so that the avatar's head is at the same location & oreintation as the HMD. // however it's fighting with the internal c++ code that also attempts to adjust the hips. if (hmdActive) { - + var UNIT_SCALE = 1 / 100; + var hmdXform = new Xform(HMD.orientation, Vec3.multiply(1 / UNIT_SCALE, HMD.position)); // convert to cm var y180Xform = new Xform({x: 0, y: 1, z: 0, w: 0}, {x: 0, y: 0, z: 0}); - var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position); + var avatarXform = new Xform(MyAvatar.orientation, Vec3.multiply(1 / UNIT_SCALE, MyAvatar.position)); // convert to cm + var hipsJointIndex = MyAvatar.getJointIndex("Hips"); + var modelOffsetInvXform = new Xform({x: 0, y: 0, z: 0, w: 1}, MyAvatar.getDefaultJointTranslation(hipsJointIndex)); + var defaultHipsXform = new Xform(MyAvatar.getDefaultJointRotation(hipsJointIndex), MyAvatar.getDefaultJointTranslation(hipsJointIndex)); + var headXform = new Xform(localRotations["Head"], localTranslations["Head"]); // transform eyes down the heirarchy chain into avatar space. @@ -213,9 +215,16 @@ NeuronAvatar.prototype.update = function (deltaTime) { var xform = new Xform(localRotations[hierarchy[i]], localTranslations[hierarchy[i]]); headXform = Xform.mul(xform, headXform); } + headXform = Xform.mul(defaultHipsXform, headXform); + + var preXform = Xform.mul(headXform, y180Xform); + var postXform = Xform.mul(avatarXform, Xform.mul(y180Xform, modelOffsetInvXform.inv())); // solve for the offset that will put the eyes at the hmd position & orientation. - var hipsXform = Xform.mul(y180Xform, Xform.mul(avatarXform.inv(), Xform.mul(hmdXform, Xform.mul(y180Xform, headXform.inv())))); + var hipsOffsetXform = Xform.mul(postXform.inv(), Xform.mul(hmdXform, preXform.inv())); + + // now combine it with the default hips transform + var hipsXform = Xform.mul(hipsOffsetXform, defaultHipsXform); MyAvatar.setJointRotation("Hips", hipsXform.rot); MyAvatar.setJointTranslation("Hips", hipsXform.pos); From 7e514d2f4dd477356d53ffff6c362549bea7de6d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 28 Dec 2015 18:42:03 -0800 Subject: [PATCH 195/209] Mac build fix --- cmake/externals/neuron/CMakeLists.txt | 9 ++++++++- plugins/hifiNeuron/src/NeuronPlugin.cpp | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cmake/externals/neuron/CMakeLists.txt b/cmake/externals/neuron/CMakeLists.txt index 324b3fb917..6936725571 100644 --- a/cmake/externals/neuron/CMakeLists.txt +++ b/cmake/externals/neuron/CMakeLists.txt @@ -41,8 +41,15 @@ if(WIN32) set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${${EXTERNAL_NAME_UPPER}_LIB_PATH}/NeuronDataReader.lib" CACHE TYPE INTERNAL) add_paths_to_fixup_libs("${${EXTERNAL_NAME_UPPER}_LIB_PATH}") + elseif(APPLE) - # TODO + + set(${EXTERNAL_NAME_UPPER}_LIB_PATH "${SOURCE_DIR}/NeuronDataReader_Mac/dylib") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE "${${EXTERNAL_NAME_UPPER}_LIB_PATH}/NeuronDataReader.dylib" CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${${EXTERNAL_NAME_UPPER}_LIB_PATH}/NeuronDataReader.dylib" CACHE TYPE INTERNAL) + + add_paths_to_fixup_libs("${${EXTERNAL_NAME_UPPER}_LIB_PATH}") + else() # UNSUPPORTED endif() diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index 97131a0a87..6132c16a43 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -523,7 +523,7 @@ QString NeuronPlugin::InputDevice::getDefaultMappingConfig() const { } void NeuronPlugin::InputDevice::update(float deltaTime, const std::vector& joints, const std::vector& prevJoints) { - for (int i = 0; i < joints.size(); i++) { + for (size_t i = 0; i < joints.size(); i++) { glm::vec3 linearVel, angularVel; glm::vec3 pos = joints[i].pos; glm::quat rot = eulerToQuat(joints[i].euler); From c35995b8e3363dda1ec0f129db5e6423cfd4c408 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 29 Dec 2015 08:51:09 -0800 Subject: [PATCH 196/209] Build fix for linux? --- cmake/macros/TargetNeuron.cmake | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cmake/macros/TargetNeuron.cmake b/cmake/macros/TargetNeuron.cmake index 01891ef525..11a92e68ad 100644 --- a/cmake/macros/TargetNeuron.cmake +++ b/cmake/macros/TargetNeuron.cmake @@ -6,9 +6,12 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # macro(TARGET_NEURON) - add_dependency_external_projects(neuron) - find_package(Neuron REQUIRED) - target_include_directories(${TARGET_NAME} PRIVATE ${NEURON_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} ${NEURON_LIBRARIES}) - add_definitions(-DHAVE_NEURON) + # Neuron data reader is only available on these platforms + if (WIN32 OR APPLE) + add_dependency_external_projects(neuron) + find_package(Neuron REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${NEURON_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${NEURON_LIBRARIES}) + add_definitions(-DHAVE_NEURON) + endif(WIN32 OR APPLE) endmacro() From e10cecd3101400d2228db6b3f5a9d195f357193c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 29 Dec 2015 09:23:03 -0800 Subject: [PATCH 197/209] Build fix for linux #2? --- plugins/hifiNeuron/src/NeuronPlugin.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index 6132c16a43..a175ce8e06 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -24,7 +24,10 @@ Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") #define __OS_XUN__ 1 #define BOOL int + +#ifdef HAVE_NEURON #include +#endif const QString NeuronPlugin::NAME = "Neuron"; const QString NeuronPlugin::NEURON_ID_STRING = "Perception Neuron"; @@ -312,6 +315,8 @@ static quat eulerToQuat(vec3 euler) { glm::angleAxis(e.z, Vectors::UNIT_Z)); } +#ifdef HAVE_NEURON + // // neuronDataReader SDK callback functions // @@ -430,17 +435,24 @@ static void SocketStatusChangedCallback(void* context, SOCKET_REF sender, Socket qCDebug(inputplugins) << "NeuronPlugin: socket status = " << message; } +#endif // #ifdef HAVE_NEURON + // // NeuronPlugin // bool NeuronPlugin::isSupported() const { +#ifdef HAVE_NEURON // Because it's a client/server network architecture, we can't tell // if the neuron is actually connected until we connect to the server. return true; +#else + return false; +#endif } void NeuronPlugin::activate() { +#ifdef HAVE_NEURON InputPlugin::activate(); // register with userInputMapper @@ -466,9 +478,11 @@ void NeuronPlugin::activate() { BRRegisterAutoSyncParmeter(_socketRef, Cmd_CombinationMode); } +#endif } void NeuronPlugin::deactivate() { +#ifdef HAVE_NEURON // unregister from userInputMapper if (_inputDevice->_deviceID != controller::Input::INVALID_DEVICE) { auto userInputMapper = DependencyManager::get(); @@ -481,6 +495,7 @@ void NeuronPlugin::deactivate() { } InputPlugin::deactivate(); +#endif } void NeuronPlugin::pluginUpdate(float deltaTime, bool jointsCaptured) { From 5d596bcbc449b26d3e5a8c89461b2af4e3ba8738 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 29 Dec 2015 10:02:46 -0800 Subject: [PATCH 198/209] Added tests for GLMHelpers::safeEulerAngles. To verify that converting to and from quats and eulers will use the same angle order. Also I fixed some naming inconsistencies in GeometryUtilTests. --- tests/shared/src/GLMHelpersTests.cpp | 57 ++++++++++++++++++++++++++ tests/shared/src/GLMHelpersTests.h | 27 ++++++++++++ tests/shared/src/GeometryUtilTests.cpp | 2 +- tests/shared/src/GeometryUtilTests.h | 8 ++-- 4 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 tests/shared/src/GLMHelpersTests.cpp create mode 100644 tests/shared/src/GLMHelpersTests.h diff --git a/tests/shared/src/GLMHelpersTests.cpp b/tests/shared/src/GLMHelpersTests.cpp new file mode 100644 index 0000000000..afb634ecbd --- /dev/null +++ b/tests/shared/src/GLMHelpersTests.cpp @@ -0,0 +1,57 @@ +// +// GLMHelpersTests.cpp +// tests/shared/src +// +// Created by Anthony Thibault on 2015.12.29 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLMHelpersTests.h" + +#include +#include + +#include <../QTestExtensions.h> + + +QTEST_MAIN(GLMHelpersTests) + +void GLMHelpersTests::testEulerDecomposition() { + // quat to euler and back again.... + + const glm::quat ROT_X_90 = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat ROT_Y_180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0, 0.0f)); + const glm::quat ROT_Z_30 = glm::angleAxis(PI / 6.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + + const float EPSILON = 0.00001f; + + std::vector quatVec = { + glm::quat(), + ROT_X_90, + ROT_Y_180, + ROT_Z_30, + ROT_X_90 * ROT_Y_180 * ROT_Z_30, + ROT_X_90 * ROT_Z_30 * ROT_Y_180, + ROT_Y_180 * ROT_Z_30 * ROT_X_90, + ROT_Y_180 * ROT_X_90 * ROT_Z_30, + ROT_Z_30 * ROT_X_90 * ROT_Y_180, + ROT_Z_30 * ROT_Y_180 * ROT_X_90, + }; + + for (auto& q : quatVec) { + glm::vec3 euler = safeEulerAngles(q); + glm::quat r(euler); + + // when the axis and angle are flipped. + if (glm::dot(q, r) < 0.0f) { + r = -r; + } + + QCOMPARE_WITH_ABS_ERROR(q, r, EPSILON); + } +} + + diff --git a/tests/shared/src/GLMHelpersTests.h b/tests/shared/src/GLMHelpersTests.h new file mode 100644 index 0000000000..5e880899e8 --- /dev/null +++ b/tests/shared/src/GLMHelpersTests.h @@ -0,0 +1,27 @@ +// +// GLMHelpersTests.h +// tests/shared/src +// +// Created by Anthony thibault on 2015.12.29 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_GLMHelpersTests_h +#define hifi_GLMHelpersTests_h + +#include +#include + +class GLMHelpersTests : public QObject { + Q_OBJECT +private slots: + void testEulerDecomposition(); +}; + +float getErrorDifference(const float& a, const float& b); +float getErrorDifference(const glm::vec3& a, const glm::vec3& b); + +#endif // hifi_GLMHelpersTest_h diff --git a/tests/shared/src/GeometryUtilTests.cpp b/tests/shared/src/GeometryUtilTests.cpp index eaf1e7cd8a..7ba22ec13d 100644 --- a/tests/shared/src/GeometryUtilTests.cpp +++ b/tests/shared/src/GeometryUtilTests.cpp @@ -1,6 +1,6 @@ // // GeometryUtilTests.cpp -// tests/physics/src +// tests/shared/src // // Created by Andrew Meadows on 2015.07.27 // Copyright 2015 High Fidelity, Inc. diff --git a/tests/shared/src/GeometryUtilTests.h b/tests/shared/src/GeometryUtilTests.h index 6996c8bcea..daf740dcd3 100644 --- a/tests/shared/src/GeometryUtilTests.h +++ b/tests/shared/src/GeometryUtilTests.h @@ -1,6 +1,6 @@ // // GeometryUtilTests.h -// tests/physics/src +// tests/shared/src // // Created by Andrew Meadows on 2014.05.30 // Copyright 2014 High Fidelity, Inc. @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_AngularConstraintTests_h -#define hifi_AngularConstraintTests_h +#ifndef hifi_GeometryUtilTests_h +#define hifi_GeometryUtilTests_h #include #include @@ -26,4 +26,4 @@ private slots: float getErrorDifference(const float& a, const float& b); float getErrorDifference(const glm::vec3& a, const glm::vec3& b); -#endif // hifi_AngularConstraintTests_h +#endif // hifi_GeometryUtilTests_h From 12fa22300491a5b3f26d22a60eb7cd10a9c8dfac Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 28 Dec 2015 16:23:19 -0800 Subject: [PATCH 199/209] Render SKY_DOME when SKY_MAP tex is loading --- interface/src/Application.cpp | 146 +++++++++--------- libraries/model/src/model/Skybox.cpp | 11 +- .../src/procedural/ProceduralSkybox.cpp | 9 +- 3 files changed, 87 insertions(+), 79 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d383ee3339..e81aa7ec52 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3486,78 +3486,86 @@ namespace render { // Background rendering decision auto skyStage = DependencyManager::get()->getSkyStage(); - if (skyStage->getBackgroundMode() == model::SunSkyStage::NO_BACKGROUND) { + auto backgroundMode = skyStage->getBackgroundMode(); + + if (backgroundMode == model::SunSkyStage::NO_BACKGROUND) { // this line intentionally left blank - } else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_DOME) { - if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { - PerformanceTimer perfTimer("stars"); - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::payloadRender() ... stars..."); - // should be the first rendering pass - w/o depth buffer / lighting - - // compute starfield alpha based on distance from atmosphere - float alpha = 1.0f; - bool hasStars = true; - - if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { - // TODO: handle this correctly for zones - const EnvironmentData& closestData = background->_environment->getClosestData(args->_viewFrustum->getPosition()); // was theCamera instead of _viewFrustum - - if (closestData.getHasStars()) { - const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f; - const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f; - - glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation()) - / closestData.getAtmosphereOuterRadius(); - float height = glm::distance(args->_viewFrustum->getPosition()/*theCamera.getPosition()*/, closestData.getAtmosphereCenter()); - if (height < closestData.getAtmosphereInnerRadius()) { - // If we're inside the atmosphere, then determine if our keyLight is below the horizon - alpha = 0.0f; - - if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) { - float directionY = glm::clamp(sunDirection.y, - -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) - + APPROXIMATE_DISTANCE_FROM_HORIZON; - alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON); - } - - - } else if (height < closestData.getAtmosphereOuterRadius()) { - alpha = (height - closestData.getAtmosphereInnerRadius()) / - (closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius()); - - if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) { - float directionY = glm::clamp(sunDirection.y, - -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) - + APPROXIMATE_DISTANCE_FROM_HORIZON; - alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON); - } - } - } else { - hasStars = false; - } + } else { + if (backgroundMode == model::SunSkyStage::SKY_BOX) { + auto skybox = skyStage->getSkybox(); + if (skybox && skybox->getCubemap() && skybox->getCubemap()->isDefined()) { + PerformanceTimer perfTimer("skybox"); + skybox->render(batch, *(args->_viewFrustum)); + } else { + // If no skybox texture is available, render the SKY_DOME while it loads + backgroundMode = model::SunSkyStage::SKY_DOME; } - - // finally render the starfield - if (hasStars) { - background->_stars.render(args, alpha); - } - - // draw the sky dome - if (/*!selfAvatarOnly &&*/ Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { - PerformanceTimer perfTimer("atmosphere"); - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::displaySide() ... atmosphere..."); - - background->_environment->renderAtmospheres(batch, *(args->_viewFrustum)); - } - } - } else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_BOX) { - PerformanceTimer perfTimer("skybox"); - auto skybox = skyStage->getSkybox(); - if (skybox) { - skybox->render(batch, *(args->_viewFrustum)); + if (backgroundMode == model::SunSkyStage::SKY_DOME) { + if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { + PerformanceTimer perfTimer("stars"); + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::payloadRender() ... stars..."); + // should be the first rendering pass - w/o depth buffer / lighting + + // compute starfield alpha based on distance from atmosphere + float alpha = 1.0f; + bool hasStars = true; + + if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { + // TODO: handle this correctly for zones + const EnvironmentData& closestData = background->_environment->getClosestData(args->_viewFrustum->getPosition()); // was theCamera instead of _viewFrustum + + if (closestData.getHasStars()) { + const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f; + const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f; + + glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation()) + / closestData.getAtmosphereOuterRadius(); + float height = glm::distance(args->_viewFrustum->getPosition()/*theCamera.getPosition()*/, closestData.getAtmosphereCenter()); + if (height < closestData.getAtmosphereInnerRadius()) { + // If we're inside the atmosphere, then determine if our keyLight is below the horizon + alpha = 0.0f; + + if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) { + float directionY = glm::clamp(sunDirection.y, + -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) + + APPROXIMATE_DISTANCE_FROM_HORIZON; + alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON); + } + + + } else if (height < closestData.getAtmosphereOuterRadius()) { + alpha = (height - closestData.getAtmosphereInnerRadius()) / + (closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius()); + + if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) { + float directionY = glm::clamp(sunDirection.y, + -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) + + APPROXIMATE_DISTANCE_FROM_HORIZON; + alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON); + } + } + } else { + hasStars = false; + } + } + + // finally render the starfield + if (hasStars) { + background->_stars.render(args, alpha); + } + + // draw the sky dome + if (/*!selfAvatarOnly &&*/ Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { + PerformanceTimer perfTimer("atmosphere"); + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... atmosphere..."); + + background->_environment->renderAtmospheres(batch, *(args->_viewFrustum)); + } + + } } } } diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index 8c37359638..476ac2fa08 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -96,7 +96,12 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky } }); + // Render + gpu::TexturePointer skymap = skybox.getCubemap(); + // FIXME: skymap->isDefined may not be threadsafe + assert(skymap && skymap->isDefined()); + glm::mat4 projMat; viewFrustum.evalProjectionMatrix(projMat); @@ -106,11 +111,6 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky batch.setViewTransform(viewTransform); batch.setModelTransform(Transform()); // only for Mac - gpu::TexturePointer skymap; - if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) { - skymap = skybox.getCubemap(); - } - batch.setPipeline(thePipeline); batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, skybox._dataBuffer); batch.setResourceTexture(SKYBOX_SKYMAP_SLOT, skymap); @@ -118,6 +118,5 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky batch.draw(gpu::TRIANGLE_STRIP, 4); batch.setResourceTexture(SKYBOX_SKYMAP_SLOT, nullptr); - } diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index ce6f29c3d5..167d49cbaf 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -48,6 +48,10 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, } if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) { + gpu::TexturePointer skymap = skybox.getCubemap(); + // FIXME: skymap->isDefined may not be threadsafe + assert(skymap && skymap->isDefined()); + glm::mat4 projMat; viewFrustum.evalProjectionMatrix(projMat); @@ -56,10 +60,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, batch.setProjectionTransform(projMat); batch.setViewTransform(viewTransform); batch.setModelTransform(Transform()); // only for Mac - - if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) { - batch.setResourceTexture(0, skybox.getCubemap()); - } + batch.setResourceTexture(0, skybox.getCubemap()); skybox._procedural->prepare(batch, glm::vec3(0), glm::vec3(1)); batch.draw(gpu::TRIANGLE_STRIP, 4); From 1a84b5c0f0c68a2f4f729bf80026b901691d4823 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 29 Dec 2015 18:13:34 -0800 Subject: [PATCH 200/209] Fixing issue with muzzle flash and hit point being out of sync for pistol --- examples/toybox/pistol/pistol.js | 206 +++++++++++++++++-------------- 1 file changed, 115 insertions(+), 91 deletions(-) diff --git a/examples/toybox/pistol/pistol.js b/examples/toybox/pistol/pistol.js index 8ef26b94c1..df249a0aaf 100644 --- a/examples/toybox/pistol/pistol.js +++ b/examples/toybox/pistol/pistol.js @@ -44,6 +44,7 @@ this.showLaser = false; + }; Pistol.prototype = { @@ -58,20 +59,36 @@ if (!this.equipped) { return; } - this.toggleWithTriggerPressure(); + this.updateProps(); if (this.showLaser) { this.updateLaser(); } + this.toggleWithTriggerPressure(); + + + }, + + updateProps: function() { + var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); + this.position = gunProps.position; + this.rotation = gunProps.rotation; + this.firingDirection = Quat.getFront(this.rotation); + var upVec = Quat.getUp(this.rotation); + this.barrelPoint = Vec3.sum(this.position, Vec3.multiply(upVec, this.laserOffsets.y)); + this.laserTip = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.laserLength)); + this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z)) + var pickRay = { + origin: this.barrelPoint, + direction: this.firingDirection + }; }, toggleWithTriggerPressure: function() { this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.hand]); if (this.triggerValue < RELOAD_THRESHOLD) { - // print('RELOAD'); this.canShoot = true; } if (this.canShoot === true && this.triggerValue === 1) { - // print('SHOOT'); this.fire(); this.canShoot = false; } @@ -91,17 +108,10 @@ }, updateLaser: function() { - var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); - var position = gunProps.position; - var rotation = gunProps.rotation; - this.firingDirection = Quat.getFront(rotation); - var upVec = Quat.getUp(rotation); - this.barrelPoint = Vec3.sum(position, Vec3.multiply(upVec, this.laserOffsets.y)); - var laserTip = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.laserLength)); - this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z)) + Overlays.editOverlay(this.laser, { start: this.barrelPoint, - end: laserTip, + end: this.laserTip, alpha: 1 }); }, @@ -114,19 +124,6 @@ }); }, - preload: function(entityID) { - this.entityID = entityID; - // this.initControllerMapping(); - this.laser = Overlays.addOverlay("line3d", { - start: ZERO_VECTOR, - end: ZERO_VECTOR, - color: COLORS.RED, - alpha: 1, - visible: true, - lineWidth: 2 - }); - }, - triggerPress: function(hand, value) { if (this.hand === hand && value === 1) { //We are pulling trigger on the hand we have the gun in, so fire @@ -135,17 +132,18 @@ }, fire: function() { - var pickRay = { - origin: this.barrelPoint, - direction: this.firingDirection - }; + Audio.playSound(this.fireSound, { position: this.barrelPoint, volume: this.fireVolume }); + var pickRay = { + origin: this.barrelPoint, + direction: this.firingDirection + }; this.createGunFireEffect(this.barrelPoint) - var intersection = Entities.findRayIntersectionBlocking(pickRay, true); + var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects) { this.createEntityHitEffect(intersection.intersection); if (Math.random() < this.playRichochetSoundChance) { @@ -170,11 +168,11 @@ }, createEntityHitEffect: function(position) { - var flash = Entities.addEntity({ + var sparks = Entities.addEntity({ type: "ParticleEffect", position: position, lifetime: 4, - "name": "Flash Emitter", + "name": "Sparks Emitter", "color": { red: 228, green: 128, @@ -228,7 +226,7 @@ }); Script.setTimeout(function() { - Entities.editEntity(flash, { + Entities.editEntity(sparks, { isEmitting: false }); }, 100); @@ -282,70 +280,96 @@ }); }, 100); - var flash = Entities.addEntity({ - type: "ParticleEffect", - position: position, - lifetime: 4, - "name": "Muzzle Flash", - "color": { - red: 228, - green: 128, - blue: 12 - }, - "maxParticles": 1000, - "lifespan": 0.1, - "emitRate": 1000, - "emitSpeed": 0.5, - "speedSpread": 0, - "emitOrientation": { - "x": -0.4, - "y": 1, - "z": -0.2, - "w": 0.7071068286895752 - }, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": Math.PI, - "azimuthStart": -3.1415927410125732, - "azimuthFinish": 2, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": 0, - "y": 0, - "z": 0 - }, - "particleRadius": 0.05, - "radiusSpread": 0.01, - "radiusStart": 0.05, - "radiusFinish": 0.05, - "colorSpread": { - red: 100, - green: 100, - blue: 20 - }, - "alpha": 1, - "alphaSpread": 0, - "alphaStart": 0, - "alphaFinish": 0, - "additiveBlending": true, - "textures": "http://ericrius1.github.io/PartiArt/assets/star.png" + Entities.editEntity(this.flash, { + isEmitting: true }); - Script.setTimeout(function() { - Entities.editEntity(flash, { + Entities.editEntity(_this.flash, { isEmitting: false }); }, 100) - } + }, + + preload: function(entityID) { + this.entityID = entityID; + this.laser = Overlays.addOverlay("line3d", { + start: ZERO_VECTOR, + end: ZERO_VECTOR, + color: COLORS.RED, + alpha: 1, + visible: true, + lineWidth: 2 + }); + + var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); + var position = gunProps.position; + var rotation = gunProps.rotation; + this.firingDirection = Quat.getFront(rotation); + var upVec = Quat.getUp(rotation); + this.barrelPoint = Vec3.sum(position, Vec3.multiply(upVec, this.laserOffsets.y)); + this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z)) + + // this.flash = Entities.addEntity({ + // type: "ParticleEffect", + // parentID: this.entityID, + // position: this.barrelPoint, + // "name": "Muzzle Flash", + // // isEmitting: false, + // "color": { + // red: 228, + // green: 128, + // blue: 12 + // }, + // "maxParticles": 1000, + // "lifespan": 0.1, + // "emitRate": 1000, + // "emitSpeed": 0.5, + // "speedSpread": 0, + // "emitOrientation": { + // "x": -0.4, + // "y": 1, + // "z": -0.2, + // "w": 0.7071068286895752 + // }, + // "emitDimensions": { + // "x": 0, + // "y": 0, + // "z": 0 + // }, + // "polarStart": 0, + // "polarFinish": Math.PI, + // "azimuthStart": -3.1415927410125732, + // "azimuthFinish": 2, + // "emitAcceleration": { + // "x": 0, + // "y": 0, + // "z": 0 + // }, + // "accelerationSpread": { + // "x": 0, + // "y": 0, + // "z": 0 + // }, + // "particleRadius": 0.05, + // "radiusSpread": 0.01, + // "radiusStart": 0.05, + // "radiusFinish": 0.05, + // "colorSpread": { + // red: 100, + // green: 100, + // blue: 20 + // }, + // "alpha": 1, + // "alphaSpread": 0, + // "alphaStart": 0, + // "alphaFinish": 0, + // "additiveBlending": true, + // "textures": "http://ericrius1.github.io/PartiArt/assets/star.png" + // }); + + }, + }; From 4cc94b44ba0f8ed1320f6dcb35e1cc67ca362292 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 29 Dec 2015 18:30:07 -0800 Subject: [PATCH 201/209] muzzle is in sync --- examples/toybox/pistol/pistol.js | 140 +++++++++++++++---------------- 1 file changed, 69 insertions(+), 71 deletions(-) diff --git a/examples/toybox/pistol/pistol.js b/examples/toybox/pistol/pistol.js index df249a0aaf..372c704219 100644 --- a/examples/toybox/pistol/pistol.js +++ b/examples/toybox/pistol/pistol.js @@ -29,20 +29,12 @@ this.equipped = false; this.forceMultiplier = 1; this.laserLength = 100; - this.laserOffsets = { - y: .095 - }; - this.firingOffsets = { - z: 0.16 - } + this.fireSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Guns/GUN-SHOT2.raw"); this.ricochetSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Guns/Ricochet.L.wav"); this.playRichochetSoundChance = 0.1; this.fireVolume = 0.2; this.bulletForce = 10; - - - this.showLaser = false; }; @@ -143,7 +135,7 @@ direction: this.firingDirection }; this.createGunFireEffect(this.barrelPoint) - var intersection = Entities.findRayIntersection(pickRay, true); + var intersection = Entities.findRayIntersectionBlocking(pickRay, true); if (intersection.intersects) { this.createEntityHitEffect(intersection.intersection); if (Math.random() < this.playRichochetSoundChance) { @@ -301,76 +293,82 @@ visible: true, lineWidth: 2 }); - + this.laserOffsets = { + y: .095 + }; + this.firingOffsets = { + z: 0.16 + } var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); var position = gunProps.position; - var rotation = gunProps.rotation; + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0); this.firingDirection = Quat.getFront(rotation); var upVec = Quat.getUp(rotation); this.barrelPoint = Vec3.sum(position, Vec3.multiply(upVec, this.laserOffsets.y)); this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z)) - // this.flash = Entities.addEntity({ - // type: "ParticleEffect", - // parentID: this.entityID, - // position: this.barrelPoint, - // "name": "Muzzle Flash", - // // isEmitting: false, - // "color": { - // red: 228, - // green: 128, - // blue: 12 - // }, - // "maxParticles": 1000, - // "lifespan": 0.1, - // "emitRate": 1000, - // "emitSpeed": 0.5, - // "speedSpread": 0, - // "emitOrientation": { - // "x": -0.4, - // "y": 1, - // "z": -0.2, - // "w": 0.7071068286895752 - // }, - // "emitDimensions": { - // "x": 0, - // "y": 0, - // "z": 0 - // }, - // "polarStart": 0, - // "polarFinish": Math.PI, - // "azimuthStart": -3.1415927410125732, - // "azimuthFinish": 2, - // "emitAcceleration": { - // "x": 0, - // "y": 0, - // "z": 0 - // }, - // "accelerationSpread": { - // "x": 0, - // "y": 0, - // "z": 0 - // }, - // "particleRadius": 0.05, - // "radiusSpread": 0.01, - // "radiusStart": 0.05, - // "radiusFinish": 0.05, - // "colorSpread": { - // red: 100, - // green: 100, - // blue: 20 - // }, - // "alpha": 1, - // "alphaSpread": 0, - // "alphaStart": 0, - // "alphaFinish": 0, - // "additiveBlending": true, - // "textures": "http://ericrius1.github.io/PartiArt/assets/star.png" - // }); + this.flash = Entities.addEntity({ + type: "ParticleEffect", + position: this.barrelPoint, + "name": "Muzzle Flash", + isEmitting: false, + "color": { + red: 228, + green: 128, + blue: 12 + }, + "maxParticles": 1000, + "lifespan": 0.1, + "emitRate": 1000, + "emitSpeed": 0.5, + "speedSpread": 0, + "emitOrientation": { + "x": -0.4, + "y": 1, + "z": -0.2, + "w": 0.7071068286895752 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": Math.PI, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 2, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.05, + "radiusSpread": 0.01, + "radiusStart": 0.05, + "radiusFinish": 0.05, + "colorSpread": { + red: 100, + green: 100, + blue: 20 + }, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 0, + "alphaFinish": 0, + "additiveBlending": true, + "textures": "http://ericrius1.github.io/PartiArt/assets/star.png" + }); + + Script.setTimeout(function() { + Entities.editEntity(_this.flash, {parentID: _this.entityID}); + }, 500) }, - - }; // entity scripts always need to return a newly constructed object of our type From 5caa6cbdbf99b1531d757976b539c6606b497b9b Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 29 Dec 2015 18:38:57 -0800 Subject: [PATCH 202/209] Update pistol.js leading zeroes --- examples/toybox/pistol/pistol.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/toybox/pistol/pistol.js b/examples/toybox/pistol/pistol.js index 372c704219..7fb05d992f 100644 --- a/examples/toybox/pistol/pistol.js +++ b/examples/toybox/pistol/pistol.js @@ -251,11 +251,11 @@ "z": 0 }, "accelerationSpread": { - "x": .2, + "x": 0.2, "y": 0, - "z": .2 + "z": 0.2 }, - "radiusSpread": .04, + "radiusSpread": 0.04, "particleRadius": 0.07, "radiusStart": 0.07, "radiusFinish": 0.07, @@ -294,7 +294,7 @@ lineWidth: 2 }); this.laserOffsets = { - y: .095 + y: 0.095 }; this.firingOffsets = { z: 0.16 @@ -373,4 +373,4 @@ // entity scripts always need to return a newly constructed object of our type return new Pistol(); -}); \ No newline at end of file +}); From 6d857296f9a4acc3e81d2df5c95d50f28bbfaa2c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 29 Dec 2015 23:37:10 -0800 Subject: [PATCH 203/209] show search sphere instead of beams, start at center of view --- examples/controllers/handControllerGrab.js | 96 ++++++++++++++++------ 1 file changed, 70 insertions(+), 26 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 3c8f1f0014..0dce72803c 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -96,7 +96,7 @@ var MSEC_PER_SEC = 1000.0; var LIFETIME = 10; var ACTION_TTL = 15; // seconds var ACTION_TTL_REFRESH = 5; -var PICKS_PER_SECOND_PER_HAND = 5; +var PICKS_PER_SECOND_PER_HAND = 60; var MSECS_PER_SEC = 1000.0; var GRABBABLE_PROPERTIES = [ "position", @@ -123,8 +123,8 @@ var blacklist = []; //we've created various ways of visualizing looking for and moving distant objects var USE_ENTITY_LINES_FOR_SEARCHING = false; -var USE_OVERLAY_LINES_FOR_SEARCHING = false; -var USE_PARTICLE_BEAM_FOR_SEARCHING = true; +var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_PARTICLE_BEAM_FOR_SEARCHING = false; var USE_ENTITY_LINES_FOR_MOVING = false; var USE_OVERLAY_LINES_FOR_MOVING = false; @@ -290,6 +290,11 @@ function MyController(hand) { this.spotlight = null; this.pointlight = null; this.overlayLine = null; + this.searchSphere = null; + + // how far from camera to search intersection? + this.intersectionDistance = 0.0; + this.searchSphereDistance = 0.0; this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; @@ -409,6 +414,23 @@ function MyController(hand) { } }; + var SEARCH_SPHERE_ALPHA = 0.5; + this.searchSphereOn = function(location, size, color) { + if (this.searchSphere === null) { + var sphereProperties = { + position: location, + size: size, + color: color, + alpha: SEARCH_SPHERE_ALPHA, + solid: true, + visible: true + } + this.searchSphere = Overlays.addOverlay("sphere", sphereProperties); + } else { + Overlays.editOverlay(this.searchSphere, { position: location, size: size, color: color, visible: true }); + } + } + this.overlayLineOn = function(closePoint, farPoint, color) { if (this.overlayLine === null) { var lineProperties = { @@ -654,6 +676,17 @@ function MyController(hand) { this.overlayLine = null; }; + this.searchSphereOff = function() { + if (this.searchSphere !== null) { + //Overlays.editOverlay(this.searchSphere, { visible: false }); + Overlays.deleteOverlay(this.searchSphere); + this.searchSphere = null; + this.searchSphereDistance = 0.0; + this.intersectionDistance = 0.0; + } + + }; + this.particleBeamOff = function() { if (this.particleBeam !== null) { Entities.editEntity(this.particleBeam, { @@ -687,6 +720,7 @@ function MyController(hand) { if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { this.particleBeamOff(); } + this.searchSphereOff(); }; this.triggerPress = function(value) { @@ -712,11 +746,6 @@ function MyController(hand) { return this.triggerValue < TRIGGER_OFF_VALUE; }; - this.triggerSqueezed = function() { - var triggerValue = this.rawTriggerValue; - return triggerValue > TRIGGER_ON_VALUE; - }; - this.bumperSqueezed = function() { return _this.rawBumperValue > BUMPER_ON_VALUE; }; @@ -726,15 +755,15 @@ function MyController(hand) { }; this.off = function() { - if (this.triggerSmoothedSqueezed()) { + if (this.triggerSmoothedSqueezed() || this.bumperSqueezed()) { this.lastPickTime = 0; - this.setState(STATE_SEARCHING); - return; - } - if (this.bumperSqueezed()) { - this.lastPickTime = 0; - this.setState(STATE_EQUIP_SEARCHING); - return; + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + this.startingHandRotation = Controller.getPoseValue(controllerHandInput).rotation; + if (this.triggerSmoothedSqueezed()) { + this.setState(STATE_SEARCHING); + } else { + this.setState(STATE_EQUIP_SEARCHING); + } } }; @@ -748,9 +777,14 @@ function MyController(hand) { // the trigger is being pressed, do a ray test var handPosition = this.getHandPosition(); + + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var currentHandRotation = Controller.getPoseValue(controllerHandInput).rotation; + var handDeltaRotation = Quat.multiply(currentHandRotation, Quat.inverse(this.startingHandRotation)); + var distantPickRay = { - origin: handPosition, - direction: Quat.getUp(this.getHandRotation()), + origin: Camera.position, + direction: Quat.getFront(Quat.multiply(Camera.orientation, handDeltaRotation)), length: PICK_MAX_DISTANCE }; @@ -789,7 +823,7 @@ function MyController(hand) { if (intersection.intersects) { // the ray is intersecting something we can move. - var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); + this.intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); @@ -800,11 +834,11 @@ function MyController(hand) { if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { continue; } - if (intersectionDistance > pickRay.length) { + if (this.intersectionDistance > pickRay.length) { // too far away for this ray. continue; } - if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { + if (this.intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { // the hand is very close to the intersected object. go into close-grabbing mode. if (grabbableData.wantsTrigger) { this.grabbedEntity = intersection.entityID; @@ -851,6 +885,7 @@ function MyController(hand) { } } + // forward ray test failed, try sphere test. if (WANT_DEBUG) { Entities.addEntity({ @@ -946,14 +981,23 @@ function MyController(hand) { this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } - if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); - } - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); } - + if (this.intersectionDistance > 0) { + var SPHERE_INTERSECTION_SIZE = 0.011; + var SEARCH_SPHERE_FOLLOW_RATE = 0.50; + var SEARCH_SPHERE_CHASE_DROP = 0.2; + this.searchSphereDistance = this.searchSphereDistance * SEARCH_SPHERE_FOLLOW_RATE + this.intersectionDistance * (1.0 - SEARCH_SPHERE_FOLLOW_RATE); + var searchSphereLocation = Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); + searchSphereLocation.y -= ((this.intersectionDistance - this.searchSphereDistance) / this.intersectionDistance) * SEARCH_SPHERE_CHASE_DROP; + this.searchSphereOn(searchSphereLocation, SPHERE_INTERSECTION_SIZE * this.intersectionDistance, NO_INTERSECT_COLOR); + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + var OVERLAY_BEAM_SETBACK = 0.9; + var startBeam = Vec3.sum(handPosition, Vec3.multiply(Vec3.subtract(searchSphereLocation, handPosition), OVERLAY_BEAM_SETBACK)); + this.overlayLineOn(startBeam, searchSphereLocation, NO_INTERSECT_COLOR); + } + } }; this.distanceHolding = function() { From e995b29712dd184a4473f79e0ca8da1a6b72bcca Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 30 Dec 2015 00:36:11 -0800 Subject: [PATCH 204/209] can target without grabbing --- examples/controllers/handControllerGrab.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 0dce72803c..e362eb22e0 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -23,8 +23,9 @@ var WANT_DEBUG = false; // these tune time-averaging and "on" value for analog trigger // -var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value -var TRIGGER_ON_VALUE = 0.4; +var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing +var TRIGGER_ON_VALUE = 0.4; // Squeezed just enough to activate search or near grab +var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab var TRIGGER_OFF_VALUE = 0.15; var BUMPER_ON_VALUE = 0.5; @@ -738,6 +739,10 @@ function MyController(hand) { (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); }; + this.triggerSmoothedGrab = function() { + return this.triggerValue > TRIGGER_GRAB_VALUE; + }; + this.triggerSmoothedSqueezed = function() { return this.triggerValue > TRIGGER_ON_VALUE; }; @@ -775,7 +780,7 @@ function MyController(hand) { return; } - // the trigger is being pressed, do a ray test + // the trigger is being pressed, so do a ray test to see what we are hitting var handPosition = this.getHandPosition(); var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; @@ -788,7 +793,7 @@ function MyController(hand) { length: PICK_MAX_DISTANCE }; - // don't pick 60x per second. + // Pick at some maximum rate, not always var pickRays = []; var now = Date.now(); if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { @@ -872,11 +877,11 @@ function MyController(hand) { // this.setState(STATE_EQUIP_SPRING); this.setState(STATE_EQUIP); return; - } else if (this.state == STATE_SEARCHING) { + } else if ((this.state == STATE_SEARCHING) && this.triggerSmoothedGrab()) { this.setState(STATE_DISTANCE_HOLDING); return; } - } else if (grabbableData.wantsTrigger) { + } else if (grabbableData.wantsTrigger && this.triggerSmoothedGrab()) { this.grabbedEntity = intersection.entityID; this.setState(STATE_FAR_TRIGGER); return; @@ -991,11 +996,11 @@ function MyController(hand) { this.searchSphereDistance = this.searchSphereDistance * SEARCH_SPHERE_FOLLOW_RATE + this.intersectionDistance * (1.0 - SEARCH_SPHERE_FOLLOW_RATE); var searchSphereLocation = Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); searchSphereLocation.y -= ((this.intersectionDistance - this.searchSphereDistance) / this.intersectionDistance) * SEARCH_SPHERE_CHASE_DROP; - this.searchSphereOn(searchSphereLocation, SPHERE_INTERSECTION_SIZE * this.intersectionDistance, NO_INTERSECT_COLOR); + this.searchSphereOn(searchSphereLocation, SPHERE_INTERSECTION_SIZE * this.intersectionDistance, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { var OVERLAY_BEAM_SETBACK = 0.9; var startBeam = Vec3.sum(handPosition, Vec3.multiply(Vec3.subtract(searchSphereLocation, handPosition), OVERLAY_BEAM_SETBACK)); - this.overlayLineOn(startBeam, searchSphereLocation, NO_INTERSECT_COLOR); + this.overlayLineOn(startBeam, searchSphereLocation, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); } } }; From 8f71a5fda548e3a7e2f424b2fd08abb2be4476af Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 30 Dec 2015 10:17:18 -0800 Subject: [PATCH 205/209] ModelEntityItem: Fix for missing pre-rotations for animated models. This should fix the issue with the Kaya and Claire models, while also not breaking the windmill model in demo. --- libraries/entities/src/ModelEntityItem.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index a1f16ee251..9215374653 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -252,9 +252,11 @@ void ModelEntityItem::getAnimationFrame(bool& newFrame, if (index < translations.size()) { translationMat = glm::translate(translations[index]); } - glm::mat4 rotationMat; + glm::mat4 rotationMat(glm::mat4::_null); if (index < rotations.size()) { - rotationMat = glm::mat4_cast(rotations[index]); + rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * rotations[index] * fbxJoints[index].postRotation); + } else { + rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * fbxJoints[index].postRotation); } glm::mat4 finalMat = (translationMat * fbxJoints[index].preTransform * rotationMat * fbxJoints[index].postTransform); From 0d4ac4387aa8c3e3e309eebb9c2e2ec48c30dada Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 31 Dec 2015 11:46:35 -0800 Subject: [PATCH 206/209] Show hand-sphere search line and point just with hand direction again --- examples/controllers/handControllerGrab.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 8af8731c8d..e747bb0897 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -789,7 +789,8 @@ function MyController(hand) { var distantPickRay = { origin: Camera.position, - direction: Quat.getFront(Quat.multiply(Camera.orientation, handDeltaRotation)), + //direction: Quat.getFront(Quat.multiply(Camera.orientation, handDeltaRotation)), + direction: Quat.getUp(this.getHandRotation()), length: PICK_MAX_DISTANCE }; @@ -1022,9 +1023,7 @@ function MyController(hand) { searchSphereLocation.y -= ((this.intersectionDistance - this.searchSphereDistance) / this.intersectionDistance) * SEARCH_SPHERE_CHASE_DROP; this.searchSphereOn(searchSphereLocation, SPHERE_INTERSECTION_SIZE * this.intersectionDistance, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - var OVERLAY_BEAM_SETBACK = 0.9; - var startBeam = Vec3.sum(handPosition, Vec3.multiply(Vec3.subtract(searchSphereLocation, handPosition), OVERLAY_BEAM_SETBACK)); - this.overlayLineOn(startBeam, searchSphereLocation, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); + this.overlayLineOn(handPosition, searchSphereLocation, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); } } }; From c18a2fc2645b9c6ed2619a839c9b483093e183c5 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 31 Dec 2015 11:56:37 -0800 Subject: [PATCH 207/209] blend 50/50 between head and hands for search --- examples/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index e747bb0897..df36366326 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -790,7 +790,7 @@ function MyController(hand) { var distantPickRay = { origin: Camera.position, //direction: Quat.getFront(Quat.multiply(Camera.orientation, handDeltaRotation)), - direction: Quat.getUp(this.getHandRotation()), + direction: Vec3.mix(Quat.getUp(this.getHandRotation()), Quat.getFront(Camera.orientation), 0.5), length: PICK_MAX_DISTANCE }; From f4389c3b1fc3d060b3c222c1177f4b7514174349 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 31 Dec 2015 13:36:24 -0800 Subject: [PATCH 208/209] Add head-to-hand mixing ratio, default to zero (hands only) --- examples/controllers/handControllerGrab.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index df36366326..1dfc0ffacd 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -30,6 +30,8 @@ var TRIGGER_OFF_VALUE = 0.15; var BUMPER_ON_VALUE = 0.5; +var HAND_HEAD_MIX_RATIO = 0.0; // 0 = only use hands for search/move. 1 = only use head for search/move. + // // distant manipulation // @@ -790,7 +792,7 @@ function MyController(hand) { var distantPickRay = { origin: Camera.position, //direction: Quat.getFront(Quat.multiply(Camera.orientation, handDeltaRotation)), - direction: Vec3.mix(Quat.getUp(this.getHandRotation()), Quat.getFront(Camera.orientation), 0.5), + direction: Vec3.mix(Quat.getUp(this.getHandRotation()), Quat.getFront(Camera.orientation), HAND_HEAD_MIX_RATIO), length: PICK_MAX_DISTANCE }; @@ -1188,15 +1190,12 @@ function MyController(hand) { y: 0.0, z: objDistance }); - var change = Vec3.subtract(before, after); + var change = Vec3.multiply(Vec3.subtract(before, after), HAND_HEAD_MIX_RATIO); this.currentCameraOrientation = Camera.orientation; this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } - } else { - // print('should not head move!'); } - var defaultConstraintData = { axisStart: false, axisEnd: false, From 85a0dfa21a042f67aae7683472f075c8675d737c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 31 Dec 2015 13:49:24 -0800 Subject: [PATCH 209/209] remove debug line --- examples/controllers/handControllerGrab.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 1dfc0ffacd..ed02bd3709 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -791,7 +791,6 @@ function MyController(hand) { var distantPickRay = { origin: Camera.position, - //direction: Quat.getFront(Quat.multiply(Camera.orientation, handDeltaRotation)), direction: Vec3.mix(Quat.getUp(this.getHandRotation()), Quat.getFront(Camera.orientation), HAND_HEAD_MIX_RATIO), length: PICK_MAX_DISTANCE };