diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index e543b3aa21..5b92dfba99 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -1,12 +1,12 @@ set(TARGET_NAME assignment-client) -setup_hifi_project(Core Gui Network Script Widgets WebSockets) +setup_hifi_project(Core Gui Network Script Quick Widgets WebSockets) # link in the shared libraries link_hifi_libraries( audio avatars octree environment gpu model fbx entities networking animation shared script-engine embedded-webserver - physics + controllers physics ) include_application_version() diff --git a/examples/controllers/controllerMappings.js b/examples/controllers/controllerMappings.js index 45383886c2..e4ef0270ab 100644 --- a/examples/controllers/controllerMappings.js +++ b/examples/controllers/controllerMappings.js @@ -54,7 +54,7 @@ return { var myFirstMappingJSON = myFirstMapping(); print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON)); -var mapping = NewControllers.parseMapping(JSON.stringify(myFirstMappingJSON)); +var mapping = Controller.parseMapping(JSON.stringify(myFirstMappingJSON)); Object.keys(Controller.Standard).forEach(function (input) { print("Controller.Standard." + input + ":" + Controller.Standard[input]); diff --git a/examples/example/scripts/controllerScriptingExamples.js b/examples/example/scripts/controllerScriptingExamples.js index e678ff26eb..b3dc92029d 100644 --- a/examples/example/scripts/controllerScriptingExamples.js +++ b/examples/example/scripts/controllerScriptingExamples.js @@ -11,6 +11,16 @@ // Assumes you only have the default keyboard connected +function findAction(name) { + var actions = Controller.getAllActions(); + for (var i = 0; i < actions.length; i++) { + if (actions[i].actionName == name) { + return i; + } + } + // If the action isn't found, it will default to the first available action + return 0; +} var hydra = Controller.Hardware.Hydra2; @@ -46,44 +56,48 @@ Controller.resetAllDeviceBindings(); // Query all actions print("All Actions: \n" + Controller.getAllActions()); +var actionId = findAction("YAW_LEFT") + +print("Yaw Left action ID: " + actionId) + // Each action stores: // action: int representation of enum -print("Action 5 int: \n" + Controller.getAllActions()[5].action); +print("Action int: \n" + Controller.getAllActions()[actionId].action); // actionName: string representation of enum -print("Action 5 name: \n" + Controller.getAllActions()[5].actionName); +print("Action name: \n" + Controller.getAllActions()[actionId].actionName); // inputChannels: list of all inputchannels that control that action -print("Action 5 input channels: \n" + Controller.getAllActions()[5].inputChannels + "\n"); +print("Action input channels: \n" + Controller.getAllActions()[actionId].inputChannels + "\n"); // Each input channel stores: // action: Action that this InputChannel maps to -print("Input channel action: \n" + Controller.getAllActions()[5].inputChannels[0].action); +print("Input channel action: \n" + Controller.getAllActions()[actionId].inputChannels[0].action); // scale: sensitivity of input -print("Input channel scale: \n" + Controller.getAllActions()[5].inputChannels[0].scale); +print("Input channel scale: \n" + Controller.getAllActions()[actionId].inputChannels[0].scale); // input and modifier: Inputs -print("Input channel input and modifier: \n" + Controller.getAllActions()[5].inputChannels[0].input + "\n" + Controller.getAllActions()[5].inputChannels[0].modifier + "\n"); +print("Input channel input and modifier: \n" + Controller.getAllActions()[actionId].inputChannels[0].input + "\n" + Controller.getAllActions()[actionId].inputChannels[0].modifier + "\n"); // Each Input stores: // device: device of input -print("Input device: \n" + Controller.getAllActions()[5].inputChannels[0].input.device); +print("Input device: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.device); // channel: channel of input -print("Input channel: \n" + Controller.getAllActions()[5].inputChannels[0].input.channel); +print("Input channel: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.channel); // type: type of input (Unknown, Button, Axis, Joint) -print("Input type: \n" + Controller.getAllActions()[5].inputChannels[0].input.type); +print("Input type: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.type); // id: id of input -print("Input id: \n" + Controller.getAllActions()[5].inputChannels[0].input.id + "\n"); +print("Input id: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.id + "\n"); // You can get the name of a device from its id -print("Device 1 name: \n" + Controller.getDeviceName(Controller.getAllActions()[5].inputChannels[0].input.id)); +print("Device 1 name: \n" + Controller.getDeviceName(Controller.getAllActions()[actionId].inputChannels[0].input.id)); // You can also get all of a devices input channels print("Device 1's input channels: \n" + Controller.getAllInputsForDevice(1) + "\n"); @@ -119,7 +133,7 @@ for (i = 0; i < availableInputs.length; i++) { // You can modify key bindings by using these avaiable inputs // This will replace e (up) with 6 -var e = Controller.getAllActions()[5].inputChannels[0]; +var e = Controller.getAllActions()[actionId].inputChannels[0]; Controller.removeInputChannel(e); e.input = availableInputs[6].input; Controller.addInputChannel(e); \ No newline at end of file diff --git a/examples/mouseLook.js b/examples/mouseLook.js index 880ec138c4..81bc9d2813 100644 --- a/examples/mouseLook.js +++ b/examples/mouseLook.js @@ -38,7 +38,7 @@ var mouseLook = (function () { keyboardID = 0; function onKeyPressEvent(event) { - if (event.text == 'M') { + if (event.text == 'm') { active = !active; updateMapping(); } diff --git a/examples/toys/ping_pong_gun/createTargets.js b/examples/toys/ping_pong_gun/createTargets.js index 22329f90f0..fb286b1928 100644 --- a/examples/toys/ping_pong_gun/createTargets.js +++ b/examples/toys/ping_pong_gun/createTargets.js @@ -16,8 +16,9 @@ var scriptURL = Script.resolvePath('wallTarget.js'); var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target.fbx'; var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target_collision_hull.obj'; +var MINIMUM_MOVE_LENGTH = 0.05; +var RESET_DISTANCE = 0.5; -var RESET_DISTANCE = 1; var TARGET_USER_DATA_KEY = 'hifi-ping_pong_target'; var NUMBER_OF_TARGETS = 6; var TARGETS_PER_ROW = 3; @@ -60,6 +61,8 @@ var targets = []; var originalPositions = []; +var lastPositions = []; + function addTargets() { var i; var row = -1; @@ -77,6 +80,7 @@ function addTargets() { position.y = startPosition.y - (row * VERTICAL_SPACING); originalPositions.push(position); + lastPositions.push(position); var targetProperties = { name: 'Target', @@ -103,7 +107,11 @@ function testTargetDistanceFromStart() { var distance = Vec3.subtract(originalPosition, currentPosition); var length = Vec3.length(distance); - if (length > RESET_DISTANCE) { + var moving = Vec3.length(Vec3.subtract(currentPosition, lastPositions[index])); + + lastPositions[index] = currentPosition; + + if (length > RESET_DISTANCE && moving < MINIMUM_MOVE_LENGTH) { Entities.deleteEntity(target); @@ -117,10 +125,16 @@ function testTargetDistanceFromStart() { compoundShapeURL: COLLISION_HULL_URL, position: originalPositions[index], rotation: rotation, - script: scriptURL + script: scriptURL, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) }; targets[index] = Entities.addEntity(targetProperties); + } }); } @@ -142,7 +156,7 @@ function deleteTargets() { } Entities.deletingEntity.connect(deleteEntity); -var distanceCheckInterval = Script.setInterval(testTargetDistanceFromStart, 1000); +var distanceCheckInterval = Script.setInterval(testTargetDistanceFromStart, 500); addTargets(); diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 95de0649ad..43db834c3c 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -98,9 +98,8 @@ endif() # link required hifi libraries link_hifi_libraries(shared octree environment gpu procedural model render fbx networking model-networking entities avatars audio audio-client animation script-engine physics - render-utils entities-renderer ui auto-updater - plugins display-plugins input-plugins - controllers) + render-utils entities-renderer ui auto-updater + controllers plugins display-plugins input-plugins ) target_bullet() target_glew() diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fd2f4e3ebc..77f353a3ff 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -60,7 +60,7 @@ #include #include #include // this should probably be removed -#include +#include #include #include #include @@ -614,7 +614,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // Setup the userInputMapper with the actions auto userInputMapper = DependencyManager::get(); - connect(userInputMapper.data(), &UserInputMapper::actionEvent, &_controllerScriptingInterface, &AbstractControllerScriptingInterface::actionEvent); + connect(userInputMapper.data(), &UserInputMapper::actionEvent, &_controllerScriptingInterface, &ControllerScriptingInterface::actionEvent); connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) { if (state) { switch (action) { @@ -1559,7 +1559,7 @@ void Application::keyPressEvent(QKeyEvent* event) { cursor->setIcon(Cursor::Icon::DEFAULT); } } else { - resetSensors(); + resetSensors(true); } break; } @@ -2708,7 +2708,7 @@ void Application::update(float deltaTime) { } // Dispatch input events - _controllerScriptingInterface.updateInputControllers(); + _controllerScriptingInterface.update(); // Transfer the user inputs to the driveKeys myAvatar->clearDriveKeys(); @@ -3581,7 +3581,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi renderArgs->_viewport = originalViewport; } -void Application::resetSensors() { +void Application::resetSensors(bool andReload) { DependencyManager::get()->reset(); DependencyManager::get()->reset(); DependencyManager::get()->reset(); @@ -3593,7 +3593,7 @@ void Application::resetSensors() { QPoint windowCenter = mainWindow->geometry().center(); _glWidget->cursor().setPos(currentScreen, windowCenter); - getMyAvatar()->reset(); + getMyAvatar()->reset(andReload); QMetaObject::invokeMethod(DependencyManager::get().data(), "reset", Qt::QueuedConnection); } diff --git a/interface/src/Application.h b/interface/src/Application.h index a2125e7e09..61421c34d6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -161,7 +161,7 @@ public: ToolWindow* getToolWindow() { return _toolWindow ; } - virtual AbstractControllerScriptingInterface* getControllerScriptingInterface() { return &_controllerScriptingInterface; } + virtual controller::ScriptingInterface* getControllerScriptingInterface() { return &_controllerScriptingInterface; } virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine); QImage renderAvatarBillboard(RenderArgs* renderArgs); @@ -274,7 +274,7 @@ public slots: void setRawAvatarUpdateThreading(); void setRawAvatarUpdateThreading(bool isThreaded); - void resetSensors(); + void resetSensors(bool andReload = false); void setActiveFaceTracker(); #ifdef HAVE_IVIEWHMD diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ae41ca2493..3d671b0447 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -461,6 +461,7 @@ Menu::Menu() { 0, false, &ConnexionClient::getInstance(), SLOT(toggleConnexion(bool))); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ComfortMode, 0, true); MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands"); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 4c9c3ef7b5..216a410603 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -159,6 +159,7 @@ namespace MenuOption { const QString CenterPlayerInView = "Center Player In View"; const QString Chat = "Chat..."; const QString Collisions = "Collisions"; + const QString ComfortMode = "Comfort Mode"; const QString Connexion = "Activate 3D Connexion Devices"; const QString Console = "Console..."; const QString ControlWithSpeech = "Control With Speech"; diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index 19bb6ab8de..079d6d0bea 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -144,7 +144,7 @@ void PluginContainerProxy::unsetFullscreen(const QScreen* avoid) { void PluginContainerProxy::requestReset() { // We could signal qApp to sequence this, but it turns out that requestReset is only used from within the main thread anyway. - qApp->resetSensors(); + qApp->resetSensors(true); } void PluginContainerProxy::showDisplayPluginsTools() { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 605a81e9d9..5b580c2a97 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -140,16 +140,18 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { return AvatarData::toByteArray(cullSmallChanges, sendAll); } -void MyAvatar::reset() { +void MyAvatar::reset(bool andReload) { // Gather animation mode... // This should be simpler when we have only graph animations always on. bool isRig = _rig->getEnableRig(); // seting rig animation to true, below, will clear the graph animation menu item, so grab it now. bool isGraph = _rig->getEnableAnimGraph() || Menu::getInstance()->isOptionChecked(MenuOption::EnableAnimGraph); // ... and get to sane configuration where other activity won't bother us. - qApp->setRawAvatarUpdateThreading(false); - _rig->disableHands = true; - setEnableRigAnimations(true); + if (andReload) { + qApp->setRawAvatarUpdateThreading(false); + _rig->disableHands = true; + setEnableRigAnimations(true); + } // Reset dynamic state. _wasPushing = _isPushing = _isBraking = _billboardValid = _straighteningLean = false; @@ -158,32 +160,34 @@ void MyAvatar::reset() { _targetVelocity = glm::vec3(0.0f); setThrust(glm::vec3(0.0f)); - // Get fresh data, in case we're really slow and out of wack. - _hmdSensorMatrix = qApp->getHMDSensorPose(); - _hmdSensorPosition = extractTranslation(_hmdSensorMatrix); - _hmdSensorOrientation = glm::quat_cast(_hmdSensorMatrix); + if (andReload) { + // Get fresh data, in case we're really slow and out of wack. + _hmdSensorMatrix = qApp->getHMDSensorPose(); + _hmdSensorPosition = extractTranslation(_hmdSensorMatrix); + _hmdSensorOrientation = glm::quat_cast(_hmdSensorMatrix); - // Reset body position/orientation under the head. - auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. - auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix; - glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix); - glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix)); + // Reset body position/orientation under the head. + auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. + auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix; + glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix); + glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix)); - // FIXME: Hack to retain the previous behavior wrt height. - // I'd like to make the body match head height, but that will have to wait for separate PR. - worldBodyPos.y = getPosition().y; + // FIXME: Hack to retain the previous behavior wrt height. + // I'd like to make the body match head height, but that will have to wait for separate PR. + worldBodyPos.y = getPosition().y; - setPosition(worldBodyPos); - setOrientation(worldBodyRot); - // If there is any discrepency between positioning and the head (as there is in initial deriveBodyFromHMDSensor), - // we can make that right by setting _bodySensorMatrix = newBodySensorMatrix. - // However, doing so will make the head want to point to the previous body orientation, as cached above. - //_bodySensorMatrix = newBodySensorMatrix; - //updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + setPosition(worldBodyPos); + setOrientation(worldBodyRot); + // If there is any discrepency between positioning and the head (as there is in initial deriveBodyFromHMDSensor), + // we can make that right by setting _bodySensorMatrix = newBodySensorMatrix. + // However, doing so will make the head want to point to the previous body orientation, as cached above. + //_bodySensorMatrix = newBodySensorMatrix; + //updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes - _skeletonModel.simulate(0.1f); // non-zero - setEnableRigAnimations(false); - _skeletonModel.simulate(0.1f); + _skeletonModel.simulate(0.1f); // non-zero + setEnableRigAnimations(false); + _skeletonModel.simulate(0.1f); + } if (isRig) { setEnableRigAnimations(true); Menu::getInstance()->setIsOptionChecked(MenuOption::EnableRigAnimations, true); @@ -191,8 +195,10 @@ void MyAvatar::reset() { setEnableAnimGraph(true); Menu::getInstance()->setIsOptionChecked(MenuOption::EnableAnimGraph, true); } - _rig->disableHands = false; - qApp->setRawAvatarUpdateThreading(); + if (andReload) { + _rig->disableHands = false; + qApp->setRawAvatarUpdateThreading(); + } } void MyAvatar::update(float deltaTime) { @@ -1514,33 +1520,69 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { void MyAvatar::updateOrientation(float deltaTime) { // Smoothly rotate body with arrow keys - float targetSpeed = (_driveKeys[ROT_LEFT] - _driveKeys[ROT_RIGHT]) * YAW_SPEED; - if (targetSpeed != 0.0f) { - const float ROTATION_RAMP_TIMESCALE = 0.1f; - float blend = deltaTime / ROTATION_RAMP_TIMESCALE; - if (blend > 1.0f) { - blend = 1.0f; - } - _bodyYawDelta = (1.0f - blend) * _bodyYawDelta + blend * targetSpeed; - } else if (_bodyYawDelta != 0.0f) { - // attenuate body rotation speed - const float ROTATION_DECAY_TIMESCALE = 0.05f; - float attenuation = 1.0f - deltaTime / ROTATION_DECAY_TIMESCALE; - if (attenuation < 0.0f) { - attenuation = 0.0f; - } - _bodyYawDelta *= attenuation; + float targetSpeed = 0.0f; + + // FIXME - this comfort mode code is a total hack, remove it when we have new input mapping + bool isComfortMode = Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode); + bool isHMDMode = qApp->getAvatarUpdater()->isHMDMode(); + + if (!isHMDMode || !isComfortMode) { + targetSpeed = (_driveKeys[ROT_LEFT] - _driveKeys[ROT_RIGHT]) * YAW_SPEED; + + if (targetSpeed != 0.0f) { + const float ROTATION_RAMP_TIMESCALE = 0.1f; + float blend = deltaTime / ROTATION_RAMP_TIMESCALE; + if (blend > 1.0f) { + blend = 1.0f; + } + _bodyYawDelta = (1.0f - blend) * _bodyYawDelta + blend * targetSpeed; + } else if (_bodyYawDelta != 0.0f) { + // attenuate body rotation speed + const float ROTATION_DECAY_TIMESCALE = 0.05f; + float attenuation = 1.0f - deltaTime / ROTATION_DECAY_TIMESCALE; + if (attenuation < 0.0f) { + attenuation = 0.0f; + } + _bodyYawDelta *= attenuation; + + float MINIMUM_ROTATION_RATE = 2.0f; + if (fabsf(_bodyYawDelta) < MINIMUM_ROTATION_RATE) { + _bodyYawDelta = 0.0f; + } + } + + // update body orientation by movement inputs + setOrientation(getOrientation() * + glm::quat(glm::radians(glm::vec3(0.0f, _bodyYawDelta * deltaTime, 0.0f)))); + + } else { + // Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll + // get an instantaneous 15 degree turn. If you keep holding the key down you'll get another + // snap turn every half second. + _bodyYawDelta = 0.0f; + + static quint64 lastPulse = 0; + quint64 now = usecTimestampNow(); + quint64 COMFORT_MODE_PULSE_TIMING = USECS_PER_SECOND / 2; // turn once per half second + + float driveLeft = _driveKeys[ROT_LEFT]; + float driveRight= _driveKeys[ROT_RIGHT]; + + if ((driveLeft != 0.0f || driveRight != 0.0f) && (now - lastPulse > COMFORT_MODE_PULSE_TIMING)) { + lastPulse = now; + + const float SNAP_TURN_DELTA = 15.0f; // degrees + float direction = (driveLeft - driveRight) < 0.0f ? -1.0f : 1.0f; + float turnAmount = direction * SNAP_TURN_DELTA; + + // update body orientation by movement inputs + setOrientation(getOrientation() * + glm::quat(glm::radians(glm::vec3(0.0f, turnAmount, 0.0f)))); - float MINIMUM_ROTATION_RATE = 2.0f; - if (fabsf(_bodyYawDelta) < MINIMUM_ROTATION_RATE) { - _bodyYawDelta = 0.0f; } } getHead()->setBasePitch(getHead()->getBasePitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime); - // update body orientation by movement inputs - setOrientation(getOrientation() * - glm::quat(glm::radians(glm::vec3(0.0f, _bodyYawDelta * deltaTime, 0.0f)))); if (qApp->getAvatarUpdater()->isHMDMode()) { glm::quat orientation = glm::quat_cast(getSensorToWorldMatrix()) * getHMDSensorOrientation(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index cca0c4152f..02c9f53082 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -58,7 +58,7 @@ public: AudioListenerMode getAudioListenerModeCamera() const { return FROM_CAMERA; } AudioListenerMode getAudioListenerModeCustom() const { return CUSTOM; } - void reset(); + void reset(bool andReload = false); void update(float deltaTime); void preRender(RenderArgs* renderArgs); diff --git a/interface/src/devices/3DConnexionClient.h b/interface/src/devices/3DConnexionClient.h index cdf8e1e2a1..bddb86a857 100755 --- a/interface/src/devices/3DConnexionClient.h +++ b/interface/src/devices/3DConnexionClient.h @@ -13,7 +13,7 @@ #include #include -#include +#include #include "InterfaceLogging.h" diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 54aa72da6b..f1f7b08587 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -9,21 +9,20 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ControllerScriptingInterface.h" + #include #include #include #include - -#include +#include #include "Application.h" #include "devices/MotionTracker.h" -#include "ControllerScriptingInterface.h" // TODO: this needs to be removed, as well as any related controller-specific information #include - ControllerScriptingInterface::ControllerScriptingInterface() : _mouseCaptured(false), _touchCaptured(false), @@ -34,7 +33,6 @@ ControllerScriptingInterface::ControllerScriptingInterface() : } ControllerScriptingInterface::~ControllerScriptingInterface() { - delete _newControllerScriptingInterface; } @@ -118,7 +116,7 @@ void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::Input inputPair.second = QString(object.property("inputName").toVariant().toString()); } -void ControllerScriptingInterface::registerControllerTypes(ScriptEngine* engine) { +void ControllerScriptingInterface::registerControllerTypes(QScriptEngine* engine) { qScriptRegisterSequenceMetaType >(engine); qScriptRegisterSequenceMetaType >(engine); qScriptRegisterSequenceMetaType >(engine); @@ -126,13 +124,6 @@ void ControllerScriptingInterface::registerControllerTypes(ScriptEngine* engine) qScriptRegisterMetaType(engine, inputChannelToScriptValue, inputChannelFromScriptValue); qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue); qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue); - - wireUpControllers(engine); - - // hack in the new controller scripting interface... - _newControllerScriptingInterface = new controller::NewControllerScriptingInterface(); - engine->registerGlobalObject("NewControllers", _newControllerScriptingInterface); - } void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) { @@ -192,6 +183,7 @@ const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const return NULL; } +/* bool ControllerScriptingInterface::isPrimaryButtonPressed() const { const PalmData* primaryPalm = getPrimaryPalm(); if (primaryPalm) { @@ -345,6 +337,7 @@ glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex } return glm::vec3(0); // bad index } +*/ bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const { return isKeyCaptured(KeyEvent(*event)); @@ -395,97 +388,64 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const { return qApp->getUiSize(); } -QString ControllerScriptingInterface::sanatizeName(const QString& name) { - QString cleanName { name }; - cleanName.remove(QRegularExpression{"[\\(\\)\\.\\s]"}); - return cleanName; -} - -void ControllerScriptingInterface::wireUpControllers(ScriptEngine* engine) { - - // Controller.Standard.* - auto standardDevice = DependencyManager::get()->getStandardDevice(); - if (standardDevice) { - auto deviceName = sanatizeName(standardDevice->getName()); - auto deviceInputs = standardDevice->getAvailabeInputs(); - for (const auto& inputMapping : deviceInputs) { - auto input = inputMapping.first; - auto inputName = sanatizeName(inputMapping.second); - QString deviceInputName{ "Controller." + deviceName + "." + inputName }; - engine->registerValue(deviceInputName, input.getID()); - } - } - - // Controller.Hardware.* - auto devices = DependencyManager::get()->getDevices(); - for(const auto& deviceMapping : devices) { - auto device = deviceMapping.second.get(); - auto deviceName = sanatizeName(device->getName()); - auto deviceInputs = device->getAvailabeInputs(); - for (const auto& inputMapping : deviceInputs) { - auto input = inputMapping.first; - auto inputName = sanatizeName(inputMapping.second); - QString deviceInputName { "Controller.Hardware." + deviceName + "." + inputName }; - engine->registerValue(deviceInputName, input.getID()); - } - } - - // Controller.Actions.* - auto actionNames = DependencyManager::get()->getActionNames(); - int actionNumber = 0; - for (const auto& actionName : actionNames) { - QString safeActionName { "Controller.Actions." + sanatizeName(actionName) }; - engine->registerValue(safeActionName, actionNumber); - actionNumber++; - } -} - -AbstractInputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) { +controller::InputController::Pointer ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) { // This is where we retreive the Device Tracker category and then the sub tracker within it - //TODO C++11 auto icIt = _inputControllers.find(0); - InputControllerMap::iterator icIt = _inputControllers.find(0); - + auto icIt = _inputControllers.find(0); if (icIt != _inputControllers.end()) { return (*icIt).second; - } else { + } - // Look for device - DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString()); - if (deviceID < 0) { - deviceID = 0; - } - // TODO in this current implementation, we just pick the device assuming there is one (normally the Leapmotion) - // in the near future we need to change that to a real mapping between the devices and the deviceName - // ALso we need to expand the spec so we can fall back on the "default" controller per categories - if (deviceID >= 0) { - // TODO here again the assumption it's the LeapMotion and so it's a MOtionTracker, this would need to be changed to support different types of devices - MotionTracker* motionTracker = dynamic_cast< MotionTracker* > (DeviceTracker::getDevice(deviceID)); - if (motionTracker) { - MotionTracker::Index trackerID = motionTracker->findJointIndex(tracker.toStdString()); - if (trackerID >= 0) { - AbstractInputController* inputController = new InputController(deviceID, trackerID, this); + // Look for device + DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString()); + if (deviceID < 0) { + deviceID = 0; + } + // TODO in this current implementation, we just pick the device assuming there is one (normally the Leapmotion) + // in the near future we need to change that to a real mapping between the devices and the deviceName + // ALso we need to expand the spec so we can fall back on the "default" controller per categories - _inputControllers.insert(InputControllerMap::value_type(inputController->getKey(), inputController)); - - return inputController; - } + if (deviceID >= 0) { + // TODO here again the assumption it's the LeapMotion and so it's a MOtionTracker, this would need to be changed to support different types of devices + MotionTracker* motionTracker = dynamic_cast< MotionTracker* > (DeviceTracker::getDevice(deviceID)); + if (motionTracker) { + MotionTracker::Index trackerID = motionTracker->findJointIndex(tracker.toStdString()); + if (trackerID >= 0) { + controller::InputController::Pointer inputController = std::make_shared(deviceID, trackerID, this); + controller::InputController::Key key = inputController->getKey(); + _inputControllers.insert(InputControllerMap::value_type(inputController->getKey(), inputController)); + return inputController; } } - - return 0; } + + return controller::InputController::Pointer(); } -void ControllerScriptingInterface::releaseInputController(AbstractInputController* input) { +void ControllerScriptingInterface::releaseInputController(controller::InputController::Pointer input) { _inputControllers.erase(input->getKey()); } -void ControllerScriptingInterface::updateInputControllers() { - //TODO C++11 for (auto it = _inputControllers.begin(); it != _inputControllers.end(); it++) { - for (InputControllerMap::iterator it = _inputControllers.begin(); it != _inputControllers.end(); it++) { - (*it).second->update(); +void ControllerScriptingInterface::update() { + static float last = secTimestampNow(); + float now = secTimestampNow(); + float delta = now - last; + last = now; + + for(auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) { + if (inputPlugin->isActive()) { + inputPlugin->pluginUpdate(delta, false); + } } + + auto userInputMapper = DependencyManager::get(); + userInputMapper->update(delta); + + for (auto entry : _inputControllers) { + entry.second->update(); + } + + controller::ScriptingInterface::update(); } QVector ControllerScriptingInterface::getAllActions() { @@ -545,7 +505,6 @@ QVector ControllerScriptingInterface::getActionNames() const { } InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : - AbstractInputController(), _deviceTrackerId(deviceTrackerId), _subTrackerId(subTrackerId), _isActive(false) @@ -568,7 +527,7 @@ void InputController::update() { joint->getLocFrame().getRotation(_eventCache.locRotation); _isActive = true; - emit spatialEvent(_eventCache); + //emit spatialEvent(_eventCache); } } } @@ -580,3 +539,19 @@ const unsigned int INPUTCONTROLLER_KEY_DEVICE_MASK = 16; InputController::Key InputController::getKey() const { return (((_deviceTrackerId & INPUTCONTROLLER_KEY_DEVICE_MASK) << INPUTCONTROLLER_KEY_DEVICE_OFFSET) | _subTrackerId); } + + +void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); } +void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } + +void ControllerScriptingInterface::emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); } +void ControllerScriptingInterface::emitMousePressEvent(QMouseEvent* event, unsigned int deviceID) { emit mousePressEvent(MouseEvent(*event, deviceID)); } +void ControllerScriptingInterface::emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); } +void ControllerScriptingInterface::emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); } + +void ControllerScriptingInterface::emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); } +void ControllerScriptingInterface::emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); } +void ControllerScriptingInterface::emitTouchUpdateEvent(const TouchEvent& event) { emit touchUpdateEvent(event); } + +void ControllerScriptingInterface::emitWheelEvent(QWheelEvent* event) { emit wheelEvent(*event); } + diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index dfe87043cd..25d9a523d3 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -14,15 +14,20 @@ #include -#include +#include +#include + +#include +#include +#include +#include +#include +#include +class ScriptEngine; -#include class PalmData; -namespace controller { - class NewControllerScriptingInterface; -} -class InputController : public AbstractInputController { +class InputController : public controller::InputController { Q_OBJECT public: @@ -53,30 +58,53 @@ signals: /// handles scripting of input controller commands from JS -class ControllerScriptingInterface : public AbstractControllerScriptingInterface { +class ControllerScriptingInterface : public controller::ScriptingInterface { Q_OBJECT + public: ControllerScriptingInterface(); ~ControllerScriptingInterface(); - virtual void registerControllerTypes(ScriptEngine* engine); + Q_INVOKABLE QVector getAllActions(); + + Q_INVOKABLE bool addInputChannel(UserInputMapper::InputChannel inputChannel); + Q_INVOKABLE bool removeInputChannel(UserInputMapper::InputChannel inputChannel); + Q_INVOKABLE QVector getInputChannelsForAction(UserInputMapper::Action action); + + Q_INVOKABLE QVector getAvailableInputs(unsigned int device); + Q_INVOKABLE QVector getAllInputsForDevice(unsigned int device); + + Q_INVOKABLE QString getDeviceName(unsigned int device); + + Q_INVOKABLE float getActionValue(int action); + + Q_INVOKABLE void resetDevice(unsigned int device); + Q_INVOKABLE void resetAllDeviceBindings(); + Q_INVOKABLE int findDevice(QString name); + Q_INVOKABLE QVector getDeviceNames(); + + Q_INVOKABLE int findAction(QString actionName); + Q_INVOKABLE QVector getActionNames() const; + + + virtual void registerControllerTypes(QScriptEngine* engine); - void emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); } - void emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } + void emitKeyPressEvent(QKeyEvent* event); + void emitKeyReleaseEvent(QKeyEvent* event); void handleMetaEvent(HFMetaEvent* event); - void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); } - void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); } - void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); } - void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); } + void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0); + void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0); + void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0); + void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0); - void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); } - void emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); } - void emitTouchUpdateEvent(const TouchEvent& event) { emit touchUpdateEvent(event); } + void emitTouchBeginEvent(const TouchEvent& event); + void emitTouchEndEvent(const TouchEvent& event); + void emitTouchUpdateEvent(const TouchEvent& event); - void emitWheelEvent(QWheelEvent* event) { emit wheelEvent(*event); } + void emitWheelEvent(QWheelEvent* event); bool isKeyCaptured(QKeyEvent* event) const; bool isKeyCaptured(const KeyEvent& event) const; @@ -86,48 +114,10 @@ public: bool areActionsCaptured() const { return _actionsCaptured; } bool isJoystickCaptured(int joystickIndex) const; - void updateInputControllers(); + virtual void update() override; public slots: - Q_INVOKABLE virtual QVector getAllActions(); - - Q_INVOKABLE virtual bool addInputChannel(UserInputMapper::InputChannel inputChannel); - Q_INVOKABLE virtual bool removeInputChannel(UserInputMapper::InputChannel inputChannel); - Q_INVOKABLE virtual QVector getInputChannelsForAction(UserInputMapper::Action action); - - Q_INVOKABLE virtual QVector getAvailableInputs(unsigned int device); - Q_INVOKABLE virtual QVector getAllInputsForDevice(unsigned int device); - - Q_INVOKABLE virtual QString getDeviceName(unsigned int device); - - Q_INVOKABLE virtual float getActionValue(int action); - Q_INVOKABLE virtual void resetDevice(unsigned int device); - Q_INVOKABLE virtual void resetAllDeviceBindings(); - Q_INVOKABLE virtual int findDevice(QString name); - Q_INVOKABLE virtual QVector getDeviceNames(); - - Q_INVOKABLE virtual int findAction(QString actionName); - Q_INVOKABLE virtual QVector getActionNames() const; - - virtual bool isPrimaryButtonPressed() const; - virtual glm::vec2 getPrimaryJoystickPosition() const; - - virtual int getNumberOfButtons() const; - virtual bool isButtonPressed(int buttonIndex) const; - - virtual int getNumberOfTriggers() const; - virtual float getTriggerValue(int triggerIndex) const; - - virtual int getNumberOfJoysticks() const; - virtual glm::vec2 getJoystickPosition(int joystickIndex) const; - - virtual int getNumberOfSpatialControls() const; - virtual glm::vec3 getSpatialControlPosition(int controlIndex) const; - virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const; - virtual glm::vec3 getSpatialControlNormal(int controlIndex) const; - virtual glm::quat getSpatialControlRawRotation(int controlIndex) const; - virtual glm::vec3 getSpatialControlRawAngularVelocity(int controlIndex) const; virtual void captureKeyEvents(const KeyEvent& event); virtual void releaseKeyEvents(const KeyEvent& event); @@ -149,9 +139,31 @@ public slots: virtual glm::vec2 getViewportDimensions() const; /// Factory to create an InputController - virtual AbstractInputController* createInputController(const QString& deviceName, const QString& tracker); + virtual controller::InputController::Pointer createInputController(const QString& deviceName, const QString& tracker); + virtual void releaseInputController(controller::InputController::Pointer input); - virtual void releaseInputController(AbstractInputController* input); +signals: + void keyPressEvent(const KeyEvent& event); + void keyReleaseEvent(const KeyEvent& event); + + void actionStartEvent(const HFActionEvent& event); + void actionEndEvent(const HFActionEvent& event); + + void backStartEvent(); + void backEndEvent(); + + void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0); + void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0); + void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0); + void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0); + + void touchBeginEvent(const TouchEvent& event); + void touchEndEvent(const TouchEvent& event); + void touchUpdateEvent(const TouchEvent& event); + + void wheelEvent(const WheelEvent& event); + + void actionEvent(int action, float state); private: QString sanatizeName(const QString& name); /// makes a name clean for inclusing in JavaScript @@ -168,12 +180,9 @@ private: QMultiMap _capturedKeys; QSet _capturedJoysticks; - typedef std::map< AbstractInputController::Key, AbstractInputController* > InputControllerMap; + using InputKey = controller::InputController::Key; + using InputControllerMap = std::map; InputControllerMap _inputControllers; - - void wireUpControllers(ScriptEngine* engine); - - controller::NewControllerScriptingInterface* _newControllerScriptingInterface = nullptr; }; const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 4e5dd0da0c..4fc2f3ddb4 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -27,7 +27,7 @@ #include "Application.h" #include // TODO: any references to sixense should be removed here -#include +#include // Used to animate the magnification windows diff --git a/libraries/controllers/CMakeLists.txt b/libraries/controllers/CMakeLists.txt index fbabbe1463..5beffce461 100644 --- a/libraries/controllers/CMakeLists.txt +++ b/libraries/controllers/CMakeLists.txt @@ -4,7 +4,7 @@ set(TARGET_NAME controllers) setup_hifi_library(Script) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -link_hifi_libraries(shared plugins input-plugins) +link_hifi_libraries(shared) GroupSources("src/controllers") diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h index bea33517f5..5c6e6c028b 100644 --- a/libraries/controllers/src/controllers/Endpoint.h +++ b/libraries/controllers/src/controllers/Endpoint.h @@ -14,7 +14,7 @@ #include #include -#include +#include "UserInputMapper.h" class QScriptValue; diff --git a/libraries/input-plugins/src/input-plugins/InputDevice.cpp b/libraries/controllers/src/controllers/InputDevice.cpp similarity index 100% rename from libraries/input-plugins/src/input-plugins/InputDevice.cpp rename to libraries/controllers/src/controllers/InputDevice.cpp diff --git a/libraries/input-plugins/src/input-plugins/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h similarity index 100% rename from libraries/input-plugins/src/input-plugins/InputDevice.h rename to libraries/controllers/src/controllers/InputDevice.h diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h deleted file mode 100644 index 784b8cf5bd..0000000000 --- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h +++ /dev/null @@ -1,92 +0,0 @@ -// -// Created by Bradley Austin Davis 2015/10/09 -// 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 -// - -#pragma once -#ifndef hifi_Controllers_NewControllerScriptingInterface_h -#define hifi_Controllers_NewControllerScriptingInterface_h - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include - -#include "Mapping.h" - -class QScriptValue; - -namespace controller { - class NewControllerScriptingInterface : public QObject { - Q_OBJECT - Q_PROPERTY(QVariantMap Hardware READ getHardware CONSTANT FINAL) - Q_PROPERTY(QVariantMap Actions READ getActions CONSTANT FINAL) - Q_PROPERTY(QVariantMap Standard READ getStandard CONSTANT FINAL) - - public: - NewControllerScriptingInterface(); - Q_INVOKABLE float getValue(const int& source); - - Q_INVOKABLE void update(); - Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString()); - Q_INVOKABLE QObject* parseMapping(const QString& json); - Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true); - Q_INVOKABLE void disableMapping(const QString& mappingName) { - enableMapping(mappingName, false); - } - - - const QVariantMap& getHardware() { return _hardware; } - const QVariantMap& getActions() { return _actions; } - const QVariantMap& getStandard() { return _standard; } - - private: - - // FIXME move to unordered set / map - using MappingMap = std::map; - using MappingStack = std::list; - using InputToEndpointMap = std::map; - using EndpointSet = std::unordered_set; - using ValueMap = std::map; - using EndpointPair = std::pair; - using EndpointPairMap = std::map; - - void update(Mapping::Pointer& mapping, EndpointSet& consumed); - float getValue(const Endpoint::Pointer& endpoint); - Endpoint::Pointer endpointFor(const QJSValue& endpoint); - Endpoint::Pointer endpointFor(const QScriptValue& endpoint); - Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint); - Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second); - - UserInputMapper::Input inputFor(const QString& inputName); - - friend class MappingBuilderProxy; - friend class RouteBuilderProxy; - private: - uint16_t _nextFunctionId; - InputToEndpointMap _endpoints; - EndpointPairMap _compositeEndpoints; - - ValueMap _overrideValues; - MappingMap _mappingsByName; - MappingStack _activeMappings; - - QVariantMap _hardware; - QVariantMap _actions; - QVariantMap _standard; - }; -} - - -#endif diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp similarity index 76% rename from libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp rename to libraries/controllers/src/controllers/ScriptingInterface.cpp index baeae55128..1c31fa9de5 100644 --- a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -5,7 +5,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "NewControllerScriptingInterface.h" +#include "ScriptingInterface.h" #include #include @@ -17,17 +17,13 @@ #include #include -#include -#include -#include -#include #include "impl/MappingBuilderProxy.h" #include "Logging.h" +#include "InputDevice.h" namespace controller { - class VirtualEndpoint : public Endpoint { public: VirtualEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input(-1)) @@ -98,18 +94,15 @@ namespace controller { Endpoint::Pointer _second; }; - QString sanatizeName(const QString& name) { - QString cleanName{ name }; - cleanName.remove(QRegularExpression{ "[\\(\\)\\.\\s]" }); - return cleanName; - } + + QRegularExpression ScriptingInterface::SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" }; QVariantMap createDeviceMap(const UserInputMapper::DeviceProxy* device) { auto userInputMapper = DependencyManager::get(); QVariantMap deviceMap; for (const auto& inputMapping : device->getAvailabeInputs()) { const auto& input = inputMapping.first; - const auto inputName = sanatizeName(inputMapping.second); + const auto inputName = QString(inputMapping.second).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION); qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType() << QString::number(input.getID(), 16) << ": " << inputName; deviceMap.insert(inputName, input.getID()); @@ -117,12 +110,12 @@ namespace controller { return deviceMap; } - NewControllerScriptingInterface::NewControllerScriptingInterface() { + ScriptingInterface::ScriptingInterface() { auto userInputMapper = DependencyManager::get(); auto devices = userInputMapper->getDevices(); for (const auto& deviceMapping : devices) { auto device = deviceMapping.second.get(); - auto deviceName = sanatizeName(device->getName()); + auto deviceName = QString(device->getName()).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION); qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName; // Expose the IDs to JS _hardware.insert(deviceName, createDeviceMap(device)); @@ -165,7 +158,8 @@ namespace controller { UserInputMapper::Input actionInput(UserInputMapper::Input::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS); qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16); // Expose the IDs to JS - _actions.insert(sanatizeName(actionName), actionInput.getID()); + QString cleanActionName = QString(actionName).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION); + _actions.insert(cleanActionName, actionInput.getID()); // Create the endpoints // FIXME action endpoints need to accumulate values, and have them cleared at each frame @@ -173,7 +167,7 @@ namespace controller { } } - QObject* NewControllerScriptingInterface::newMapping(const QString& mappingName) { + QObject* ScriptingInterface::newMapping(const QString& mappingName) { if (_mappingsByName.count(mappingName)) { qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName; } @@ -183,7 +177,7 @@ namespace controller { return new MappingBuilderProxy(*this, mapping); } - QObject* NewControllerScriptingInterface::parseMapping(const QString& json) { + QObject* ScriptingInterface::parseMapping(const QString& json) { QJsonObject obj; QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8()); @@ -211,7 +205,7 @@ namespace controller { Q_INVOKABLE QObject* newMapping(const QJsonObject& json); - void NewControllerScriptingInterface::enableMapping(const QString& mappingName, bool enable) { + void ScriptingInterface::enableMapping(const QString& mappingName, bool enable) { auto iterator = _mappingsByName.find(mappingName); if (_mappingsByName.end() == iterator) { qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName; @@ -231,7 +225,7 @@ namespace controller { } } - float NewControllerScriptingInterface::getValue(const int& source) { + float ScriptingInterface::getValue(const int& source) const { // return (sin(secTimestampNow()) + 1.0f) / 2.0f; UserInputMapper::Input input(source); auto iterator = _endpoints.find(input); @@ -243,7 +237,7 @@ namespace controller { return getValue(endpoint); } - float NewControllerScriptingInterface::getValue(const Endpoint::Pointer& endpoint) { + float ScriptingInterface::getValue(const Endpoint::Pointer& endpoint) const { auto valuesIterator = _overrideValues.find(endpoint); if (_overrideValues.end() != valuesIterator) { return valuesIterator->second; @@ -252,19 +246,20 @@ namespace controller { return endpoint->value(); } - - void NewControllerScriptingInterface::update() { - static float last = secTimestampNow(); - float now = secTimestampNow(); - float delta = now - last; - last = now; + float ScriptingInterface::getButtonValue(StandardButtonChannel source, uint16_t device) const { + return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::BUTTON).getID()); + } - foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { - inputPlugin->pluginUpdate(delta, false); - } + float ScriptingInterface::getAxisValue(StandardAxisChannel source, uint16_t device) const { + return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::AXIS).getID()); + } + glm::mat4 ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const { + return glm::mat4(); + } + + void ScriptingInterface::update() { auto userInputMapper = DependencyManager::get(); - userInputMapper->update(delta); _overrideValues.clear(); EndpointSet readEndpoints; @@ -324,9 +319,7 @@ namespace controller { } } - - - Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const QJSValue& endpoint) { + Endpoint::Pointer ScriptingInterface::endpointFor(const QJSValue& endpoint) { if (endpoint.isNumber()) { return endpointFor(UserInputMapper::Input(endpoint.toInt())); } @@ -340,7 +333,7 @@ namespace controller { return Endpoint::Pointer(); } - Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const QScriptValue& endpoint) { + Endpoint::Pointer ScriptingInterface::endpointFor(const QScriptValue& endpoint) { if (endpoint.isNumber()) { return endpointFor(UserInputMapper::Input(endpoint.toInt32())); } @@ -354,11 +347,11 @@ namespace controller { return Endpoint::Pointer(); } - UserInputMapper::Input NewControllerScriptingInterface::inputFor(const QString& inputName) { + UserInputMapper::Input ScriptingInterface::inputFor(const QString& inputName) { return DependencyManager::get()->findDeviceInput(inputName); } - Endpoint::Pointer NewControllerScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) { + Endpoint::Pointer ScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) { auto iterator = _endpoints.find(inputId); if (_endpoints.end() == iterator) { qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16); @@ -367,7 +360,7 @@ namespace controller { return iterator->second; } - Endpoint::Pointer NewControllerScriptingInterface::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) { + Endpoint::Pointer ScriptingInterface::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) { EndpointPair pair(first, second); Endpoint::Pointer result; auto iterator = _compositeEndpoints.find(pair); @@ -380,6 +373,70 @@ namespace controller { return result; } + bool ScriptingInterface::isPrimaryButtonPressed() const { + return isButtonPressed(StandardButtonChannel::A); + } + + glm::vec2 ScriptingInterface::getPrimaryJoystickPosition() const { + return getJoystickPosition(0); + } + + int ScriptingInterface::getNumberOfButtons() const { + return StandardButtonChannel::NUM_STANDARD_BUTTONS; + } + + bool ScriptingInterface::isButtonPressed(int buttonIndex) const { + return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0 ? false : true; + } + + int ScriptingInterface::getNumberOfTriggers() const { + return StandardCounts::TRIGGERS; + } + + float ScriptingInterface::getTriggerValue(int triggerIndex) const { + return getAxisValue(triggerIndex == 0 ? StandardAxisChannel::LT : StandardAxisChannel::RT); + } + + int ScriptingInterface::getNumberOfJoysticks() const { + return StandardCounts::ANALOG_STICKS; + } + + glm::vec2 ScriptingInterface::getJoystickPosition(int joystickIndex) const { + StandardAxisChannel xid = StandardAxisChannel::LX; + StandardAxisChannel yid = StandardAxisChannel::LY; + if (joystickIndex != 0) { + xid = StandardAxisChannel::RX; + yid = StandardAxisChannel::RY; + } + vec2 result; + result.x = getAxisValue(xid); + result.y = getAxisValue(yid); + return result; + } + + int ScriptingInterface::getNumberOfSpatialControls() const { + return StandardCounts::POSES; + } + + glm::vec3 ScriptingInterface::getSpatialControlPosition(int controlIndex) const { + // FIXME extract the position from the standard pose + return vec3(); + } + + glm::vec3 ScriptingInterface::getSpatialControlVelocity(int controlIndex) const { + // FIXME extract the velocity from the standard pose + return vec3(); + } + + glm::vec3 ScriptingInterface::getSpatialControlNormal(int controlIndex) const { + // FIXME extract the normal from the standard pose + return vec3(); + } + + glm::quat ScriptingInterface::getSpatialControlRawRotation(int controlIndex) const { + // FIXME extract the rotation from the standard pose + return quat(); + } } // namespace controllers //var mapping = Controller.newMapping(); diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h new file mode 100644 index 0000000000..7b9f738337 --- /dev/null +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -0,0 +1,141 @@ +// +// AbstractControllerScriptingInterface.h +// libraries/script-engine/src +// +// Created by Brad Hefta-Gaub on 12/17/13. +// Copyright 2013 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 +// + +#pragma once +#ifndef hifi_AbstractControllerScriptingInterface_h +#define hifi_AbstractControllerScriptingInterface_h + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "UserInputMapper.h" +#include "StandardControls.h" +#include "Mapping.h" + +namespace controller { + class InputController : public QObject { + Q_OBJECT + + public: + using Key = unsigned int; + using Pointer = std::shared_ptr; + + virtual void update() = 0; + virtual Key getKey() const = 0; + + public slots: + virtual bool isActive() const = 0; + virtual glm::vec3 getAbsTranslation() const = 0; + virtual glm::quat getAbsRotation() const = 0; + virtual glm::vec3 getLocTranslation() const = 0; + virtual glm::quat getLocRotation() const = 0; + + signals: + //void spatialEvent(const SpatialEvent& event); + }; + + /// handles scripting of input controller commands from JS + class ScriptingInterface : public QObject { + Q_OBJECT + Q_PROPERTY(QVariantMap Hardware READ getHardware CONSTANT FINAL) + Q_PROPERTY(QVariantMap Actions READ getActions CONSTANT FINAL) + Q_PROPERTY(QVariantMap Standard READ getStandard CONSTANT FINAL) + + public: + ScriptingInterface(); + + Q_INVOKABLE float getValue(const int& source) const; + Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const; + Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const; + Q_INVOKABLE glm::mat4 getPoseValue(StandardPoseChannel source, uint16_t device = 0) const; + Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString()); + Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true); + Q_INVOKABLE void disableMapping(const QString& mappingName) { + enableMapping(mappingName, false); + } + Q_INVOKABLE QObject* parseMapping(const QString& json); + + Q_INVOKABLE bool isPrimaryButtonPressed() const; + Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const; + + Q_INVOKABLE int getNumberOfButtons() const; + Q_INVOKABLE bool isButtonPressed(int buttonIndex) const; + + Q_INVOKABLE int getNumberOfTriggers() const; + Q_INVOKABLE float getTriggerValue(int triggerIndex) const; + + Q_INVOKABLE int getNumberOfJoysticks() const; + Q_INVOKABLE glm::vec2 getJoystickPosition(int joystickIndex) const; + + Q_INVOKABLE int getNumberOfSpatialControls() const; + Q_INVOKABLE glm::vec3 getSpatialControlPosition(int controlIndex) const; + Q_INVOKABLE glm::vec3 getSpatialControlVelocity(int controlIndex) const; + Q_INVOKABLE glm::vec3 getSpatialControlNormal(int controlIndex) const; + Q_INVOKABLE glm::quat getSpatialControlRawRotation(int controlIndex) const; + + Q_INVOKABLE const QVariantMap& getHardware() { return _hardware; } + Q_INVOKABLE const QVariantMap& getActions() { return _actions; } + Q_INVOKABLE const QVariantMap& getStandard() { return _standard; } + + static QRegularExpression SANITIZE_NAME_EXPRESSION; + + public slots: + virtual void update(); + virtual void registerControllerTypes(QScriptEngine* engine) = 0; + + private: + friend class MappingBuilderProxy; + friend class RouteBuilderProxy; + + // FIXME move to unordered set / map + using MappingMap = std::map; + using MappingStack = std::list; + using InputToEndpointMap = std::map; + using EndpointSet = std::unordered_set; + using ValueMap = std::map; + using EndpointPair = std::pair; + using EndpointPairMap = std::map; + + void update(Mapping::Pointer& mapping, EndpointSet& consumed); + float getValue(const Endpoint::Pointer& endpoint) const; + Endpoint::Pointer endpointFor(const QJSValue& endpoint); + Endpoint::Pointer endpointFor(const QScriptValue& endpoint); + Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint); + Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second); + + UserInputMapper::Input inputFor(const QString& inputName); + + QVariantMap _hardware; + QVariantMap _actions; + QVariantMap _standard; + + InputToEndpointMap _endpoints; + EndpointPairMap _compositeEndpoints; + + ValueMap _overrideValues; + MappingMap _mappingsByName; + MappingStack _activeMappings; + }; +} + + +#endif // hifi_AbstractControllerScriptingInterface_h diff --git a/libraries/input-plugins/src/input-plugins/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp similarity index 75% rename from libraries/input-plugins/src/input-plugins/StandardController.cpp rename to libraries/controllers/src/controllers/StandardController.cpp index 988714a962..9c423eded2 100644 --- a/libraries/input-plugins/src/input-plugins/StandardController.cpp +++ b/libraries/controllers/src/controllers/StandardController.cpp @@ -38,59 +38,59 @@ void StandardController::registerToUserInputMapper(UserInputMapper& mapper) { proxy->getAvailabeInputs = [this] () -> QVector { QVector availableInputs; // Buttons - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "A")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "B")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "X")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Y")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y")); // DPad - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "DU")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "DD")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "DL")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "DR")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR")); // Bumpers - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "LB")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "RB")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB")); // Stick press - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "LS")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "RS")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS")); // Center buttons - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::START), "Start")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Back")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back")); // Analog sticks - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LY), "LY")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LX), "LX")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RY), "RY")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RX), "RX")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX")); // Triggers - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "LT")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "RT")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT")); // Poses - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LeftPose), "LeftPose")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RightPose), "RightPose")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT), "LeftPose")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT), "RightPose")); // Aliases, PlayStation style names - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "L1")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "R1")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "L2")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "R2")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "L3")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "R3")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Select")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "Cross")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "Circle")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "Square")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Triangle")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "Up")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "Down")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "Left")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "Right")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right")); return availableInputs; @@ -108,14 +108,14 @@ void StandardController::registerToUserInputMapper(UserInputMapper& mapper) { void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) { } -UserInputMapper::Input StandardController::makeInput(Controllers::StandardButtonChannel button) { +UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) { return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); } -UserInputMapper::Input StandardController::makeInput(Controllers::StandardAxisChannel axis) { +UserInputMapper::Input StandardController::makeInput(controller::StandardAxisChannel axis) { return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); } -UserInputMapper::Input StandardController::makeInput(Controllers::StandardPoseChannel pose) { +UserInputMapper::Input StandardController::makeInput(controller::StandardPoseChannel pose) { return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE); } diff --git a/libraries/input-plugins/src/input-plugins/StandardController.h b/libraries/controllers/src/controllers/StandardController.h similarity index 83% rename from libraries/input-plugins/src/input-plugins/StandardController.h rename to libraries/controllers/src/controllers/StandardController.h index fa660e15b8..c393af80f4 100644 --- a/libraries/input-plugins/src/input-plugins/StandardController.h +++ b/libraries/controllers/src/controllers/StandardController.h @@ -38,9 +38,9 @@ public: StandardController() : InputDevice("Standard") {} ~StandardController(); - UserInputMapper::Input makeInput(Controllers::StandardButtonChannel button); - UserInputMapper::Input makeInput(Controllers::StandardAxisChannel axis); - UserInputMapper::Input makeInput(Controllers::StandardPoseChannel pose); + UserInputMapper::Input makeInput(controller::StandardButtonChannel button); + UserInputMapper::Input makeInput(controller::StandardAxisChannel axis); + UserInputMapper::Input makeInput(controller::StandardPoseChannel pose); private: }; diff --git a/libraries/input-plugins/src/input-plugins/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h similarity index 75% rename from libraries/input-plugins/src/input-plugins/StandardControls.h rename to libraries/controllers/src/controllers/StandardControls.h index 9b79bbdae1..0990e34224 100644 --- a/libraries/input-plugins/src/input-plugins/StandardControls.h +++ b/libraries/controllers/src/controllers/StandardControls.h @@ -7,7 +7,7 @@ // #pragma once -namespace Controllers { +namespace controller { // Needs to match order and values of SDL_GameControllerButton enum StandardButtonChannel { @@ -30,7 +30,8 @@ namespace Controllers { DU, DD, DL, - DR + DR, + NUM_STANDARD_BUTTONS }; // Needs to match order and values of SDL_GameControllerAxis @@ -43,13 +44,21 @@ namespace Controllers { RY, // Triggers LT, - RT + RT, + NUM_STANDARD_AXES }; // No correlation to SDL enum StandardPoseChannel { - LeftPose = 0, - RightPose + LEFT = 0, + RIGHT, + HEAD, + NUM_STANDARD_POSES }; + enum StandardCounts { + TRIGGERS = 2, + ANALOG_STICKS = 2, + POSES = 2, // FIXME 3? if we want to expose the head? + }; } diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp similarity index 89% rename from libraries/input-plugins/src/input-plugins/UserInputMapper.cpp rename to libraries/controllers/src/controllers/UserInputMapper.cpp index 0f797e9ad0..b62e2e0e8f 100755 --- a/libraries/input-plugins/src/input-plugins/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -12,9 +12,7 @@ #include "UserInputMapper.h" #include "StandardController.h" -#include -Q_DECLARE_LOGGING_CATEGORY(userInputMapper) -Q_LOGGING_CATEGORY(userInputMapper, "hifi.userInputMapper") +#include "Logging.h" const UserInputMapper::Input UserInputMapper::Input::INVALID_INPUT = UserInputMapper::Input(UINT16_MAX); const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice(); @@ -36,7 +34,7 @@ UserInputMapper::~UserInputMapper() { bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){ proxy->_name += " (" + QString::number(deviceID) + ")"; _registeredDevices[deviceID] = proxy; - qCDebug(userInputMapper) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID; + qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID; return true; } @@ -115,7 +113,7 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName } } - qCDebug(userInputMapper) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">"; + qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">"; } else if (deviceName == "Actions") { deviceID = Input::ACTIONS_DEVICE; @@ -127,13 +125,13 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName actionNum++; } - qCDebug(userInputMapper) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions"; + qCDebug(controllers) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions"; } else { - qCDebug(userInputMapper) << "Couldn\'t find InputDevice named <" << deviceName << ">"; + qCDebug(controllers) << "Couldn\'t find InputDevice named <" << deviceName << ">"; } } else { - qCDebug(userInputMapper) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName"; + qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName"; } return Input(); @@ -364,12 +362,12 @@ void UserInputMapper::assignDefaulActionScales() { _actionStates[SHIFT] = 1.0f; // on _actionStates[ACTION1] = 1.0f; // default _actionStates[ACTION2] = 1.0f; // default - _actionStates[TranslateX] = 1.0f; // default - _actionStates[TranslateY] = 1.0f; // default - _actionStates[TranslateZ] = 1.0f; // default - _actionStates[Roll] = 1.0f; // default - _actionStates[Pitch] = 1.0f; // default - _actionStates[Yaw] = 1.0f; // default + _actionStates[TRANSLATE_X] = 1.0f; // default + _actionStates[TRANSLATE_Y] = 1.0f; // default + _actionStates[TRANSLATE_Z] = 1.0f; // default + _actionStates[ROLL] = 1.0f; // default + _actionStates[PITCH] = 1.0f; // default + _actionStates[YAW] = 1.0f; // default } // This is only necessary as long as the actions are hardcoded @@ -396,12 +394,12 @@ void UserInputMapper::createActionNames() { _actionNames[ACTION2] = "ACTION2"; _actionNames[CONTEXT_MENU] = "CONTEXT_MENU"; _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE"; - _actionNames[TranslateX] = "TranslateX"; - _actionNames[TranslateY] = "TranslateY"; - _actionNames[TranslateZ] = "TranslateZ"; - _actionNames[Roll] = "Roll"; - _actionNames[Pitch] = "Pitch"; - _actionNames[Yaw] = "Yaw"; + _actionNames[TRANSLATE_X] = "TranslateX"; + _actionNames[TRANSLATE_Y] = "TranslateY"; + _actionNames[TRANSLATE_Z] = "TranslateZ"; + _actionNames[ROLL] = "Roll"; + _actionNames[PITCH] = "Pitch"; + _actionNames[YAW] = "Yaw"; } void UserInputMapper::registerStandardDevice() { @@ -423,4 +421,4 @@ float UserInputMapper::DeviceProxy::getValue(const Input& input, int timestamp) default: return 0.0f; } -} +} \ No newline at end of file diff --git a/libraries/input-plugins/src/input-plugins/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h old mode 100755 new mode 100644 similarity index 96% rename from libraries/input-plugins/src/input-plugins/UserInputMapper.h rename to libraries/controllers/src/controllers/UserInputMapper.h index fae77cca92..b6063787b1 --- a/libraries/input-plugins/src/input-plugins/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -152,44 +152,52 @@ public: // Actions are the output channels of the Mapper, that's what the InputChannel map to // For now the Actions are hardcoded, this is bad, but we will fix that in the near future enum Action { - LONGITUDINAL_BACKWARD = 0, - LONGITUDINAL_FORWARD, + TRANSLATE_X = 0, + TRANSLATE_Y, + TRANSLATE_Z, + ROTATE_X, PITCH = ROTATE_X, + ROTATE_Y, YAW = ROTATE_Y, + ROTATE_Z, ROLL = ROTATE_Z, - LATERAL_LEFT, - LATERAL_RIGHT, + TRANSLATE_CAMERA_Z, - VERTICAL_DOWN, - VERTICAL_UP, - - YAW_LEFT, - YAW_RIGHT, - - PITCH_DOWN, - PITCH_UP, - - BOOM_IN, - BOOM_OUT, - LEFT_HAND, RIGHT_HAND, LEFT_HAND_CLICK, RIGHT_HAND_CLICK, - SHIFT, - ACTION1, ACTION2, CONTEXT_MENU, TOGGLE_MUTE, - TranslateX, - TranslateY, - TranslateZ, - Roll, - Pitch, - Yaw, + SHIFT, + + // Biseced aliases for TRANSLATE_Z + LONGITUDINAL_BACKWARD, + LONGITUDINAL_FORWARD, + + // Biseced aliases for TRANSLATE_X + LATERAL_LEFT, + LATERAL_RIGHT, + + // Biseced aliases for TRANSLATE_Y + VERTICAL_DOWN, + VERTICAL_UP, + + // Biseced aliases for ROTATE_Y + YAW_LEFT, + YAW_RIGHT, + + // Biseced aliases for ROTATE_X + PITCH_DOWN, + PITCH_UP, + + // Biseced aliases for TRANSLATE_CAMERA_Z + BOOM_IN, + BOOM_OUT, NUM_ACTIONS, }; diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp index a191e19be2..b347d8b7c6 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp @@ -15,7 +15,7 @@ #include #include "RouteBuilderProxy.h" -#include "../NewControllerScriptingInterface.h" +#include "../ScriptingInterface.h" #include "../Logging.h" using namespace controller; diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h index c71cc83569..9531d8bbea 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h @@ -21,12 +21,14 @@ class QJsonValue; namespace controller { -class NewControllerScriptingInterface; +class ScriptingInterface; +// TODO migrate functionality to a MappingBuilder class and make the proxy defer to that +// (for easier use in both C++ and JS) class MappingBuilderProxy : public QObject { Q_OBJECT public: - MappingBuilderProxy(NewControllerScriptingInterface& parent, Mapping::Pointer mapping) + MappingBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping) : _parent(parent), _mapping(mapping) { } Q_INVOKABLE QObject* from(const QJSValue& source); @@ -48,7 +50,7 @@ protected: QObject* from(const Endpoint::Pointer& source); friend class RouteBuilderProxy; - NewControllerScriptingInterface& _parent; + ScriptingInterface& _parent; Mapping::Pointer _mapping; diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp index 38efcfdb00..aeef081b5f 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp @@ -15,7 +15,7 @@ #include #include "MappingBuilderProxy.h" -#include "../NewControllerScriptingInterface.h" +#include "../ScriptingInterface.h" #include "../Logging.h" namespace controller { diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h index 573e841e85..6fd5f1467a 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -20,12 +20,14 @@ class QJsonValue; namespace controller { -class NewControllerScriptingInterface; +class ScriptingInterface; +// TODO migrate functionality to a RouteBuilder class and make the proxy defer to that +// (for easier use in both C++ and JS) class RouteBuilderProxy : public QObject { Q_OBJECT public: - RouteBuilderProxy(NewControllerScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route) + RouteBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route) : _parent(parent), _mapping(mapping), _route(route) { } Q_INVOKABLE void to(const QJSValue& destination); @@ -52,7 +54,7 @@ class RouteBuilderProxy : public QObject { Mapping::Pointer _mapping; Route::Pointer _route; - NewControllerScriptingInterface& _parent; + ScriptingInterface& _parent; }; } diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index bb90c04c95..4f2a525f07 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME entities-renderer) AUTOSCRIBE_SHADER_LIB(gpu model render render-utils) setup_hifi_library(Widgets Network Script) -link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils) +link_hifi_libraries(shared gpu procedural model model-networking script-engine controllers render render-utils) target_bullet() diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt index 094a697012..4c33b2517a 100644 --- a/libraries/input-plugins/CMakeLists.txt +++ b/libraries/input-plugins/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME input-plugins) setup_hifi_library() -link_hifi_libraries(shared plugins gpu render-utils) +link_hifi_libraries(shared plugins controllers) GroupSources("src/input-plugins") diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp index 2b16d905f5..227bd12e1b 100644 --- a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp +++ b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp @@ -23,7 +23,7 @@ InputPluginList getInputPlugins() { new KeyboardMouseDevice(), new SDL2Manager(), new SixenseManager(), - //new ViveControllerManager(), + new ViveControllerManager(), nullptr }; diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp index 5c6f43c604..e7a0124deb 100644 --- a/libraries/input-plugins/src/input-plugins/Joystick.cpp +++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp @@ -1,167 +1,164 @@ -// -// Joystick.cpp -// input-plugins/src/input-plugins -// -// Created by Stephen Birarda on 2014-09-23. -// Copyright 2014 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 "Joystick.h" - -#include "StandardControls.h" - -const float CONTROLLER_THRESHOLD = 0.3f; - -#ifdef HAVE_SDL2 -const float MAX_AXIS = 32768.0f; - -Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) : - InputDevice(name), - _sdlGameController(sdlGameController), - _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)), - _instanceId(instanceId) -{ - -} - -#endif - -Joystick::~Joystick() { - closeJoystick(); -} - -void Joystick::closeJoystick() { -#ifdef HAVE_SDL2 - SDL_GameControllerClose(_sdlGameController); -#endif -} - -void Joystick::update(float deltaTime, bool jointsCaptured) { - for (auto axisState : _axisStateMap) { - if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) { - _axisStateMap[axisState.first] = 0.0f; - } - } -} - -void Joystick::focusOutEvent() { - _axisStateMap.clear(); - _buttonPressedMap.clear(); -}; - -#ifdef HAVE_SDL2 - -void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) { - SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis; - _axisStateMap[makeInput((Controllers::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS; -} - -void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) { - auto input = makeInput((Controllers::StandardButtonChannel)event.button); - bool newValue = event.state == SDL_PRESSED; - if (newValue) { - _buttonPressedMap.insert(input.getChannel()); - } else { - _buttonPressedMap.erase(input.getChannel()); - } -} - -#endif - - -void Joystick::registerToUserInputMapper(UserInputMapper& mapper) { - // Grab the current free device ID - _deviceID = mapper.getFreeDeviceID(); - - auto proxy = std::make_shared(_name); - proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; - proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); }; - proxy->getAvailabeInputs = [this] () -> QVector { - QVector availableInputs; - // Buttons - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "A")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "B")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "X")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Y")); - - // DPad - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "DU")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "DD")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "DL")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "DR")); - - // Bumpers - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "LB")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "RB")); - - // Stick press - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "LS")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "RS")); - - // Center buttons - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::START), "Start")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Back")); - - // Analog sticks - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LY), "LY")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LX), "LX")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RY), "RY")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RX), "RX")); - - // Triggers - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "LT")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "RT")); - - // Aliases, PlayStation style names - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LB), "L1")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RB), "R1")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LT), "L2")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RT), "R2")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::LS), "L3")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::RS), "R3")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::BACK), "Select")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::A), "Cross")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::B), "Circle")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::X), "Square")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::Y), "Triangle")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DU), "Up")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DD), "Down")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DL), "Left")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Controllers::DR), "Right")); - - return availableInputs; - }; - proxy->resetDeviceBindings = [this, &mapper] () -> bool { - mapper.removeAllInputChannelsForDevice(_deviceID); - this->assignDefaultInputMapping(mapper); - return true; - }; - mapper.registerDevice(_deviceID, proxy); -} - -void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) { -#ifdef HAVE_SDL2 - const float JOYSTICK_MOVE_SPEED = 1.0f; - const float DPAD_MOVE_SPEED = 0.5f; - const float JOYSTICK_YAW_SPEED = 0.5f; - const float JOYSTICK_PITCH_SPEED = 0.25f; - const float BOOM_SPEED = 0.1f; - -#endif -} - -UserInputMapper::Input Joystick::makeInput(Controllers::StandardButtonChannel button) { - return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); -} - -UserInputMapper::Input Joystick::makeInput(Controllers::StandardAxisChannel axis) { - return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); -} - +// +// Joystick.cpp +// input-plugins/src/input-plugins +// +// Created by Stephen Birarda on 2014-09-23. +// Copyright 2014 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 "Joystick.h" + +#include +#include + +const float CONTROLLER_THRESHOLD = 0.3f; + +#ifdef HAVE_SDL2 +const float MAX_AXIS = 32768.0f; + +Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) : + InputDevice(name), + _sdlGameController(sdlGameController), + _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)), + _instanceId(instanceId) +{ + +} + +#endif + +Joystick::~Joystick() { + closeJoystick(); +} + +void Joystick::closeJoystick() { +#ifdef HAVE_SDL2 + SDL_GameControllerClose(_sdlGameController); +#endif +} + +void Joystick::update(float deltaTime, bool jointsCaptured) { + for (auto axisState : _axisStateMap) { + if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) { + _axisStateMap[axisState.first] = 0.0f; + } + } +} + +void Joystick::focusOutEvent() { + _axisStateMap.clear(); + _buttonPressedMap.clear(); +}; + +#ifdef HAVE_SDL2 + +void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) { + SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis; + _axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS; +} + +void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) { + auto input = makeInput((controller::StandardButtonChannel)event.button); + bool newValue = event.state == SDL_PRESSED; + if (newValue) { + _buttonPressedMap.insert(input.getChannel()); + } else { + _buttonPressedMap.erase(input.getChannel()); + } +} + +#endif + + +void Joystick::registerToUserInputMapper(UserInputMapper& mapper) { + // Grab the current free device ID + _deviceID = mapper.getFreeDeviceID(); + + auto proxy = std::make_shared(_name); + proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; + proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); }; + proxy->getAvailabeInputs = [this] () -> QVector { + QVector availableInputs; + // Buttons + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y")); + + // DPad + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR")); + + // Bumpers + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB")); + + // Stick press + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS")); + + // Center buttons + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back")); + + // Analog sticks + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX")); + + // Triggers + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT")); + + // Aliases, PlayStation style names + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right")); + + return availableInputs; + }; + proxy->resetDeviceBindings = [this, &mapper] () -> bool { + mapper.removeAllInputChannelsForDevice(_deviceID); + this->assignDefaultInputMapping(mapper); + return true; + }; + mapper.registerDevice(_deviceID, proxy); +} + +void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) { +#ifdef HAVE_SDL2 + const float JOYSTICK_MOVE_SPEED = 1.0f; + const float DPAD_MOVE_SPEED = 0.5f; + const float JOYSTICK_YAW_SPEED = 0.5f; + const float JOYSTICK_PITCH_SPEED = 0.25f; + const float BOOM_SPEED = 0.1f; + +#endif +} + +UserInputMapper::Input Joystick::makeInput(controller::StandardButtonChannel button) { + return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); +} + +UserInputMapper::Input Joystick::makeInput(controller::StandardAxisChannel axis) { + return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); +} + diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h index 70949a8b83..c6537acafe 100644 --- a/libraries/input-plugins/src/input-plugins/Joystick.h +++ b/libraries/input-plugins/src/input-plugins/Joystick.h @@ -1,73 +1,73 @@ -// -// Joystick.h -// input-plugins/src/input-plugins -// -// Created by Stephen Birarda on 2014-09-23. -// Copyright 2014 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_Joystick_h -#define hifi_Joystick_h - -#include -#include - -#ifdef HAVE_SDL2 -#include -#undef main -#endif - -#include "InputDevice.h" -#include "StandardControls.h" - -class Joystick : public QObject, public InputDevice { - Q_OBJECT - Q_PROPERTY(QString name READ getName) - -#ifdef HAVE_SDL2 - Q_PROPERTY(int instanceId READ getInstanceId) -#endif - -public: - - const QString& getName() const { return _name; } - - // Device functions - virtual void registerToUserInputMapper(UserInputMapper& mapper) override; - virtual void assignDefaultInputMapping(UserInputMapper& mapper) override; - virtual void update(float deltaTime, bool jointsCaptured) override; - virtual void focusOutEvent() override; - - Joystick() : InputDevice("Joystick") {} - ~Joystick(); - - UserInputMapper::Input makeInput(Controllers::StandardButtonChannel button); - UserInputMapper::Input makeInput(Controllers::StandardAxisChannel axis); - -#ifdef HAVE_SDL2 - Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController); -#endif - - void closeJoystick(); - -#ifdef HAVE_SDL2 - void handleAxisEvent(const SDL_ControllerAxisEvent& event); - void handleButtonEvent(const SDL_ControllerButtonEvent& event); -#endif - -#ifdef HAVE_SDL2 - int getInstanceId() const { return _instanceId; } -#endif - -private: -#ifdef HAVE_SDL2 - SDL_GameController* _sdlGameController; - SDL_Joystick* _sdlJoystick; - SDL_JoystickID _instanceId; -#endif -}; - -#endif // hifi_Joystick_h +// +// Joystick.h +// input-plugins/src/input-plugins +// +// Created by Stephen Birarda on 2014-09-23. +// Copyright 2014 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_Joystick_h +#define hifi_Joystick_h + +#include +#include + +#ifdef HAVE_SDL2 +#include +#undef main +#endif + +#include +#include + +class Joystick : public QObject, public InputDevice { + Q_OBJECT + Q_PROPERTY(QString name READ getName) + +#ifdef HAVE_SDL2 + Q_PROPERTY(int instanceId READ getInstanceId) +#endif + +public: + + const QString& getName() const { return _name; } + + // Device functions + virtual void registerToUserInputMapper(UserInputMapper& mapper) override; + virtual void assignDefaultInputMapping(UserInputMapper& mapper) override; + virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void focusOutEvent() override; + + Joystick() : InputDevice("Joystick") {} + ~Joystick(); + + UserInputMapper::Input makeInput(controller::StandardButtonChannel button); + UserInputMapper::Input makeInput(controller::StandardAxisChannel axis); + +#ifdef HAVE_SDL2 + Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController); +#endif + + void closeJoystick(); + +#ifdef HAVE_SDL2 + void handleAxisEvent(const SDL_ControllerAxisEvent& event); + void handleButtonEvent(const SDL_ControllerButtonEvent& event); +#endif + +#ifdef HAVE_SDL2 + int getInstanceId() const { return _instanceId; } +#endif + +private: +#ifdef HAVE_SDL2 + SDL_GameController* _sdlGameController; + SDL_Joystick* _sdlJoystick; + SDL_JoystickID _instanceId; +#endif +}; + +#endif // hifi_Joystick_h diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h index e8a6131387..3c935cab26 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h @@ -16,7 +16,7 @@ #include -#include "InputDevice.h" +#include #include "InputPlugin.h" class QTouchEvent; diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.h b/libraries/input-plugins/src/input-plugins/SDL2Manager.h index 23e3ee059f..fec6972591 100644 --- a/libraries/input-plugins/src/input-plugins/SDL2Manager.h +++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.h @@ -16,9 +16,9 @@ #include #endif -#include "InputPlugin.h" -#include "UserInputMapper.h" +#include +#include "InputPlugin.h" #include "Joystick.h" class SDL2Manager : public InputPlugin { diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h index 9fa7f84a86..53ee7f3c29 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.h +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h @@ -24,8 +24,9 @@ #endif +#include + #include "InputPlugin.h" -#include "InputDevice.h" class QLibrary; diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index 5cae8daaf4..bcc27d07ae 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -19,7 +19,7 @@ #include #include -#include "InputDevice.h" +#include #include "InputPlugin.h" #include #include diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index ecbe80cddb..eba9e45e5c 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -24,7 +24,7 @@ void AssetResourceRequest::doSend() { // Make request to atp auto assetClient = DependencyManager::get(); auto parts = _url.path().split(".", QString::SkipEmptyParts); - auto hash = parts[0]; + auto hash = parts.length() > 0 ? parts[0] : ""; auto extension = parts.length() > 1 ? parts[1] : ""; if (hash.length() != SHA256_HASH_HEX_LENGTH) { diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index cfe0afd220..5e3d135034 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME script-engine) setup_hifi_library(Gui Network Script WebSockets Widgets) -link_hifi_libraries(shared networking octree gpu procedural model model-networking fbx entities animation audio physics) +link_hifi_libraries(shared networking octree gpu procedural model model-networking fbx entities controllers animation audio physics) diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h deleted file mode 100644 index d6a6b51b62..0000000000 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ /dev/null @@ -1,125 +0,0 @@ -// -// AbstractControllerScriptingInterface.h -// libraries/script-engine/src -// -// Created by Brad Hefta-Gaub on 12/17/13. -// Copyright 2013 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_AbstractControllerScriptingInterface_h -#define hifi_AbstractControllerScriptingInterface_h - -#include - -#include -#include - -#include "HFActionEvent.h" -#include "KeyEvent.h" -#include "MouseEvent.h" -#include "SpatialEvent.h" -#include "TouchEvent.h" -#include "WheelEvent.h" - -class ScriptEngine; - -class AbstractInputController : public QObject { - Q_OBJECT - -public: - typedef unsigned int Key; - - virtual void update() = 0; - - virtual Key getKey() const = 0; - -public slots: - - virtual bool isActive() const = 0; - virtual glm::vec3 getAbsTranslation() const = 0; - virtual glm::quat getAbsRotation() const = 0; - virtual glm::vec3 getLocTranslation() const = 0; - virtual glm::quat getLocRotation() const = 0; - -signals: - void spatialEvent(const SpatialEvent& event); - -}; - -/// handles scripting of input controller commands from JS -class AbstractControllerScriptingInterface : public QObject { - Q_OBJECT - -public slots: - virtual void registerControllerTypes(ScriptEngine* engine) = 0; - - virtual bool isPrimaryButtonPressed() const = 0; - virtual glm::vec2 getPrimaryJoystickPosition() const = 0; - - virtual int getNumberOfButtons() const = 0; - virtual bool isButtonPressed(int buttonIndex) const = 0; - - virtual int getNumberOfTriggers() const = 0; - virtual float getTriggerValue(int triggerIndex) const = 0; - - virtual int getNumberOfJoysticks() const = 0; - virtual glm::vec2 getJoystickPosition(int joystickIndex) const = 0; - - virtual int getNumberOfSpatialControls() const = 0; - virtual glm::vec3 getSpatialControlPosition(int controlIndex) const = 0; - virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const = 0; - virtual glm::vec3 getSpatialControlNormal(int controlIndex) const = 0; - virtual glm::quat getSpatialControlRawRotation(int controlIndex) const = 0; - - virtual void captureKeyEvents(const KeyEvent& event) = 0; - virtual void releaseKeyEvents(const KeyEvent& event) = 0; - - virtual void captureMouseEvents() = 0; - virtual void releaseMouseEvents() = 0; - - virtual void captureTouchEvents() = 0; - virtual void releaseTouchEvents() = 0; - - virtual void captureWheelEvents() = 0; - virtual void releaseWheelEvents() = 0; - - virtual void captureActionEvents() = 0; - virtual void releaseActionEvents() = 0; - - virtual void captureJoystick(int joystickIndex) = 0; - virtual void releaseJoystick(int joystickIndex) = 0; - - virtual glm::vec2 getViewportDimensions() const = 0; - - - virtual AbstractInputController* createInputController( const QString& category, const QString& tracker ) = 0; - -signals: - void keyPressEvent(const KeyEvent& event); - void keyReleaseEvent(const KeyEvent& event); - - void actionStartEvent(const HFActionEvent& event); - void actionEndEvent(const HFActionEvent& event); - - void backStartEvent(); - void backEndEvent(); - - void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0); - void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0); - void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0); - void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0); - - void touchBeginEvent(const TouchEvent& event); - void touchEndEvent(const TouchEvent& event); - void touchUpdateEvent(const TouchEvent& event); - - void wheelEvent(const WheelEvent& event); - - void actionEvent(int action, float state); - -}; - -#endif // hifi_AbstractControllerScriptingInterface_h diff --git a/libraries/script-engine/src/AbstractScriptingServicesInterface.h b/libraries/script-engine/src/AbstractScriptingServicesInterface.h index 9d24531b60..565a415f63 100644 --- a/libraries/script-engine/src/AbstractScriptingServicesInterface.h +++ b/libraries/script-engine/src/AbstractScriptingServicesInterface.h @@ -12,7 +12,10 @@ #ifndef hifi_AbstractScriptingServicesInterface_h #define hifi_AbstractScriptingServicesInterface_h -class AbstractControllerScriptingInterface; +namespace controller { + class ScriptingInterface; +} + class Transform; class ScriptEngine; class QThread; @@ -22,7 +25,7 @@ class AbstractScriptingServicesInterface { public: /// Returns the controller interface for the application - virtual AbstractControllerScriptingInterface* getControllerScriptingInterface() = 0; + virtual controller::ScriptingInterface* getControllerScriptingInterface() = 0; /// Registers application specific services with a script engine. virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) = 0; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 76590f266b..494f038a61 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -76,16 +76,16 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) { out = qobject_cast(object.toQObject()); } -QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) { +QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) { return engine->newQObject(in); } -void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputController* &out) { - out = qobject_cast(object.toQObject()); +void inputControllerFromScriptValue(const QScriptValue &object, controller::InputController* &out) { + out = qobject_cast(object.toQObject()); } ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, - AbstractControllerScriptingInterface* controllerScriptingInterface, bool wantSignals) : + controller::ScriptingInterface* controllerScriptingInterface, bool wantSignals) : _scriptContents(scriptContents), _isFinished(false), @@ -93,7 +93,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _isInitialized(false), _timerFunctionMap(), _wantSignals(wantSignals), - _controllerScriptingInterface(controllerScriptingInterface), + _controllerScriptingInterface(controllerScriptingInterface), _fileNameString(fileNameString), _quatLibrary(), _vec3Library(), diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 1d3986143a..642159339e 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -26,8 +26,10 @@ #include #include #include +#include -#include "AbstractControllerScriptingInterface.h" + +#include "MouseEvent.h" #include "ArrayBufferClass.h" #include "AudioScriptingInterface.h" #include "Quat.h" @@ -53,7 +55,7 @@ class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScr public: ScriptEngine(const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString(""), - AbstractControllerScriptingInterface* controllerScriptingInterface = NULL, + controller::ScriptingInterface* controllerScriptingInterface = nullptr, bool wantSignals = true); ~ScriptEngine(); @@ -182,7 +184,7 @@ private: QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); - AbstractControllerScriptingInterface* _controllerScriptingInterface; + controller::ScriptingInterface* _controllerScriptingInterface; QString _fileNameString; Quat _quatLibrary; Vec3 _vec3Library; diff --git a/tests/controllers/qml/content.qml b/tests/controllers/qml/content.qml index 41d623a389..5f9bbd455e 100644 --- a/tests/controllers/qml/content.qml +++ b/tests/controllers/qml/content.qml @@ -8,17 +8,17 @@ import "./controls" Column { id: root - property var actions: NewControllers.Actions - property var standard: NewControllers.Standard + property var actions: Controllers.Actions + property var standard: Controllers.Standard property var testMapping: null property var xbox: null Component.onCompleted: { var patt = /^X360Controller/; - for (var prop in NewControllers.Hardware) { + for (var prop in Controllers.Hardware) { if(patt.test(prop)) { - root.xbox = NewControllers.Hardware[prop] + root.xbox = Controllers.Hardware[prop] break } } @@ -29,7 +29,7 @@ Column { Timer { interval: 50; running: true; repeat: true onTriggered: { - NewControllers.update(); + Controllers.update(); } } @@ -38,7 +38,7 @@ Column { Button { text: "Default Mapping" onClicked: { - var mapping = NewControllers.newMapping("Default"); + var mapping = Controllers.newMapping("Default"); mapping.from(xbox.A).to(standard.A); mapping.from(xbox.B).to(standard.B); mapping.from(xbox.X).to(standard.X); @@ -59,7 +59,7 @@ Column { mapping.from(xbox.RX).to(standard.RX); mapping.from(xbox.LT).to(standard.LT); mapping.from(xbox.RT).to(standard.RT); - NewControllers.enableMapping("Default"); + Controllers.enableMapping("Default"); enabled = false; text = "Built" } @@ -68,16 +68,35 @@ Column { Button { text: "Build Mapping" onClicked: { - var mapping = NewControllers.newMapping(); + var mapping = Controllers.newMapping(); // Inverting a value mapping.from(xbox.RY).invert().to(standard.RY); // Assigning a value from a function mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX); // Constrainting a value to -1, 0, or 1, with a deadzone mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY); - mapping.join(standard.LB, standard.RB).pulse(0.5).to(actions.Yaw); + // change join to makeAxis + mapping.join(standard.LB, standard.RB).to(actions.Yaw); mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT); mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT); + + // mapping.modifier(keyboard.Ctrl).scale(2.0) + +// mapping.from(keyboard.A).to(actions.TranslateLeft) +// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft) +// mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft) + +// // First loopbacks +// // Then non-loopbacks by constraint level (number of inputs) +// mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX) + +// mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft) + + +// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft) + + +// mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward) testMapping = mapping; enabled = false text = "Built" @@ -105,7 +124,7 @@ Column { Row { spacing: 8 ScrollingGraph { - controlId: NewControllers.Actions.Yaw + controlId: Controllers.Actions.Yaw label: "Yaw" min: -3.0 max: 3.0 @@ -113,7 +132,7 @@ Column { } ScrollingGraph { - controlId: NewControllers.Actions.YAW_LEFT + controlId: Controllers.Actions.YAW_LEFT label: "Yaw Left" min: -3.0 max: 3.0 @@ -121,7 +140,7 @@ Column { } ScrollingGraph { - controlId: NewControllers.Actions.YAW_RIGHT + controlId: Controllers.Actions.YAW_RIGHT label: "Yaw Right" min: -3.0 max: 3.0 diff --git a/tests/controllers/qml/controls/AnalogButton.qml b/tests/controllers/qml/controls/AnalogButton.qml index 26f91458ac..141c131063 100644 --- a/tests/controllers/qml/controls/AnalogButton.qml +++ b/tests/controllers/qml/controls/AnalogButton.qml @@ -13,7 +13,7 @@ Item { property color color: 'black' function update() { - value = NewControllers.getValue(controlId); + value = Controllers.getValue(controlId); canvas.requestPaint(); } diff --git a/tests/controllers/qml/controls/AnalogStick.qml b/tests/controllers/qml/controls/AnalogStick.qml index 8860aea49c..5d011411c9 100644 --- a/tests/controllers/qml/controls/AnalogStick.qml +++ b/tests/controllers/qml/controls/AnalogStick.qml @@ -15,8 +15,8 @@ Item { function update() { value = Qt.vector2d( - NewControllers.getValue(controlIds[0]), - NewControllers.getValue(controlIds[1]) + Controllers.getValue(controlIds[0]), + Controllers.getValue(controlIds[1]) ); canvas.requestPaint(); } diff --git a/tests/controllers/qml/controls/ScrollingGraph.qml b/tests/controllers/qml/controls/ScrollingGraph.qml index 69f919aaf1..471d142d27 100644 --- a/tests/controllers/qml/controls/ScrollingGraph.qml +++ b/tests/controllers/qml/controls/ScrollingGraph.qml @@ -22,7 +22,7 @@ Item { property string label: "" function update() { - value = NewControllers.getValue(controlId); + value = Controllers.getValue(controlId); canvas.requestPaint(); } diff --git a/tests/controllers/qml/controls/ToggleButton.qml b/tests/controllers/qml/controls/ToggleButton.qml index 9ef54f5971..46a7b4bdfd 100644 --- a/tests/controllers/qml/controls/ToggleButton.qml +++ b/tests/controllers/qml/controls/ToggleButton.qml @@ -15,7 +15,7 @@ Item { Timer { interval: 50; running: true; repeat: true onTriggered: { - root.value = NewControllers.getValue(root.controlId); + root.value = Controllers.getValue(root.controlId); canvas.requestPaint(); } } diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index 9212cbb3e8..e173b7893f 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -38,10 +38,10 @@ #include #include #include -#include +#include #include -#include +#include const QString& getQmlDir() { static QString dir; @@ -79,16 +79,39 @@ public: virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr; } }; +class MyControllerScriptingInterface : public controller::ScriptingInterface { +public: + virtual void registerControllerTypes(QScriptEngine* engine) {}; +}; + + int main(int argc, char** argv) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; for (auto path : qApp->libraryPaths()) { qDebug() << path; } - + for (auto path : qApp->libraryPaths()) { qDebug() << path; } + + QTimer timer; + QObject::connect(&timer, &QTimer::timeout, [] { + static float last = secTimestampNow(); + float now = secTimestampNow(); + float delta = now - last; + last = now; + + foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { + inputPlugin->pluginUpdate(delta, false); + } + + auto userInputMapper = DependencyManager::get(); + userInputMapper->update(delta); + }); + timer.start(50); + { DependencyManager::set(); foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { @@ -100,17 +123,9 @@ int main(int argc, char** argv) { keyboardMouseDevice->registerToUserInputMapper(*userInputMapper); } } - - //new PluginContainerProxy(); auto rootContext = engine.rootContext(); - - auto controllers = new NewControllerScriptingInterface(); - rootContext->setContextProperty("NewControllers", controllers); - QVariantMap map; - map.insert("Hardware", controllers->property("Hardware")); - map.insert("Actions", controllers->property("Actions")); - rootContext->setContextProperty("ControllerIds", map); + rootContext->setContextProperty("Controllers", new MyControllerScriptingInterface()); } engine.load(getQmlDir() + "main.qml"); app.exec(); diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 0a678d668e..13e5f89914 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -319,6 +319,9 @@ userData: JSON.stringify({ resetMe: { resetMe: true + }, + grabbableKey: { + invertSolidWhileHeld: true } }) }); @@ -378,7 +381,8 @@ var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target.fbx'; var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target_collision_hull.obj'; - var RESET_DISTANCE = 1; + var MINIMUM_MOVE_LENGTH = 0.05; + var RESET_DISTANCE = 0.5; var TARGET_USER_DATA_KEY = 'hifi-ping_pong_target'; var NUMBER_OF_TARGETS = 6; var TARGETS_PER_ROW = 3; @@ -392,7 +396,6 @@ var VERTICAL_SPACING = TARGET_DIMENSIONS.y + 0.5; var HORIZONTAL_SPACING = TARGET_DIMENSIONS.z + 0.5; - var startPosition = { x: 548.68, y: 497.30, @@ -413,6 +416,9 @@ userData: JSON.stringify({ resetMe: { resetMe: true + }, + grabbableKey: { + grabbable: false } }) }); @@ -421,6 +427,8 @@ var originalPositions = []; + var lastPositions = []; + function addTargets() { var i; var row = -1; @@ -437,6 +445,7 @@ position.y = startPosition.y - (row * VERTICAL_SPACING); originalPositions.push(position); + lastPositions.push(position); var targetProperties = { name: 'Target', @@ -452,6 +461,9 @@ userData: JSON.stringify({ resetMe: { resetMe: true + }, + grabbableKey: { + grabbable: false } }) }; @@ -468,7 +480,11 @@ var distance = Vec3.subtract(originalPosition, currentPosition); var length = Vec3.length(distance); - if (length > RESET_DISTANCE) { + var moving = Vec3.length(Vec3.subtract(currentPosition, lastPositions[index])); + + lastPositions[index] = currentPosition; + + if (length > RESET_DISTANCE && moving < MINIMUM_MOVE_LENGTH) { Entities.deleteEntity(target); @@ -486,11 +502,14 @@ userData: JSON.stringify({ resetMe: { resetMe: true + }, + grabbableKey: { + grabbable: false } }) }; - var target = Entities.addEntity(targetProperties); - targets[index] = target; + + targets[index] = Entities.addEntity(targetProperties); } }); @@ -548,6 +567,9 @@ userData: JSON.stringify({ resetMe: { resetMe: true + }, + grabbableKey: { + grabbable: false } }) }); @@ -583,7 +605,11 @@ userData: JSON.stringify({ resetMe: { resetMe: true + }, + grabbableKey: { + invertSolidWhileHeld: true } + }) }); @@ -851,6 +877,9 @@ userData: JSON.stringify({ resetMe: { resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true } }) }; @@ -940,6 +969,9 @@ userData: JSON.stringify({ resetMe: { resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true } }) }); @@ -1014,6 +1046,9 @@ userData: JSON.stringify({ resetMe: { resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true } }) }); @@ -1053,6 +1088,9 @@ userData: JSON.stringify({ resetMe: { resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true } }) }); @@ -1090,6 +1128,9 @@ userData: JSON.stringify({ resetMe: { resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true } }) }); @@ -1126,6 +1167,9 @@ userData: JSON.stringify({ resetMe: { resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true } }) }); diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index d9199a124d..f855caa9a1 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -26,463 +26,481 @@ var targetsScriptURL = Script.resolvePath('../examples/toys/ping_pong_gun/wallTa MasterReset = function() { - var resetKey = "resetMe"; - var GRABBABLE_DATA_KEY = "grabbableKey"; + var resetKey = "resetMe"; + var GRABBABLE_DATA_KEY = "grabbableKey"; - var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; - var shouldDeleteOnEndScript = false; + var shouldDeleteOnEndScript = false; - //Before creating anything, first search a radius and delete all the things that should be deleted - deleteAllToys(); - createAllToys(); + //Before creating anything, first search a radius and delete all the things that should be deleted + deleteAllToys(); + createAllToys(); - function createAllToys() { - createBlocks({ - x: 548.3, - y: 495.55, - z: 504.4 - }); - - createBasketBall({ - x: 547.73, - y: 495.5, - z: 505.47 - }); - - createDoll({ - x: 546.67, - y: 495.41, - z: 505.09 - }); - - createWand({ - x: 546.71, - y: 495.55, - z: 506.15 - }); - - createDice(); - - createFlashlight({ - x: 545.72, - y: 495.41, - z: 505.78 - }); - - - - createCombinedArmChair({ - x: 549.29, - y: 494.9, - z: 508.22 - }); - - createPottedPlant({ - x: 554.26, - y: 495.2, - z: 504.53 - }); - - createPingPongBallGun(); - - createBasketballHoop(); - createBasketballRack(); - - createGates(); - - createFire(); - // Handles toggling of all sconce lights - createLights(); - - - - createCat({ - x: 551.09, - y: 494.98, - z: 503.49 - }); - - - createSprayCan({ - x: 549.7, - y: 495.6, - z: 503.91 - }); - - createTargets(); - - } - - function deleteAllToys() { - var entities = Entities.findEntities(MyAvatar.position, 100); - - entities.forEach(function(entity) { - //params: customKey, id, defaultValue - var shouldReset = getEntityCustomData(resetKey, entity, {}).resetMe; - if (shouldReset === true) { - Entities.deleteEntity(entity); - } - }); - } - - function createFire() { - - - var myOrientation = Quat.fromPitchYawRollDegrees(-90, 0, 0.0); - - var animationSettings = JSON.stringify({ - fps: 30, - running: true, - loop: true, - firstFrame: 1, - lastFrame: 10000 - }); - - - var fire = Entities.addEntity({ - type: "ParticleEffect", - name: "fire", - animationSettings: animationSettings, - textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - position: { - x: 551.45, - y: 494.82, - z: 502.05 - }, - emitRate: 100, - colorStart: { - red: 70, - green: 70, - blue: 137 - }, - color: { - red: 200, - green: 99, - blue: 42 - }, - colorFinish: { - red: 255, - green: 99, - blue: 32 - }, - radiusSpread: 0.01, - radiusStart: 0.02, - radiusEnd: 0.001, - particleRadius: 0.05, - radiusFinish: 0.0, - emitOrientation: myOrientation, - emitSpeed: 0.3, - speedSpread: 0.1, - alphaStart: 0.05, - alpha: 0.1, - alphaFinish: 0.05, - emitDimensions: { - x: 1, - y: 1, - z: 0.1 - }, - polarFinish: 0.1, - emitAcceleration: { - x: 0.0, - y: 0.0, - z: 0.0 - }, - accelerationSpread: { - x: 0.1, - y: 0.01, - z: 0.1 - }, - lifespan: 1, - userData: JSON.stringify({ - resetMe: { - resetMe: true - } - }) - }); - } - - function createBasketballRack() { - var NUMBER_OF_BALLS = 4; - var DIAMETER = 0.30; - var RESET_DISTANCE = 1; - var MINIMUM_MOVE_LENGTH = 0.05; - var basketballURL = HIFI_PUBLIC_BUCKET + "models/content/basketball2.fbx"; - var basketballCollisionSoundURL = HIFI_PUBLIC_BUCKET + "sounds/basketball/basketball.wav"; - var rackURL = HIFI_PUBLIC_BUCKET + "models/basketball_hoop/basketball_rack.fbx"; - var rackCollisionHullURL = HIFI_PUBLIC_BUCKET + "models/basketball_hoop/rack_collision_hull.obj"; - - var rackRotation = Quat.fromPitchYawRollDegrees(0, -90, 0); - - var rackStartPosition = { - x: 542.86, - y: 494.84, - z: 475.06 - }; - var rack = Entities.addEntity({ - name: 'Basketball Rack', - type: "Model", - modelURL: rackURL, - position: rackStartPosition, - rotation: rackRotation, - shapeType: 'compound', - gravity: { - x: 0, - y: -9.8, - z: 0 - }, - linearDamping: 1, - dimensions: { - x: 0.4, - y: 1.37, - z: 1.73 - }, - collisionsWillMove: true, - ignoreForCollisions: false, - compoundShapeURL: rackCollisionHullURL, - userData: JSON.stringify({ - resetMe: { - resetMe: true - }, - grabbableKey: { - grabbable: false - } - - }) - }); - - var collidingBalls = []; - var originalBallPositions = []; - - function createCollidingBalls() { - var position = rackStartPosition; - - var i; - for (i = 0; i < NUMBER_OF_BALLS; i++) { - var ballPosition = { - x: position.x, - y: position.y + DIAMETER * 2, - z: position.z + (DIAMETER) - (DIAMETER * i) - }; - - var collidingBall = Entities.addEntity({ - type: "Model", - name: 'Colliding Basketball', - shapeType: 'Sphere', - position: { - x: position.x + (DIAMETER * 2) - (DIAMETER * i), - y: position.y + DIAMETER * 2, - z: position.z - }, - dimensions: { - x: DIAMETER, - y: DIAMETER, - z: DIAMETER - }, - restitution: 1.0, - linearDamping: 0.00001, - gravity: { - x: 0, - y: -9.8, - z: 0 - }, - collisionsWillMove: true, - ignoreForCollisions: false, - modelURL: basketballURL, - userData: JSON.stringify({ - resetMe: { - resetMe: true - } - }) + function createAllToys() { + createBlocks({ + x: 548.3, + y: 495.55, + z: 504.4 }); - collidingBalls.push(collidingBall); - originalBallPositions.push(position); - } + createBasketBall({ + x: 547.73, + y: 495.5, + z: 505.47 + }); + + createDoll({ + x: 546.67, + y: 495.41, + z: 505.09 + }); + + createWand({ + x: 546.71, + y: 495.55, + z: 506.15 + }); + + createDice(); + + createFlashlight({ + x: 545.72, + y: 495.41, + z: 505.78 + }); + + + + createCombinedArmChair({ + x: 549.29, + y: 494.9, + z: 508.22 + }); + + createPottedPlant({ + x: 554.26, + y: 495.2, + z: 504.53 + }); + + createPingPongBallGun(); + + createBasketballHoop(); + createBasketballRack(); + + createGates(); + + createFire(); + // Handles toggling of all sconce lights + createLights(); + + + + createCat({ + x: 551.09, + y: 494.98, + z: 503.49 + }); + + + createSprayCan({ + x: 549.7, + y: 495.6, + z: 503.91 + }); + + createTargets(); + } - function testBallDistanceFromStart() { - var resetCount = 0; + function deleteAllToys() { + var entities = Entities.findEntities(MyAvatar.position, 100); - collidingBalls.forEach(function(ball, index) { - var currentPosition = Entities.getEntityProperties(ball, "position").position; - var originalPosition = originalBallPositions[index]; - var distance = Vec3.subtract(originalPosition, currentPosition); - var length = Vec3.length(distance); - - if (length > RESET_DISTANCE) { - Script.setTimeout(function() { - var newPosition = Entities.getEntityProperties(ball, "position").position; - var moving = Vec3.length(Vec3.subtract(currentPosition, newPosition)); - if (moving < MINIMUM_MOVE_LENGTH) { - resetCount++; - if (resetCount === NUMBER_OF_BALLS) { - deleteCollidingBalls(); - createCollidingBalls(); - } + entities.forEach(function(entity) { + //params: customKey, id, defaultValue + var shouldReset = getEntityCustomData(resetKey, entity, {}).resetMe; + if (shouldReset === true) { + Entities.deleteEntity(entity); } - }, 200); - } - }); + }); } - function deleteEntity(entityID) { - if (entityID === rack) { - deleteCollidingBalls(); - Script.clearInterval(distanceCheckInterval); - Entities.deletingEntity.disconnect(deleteEntity); - } - } - - function deleteCollidingBalls() { - while (collidingBalls.length > 0) { - Entities.deleteEntity(collidingBalls.pop()); - } - } - - createCollidingBalls(); - Entities.deletingEntity.connect(deleteEntity); - - var distanceCheckInterval = Script.setInterval(testBallDistanceFromStart, 1000); - } - - function createTargets() { - - var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target.fbx'; - var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target_collision_hull.obj'; - - var RESET_DISTANCE = 1; - var TARGET_USER_DATA_KEY = 'hifi-ping_pong_target'; - var NUMBER_OF_TARGETS = 6; - var TARGETS_PER_ROW = 3; - - var TARGET_DIMENSIONS = { - x: 0.06, - y: 0.42, - z: 0.42 - }; - - var VERTICAL_SPACING = TARGET_DIMENSIONS.y + 0.5; - var HORIZONTAL_SPACING = TARGET_DIMENSIONS.z + 0.5; + function createFire() { - var startPosition = { - x: 548.68, - y: 497.30, - z: 509.74 - }; + var myOrientation = Quat.fromPitchYawRollDegrees(-90, 0, 0.0); - var rotation = Quat.fromPitchYawRollDegrees(0, -55.25, 0); + var animationSettings = JSON.stringify({ + fps: 30, + running: true, + loop: true, + firstFrame: 1, + lastFrame: 10000 + }); - var targetIntervalClearer = Entities.addEntity({ - name: 'Target Interval Clearer - delete me to clear', - type: 'Box', - position: startPosition, - dimensions: TARGET_DIMENSIONS, - rotation: rotation, - visible: false, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - resetMe: { - resetMe: true - } - }) - }); - var targets = []; - - var originalPositions = []; - - function addTargets() { - var i; - var row = -1; - for (i = 0; i < NUMBER_OF_TARGETS; i++) { - - if (i % TARGETS_PER_ROW === 0) { - row++; - } - - var vHat = Quat.getFront(rotation); - var spacer = HORIZONTAL_SPACING * (i % TARGETS_PER_ROW) + (row * HORIZONTAL_SPACING / 2); - var multiplier = Vec3.multiply(spacer, vHat); - var position = Vec3.sum(startPosition, multiplier); - position.y = startPosition.y - (row * VERTICAL_SPACING); - - originalPositions.push(position); - - var targetProperties = { - name: 'Target', - type: 'Model', - modelURL: MODEL_URL, - shapeType: 'compound', - collisionsWillMove: true, - dimensions: TARGET_DIMENSIONS, - compoundShapeURL: COLLISION_HULL_URL, - position: position, - rotation: rotation, - script: targetsScriptURL, - userData: JSON.stringify({ - resetMe: { - resetMe: true - } - }) - }; - var target = Entities.addEntity(targetProperties); - targets.push(target); - } - } - - function testTargetDistanceFromStart() { - targets.forEach(function(target, index) { - - var currentPosition = Entities.getEntityProperties(target, "position").position; - var originalPosition = originalPositions[index]; - var distance = Vec3.subtract(originalPosition, currentPosition); - var length = Vec3.length(distance); - - if (length > RESET_DISTANCE) { - - Entities.deleteEntity(target); - - var targetProperties = { - name: 'Target', - type: 'Model', - modelURL: MODEL_URL, - shapeType: 'compound', - collisionsWillMove: true, - dimensions: TARGET_DIMENSIONS, - compoundShapeURL: COLLISION_HULL_URL, - position: originalPositions[index], - rotation: rotation, - script: targetsScriptURL, + var fire = Entities.addEntity({ + type: "ParticleEffect", + name: "fire", + animationSettings: animationSettings, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + position: { + x: 551.45, + y: 494.82, + z: 502.05 + }, + emitRate: 100, + colorStart: { + red: 70, + green: 70, + blue: 137 + }, + color: { + red: 200, + green: 99, + blue: 42 + }, + colorFinish: { + red: 255, + green: 99, + blue: 32 + }, + radiusSpread: 0.01, + radiusStart: 0.02, + radiusEnd: 0.001, + particleRadius: 0.05, + radiusFinish: 0.0, + emitOrientation: myOrientation, + emitSpeed: 0.3, + speedSpread: 0.1, + alphaStart: 0.05, + alpha: 0.1, + alphaFinish: 0.05, + emitDimensions: { + x: 1, + y: 1, + z: 0.1 + }, + polarFinish: 0.1, + emitAcceleration: { + x: 0.0, + y: 0.0, + z: 0.0 + }, + accelerationSpread: { + x: 0.1, + y: 0.01, + z: 0.1 + }, + lifespan: 1, userData: JSON.stringify({ - resetMe: { - resetMe: true - } + resetMe: { + resetMe: true + } }) - }; - var target = Entities.addEntity(targetProperties); - targets[index] = target; + }); + } + function createBasketballRack() { + var NUMBER_OF_BALLS = 4; + var DIAMETER = 0.30; + var RESET_DISTANCE = 1; + var MINIMUM_MOVE_LENGTH = 0.05; + var basketballURL = HIFI_PUBLIC_BUCKET + "models/content/basketball2.fbx"; + var basketballCollisionSoundURL = HIFI_PUBLIC_BUCKET + "sounds/basketball/basketball.wav"; + var rackURL = HIFI_PUBLIC_BUCKET + "models/basketball_hoop/basketball_rack.fbx"; + var rackCollisionHullURL = HIFI_PUBLIC_BUCKET + "models/basketball_hoop/rack_collision_hull.obj"; + + var rackRotation = Quat.fromPitchYawRollDegrees(0, -90, 0); + + var rackStartPosition = { + x: 542.86, + y: 494.84, + z: 475.06 + }; + var rack = Entities.addEntity({ + name: 'Basketball Rack', + type: "Model", + modelURL: rackURL, + position: rackStartPosition, + rotation: rackRotation, + shapeType: 'compound', + gravity: { + x: 0, + y: -9.8, + z: 0 + }, + linearDamping: 1, + dimensions: { + x: 0.4, + y: 1.37, + z: 1.73 + }, + collisionsWillMove: true, + ignoreForCollisions: false, + compoundShapeURL: rackCollisionHullURL, + userData: JSON.stringify({ + resetMe: { + resetMe: true + }, + grabbableKey: { + grabbable: false + } + }) + }); + + var collidingBalls = []; + var originalBallPositions = []; + + function createCollidingBalls() { + var position = rackStartPosition; + + var i; + for (i = 0; i < NUMBER_OF_BALLS; i++) { + var ballPosition = { + x: position.x, + y: position.y + DIAMETER * 2, + z: position.z + (DIAMETER) - (DIAMETER * i) + }; + + var collidingBall = Entities.addEntity({ + type: "Model", + name: 'Colliding Basketball', + shapeType: 'Sphere', + position: { + x: position.x + (DIAMETER * 2) - (DIAMETER * i), + y: position.y + DIAMETER * 2, + z: position.z + }, + dimensions: { + x: DIAMETER, + y: DIAMETER, + z: DIAMETER + }, + restitution: 1.0, + linearDamping: 0.00001, + gravity: { + x: 0, + y: -9.8, + z: 0 + }, + collisionsWillMove: true, + ignoreForCollisions: false, + modelURL: basketballURL, + userData: JSON.stringify({ + resetMe: { + resetMe: true + }, + grabbable: { + invertSolidWhileHeld: true + } + }) + }); + + collidingBalls.push(collidingBall); + originalBallPositions.push(position); + } } - }); + + function testBallDistanceFromStart() { + var resetCount = 0; + + collidingBalls.forEach(function(ball, index) { + var currentPosition = Entities.getEntityProperties(ball, "position").position; + var originalPosition = originalBallPositions[index]; + var distance = Vec3.subtract(originalPosition, currentPosition); + var length = Vec3.length(distance); + + if (length > RESET_DISTANCE) { + Script.setTimeout(function() { + var newPosition = Entities.getEntityProperties(ball, "position").position; + var moving = Vec3.length(Vec3.subtract(currentPosition, newPosition)); + if (moving < MINIMUM_MOVE_LENGTH) { + resetCount++; + if (resetCount === NUMBER_OF_BALLS) { + deleteCollidingBalls(); + createCollidingBalls(); + } + } + }, 200); + } + }); + } + + function deleteEntity(entityID) { + if (entityID === rack) { + deleteCollidingBalls(); + Script.clearInterval(distanceCheckInterval); + Entities.deletingEntity.disconnect(deleteEntity); + } + } + + function deleteCollidingBalls() { + while (collidingBalls.length > 0) { + Entities.deleteEntity(collidingBalls.pop()); + } + } + + createCollidingBalls(); + Entities.deletingEntity.connect(deleteEntity); + + var distanceCheckInterval = Script.setInterval(testBallDistanceFromStart, 1000); + } + + function createTargets() { + + var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target.fbx'; + var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target_collision_hull.obj'; + + var MINIMUM_MOVE_LENGTH = 0.05; + var RESET_DISTANCE = 0.5; + var TARGET_USER_DATA_KEY = 'hifi-ping_pong_target'; + var NUMBER_OF_TARGETS = 6; + var TARGETS_PER_ROW = 3; + + var TARGET_DIMENSIONS = { + x: 0.06, + y: 0.42, + z: 0.42 + }; + + var VERTICAL_SPACING = TARGET_DIMENSIONS.y + 0.5; + var HORIZONTAL_SPACING = TARGET_DIMENSIONS.z + 0.5; + + + var startPosition = { + x: 548.68, + y: 497.30, + z: 509.74 + }; + + var rotation = Quat.fromPitchYawRollDegrees(0, -55.25, 0); + + var targetIntervalClearer = Entities.addEntity({ + name: 'Target Interval Clearer - delete me to clear', + type: 'Box', + position: startPosition, + dimensions: TARGET_DIMENSIONS, + rotation: rotation, + visible: false, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + resetMe: { + resetMe: true + } + }) + }); + + var targets = []; + + var originalPositions = []; + var lastPositions = []; + + function addTargets() { + var i; + var row = -1; + for (i = 0; i < NUMBER_OF_TARGETS; i++) { + + if (i % TARGETS_PER_ROW === 0) { + row++; + } + + var vHat = Quat.getFront(rotation); + var spacer = HORIZONTAL_SPACING * (i % TARGETS_PER_ROW) + (row * HORIZONTAL_SPACING / 2); + var multiplier = Vec3.multiply(spacer, vHat); + var position = Vec3.sum(startPosition, multiplier); + position.y = startPosition.y - (row * VERTICAL_SPACING); + + originalPositions.push(position); + lastPositions.push(position); + + var targetProperties = { + name: 'Target', + type: 'Model', + modelURL: MODEL_URL, + shapeType: 'compound', + collisionsWillMove: true, + dimensions: TARGET_DIMENSIONS, + compoundShapeURL: COLLISION_HULL_URL, + position: position, + rotation: rotation, + script: targetsScriptURL, + userData: JSON.stringify({ + resetMe: { + resetMe: true + }, + grabbableKey: { + grabbable: false + } + }) + }; + + var target = Entities.addEntity(targetProperties); + targets.push(target); + + } + } + + function testTargetDistanceFromStart() { + targets.forEach(function(target, index) { + + var currentPosition = Entities.getEntityProperties(target, "position").position; + var originalPosition = originalPositions[index]; + var distance = Vec3.subtract(originalPosition, currentPosition); + var length = Vec3.length(distance); + + var moving = Vec3.length(Vec3.subtract(currentPosition, lastPositions[index])); + + lastPositions[index] = currentPosition; + + if (length > RESET_DISTANCE && moving < MINIMUM_MOVE_LENGTH) { + + Entities.deleteEntity(target); + + var targetProperties = { + name: 'Target', + type: 'Model', + modelURL: MODEL_URL, + shapeType: 'compound', + collisionsWillMove: true, + dimensions: TARGET_DIMENSIONS, + compoundShapeURL: COLLISION_HULL_URL, + position: originalPositions[index], + rotation: rotation, + script: targetsScriptURL, + userData: JSON.stringify({ + resetMe: { + resetMe: true + }, + grabbableKey: { + grabbable: false + } + } + }) + }; + + targets[index] = Entities.addEntity(targetProperties); + + } + }); } function deleteEntity(entityID) { - if (entityID === targetIntervalClearer) { - deleteTargets(); - Script.clearInterval(distanceCheckInterval); - Entities.deletingEntity.disconnect(deleteEntity); - } + if (entityID === targetIntervalClearer) { + deleteTargets(); + Script.clearInterval(distanceCheckInterval); + Entities.deletingEntity.disconnect(deleteEntity); + } } function deleteTargets() { - while (targets.length > 0) { - Entities.deleteEntity(targets.pop()); - } - Entities.deleteEntity(targetIntervalClearer); + while (targets.length > 0) { + Entities.deleteEntity(targets.pop()); + } + Entities.deleteEntity(targetIntervalClearer); } Entities.deletingEntity.connect(deleteEntity); @@ -490,439 +508,455 @@ MasterReset = function() { addTargets(); - } +} - function createCat(position) { +function createCat(position) { var modelURL = "http://hifi-public.s3.amazonaws.com/ryan/Dark_Cat.fbx"; var animationURL = "http://hifi-public.s3.amazonaws.com/ryan/sleeping.fbx"; var animationSettings = JSON.stringify({ - running: true, + running: true, }); var cat = Entities.addEntity({ - type: "Model", - modelURL: modelURL, - name: "cat", - script: catScriptURL, - animationURL: animationURL, - animationSettings: animationSettings, - position: position, - rotation: { - w: 0.35020983219146729, - x: -4.57763671875e-05, - y: 0.93664455413818359, - z: -1.52587890625e-05 - }, - dimensions: { - x: 0.15723302960395813, - y: 0.50762706995010376, - z: 0.90716040134429932 - }, - userData: JSON.stringify({ - resetMe: { - resetMe: true - } - }) + type: "Model", + modelURL: modelURL, + name: "cat", + script: catScriptURL, + animationURL: animationURL, + animationSettings: animationSettings, + position: position, + rotation: { + w: 0.35020983219146729, + x: -4.57763671875e-05, + y: 0.93664455413818359, + z: -1.52587890625e-05 + }, + dimensions: { + x: 0.15723302960395813, + y: 0.50762706995010376, + z: 0.90716040134429932 + }, + userData: JSON.stringify({ + resetMe: { + resetMe: true + }, + grabbableKey: { + grabbable: false + } + } + }) }); - } +} - function createFlashlight(position) { +function createFlashlight(position) { var modelURL = "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx"; var flashlight = Entities.addEntity({ - type: "Model", - modelURL: modelURL, - name: "flashlight", - script: flashlightScriptURL, - position: position, - dimensions: { - x: 0.08, - y: 0.30, - z: 0.08 - }, - collisionsWillMove: true, - gravity: { - x: 0, - y: -3.5, - z: 0 - }, - velocity: { - x: 0, - y: -0.01, - z: 0 - }, - shapeType: 'box', - userData: JSON.stringify({ - resetMe: { - resetMe: true - } - }) + type: "Model", + modelURL: modelURL, + name: "flashlight", + script: flashlightScriptURL, + position: position, + dimensions: { + x: 0.08, + y: 0.30, + z: 0.08 + }, + collisionsWillMove: true, + gravity: { + x: 0, + y: -3.5, + z: 0 + }, + velocity: { + x: 0, + y: -0.01, + z: 0 + }, + shapeType: 'box', + userData: JSON.stringify({ + resetMe: { + resetMe: true + }, + grabbableKey: { + invertSolidWhileHeld: true + } + } + }) }); - } +} - function createLights() { +function createLights() { var modelURL = "http://hifi-public.s3.amazonaws.com/ryan/lightswitch.fbx"; var rotation = { - w: 0.63280689716339111, - x: 0.63280689716339111, - y: -0.31551080942153931, - z: 0.31548023223876953 + w: 0.63280689716339111, + x: 0.63280689716339111, + y: -0.31551080942153931, + z: 0.31548023223876953 }; var axis = { - x: 0, - y: 1, - z: 0 + x: 0, + y: 1, + z: 0 }; var dQ = Quat.angleAxis(180, axis); rotation = Quat.multiply(rotation, dQ); var lightSwitchHall = Entities.addEntity({ - type: "Model", - modelURL: modelURL, - name: "Light Switch Hall", - script: lightsScriptURL, - position: { - x: 543.27764892578125, - y: 495.67999267578125, - z: 511.00564575195312 - }, - rotation: rotation, - dimensions: { - x: 0.10546875, - y: 0.032372996211051941, - z: 0.16242524981498718 - }, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - on: true, - type: "Hall Light" - } - }) + type: "Model", + modelURL: modelURL, + name: "Light Switch Hall", + script: lightsScriptURL, + position: { + x: 543.27764892578125, + y: 495.67999267578125, + z: 511.00564575195312 + }, + rotation: rotation, + dimensions: { + x: 0.10546875, + y: 0.032372996211051941, + z: 0.16242524981498718 + }, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + on: true, + type: "Hall Light" + } + }) }); var sconceLight1 = Entities.addEntity({ - type: "Light", - position: { - x: 543.75, - y: 496.24, - z: 511.13 - }, - name: "Sconce 1 Light", - dimensions: { - x: 2.545, - y: 2.545, - z: 2.545 - }, - cutoff: 90, - color: { - red: 217, - green: 146, - blue: 24 - }, - isSpotlight: false, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - type: "Hall Light" - } - }) + type: "Light", + position: { + x: 543.75, + y: 496.24, + z: 511.13 + }, + name: "Sconce 1 Light", + dimensions: { + x: 2.545, + y: 2.545, + z: 2.545 + }, + cutoff: 90, + color: { + red: 217, + green: 146, + blue: 24 + }, + isSpotlight: false, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + type: "Hall Light" + } + }) }); var sconceLight2 = Entities.addEntity({ - type: "Light", - position: { - x: 540.1, - y: 496.24, - z: 505.57 - }, - name: "Sconce 2 Light", - dimensions: { - x: 2.545, - y: 2.545, - z: 2.545 - }, - cutoff: 90, - color: { - red: 217, - green: 146, - blue: 24 - }, - isSpotlight: false, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - type: "Hall Light" - } - }) + type: "Light", + position: { + x: 540.1, + y: 496.24, + z: 505.57 + }, + name: "Sconce 2 Light", + dimensions: { + x: 2.545, + y: 2.545, + z: 2.545 + }, + cutoff: 90, + color: { + red: 217, + green: 146, + blue: 24 + }, + isSpotlight: false, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + type: "Hall Light" + } + }) }); rotation = { - w: 0.20082402229309082, - x: 0.20082402229309082, - y: -0.67800414562225342, - z: 0.67797362804412842 + w: 0.20082402229309082, + x: 0.20082402229309082, + y: -0.67800414562225342, + z: 0.67797362804412842 }; axis = { - x: 0, - y: 1, - z: 0 + x: 0, + y: 1, + z: 0 }; dQ = Quat.angleAxis(180, axis); rotation = Quat.multiply(rotation, dQ); var lightSwitchGarage = Entities.addEntity({ - type: "Model", - modelURL: modelURL, - name: "Light Switch Garage", - script: lightsScriptURL, - position: { - x: 545.62, - y: 495.68, - z: 500.21 - }, - rotation: rotation, - dimensions: { - x: 0.10546875, - y: 0.032372996211051941, - z: 0.16242524981498718 - }, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - on: true, - type: "Garage Light" - } - }) + type: "Model", + modelURL: modelURL, + name: "Light Switch Garage", + script: lightsScriptURL, + position: { + x: 545.62, + y: 495.68, + z: 500.21 + }, + rotation: rotation, + dimensions: { + x: 0.10546875, + y: 0.032372996211051941, + z: 0.16242524981498718 + }, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + on: true, + type: "Garage Light" + } + }) }); var sconceLight3 = Entities.addEntity({ - type: "Light", - position: { - x: 545.49468994140625, - y: 496.24026489257812, - z: 500.63516235351562 - }, + type: "Light", + position: { + x: 545.49468994140625, + y: 496.24026489257812, + z: 500.63516235351562 + }, - name: "Sconce 3 Light", - dimensions: { - x: 2.545, - y: 2.545, - z: 2.545 - }, - cutoff: 90, - color: { - red: 217, - green: 146, - blue: 24 - }, - isSpotlight: false, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - type: "Garage Light" - } - }) + name: "Sconce 3 Light", + dimensions: { + x: 2.545, + y: 2.545, + z: 2.545 + }, + cutoff: 90, + color: { + red: 217, + green: 146, + blue: 24 + }, + isSpotlight: false, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + type: "Garage Light" + } + }) }); var sconceLight4 = Entities.addEntity({ - type: "Light", - position: { - x: 550.90399169921875, - y: 496.24026489257812, - z: 507.90237426757812 - }, - name: "Sconce 4 Light", - dimensions: { - x: 2.545, - y: 2.545, - z: 2.545 - }, - cutoff: 90, - color: { - red: 217, - green: 146, - blue: 24 - }, - isSpotlight: false, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - type: "Garage Light" - } - }) + type: "Light", + position: { + x: 550.90399169921875, + y: 496.24026489257812, + z: 507.90237426757812 + }, + name: "Sconce 4 Light", + dimensions: { + x: 2.545, + y: 2.545, + z: 2.545 + }, + cutoff: 90, + color: { + red: 217, + green: 146, + blue: 24 + }, + isSpotlight: false, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + type: "Garage Light" + } + }) }); var sconceLight5 = Entities.addEntity({ - type: "Light", - position: { - x: 548.407958984375, - y: 496.24026489257812, - z: 509.5504150390625 - }, - name: "Sconce 5 Light", - dimensions: { - x: 2.545, - y: 2.545, - z: 2.545 - }, - cutoff: 90, - color: { - red: 217, - green: 146, - blue: 24 - }, - isSpotlight: false, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - type: "Garage Light" - } - }) + type: "Light", + position: { + x: 548.407958984375, + y: 496.24026489257812, + z: 509.5504150390625 + }, + name: "Sconce 5 Light", + dimensions: { + x: 2.545, + y: 2.545, + z: 2.545 + }, + cutoff: 90, + color: { + red: 217, + green: 146, + blue: 24 + }, + isSpotlight: false, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + type: "Garage Light" + } + }) }); - } +} - function createDice() { +function createDice() { var diceProps = { - type: "Model", - modelURL: "http://s3.amazonaws.com/hifi-public/models/props/Dice/goldDie.fbx", - collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/dice/diceCollide.wav", - name: "dice", - position: { - x: 541, - y: 494.96, - z: 509.1 - }, - dimensions: { - x: 0.09, - y: 0.09, - z: 0.09 - }, - gravity: { - x: 0, - y: -3.5, - z: 0 - }, - velocity: { - x: 0, - y: -0.01, - z: 0 - }, - shapeType: "box", - collisionsWillMove: true, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - } - }) - }; - var dice1 = Entities.addEntity(diceProps); + type: "Model", + modelURL: "http://s3.amazonaws.com/hifi-public/models/props/Dice/goldDie.fbx", + collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/dice/diceCollide.wav", + name: "dice", + position: { + x: 541, + y: 494.96, + z: 509.1 + }, + dimensions: { + x: 0.09, + y: 0.09, + z: 0.09 + }, + gravity: { + x: 0, + y: -3.5, + z: 0 + }, + velocity: { + x: 0, + y: -0.01, + z: 0 + }, + shapeType: "box", + collisionsWillMove: true, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true + } + } + }) +}; +var dice1 = Entities.addEntity(diceProps); - diceProps.position = { - x: 541.05, - y: 494.96, - z: 509.0 - }; +diceProps.position = { + x: 541.05, + y: 494.96, + z: 509.0 +}; - var dice2 = Entities.addEntity(diceProps); +var dice2 = Entities.addEntity(diceProps); - } +} - function createGates() { +function createGates() { var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/ryan/fence.fbx'; var rotation = Quat.fromPitchYawRollDegrees(0, -16, 0); var gate = Entities.addEntity({ - name: 'Front Door Fence', - type: 'Model', - modelURL: MODEL_URL, - shapeType: 'box', - position: { - x: 531.15, - y: 495.11, - z: 520.20 - }, - dimensions: { - x: 1.42, - y: 1.13, - z: 0.2 - }, - rotation: rotation, - collisionsWillMove: true, - gravity: { - x: 0, - y: -100, - z: 0 - }, - linearDamping: 1, - angularDamping: 10, - mass: 10, - userData: JSON.stringify({ - resetMe: { - resetMe: true, + name: 'Front Door Fence', + type: 'Model', + modelURL: MODEL_URL, + shapeType: 'box', + position: { + x: 531.15, + y: 495.11, + z: 520.20 }, - grabbableKey: { - grabbable: false - } - }) + dimensions: { + x: 1.42, + y: 1.13, + z: 0.2 + }, + rotation: rotation, + collisionsWillMove: true, + gravity: { + x: 0, + y: -100, + z: 0 + }, + linearDamping: 1, + angularDamping: 10, + mass: 10, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + }, + grabbableKey: { + grabbable: false + } + }) }); - } +} - function createPingPongBallGun() { +function createPingPongBallGun() { var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx'; var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_collision_hull.obj'; var position = { - x: 548.6, - y: 495.4, - z: 503.39 + x: 548.6, + y: 495.4, + z: 503.39 }; var rotation = Quat.fromPitchYawRollDegrees(0, 36, 0); var pingPongGun = Entities.addEntity({ - type: "Model", - modelURL: MODEL_URL, - shapeType: 'box', - script: pingPongScriptURL, - position: position, - rotation: rotation, - gravity: { - x: 0, - y: -9.8, - z: 0 - }, - dimensions: { - x: 0.08, - y: 0.21, - z: 0.47 - }, - collisionsWillMove: true, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - } - }) + type: "Model", + modelURL: MODEL_URL, + shapeType: 'box', + script: pingPongScriptURL, + position: position, + rotation: rotation, + gravity: { + x: 0, + y: -9.8, + z: 0 + }, + dimensions: { + x: 0.08, + y: 0.21, + z: 0.47 + }, + collisionsWillMove: true, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true + } + } + }) }); - } +} - function createBasketballHoop() { +function createBasketballHoop() { var position = { - x: 539.23, - y: 496.13, - z: 475.89 + x: 539.23, + y: 496.13, + z: 475.89 }; var rotation = Quat.fromPitchYawRollDegrees(0, 58.49, 0); @@ -930,349 +964,365 @@ MasterReset = function() { var hoopCollisionHullURL = "http://hifi-public.s3.amazonaws.com/models/basketball_hoop/basketball_hoop_collision_hull.obj"; var hoop = Entities.addEntity({ - type: "Model", - modelURL: hoopURL, - position: position, - rotation: rotation, - shapeType: 'compound', - gravity: { - x: 0, - y: -9.8, - z: 0 - }, - dimensions: { - x: 1.89, - y: 3.99, - z: 3.79 - }, - compoundShapeURL: hoopCollisionHullURL, - userData: JSON.stringify({ - resetMe: { - resetMe: true, + type: "Model", + modelURL: hoopURL, + position: position, + rotation: rotation, + shapeType: 'compound', + gravity: { + x: 0, + y: -9.8, + z: 0 }, - grabbableKey: { - grabbable: false - } - }) + dimensions: { + x: 1.89, + y: 3.99, + z: 3.79 + }, + compoundShapeURL: hoopCollisionHullURL, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + }, + grabbableKey: { + grabbable: false + } + }) }); - } +} - function createWand(position) { +function createWand(position) { var WAND_MODEL = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/wand.fbx'; var WAND_COLLISION_SHAPE = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/actual_no_top_collision_hull.obj'; var entity = Entities.addEntity({ - name: 'Bubble Wand', - type: "Model", - modelURL: WAND_MODEL, - position: position, - gravity: { - x: 0, - y: -9.8, - z: 0 - }, - dimensions: { - x: 0.05, - y: 0.25, - z: 0.05 - }, - //must be enabled to be grabbable in the physics engine - shapeType: 'compound', - collisionsWillMove: true, - compoundShapeURL: WAND_COLLISION_SHAPE, - //Look into why bubble wand is going through table when gravity is enabled - // gravity: {x: 0, y: -3.5, z: 0}, - // velocity: {x: 0, y: -0.01, z:0}, - script: wandScriptURL, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - } - }) + name: 'Bubble Wand', + type: "Model", + modelURL: WAND_MODEL, + position: position, + gravity: { + x: 0, + y: -9.8, + z: 0 + }, + dimensions: { + x: 0.05, + y: 0.25, + z: 0.05 + }, + //must be enabled to be grabbable in the physics engine + shapeType: 'compound', + collisionsWillMove: true, + compoundShapeURL: WAND_COLLISION_SHAPE, + //Look into why bubble wand is going through table when gravity is enabled + // gravity: {x: 0, y: -3.5, z: 0}, + // velocity: {x: 0, y: -0.01, z:0}, + script: wandScriptURL, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true + } + } + }) }); - } +} - function createBasketBall(position) { +function createBasketBall(position) { var modelURL = "http://s3.amazonaws.com/hifi-public/models/content/basketball2.fbx"; var entity = Entities.addEntity({ - type: "Model", - modelURL: modelURL, - position: position, - collisionsWillMove: true, - shapeType: "sphere", - name: "basketball", - dimensions: { - x: 0.25, - y: 0.26, - z: 0.25 - }, - gravity: { - x: 0, - y: -7, - z: 0 - }, - restitution: 10, - linearDamping: 0.0, - velocity: { - x: 0, - y: -0.01, - z: 0 - }, - collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/basketball/basketball.wav", - userData: JSON.stringify({ - resetMe: { - resetMe: true, - } - }) + type: "Model", + modelURL: modelURL, + position: position, + collisionsWillMove: true, + shapeType: "sphere", + name: "basketball", + dimensions: { + x: 0.25, + y: 0.26, + z: 0.25 + }, + gravity: { + x: 0, + y: -7, + z: 0 + }, + restitution: 10, + linearDamping: 0.0, + velocity: { + x: 0, + y: -0.01, + z: 0 + }, + collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/basketball/basketball.wav", + userData: JSON.stringify({ + resetMe: { + resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true + } + } + }) }); - } +} - function createDoll(position) { +function createDoll(position) { var modelURL = "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx"; var naturalDimensions = { - x: 1.63, - y: 1.67, - z: 0.26 + x: 1.63, + y: 1.67, + z: 0.26 }; var desiredDimensions = Vec3.multiply(naturalDimensions, 0.15); var entity = Entities.addEntity({ - type: "Model", - name: "doll", - modelURL: modelURL, - script: dollScriptURL, - position: position, - shapeType: 'box', - dimensions: desiredDimensions, - gravity: { - x: 0, - y: -5, - z: 0 - }, - velocity: { - x: 0, - y: -0.1, - z: 0 - }, - collisionsWillMove: true, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - } - }) + type: "Model", + name: "doll", + modelURL: modelURL, + script: dollScriptURL, + position: position, + shapeType: 'box', + dimensions: desiredDimensions, + gravity: { + x: 0, + y: -5, + z: 0 + }, + velocity: { + x: 0, + y: -0.1, + z: 0 + }, + collisionsWillMove: true, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true + } + } + }) }); - } +} - function createSprayCan(position) { +function createSprayCan(position) { var modelURL = "https://hifi-public.s3.amazonaws.com/eric/models/paintcan.fbx"; var entity = Entities.addEntity({ - type: "Model", - name: "spraycan", - script: sprayPaintScriptURL, - modelURL: modelURL, - position: position, - dimensions: { - x: 0.07, - y: 0.17, - z: 0.07 - }, - collisionsWillMove: true, - shapeType: 'box', - gravity: { - x: 0, - y: -0.5, - z: 0 - }, - velocity: { - x: 0, - y: -1, - z: 0 - }, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - } - }) + type: "Model", + name: "spraycan", + script: sprayPaintScriptURL, + modelURL: modelURL, + position: position, + dimensions: { + x: 0.07, + y: 0.17, + z: 0.07 + }, + collisionsWillMove: true, + shapeType: 'box', + gravity: { + x: 0, + y: -0.5, + z: 0 + }, + velocity: { + x: 0, + y: -1, + z: 0 + }, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + }, + grabbableKey: { + invertSolidWhileHeld: true + } + } + }) }); - } +} - function createPottedPlant(position) { +function createPottedPlant(position) { var modelURL = "http://hifi-public.s3.amazonaws.com/models/potted_plant/potted_plant.fbx"; var entity = Entities.addEntity({ - type: "Model", - name: "Potted Plant", - modelURL: modelURL, - position: position, - dimensions: { - x: 1.10, - y: 2.18, - z: 1.07 - }, - collisionsWillMove: true, - shapeType: 'box', - gravity: { - x: 0, - y: -9.8, - z: 0 - }, - velocity: { - x: 0, - y: 0, - z: 0 - }, - linearDamping: 0.4, - userData: JSON.stringify({ - resetMe: { - resetMe: true, + type: "Model", + name: "Potted Plant", + modelURL: modelURL, + position: position, + dimensions: { + x: 1.10, + y: 2.18, + z: 1.07 }, - grabbableKey: { - grabbable: false - } - }) + collisionsWillMove: true, + shapeType: 'box', + gravity: { + x: 0, + y: -9.8, + z: 0 + }, + velocity: { + x: 0, + y: 0, + z: 0 + }, + linearDamping: 0.4, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + }, + grabbableKey: { + grabbable: false + } + }) }); - } +} - function createCombinedArmChair(position) { +function createCombinedArmChair(position) { var modelURL = "http://hifi-public.s3.amazonaws.com/models/red_arm_chair/combined_chair.fbx"; var RED_ARM_CHAIR_COLLISION_HULL = "http://hifi-public.s3.amazonaws.com/models/red_arm_chair/red_arm_chair_collision_hull.obj"; var rotation = Quat.fromPitchYawRollDegrees(0, -143, 0); var entity = Entities.addEntity({ - type: "Model", - name: "Red Arm Chair", - modelURL: modelURL, - shapeType: 'compound', - compoundShapeURL: RED_ARM_CHAIR_COLLISION_HULL, - position: position, - rotation: rotation, - dimensions: { - x: 1.26, - y: 1.56, - z: 1.35 - }, - collisionsWillMove: true, - gravity: { - x: 0, - y: -0.8, - z: 0 - }, - velocity: { - x: 0, - y: 0, - z: 0 - }, - linearDamping: 0.2, - userData: JSON.stringify({ - resetMe: { - resetMe: true, + type: "Model", + name: "Red Arm Chair", + modelURL: modelURL, + shapeType: 'compound', + compoundShapeURL: RED_ARM_CHAIR_COLLISION_HULL, + position: position, + rotation: rotation, + dimensions: { + x: 1.26, + y: 1.56, + z: 1.35 }, - grabbableKey: { - grabbable: false - } - }) + collisionsWillMove: true, + gravity: { + x: 0, + y: -0.8, + z: 0 + }, + velocity: { + x: 0, + y: 0, + z: 0 + }, + linearDamping: 0.2, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + }, + grabbableKey: { + grabbable: false + } + }) }); - } +} - function createBlocks(position) { +function createBlocks(position) { var baseURL = HIFI_PUBLIC_BUCKET + "models/content/planky/"; var collisionSoundURL = "https://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/ToyWoodBlock.L.wav"; var NUM_BLOCKS_PER_COLOR = 4; var i, j; var blockTypes = [{ - url: "planky_blue.fbx", - dimensions: { - x: 0.05, - y: 0.05, - z: 0.25 - } + url: "planky_blue.fbx", + dimensions: { + x: 0.05, + y: 0.05, + z: 0.25 + } }, { - url: "planky_green.fbx", - dimensions: { - x: 0.1, - y: 0.1, - z: 0.25 - } + url: "planky_green.fbx", + dimensions: { + x: 0.1, + y: 0.1, + z: 0.25 + } }, { - url: "planky_natural.fbx", - dimensions: { - x: 0.05, - y: 0.05, - z: 0.05 - } + url: "planky_natural.fbx", + dimensions: { + x: 0.05, + y: 0.05, + z: 0.05 + } }, { - url: "planky_yellow.fbx", - dimensions: { - x: 0.03, - y: 0.05, - z: 0.25 - } + url: "planky_yellow.fbx", + dimensions: { + x: 0.03, + y: 0.05, + z: 0.25 + } }, { - url: "planky_red.fbx", - dimensions: { - x: 0.1, - y: 0.05, - z: 0.25 - } + url: "planky_red.fbx", + dimensions: { + x: 0.1, + y: 0.05, + z: 0.25 + } }, ]; var modelURL, entity; for (i = 0; i < blockTypes.length; i++) { - for (j = 0; j < NUM_BLOCKS_PER_COLOR; j++) { - modelURL = baseURL + blockTypes[i].url; - entity = Entities.addEntity({ - type: "Model", - modelURL: modelURL, - position: Vec3.sum(position, { - x: j / 10, - y: i / 10, - z: 0 - }), - shapeType: 'box', - name: "block", - dimensions: blockTypes[i].dimensions, - collisionsWillMove: true, - collisionSoundURL: collisionSoundURL, - gravity: { - x: 0, - y: -2.5, - z: 0 - }, - velocity: { - x: 0, - y: -0.01, - z: 0 - }, - userData: JSON.stringify({ - resetMe: { - resetMe: true, - } - }) - }); + for (j = 0; j < NUM_BLOCKS_PER_COLOR; j++) { + modelURL = baseURL + blockTypes[i].url; + entity = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + position: Vec3.sum(position, { + x: j / 10, + y: i / 10, + z: 0 + }), + shapeType: 'box', + name: "block", + dimensions: blockTypes[i].dimensions, + collisionsWillMove: true, + collisionSoundURL: collisionSoundURL, + gravity: { + x: 0, + y: -2.5, + z: 0 + }, + velocity: { + x: 0, + y: -0.01, + z: 0 + }, + userData: JSON.stringify({ + resetMe: { + resetMe: true, + } + }) + }); - } + } } - } +} - function cleanup() { +function cleanup() { deleteAllToys(); - } +} - if (shouldDeleteOnEndScript) { +if (shouldDeleteOnEndScript) { Script.scriptEnding.connect(cleanup); - } +} }; \ No newline at end of file