mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 19:04:32 +02:00
Merge branch 'master' of https://github.com/worklist/hifi
This commit is contained in:
commit
693bc11868
28 changed files with 789 additions and 238 deletions
19
examples/xbox.js
Normal file
19
examples/xbox.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// xbox.js
|
||||
// examples
|
||||
//
|
||||
// Created by Stephen Birarda on September 23, 2014
|
||||
//
|
||||
// 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
|
||||
//
|
||||
|
||||
gamepad = Joysticks.joystickWithName("Wireless 360 Controller");
|
||||
|
||||
function reportAxisValue(axis, newValue, oldValue) {
|
||||
print("The value for axis " + axis + " has changed to " + newValue + ". It was " + oldValue);
|
||||
}
|
||||
|
||||
gamepad.axisValueChanged.connect(reportAxisValue);
|
|
@ -2,7 +2,7 @@ set(TARGET_NAME interface)
|
|||
project(${TARGET_NAME})
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "Faceplus" "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp")
|
||||
set(OPTIONAL_EXTERNALS "Faceplus" "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL")
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
|
||||
|
@ -120,6 +120,10 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
|||
add_definitions(-DHAVE_${${EXTERNAL}_UPPERCASE})
|
||||
|
||||
# include the library directories (ignoring warnings)
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS)
|
||||
set(${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIR})
|
||||
endif ()
|
||||
|
||||
include_directories(SYSTEM ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
|
||||
|
||||
# perform the system include hack for OS X to ignore warnings
|
||||
|
@ -129,6 +133,10 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
|||
endforeach()
|
||||
endif ()
|
||||
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_LIBRARIES)
|
||||
set(${${EXTERNAL}_UPPERCASE}_LIBRARIES ${${${EXTERNAL}_UPPERCASE}_LIBRARY})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES})
|
||||
|
||||
endif ()
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#include "scripting/AccountScriptingInterface.h"
|
||||
#include "scripting/AudioDeviceScriptingInterface.h"
|
||||
#include "scripting/ClipboardScriptingInterface.h"
|
||||
#include "scripting/JoystickScriptingInterface.h"
|
||||
#include "scripting/GlobalServicesScriptingInterface.h"
|
||||
#include "scripting/LocationScriptingInterface.h"
|
||||
#include "scripting/MenuScriptingInterface.h"
|
||||
|
@ -1822,6 +1823,8 @@ void Application::init() {
|
|||
_entities.init();
|
||||
_entities.setViewFrustum(getViewFrustum());
|
||||
|
||||
_entityCollisionSystem.init(&_entityEditSender, _entities.getTree(), _voxels.getTree(), &_audio, &_avatarManager);
|
||||
|
||||
_entityClipboardRenderer.init();
|
||||
_entityClipboardRenderer.setViewFrustum(getViewFrustum());
|
||||
_entityClipboardRenderer.setTree(&_entityClipboard);
|
||||
|
@ -2165,7 +2168,7 @@ void Application::update(float deltaTime) {
|
|||
updateFaceshift();
|
||||
updateVisage();
|
||||
_sixenseManager.update(deltaTime);
|
||||
_joystickManager.update();
|
||||
JoystickScriptingInterface::getInstance().update();
|
||||
_prioVR.update(deltaTime);
|
||||
|
||||
}
|
||||
|
@ -2194,6 +2197,10 @@ void Application::update(float deltaTime) {
|
|||
{
|
||||
PerformanceTimer perfTimer("entities");
|
||||
_entities.update(); // update the models...
|
||||
{
|
||||
PerformanceTimer perfTimer("collisions");
|
||||
_entityCollisionSystem.update(); // collide the entities...
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -3775,6 +3782,14 @@ void Application::saveScripts() {
|
|||
_settings->endArray();
|
||||
}
|
||||
|
||||
QScriptValue joystickToScriptValue(QScriptEngine *engine, Joystick* const &in) {
|
||||
return engine->newQObject(in);
|
||||
}
|
||||
|
||||
void joystickFromScriptValue(const QScriptValue &object, Joystick* &out) {
|
||||
out = qobject_cast<Joystick*>(object.toQObject());
|
||||
}
|
||||
|
||||
ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUserLoaded,
|
||||
bool loadScriptFromEditor, bool activateMainWindow) {
|
||||
QUrl scriptUrl(scriptFilename);
|
||||
|
@ -3857,6 +3872,9 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
|
|||
scriptEngine->registerGlobalObject("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
|
||||
scriptEngine->registerGlobalObject("AvatarManager", &_avatarManager);
|
||||
|
||||
scriptEngine->registerGlobalObject("Joysticks", &JoystickScriptingInterface::getInstance());
|
||||
qScriptRegisterMetaType(scriptEngine, joystickToScriptValue, joystickFromScriptValue);
|
||||
|
||||
#ifdef HAVE_RTMIDI
|
||||
scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance());
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <QSystemTrayIcon>
|
||||
|
||||
#include <EntityEditPacketSender.h>
|
||||
#include <EntityCollisionSystem.h>
|
||||
#include <NetworkPacket.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
|
@ -59,7 +60,6 @@
|
|||
#include "avatar/MyAvatar.h"
|
||||
#include "devices/Faceplus.h"
|
||||
#include "devices/Faceshift.h"
|
||||
#include "devices/JoystickManager.h"
|
||||
#include "devices/PrioVR.h"
|
||||
#include "devices/SixenseManager.h"
|
||||
#include "devices/Visage.h"
|
||||
|
@ -221,7 +221,6 @@ public:
|
|||
FaceTracker* getActiveFaceTracker();
|
||||
SixenseManager* getSixenseManager() { return &_sixenseManager; }
|
||||
PrioVR* getPrioVR() { return &_prioVR; }
|
||||
JoystickManager* getJoystickManager() { return &_joystickManager; }
|
||||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
||||
|
@ -483,6 +482,7 @@ private:
|
|||
ParticleCollisionSystem _particleCollisionSystem;
|
||||
|
||||
EntityTreeRenderer _entities;
|
||||
EntityCollisionSystem _entityCollisionSystem;
|
||||
EntityTreeRenderer _entityClipboardRenderer;
|
||||
EntityTree _entityClipboard;
|
||||
|
||||
|
@ -512,7 +512,6 @@ private:
|
|||
|
||||
SixenseManager _sixenseManager;
|
||||
PrioVR _prioVR;
|
||||
JoystickManager _joystickManager;
|
||||
|
||||
Camera _myCamera; // My view onto the world
|
||||
Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
|
||||
|
|
|
@ -158,7 +158,8 @@ Menu::Menu() :
|
|||
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_O, appInstance, SLOT(loadScriptURLDialog()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, appInstance, SLOT(stopAllScripts()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, 0, appInstance, SLOT(reloadAllScripts()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::SHIFT | Qt::Key_R,
|
||||
appInstance, SLOT(reloadAllScripts()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J,
|
||||
appInstance, SLOT(toggleRunningScriptsWidget()));
|
||||
|
||||
|
|
60
interface/src/devices/Joystick.cpp
Normal file
60
interface/src/devices/Joystick.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Joystick.cpp
|
||||
// interface/src/devices
|
||||
//
|
||||
// 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 <limits>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Joystick.h"
|
||||
|
||||
#ifdef HAVE_SDL
|
||||
|
||||
Joystick::Joystick(const QString& name, SDL_Joystick* sdlJoystick) :
|
||||
_name(name),
|
||||
_axes(QVector<float>(SDL_JoystickNumAxes(sdlJoystick))),
|
||||
_buttons(QVector<bool>(SDL_JoystickNumButtons(sdlJoystick))),
|
||||
_sdlJoystick(sdlJoystick)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Joystick::~Joystick() {
|
||||
#ifdef HAVE_SDL
|
||||
SDL_JoystickClose(_sdlJoystick);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Joystick::update() {
|
||||
#ifdef HAVE_SDL
|
||||
// update our current values, emit a signal when there is a change
|
||||
for (int j = 0; j < getNumAxes(); j++) {
|
||||
float value = glm::round(SDL_JoystickGetAxis(_sdlJoystick, j) + 0.5f) / std::numeric_limits<short>::max();
|
||||
const float DEAD_ZONE = 0.1f;
|
||||
float cleanValue = glm::abs(value) < DEAD_ZONE ? 0.0f : value;
|
||||
|
||||
if (_axes[j] != cleanValue) {
|
||||
float oldValue = _axes[j];
|
||||
_axes[j] = cleanValue;
|
||||
emit axisValueChanged(j, cleanValue, oldValue);
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < getNumButtons(); j++) {
|
||||
bool newValue = SDL_JoystickGetButton(_sdlJoystick, j);
|
||||
if (_buttons[j] != newValue) {
|
||||
bool oldValue = _buttons[j];
|
||||
_buttons[j] = newValue;
|
||||
emit buttonStateChanged(j, newValue, oldValue);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
61
interface/src/devices/Joystick.h
Normal file
61
interface/src/devices/Joystick.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// Joystick.h
|
||||
// interface/src/devices
|
||||
//
|
||||
// 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 <qobject.h>
|
||||
#include <qvector.h>
|
||||
|
||||
#ifdef HAVE_SDL
|
||||
#include <SDL.h>
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
class Joystick : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString name READ getName)
|
||||
|
||||
Q_PROPERTY(int numAxes READ getNumAxes)
|
||||
Q_PROPERTY(int numButtons READ getNumButtons)
|
||||
public:
|
||||
Joystick();
|
||||
~Joystick();
|
||||
|
||||
#ifdef HAVE_SDL
|
||||
Joystick(const QString& name, SDL_Joystick* sdlJoystick);
|
||||
#endif
|
||||
|
||||
void update();
|
||||
|
||||
const QString& getName() const { return _name; }
|
||||
|
||||
const QVector<float>& getAxes() const { return _axes; }
|
||||
const QVector<bool>& getButtons() const { return _buttons; }
|
||||
|
||||
int getNumAxes() const { return _axes.size(); }
|
||||
int getNumButtons() const { return _buttons.size(); }
|
||||
|
||||
signals:
|
||||
void axisValueChanged(int axis, float newValue, float oldValue);
|
||||
void buttonStateChanged(int button, float newValue, float oldValue);
|
||||
private:
|
||||
QString _name;
|
||||
QVector<float> _axes;
|
||||
QVector<bool> _buttons;
|
||||
|
||||
#ifdef HAVE_SDL
|
||||
SDL_Joystick* _sdlJoystick;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // hifi_JoystickTracker_h
|
|
@ -1,66 +0,0 @@
|
|||
//
|
||||
// JoystickManager.cpp
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/15/14.
|
||||
// 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 <limits>
|
||||
|
||||
#include <QtDebug>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "JoystickManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
JoystickManager::JoystickManager() {
|
||||
#ifdef HAVE_SDL
|
||||
SDL_Init(SDL_INIT_JOYSTICK);
|
||||
int joystickCount = SDL_NumJoysticks();
|
||||
for (int i = 0; i < joystickCount; i++) {
|
||||
SDL_Joystick* joystick = SDL_JoystickOpen(i);
|
||||
if (joystick) {
|
||||
JoystickState state = { SDL_JoystickName(i), QVector<float>(SDL_JoystickNumAxes(joystick)),
|
||||
QVector<bool>(SDL_JoystickNumButtons(joystick)) };
|
||||
_joystickStates.append(state);
|
||||
_joysticks.append(joystick);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JoystickManager::~JoystickManager() {
|
||||
#ifdef HAVE_SDL
|
||||
foreach (SDL_Joystick* joystick, _joysticks) {
|
||||
SDL_JoystickClose(joystick);
|
||||
}
|
||||
SDL_Quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void JoystickManager::update() {
|
||||
#ifdef HAVE_SDL
|
||||
PerformanceTimer perfTimer("joystick");
|
||||
SDL_JoystickUpdate();
|
||||
|
||||
for (int i = 0; i < _joystickStates.size(); i++) {
|
||||
SDL_Joystick* joystick = _joysticks.at(i);
|
||||
JoystickState& state = _joystickStates[i];
|
||||
for (int j = 0; j < state.axes.size(); j++) {
|
||||
float value = glm::round(SDL_JoystickGetAxis(joystick, j) + 0.5f) / numeric_limits<short>::max();
|
||||
const float DEAD_ZONE = 0.1f;
|
||||
state.axes[j] = glm::abs(value) < DEAD_ZONE ? 0.0f : value;
|
||||
}
|
||||
for (int j = 0; j < state.buttons.size(); j++) {
|
||||
state.buttons[j] = SDL_JoystickGetButton(joystick, j);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
//
|
||||
// JoystickManager.h
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/15/14.
|
||||
// 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_JoystickManager_h
|
||||
#define hifi_JoystickManager_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
#ifdef HAVE_SDL
|
||||
#include <SDL.h>
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
class JoystickState;
|
||||
|
||||
/// Handles joystick input through SDL.
|
||||
class JoystickManager : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
JoystickManager();
|
||||
virtual ~JoystickManager();
|
||||
|
||||
const QVector<JoystickState>& getJoystickStates() const { return _joystickStates; }
|
||||
|
||||
void update();
|
||||
|
||||
private:
|
||||
QVector<JoystickState> _joystickStates;
|
||||
|
||||
#ifdef HAVE_SDL
|
||||
QVector<SDL_Joystick*> _joysticks;
|
||||
#endif
|
||||
};
|
||||
|
||||
class JoystickState {
|
||||
public:
|
||||
QString name;
|
||||
QVector<float> axes;
|
||||
QVector<bool> buttons;
|
||||
};
|
||||
|
||||
#endif // hifi_JoystickManager_h
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "Application.h"
|
||||
#include "PrioVR.h"
|
||||
#include "scripting/JoystickScriptingInterface.h"
|
||||
#include "ui/TextRenderer.h"
|
||||
|
||||
#ifdef HAVE_PRIOVR
|
||||
|
@ -61,18 +62,22 @@ static void setPalm(float deltaTime, int index) {
|
|||
palm->setActive(true);
|
||||
|
||||
// Read controller buttons and joystick into the hand
|
||||
if (!Application::getInstance()->getJoystickManager()->getJoystickStates().isEmpty()) {
|
||||
const JoystickState& state = Application::getInstance()->getJoystickManager()->getJoystickStates().at(0);
|
||||
if (state.axes.size() >= 4 && state.buttons.size() >= 4) {
|
||||
const QString PRIO_JOYSTICK_NAME = "PrioVR";
|
||||
Joystick* prioJoystick = JoystickScriptingInterface::getInstance().joystickWithName(PRIO_JOYSTICK_NAME);
|
||||
if (prioJoystick) {
|
||||
const QVector<float> axes = prioJoystick->getAxes();
|
||||
const QVector<bool> buttons = prioJoystick->getButtons();
|
||||
|
||||
if (axes.size() >= 4 && buttons.size() >= 4) {
|
||||
if (index == LEFT_HAND_INDEX) {
|
||||
palm->setControllerButtons(state.buttons.at(1) ? BUTTON_FWD : 0);
|
||||
palm->setTrigger(state.buttons.at(0) ? 1.0f : 0.0f);
|
||||
palm->setJoystick(state.axes.at(0), -state.axes.at(1));
|
||||
palm->setControllerButtons(buttons[1] ? BUTTON_FWD : 0);
|
||||
palm->setTrigger(buttons[0] ? 1.0f : 0.0f);
|
||||
palm->setJoystick(axes[0], -axes[1]);
|
||||
|
||||
} else {
|
||||
palm->setControllerButtons(state.buttons.at(3) ? BUTTON_FWD : 0);
|
||||
palm->setTrigger(state.buttons.at(2) ? 1.0f : 0.0f);
|
||||
palm->setJoystick(state.axes.at(2), -state.axes.at(3));
|
||||
palm->setControllerButtons(buttons[3] ? BUTTON_FWD : 0);
|
||||
palm->setTrigger(buttons[2] ? 1.0f : 0.0f);
|
||||
palm->setJoystick(axes[2], -axes[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -296,7 +296,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
|||
ModelEntityItem* modelEntity = static_cast<ModelEntityItem*>(entityItem);
|
||||
qDebug() << " url:" << modelEntity->getModelURL();
|
||||
}
|
||||
qDebug() << " entityBox:" << entityBox;
|
||||
qDebug() << " entityBox:" << entityItem->getAABox();
|
||||
qDebug() << " dimensions:" << entityItem->getDimensionsInMeters() << "in meters";
|
||||
qDebug() << " largestDimension:" << entityBox.getLargestDimension() << "in meters";
|
||||
qDebug() << " shouldRender:" << shouldRenderEntity(entityBox.getLargestDimension(), distance);
|
||||
|
|
84
interface/src/scripting/JoystickScriptingInterface.cpp
Normal file
84
interface/src/scripting/JoystickScriptingInterface.cpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// JoystickScriptingInterface.cpp
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/15/14.
|
||||
// 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 <QtDebug>
|
||||
|
||||
#ifdef HAVE_SDL
|
||||
#include <SDL.h>
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "JoystickScriptingInterface.h"
|
||||
|
||||
JoystickScriptingInterface& JoystickScriptingInterface::getInstance() {
|
||||
static JoystickScriptingInterface sharedInstance;
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
JoystickScriptingInterface::JoystickScriptingInterface() :
|
||||
_openJoysticks(),
|
||||
_availableDeviceNames()
|
||||
{
|
||||
#ifdef HAVE_SDL
|
||||
SDL_Init(SDL_INIT_JOYSTICK);
|
||||
|
||||
int joystickCount = SDL_NumJoysticks();
|
||||
|
||||
for (int i = 0; i < joystickCount; i++) {
|
||||
_availableDeviceNames << SDL_JoystickName(i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JoystickScriptingInterface::~JoystickScriptingInterface() {
|
||||
qDeleteAll(_openJoysticks);
|
||||
|
||||
#ifdef HAVE_SDL
|
||||
SDL_Quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void JoystickScriptingInterface::update() {
|
||||
#ifdef HAVE_SDL
|
||||
PerformanceTimer perfTimer("JoystickScriptingInterface::update");
|
||||
SDL_JoystickUpdate();
|
||||
|
||||
foreach(Joystick* joystick, _openJoysticks) {
|
||||
joystick->update();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
Joystick* JoystickScriptingInterface::joystickWithName(const QString& name) {
|
||||
Joystick* matchingJoystick = _openJoysticks.value(name);
|
||||
#ifdef HAVE_SDL
|
||||
if (!matchingJoystick) {
|
||||
// we haven't opened a joystick with this name yet - enumerate our SDL devices and see if it exists
|
||||
int joystickCount = SDL_NumJoysticks();
|
||||
|
||||
for (int i = 0; i < joystickCount; i++) {
|
||||
if (SDL_JoystickName(i) == name) {
|
||||
matchingJoystick = _openJoysticks.insert(name, new Joystick(name, SDL_JoystickOpen(i))).value();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "No matching joystick found with name" << name << "- returning NULL pointer.";
|
||||
}
|
||||
#endif
|
||||
|
||||
return matchingJoystick;
|
||||
}
|
||||
|
||||
|
43
interface/src/scripting/JoystickScriptingInterface.h
Normal file
43
interface/src/scripting/JoystickScriptingInterface.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// JoystickScriptingInterface.h
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/15/14.
|
||||
// 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_JoystickScriptingInterface_h
|
||||
#define hifi_JoystickScriptingInterface_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
#include "devices/Joystick.h"
|
||||
|
||||
/// Handles joystick input through SDL.
|
||||
class JoystickScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QStringList availableJoystickNames READ getAvailableJoystickNames)
|
||||
public:
|
||||
static JoystickScriptingInterface& getInstance();
|
||||
|
||||
const QStringList& getAvailableJoystickNames() const { return _availableDeviceNames; }
|
||||
|
||||
void update();
|
||||
|
||||
public slots:
|
||||
Joystick* joystickWithName(const QString& name);
|
||||
|
||||
private:
|
||||
JoystickScriptingInterface();
|
||||
~JoystickScriptingInterface();
|
||||
|
||||
QMap<QString, Joystick*> _openJoysticks;
|
||||
QStringList _availableDeviceNames;
|
||||
};
|
||||
|
||||
#endif // hifi_JoystickScriptingInterface_h
|
|
@ -136,6 +136,7 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) {
|
|||
|
||||
|
||||
ui->noRunningScriptsLabel->setVisible(list.isEmpty());
|
||||
ui->runningScriptsList->setVisible(!list.isEmpty());
|
||||
ui->reloadAllButton->setVisible(!list.isEmpty());
|
||||
ui->stopAllButton->setVisible(!list.isEmpty());
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>324</width>
|
||||
<height>643</height>
|
||||
<width>319</width>
|
||||
<height>481</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -29,57 +29,12 @@
|
|||
<property name="bottomMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="header" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="widgetTitle">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #0e7077;
|
||||
font-size: 20px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Running Scripts</string>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="indent">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="runningScriptsArea" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
|
@ -157,7 +112,7 @@ font: bold 16px;
|
|||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>8</height>
|
||||
<height>4</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
|
@ -218,6 +173,12 @@ font: bold 16px;
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_4" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
|
@ -236,6 +197,12 @@ font: bold 16px;
|
|||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="runningScriptsList">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Helvetica,Arial,sans-serif</family>
|
||||
|
@ -252,10 +219,13 @@ font: bold 16px;
|
|||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
|
@ -268,7 +238,7 @@ font: bold 16px;
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>284</width>
|
||||
<width>264</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -278,6 +248,9 @@ font: bold 16px;
|
|||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font-size: 14px;</string>
|
||||
</property>
|
||||
|
@ -303,14 +276,20 @@ font: bold 16px;
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="noRunningScriptsLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 14px;</string>
|
||||
<string notr="true">font: 14px; color: #5f5f5f;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>There are no scripts currently running.</string>
|
||||
<string>There are no scripts running.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -325,15 +304,9 @@ font: bold 16px;
|
|||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>2</verstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
|
@ -352,6 +325,12 @@ font: bold 16px;
|
|||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
|
@ -432,6 +411,12 @@ font: bold 16px;</string>
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="scriptListView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
static const int MAGIC_NUMBER_SIZE = 8;
|
||||
static const char MAGIC_NUMBER[MAGIC_NUMBER_SIZE] = {17, 72, 70, 82, 13, 10, 26, 10};
|
||||
// Version (Major, Minor)
|
||||
static const QPair<quint8, quint8> VERSION(0, 1);
|
||||
static const QPair<quint8, quint8> VERSION(0, 2);
|
||||
|
||||
int SCALE_RADIX = 10;
|
||||
int BLENDSHAPE_RADIX = 15;
|
||||
|
@ -118,12 +118,6 @@ bool readQuat(QDataStream& stream, glm::quat& value) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void writeFloat(QDataStream& stream, float value, int radix) {
|
||||
unsigned char buffer[256];
|
||||
int writtenToBuffer = packFloatScalarToSignedTwoByteFixed(buffer, value, radix);
|
||||
stream.writeRawData(reinterpret_cast<char*>(buffer), writtenToBuffer);
|
||||
}
|
||||
|
||||
bool readFloat(QDataStream& stream, float& value, int radix) {
|
||||
int floatByteSize = 2; // 1 floats * 2 bytes
|
||||
int16_t buffer[256];
|
||||
|
@ -185,7 +179,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) {
|
|||
// Orientation
|
||||
writeQuat(fileStream, context.orientation);
|
||||
// Scale
|
||||
writeFloat(fileStream, context.scale, SCALE_RADIX);
|
||||
fileStream << context.scale;
|
||||
// Head model
|
||||
fileStream << context.headModel;
|
||||
// Skeleton model
|
||||
|
@ -204,7 +198,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) {
|
|||
// Orientation
|
||||
writeQuat(fileStream, data.rotation);
|
||||
// Scale
|
||||
writeFloat(fileStream, data.scale, SCALE_RADIX);
|
||||
fileStream << data.scale;
|
||||
}
|
||||
|
||||
// RECORDING
|
||||
|
@ -231,7 +225,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) {
|
|||
for (quint32 j = 0; j < numBlendshapes; ++j) {
|
||||
if (i == 0 ||
|
||||
frame._blendshapeCoefficients[j] != previousFrame._blendshapeCoefficients[j]) {
|
||||
writeFloat(stream, frame.getBlendshapeCoefficients()[j], BLENDSHAPE_RADIX);
|
||||
stream << frame.getBlendshapeCoefficients()[j];
|
||||
mask.setBit(maskIndex);
|
||||
}
|
||||
++maskIndex;
|
||||
|
@ -277,7 +271,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) {
|
|||
mask.resize(mask.size() + 1);
|
||||
}
|
||||
if (i == 0 || frame._scale != previousFrame._scale) {
|
||||
writeFloat(stream, frame._scale, SCALE_RADIX);
|
||||
stream << frame._scale;
|
||||
mask.setBit(maskIndex);
|
||||
}
|
||||
maskIndex++;
|
||||
|
@ -297,7 +291,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) {
|
|||
mask.resize(mask.size() + 1);
|
||||
}
|
||||
if (i == 0 || frame._leanSideways != previousFrame._leanSideways) {
|
||||
writeFloat(stream, frame._leanSideways, LEAN_RADIX);
|
||||
stream << frame._leanSideways;
|
||||
mask.setBit(maskIndex);
|
||||
}
|
||||
maskIndex++;
|
||||
|
@ -307,7 +301,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) {
|
|||
mask.resize(mask.size() + 1);
|
||||
}
|
||||
if (i == 0 || frame._leanForward != previousFrame._leanForward) {
|
||||
writeFloat(stream, frame._leanForward, LEAN_RADIX);
|
||||
stream << frame._leanForward;
|
||||
mask.setBit(maskIndex);
|
||||
}
|
||||
maskIndex++;
|
||||
|
@ -438,7 +432,7 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString
|
|||
|
||||
QPair<quint8, quint8> version;
|
||||
fileStream >> version; // File format version
|
||||
if (version != VERSION) {
|
||||
if (version != VERSION && version != QPair<quint8, quint8>(0,1)) {
|
||||
qDebug() << "ERROR: This file format version is not supported.";
|
||||
return recording;
|
||||
}
|
||||
|
@ -484,10 +478,10 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString
|
|||
}
|
||||
|
||||
// Scale
|
||||
if (!readFloat(fileStream, context.scale, SCALE_RADIX)) {
|
||||
qDebug() << "Couldn't read file correctly. (Invalid float)";
|
||||
recording.clear();
|
||||
return recording;
|
||||
if (version == QPair<quint8, quint8>(0,1)) {
|
||||
readFloat(fileStream, context.scale, SCALE_RADIX);
|
||||
} else {
|
||||
fileStream >> context.scale;
|
||||
}
|
||||
// Head model
|
||||
fileStream >> context.headModel;
|
||||
|
@ -519,9 +513,10 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString
|
|||
}
|
||||
|
||||
// Scale
|
||||
if (!readFloat(fileStream, data.scale, SCALE_RADIX)) {
|
||||
qDebug() << "Couldn't read attachment correctly. (Invalid float)";
|
||||
continue;
|
||||
if (version == QPair<quint8, quint8>(0,1)) {
|
||||
readFloat(fileStream, data.scale, SCALE_RADIX);
|
||||
} else {
|
||||
fileStream >> data.scale;
|
||||
}
|
||||
context.attachments << data;
|
||||
}
|
||||
|
@ -548,8 +543,12 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString
|
|||
}
|
||||
frame._blendshapeCoefficients.resize(numBlendshapes);
|
||||
for (quint32 j = 0; j < numBlendshapes; ++j) {
|
||||
if (!mask[maskIndex++] || !readFloat(stream, frame._blendshapeCoefficients[j], BLENDSHAPE_RADIX)) {
|
||||
if (!mask[maskIndex++]) {
|
||||
frame._blendshapeCoefficients[j] = previousFrame._blendshapeCoefficients[j];
|
||||
} else if (version == QPair<quint8, quint8>(0,1)) {
|
||||
readFloat(stream, frame._blendshapeCoefficients[j], BLENDSHAPE_RADIX);
|
||||
} else {
|
||||
stream >> frame._blendshapeCoefficients[j];
|
||||
}
|
||||
}
|
||||
// Joint Rotations
|
||||
|
@ -571,20 +570,32 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString
|
|||
frame._rotation = previousFrame._rotation;
|
||||
}
|
||||
|
||||
if (!mask[maskIndex++] || !readFloat(stream, frame._scale, SCALE_RADIX)) {
|
||||
if (!mask[maskIndex++]) {
|
||||
frame._scale = previousFrame._scale;
|
||||
} else if (version == QPair<quint8, quint8>(0,1)) {
|
||||
readFloat(stream, frame._scale, SCALE_RADIX);
|
||||
} else {
|
||||
stream >> frame._scale;
|
||||
}
|
||||
|
||||
if (!mask[maskIndex++] || !readQuat(stream, frame._headRotation)) {
|
||||
frame._headRotation = previousFrame._headRotation;
|
||||
}
|
||||
|
||||
if (!mask[maskIndex++] || !readFloat(stream, frame._leanSideways, LEAN_RADIX)) {
|
||||
if (!mask[maskIndex++]) {
|
||||
frame._leanSideways = previousFrame._leanSideways;
|
||||
} else if (version == QPair<quint8, quint8>(0,1)) {
|
||||
readFloat(stream, frame._leanSideways, LEAN_RADIX);
|
||||
} else {
|
||||
stream >> frame._leanSideways;
|
||||
}
|
||||
|
||||
if (!mask[maskIndex++] || !readFloat(stream, frame._leanForward, LEAN_RADIX)) {
|
||||
if (!mask[maskIndex++]) {
|
||||
frame._leanForward = previousFrame._leanForward;
|
||||
} else if (version == QPair<quint8, quint8>(0,1)) {
|
||||
readFloat(stream, frame._leanForward, LEAN_RADIX);
|
||||
} else {
|
||||
stream >> frame._leanForward;
|
||||
}
|
||||
|
||||
if (!mask[maskIndex++] || !readVec3(stream, frame._lookAtPosition)) {
|
||||
|
|
259
libraries/entities/src/EntityCollisionSystem.cpp
Normal file
259
libraries/entities/src/EntityCollisionSystem.cpp
Normal file
|
@ -0,0 +1,259 @@
|
|||
//
|
||||
// EntityCollisionSystem.cpp
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 9/23/14.
|
||||
// Copyright 2013-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 <algorithm>
|
||||
#include <AbstractAudioInterface.h>
|
||||
#include <VoxelTree.h>
|
||||
#include <AvatarData.h>
|
||||
#include <HeadData.h>
|
||||
#include <HandData.h>
|
||||
|
||||
#include "EntityItem.h"
|
||||
#include "EntityCollisionSystem.h"
|
||||
#include "EntityEditPacketSender.h"
|
||||
#include "EntityTree.h"
|
||||
#include "EntityTreeElement.h"
|
||||
|
||||
const int MAX_COLLISIONS_PER_Entity = 16;
|
||||
|
||||
EntityCollisionSystem::EntityCollisionSystem(EntityEditPacketSender* packetSender,
|
||||
EntityTree* Entities, VoxelTree* voxels, AbstractAudioInterface* audio,
|
||||
AvatarHashMap* avatars) : _collisions(MAX_COLLISIONS_PER_Entity) {
|
||||
init(packetSender, Entities, voxels, audio, avatars);
|
||||
}
|
||||
|
||||
void EntityCollisionSystem::init(EntityEditPacketSender* packetSender,
|
||||
EntityTree* Entities, VoxelTree* voxels, AbstractAudioInterface* audio,
|
||||
AvatarHashMap* avatars) {
|
||||
_packetSender = packetSender;
|
||||
_entities = Entities;
|
||||
_voxels = voxels;
|
||||
_audio = audio;
|
||||
_avatars = avatars;
|
||||
}
|
||||
|
||||
EntityCollisionSystem::~EntityCollisionSystem() {
|
||||
}
|
||||
|
||||
void EntityCollisionSystem::update() {
|
||||
// update all Entities
|
||||
if (_entities->tryLockForRead()) {
|
||||
QList<EntityItem*>& movingEntities = _entities->getMovingEntities();
|
||||
foreach (EntityItem* entity, movingEntities) {
|
||||
checkEntity(entity);
|
||||
}
|
||||
_entities->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EntityCollisionSystem::checkEntity(EntityItem* entity) {
|
||||
updateCollisionWithVoxels(entity);
|
||||
updateCollisionWithEntities(entity);
|
||||
updateCollisionWithAvatars(entity);
|
||||
}
|
||||
|
||||
void EntityCollisionSystem::emitGlobalEntityCollisionWithVoxel(EntityItem* entity,
|
||||
VoxelDetail* voxelDetails, const CollisionInfo& collision) {
|
||||
EntityItemID entityItemID = entity->getEntityItemID();
|
||||
emit EntityCollisionWithVoxel(entityItemID, *voxelDetails, collision);
|
||||
}
|
||||
|
||||
void EntityCollisionSystem::emitGlobalEntityCollisionWithEntity(EntityItem* entityA,
|
||||
EntityItem* entityB, const CollisionInfo& collision) {
|
||||
|
||||
EntityItemID idA = entityA->getEntityItemID();
|
||||
EntityItemID idB = entityB->getEntityItemID();
|
||||
emit EntityCollisionWithEntity(idA, idB, collision);
|
||||
}
|
||||
|
||||
void EntityCollisionSystem::updateCollisionWithVoxels(EntityItem* entity) {
|
||||
glm::vec3 center = entity->getPosition() * (float)(TREE_SCALE);
|
||||
float radius = entity->getRadius() * (float)(TREE_SCALE);
|
||||
const float ELASTICITY = 0.4f;
|
||||
const float DAMPING = 0.05f;
|
||||
CollisionInfo collisionInfo;
|
||||
collisionInfo._damping = DAMPING;
|
||||
collisionInfo._elasticity = ELASTICITY;
|
||||
VoxelDetail* voxelDetails = NULL;
|
||||
if (_voxels->findSpherePenetration(center, radius, collisionInfo._penetration, (void**)&voxelDetails)) {
|
||||
|
||||
// findSpherePenetration() only computes the penetration but we also want some other collision info
|
||||
// so we compute it ourselves here. Note that we must multiply scale by TREE_SCALE when feeding
|
||||
// the results to systems outside of this octree reference frame.
|
||||
collisionInfo._contactPoint = (float)TREE_SCALE * (entity->getPosition() + entity->getRadius() * glm::normalize(collisionInfo._penetration));
|
||||
// let the global script run their collision scripts for Entities if they have them
|
||||
emitGlobalEntityCollisionWithVoxel(entity, voxelDetails, collisionInfo);
|
||||
|
||||
// we must scale back down to the octree reference frame before updating the Entity properties
|
||||
collisionInfo._penetration /= (float)(TREE_SCALE);
|
||||
collisionInfo._contactPoint /= (float)(TREE_SCALE);
|
||||
|
||||
applyHardCollision(entity, collisionInfo);
|
||||
delete voxelDetails; // cleanup returned details
|
||||
}
|
||||
}
|
||||
|
||||
void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) {
|
||||
glm::vec3 center = entityA->getPosition() * (float)(TREE_SCALE);
|
||||
float radius = entityA->getRadius() * (float)(TREE_SCALE);
|
||||
glm::vec3 penetration;
|
||||
EntityItem* entityB;
|
||||
if (_entities->findSpherePenetration(center, radius, penetration, (void**)&entityB, Octree::NoLock)) {
|
||||
// NOTE: 'penetration' is the depth that 'entityA' overlaps 'entityB'. It points from A into B.
|
||||
glm::vec3 penetrationInTreeUnits = penetration / (float)(TREE_SCALE);
|
||||
|
||||
// Even if the Entities overlap... when the Entities are already moving appart
|
||||
// we don't want to count this as a collision.
|
||||
glm::vec3 relativeVelocity = entityA->getVelocity() - entityB->getVelocity();
|
||||
|
||||
bool movingTowardEachOther = glm::dot(relativeVelocity, penetrationInTreeUnits) > 0.0f;
|
||||
bool doCollisions = movingTowardEachOther; // don't do collisions if the entities are moving away from each other
|
||||
|
||||
if (doCollisions) {
|
||||
quint64 now = usecTimestampNow();
|
||||
|
||||
CollisionInfo collision;
|
||||
collision._penetration = penetration;
|
||||
// for now the contactPoint is the average between the the two paricle centers
|
||||
collision._contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition());
|
||||
emitGlobalEntityCollisionWithEntity(entityA, entityB, collision);
|
||||
|
||||
glm::vec3 axis = glm::normalize(penetration);
|
||||
glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis;
|
||||
|
||||
float massA = entityA->getMass();
|
||||
float massB = entityB->getMass();
|
||||
float totalMass = massA + massB;
|
||||
|
||||
// handle Entity A
|
||||
glm::vec3 newVelocityA = entityA->getVelocity() - axialVelocity * (2.0f * massB / totalMass);
|
||||
glm::vec3 newPositionA = entityA->getPosition() - 0.5f * penetrationInTreeUnits;
|
||||
|
||||
EntityItemProperties propertiesA = entityA->getProperties();
|
||||
EntityItemID idA(entityA->getID());
|
||||
propertiesA.setVelocity(newVelocityA * (float)TREE_SCALE);
|
||||
propertiesA.setPosition(newPositionA * (float)TREE_SCALE);
|
||||
propertiesA.setLastEdited(now);
|
||||
|
||||
_entities->updateEntity(idA, propertiesA);
|
||||
_packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idA, propertiesA);
|
||||
|
||||
glm::vec3 newVelocityB = entityB->getVelocity() + axialVelocity * (2.0f * massA / totalMass);
|
||||
glm::vec3 newPositionB = entityB->getPosition() + 0.5f * penetrationInTreeUnits;
|
||||
|
||||
EntityItemProperties propertiesB = entityB->getProperties();
|
||||
|
||||
EntityItemID idB(entityB->getID());
|
||||
propertiesB.setVelocity(newVelocityB * (float)TREE_SCALE);
|
||||
propertiesB.setPosition(newPositionB * (float)TREE_SCALE);
|
||||
propertiesB.setLastEdited(now);
|
||||
|
||||
_entities->updateEntity(idB, propertiesB);
|
||||
_packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idB, propertiesB);
|
||||
|
||||
// TODO: Do we need this?
|
||||
//_packetSender->releaseQueuedMessages();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) {
|
||||
|
||||
// Entities that are in hand, don't collide with avatars
|
||||
if (!_avatars) {
|
||||
return;
|
||||
}
|
||||
|
||||
glm::vec3 center = entity->getPosition() * (float)(TREE_SCALE);
|
||||
float radius = entity->getRadius() * (float)(TREE_SCALE);
|
||||
const float ELASTICITY = 0.9f;
|
||||
const float DAMPING = 0.1f;
|
||||
glm::vec3 penetration;
|
||||
|
||||
_collisions.clear();
|
||||
foreach (const AvatarSharedPointer& avatarPointer, _avatars->getAvatarHash()) {
|
||||
AvatarData* avatar = avatarPointer.data();
|
||||
|
||||
float totalRadius = avatar->getBoundingRadius() + radius;
|
||||
glm::vec3 relativePosition = center - avatar->getPosition();
|
||||
if (glm::dot(relativePosition, relativePosition) > (totalRadius * totalRadius)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (avatar->findSphereCollisions(center, radius, _collisions)) {
|
||||
int numCollisions = _collisions.size();
|
||||
for (int i = 0; i < numCollisions; ++i) {
|
||||
CollisionInfo* collision = _collisions.getCollision(i);
|
||||
collision->_damping = DAMPING;
|
||||
collision->_elasticity = ELASTICITY;
|
||||
|
||||
collision->_addedVelocity /= (float)(TREE_SCALE);
|
||||
glm::vec3 relativeVelocity = collision->_addedVelocity - entity->getVelocity();
|
||||
|
||||
if (glm::dot(relativeVelocity, collision->_penetration) <= 0.f) {
|
||||
// only collide when Entity and collision point are moving toward each other
|
||||
// (doing this prevents some "collision snagging" when Entity penetrates the object)
|
||||
collision->_penetration /= (float)(TREE_SCALE);
|
||||
applyHardCollision(entity, *collision);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityCollisionSystem::applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo) {
|
||||
// HALTING_* params are determined using expected acceleration of gravity over some timescale.
|
||||
// This is a HACK for entities that bounce in a 1.0 gravitational field and should eventually be made more universal.
|
||||
const float HALTING_ENTITY_PERIOD = 0.0167f; // ~1/60th of a second
|
||||
const float HALTING_ENTITY_SPEED = 9.8 * HALTING_ENTITY_PERIOD / (float)(TREE_SCALE);
|
||||
|
||||
//
|
||||
// Update the entity in response to a hard collision. Position will be reset exactly
|
||||
// to outside the colliding surface. Velocity will be modified according to elasticity.
|
||||
//
|
||||
// if elasticity = 0.0, collision is inelastic (vel normal to collision is lost)
|
||||
// if elasticity = 1.0, collision is 100% elastic.
|
||||
//
|
||||
glm::vec3 position = entity->getPosition();
|
||||
glm::vec3 velocity = entity->getVelocity();
|
||||
|
||||
const float EPSILON = 0.0f;
|
||||
glm::vec3 relativeVelocity = collisionInfo._addedVelocity - velocity;
|
||||
float velocityDotPenetration = glm::dot(relativeVelocity, collisionInfo._penetration);
|
||||
if (velocityDotPenetration < EPSILON) {
|
||||
// entity is moving into collision surface
|
||||
//
|
||||
// TODO: do something smarter here by comparing the mass of the entity vs that of the other thing
|
||||
// (other's mass could be stored in the Collision Info). The smaller mass should surrender more
|
||||
// position offset and should slave more to the other's velocity in the static-friction case.
|
||||
position -= collisionInfo._penetration;
|
||||
|
||||
if (glm::length(relativeVelocity) < HALTING_ENTITY_SPEED) {
|
||||
// static friction kicks in and entities moves with colliding object
|
||||
velocity = collisionInfo._addedVelocity;
|
||||
} else {
|
||||
glm::vec3 direction = glm::normalize(collisionInfo._penetration);
|
||||
velocity += glm::dot(relativeVelocity, direction) * (1.0f + collisionInfo._elasticity) * direction; // dynamic reflection
|
||||
velocity += glm::clamp(collisionInfo._damping, 0.0f, 1.0f) * (relativeVelocity - glm::dot(relativeVelocity, direction) * direction); // dynamic friction
|
||||
}
|
||||
}
|
||||
|
||||
EntityItemProperties properties = entity->getProperties();
|
||||
EntityItemID entityItemID(entity->getID());
|
||||
|
||||
properties.setPosition(position * (float)TREE_SCALE);
|
||||
properties.setVelocity(velocity * (float)TREE_SCALE);
|
||||
properties.setLastEdited(usecTimestampNow());
|
||||
|
||||
_entities->updateEntity(entityItemID, properties);
|
||||
_packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, entityItemID, properties);
|
||||
}
|
75
libraries/entities/src/EntityCollisionSystem.h
Normal file
75
libraries/entities/src/EntityCollisionSystem.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// EntityCollisionSystem.h
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 9/23/14.
|
||||
// Copyright 2013-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_EntityCollisionSystem_h
|
||||
#define hifi_EntityCollisionSystem_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <AvatarHashMap.h>
|
||||
#include <CollisionInfo.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <OctreePacketData.h>
|
||||
#include <VoxelDetail.h>
|
||||
|
||||
#include "EntityItem.h"
|
||||
|
||||
class AbstractAudioInterface;
|
||||
class AvatarData;
|
||||
class EntityEditPacketSender;
|
||||
class EntityTree;
|
||||
class VoxelTree;
|
||||
|
||||
class EntityCollisionSystem : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EntityCollisionSystem(EntityEditPacketSender* packetSender = NULL, EntityTree* Entitys = NULL,
|
||||
VoxelTree* voxels = NULL, AbstractAudioInterface* audio = NULL,
|
||||
AvatarHashMap* avatars = NULL);
|
||||
|
||||
void init(EntityEditPacketSender* packetSender, EntityTree* Entitys, VoxelTree* voxels,
|
||||
AbstractAudioInterface* audio = NULL, AvatarHashMap* _avatars = NULL);
|
||||
|
||||
~EntityCollisionSystem();
|
||||
|
||||
void update();
|
||||
|
||||
void checkEntity(EntityItem* Entity);
|
||||
void updateCollisionWithVoxels(EntityItem* Entity);
|
||||
void updateCollisionWithEntities(EntityItem* Entity);
|
||||
void updateCollisionWithAvatars(EntityItem* Entity);
|
||||
void queueEntityPropertiesUpdate(EntityItem* Entity);
|
||||
void updateCollisionSound(EntityItem* Entity, const glm::vec3 &penetration, float frequency);
|
||||
|
||||
signals:
|
||||
void EntityCollisionWithVoxel(const EntityItemID& entityItemID, const VoxelDetail& voxel, const CollisionInfo& penetration);
|
||||
void EntityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& penetration);
|
||||
|
||||
private:
|
||||
void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo);
|
||||
|
||||
static bool updateOperation(OctreeElement* element, void* extraData);
|
||||
void emitGlobalEntityCollisionWithVoxel(EntityItem* Entity, VoxelDetail* voxelDetails, const CollisionInfo& penetration);
|
||||
void emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const CollisionInfo& penetration);
|
||||
|
||||
EntityEditPacketSender* _packetSender;
|
||||
EntityTree* _entities;
|
||||
VoxelTree* _voxels;
|
||||
AbstractAudioInterface* _audio;
|
||||
AvatarHashMap* _avatars;
|
||||
CollisionList _collisions;
|
||||
};
|
||||
|
||||
#endif // hifi_EntityCollisionSystem_h
|
|
@ -535,6 +535,10 @@ bool EntityItem::isRestingOnSurface() const {
|
|||
|
||||
void EntityItem::update(const quint64& updateTime) {
|
||||
bool wantDebug = false;
|
||||
|
||||
if (_lastUpdated == 0) {
|
||||
_lastUpdated = updateTime;
|
||||
}
|
||||
|
||||
float timeElapsed = (float)(updateTime - _lastUpdated) / (float)(USECS_PER_SECOND);
|
||||
|
||||
|
@ -578,7 +582,7 @@ void EntityItem::update(const quint64& updateTime) {
|
|||
_lastUpdated = updateTime;
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << "********** EntityItem::update() .... SETTING _lastUpdated=" << _lastUpdated;
|
||||
qDebug() << " ********** EntityItem::update() .... SETTING _lastUpdated=" << _lastUpdated;
|
||||
}
|
||||
|
||||
if (hasAngularVelocity()) {
|
||||
|
@ -614,7 +618,7 @@ void EntityItem::update(const quint64& updateTime) {
|
|||
glm::vec3 newPosition = position + (velocity * timeElapsed);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << "EntityItem::update()....";
|
||||
qDebug() << " EntityItem::update()....";
|
||||
qDebug() << " timeElapsed:" << timeElapsed;
|
||||
qDebug() << " old AACube:" << getMaximumAACube();
|
||||
qDebug() << " old position:" << position;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <Octree.h> // for EncodeBitstreamParams class
|
||||
#include <OctreeElement.h> // for OctreeElement::AppendState
|
||||
#include <OctreePacketData.h>
|
||||
#include <VoxelDetail.h>
|
||||
|
||||
#include "EntityItemID.h"
|
||||
#include "EntityItemProperties.h"
|
||||
|
@ -227,6 +228,7 @@ public:
|
|||
// TODO: We need to get rid of these users of getRadius()...
|
||||
float getRadius() const;
|
||||
|
||||
void applyHardCollision(const CollisionInfo& collisionInfo);
|
||||
|
||||
protected:
|
||||
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
|
||||
|
|
|
@ -24,7 +24,7 @@ EntityItemProperties::EntityItemProperties() :
|
|||
|
||||
_id(UNKNOWN_ENTITY_ID),
|
||||
_idSet(false),
|
||||
_lastEdited(0),
|
||||
_lastEdited(0), // ????
|
||||
_created(UNKNOWN_CREATED_TIME),
|
||||
_type(EntityTypes::Unknown),
|
||||
|
||||
|
|
|
@ -90,6 +90,8 @@ public:
|
|||
|
||||
// editing related features supported by all entities
|
||||
quint64 getLastEdited() const { return _lastEdited; }
|
||||
float getEditedAgo() const /// Elapsed seconds since this entity was last edited
|
||||
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
|
||||
EntityPropertyFlags getChangedProperties() const;
|
||||
|
||||
/// used by EntityScriptingInterface to return EntityItemProperties for unknown models
|
||||
|
@ -121,14 +123,14 @@ public:
|
|||
float getMass() const { return _mass; }
|
||||
void setMass(float value) { _mass = value; _massChanged = true; }
|
||||
|
||||
/// velocity in domain scale units (0.0-1.0) per second
|
||||
/// velocity in meters (0.0-1.0) per second
|
||||
const glm::vec3& getVelocity() const { return _velocity; }
|
||||
/// velocity in domain scale units (0.0-1.0) per second
|
||||
/// velocity in meters (0.0-1.0) per second
|
||||
void setVelocity(const glm::vec3& value) { _velocity = value; _velocityChanged = true; }
|
||||
|
||||
/// gravity in domain scale units (0.0-1.0) per second squared
|
||||
/// gravity in meters (0.0-TREE_SCALE) per second squared
|
||||
const glm::vec3& getGravity() const { return _gravity; }
|
||||
/// gravity in domain scale units (0.0-1.0) per second squared
|
||||
/// gravity in meters (0.0-TREE_SCALE) per second squared
|
||||
void setGravity(const glm::vec3& value) { _gravity = value; _gravityChanged = true; }
|
||||
|
||||
float getDamping() const { return _damping; }
|
||||
|
@ -219,9 +221,10 @@ public:
|
|||
bool getVisible() const { return _visible; }
|
||||
void setVisible(bool value) { _visible = value; _visibleChanged = true; }
|
||||
|
||||
private:
|
||||
void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; }
|
||||
|
||||
private:
|
||||
|
||||
QUuid _id;
|
||||
bool _idSet;
|
||||
quint64 _lastEdited;
|
||||
|
@ -285,4 +288,16 @@ Q_DECLARE_METATYPE(EntityItemProperties);
|
|||
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
|
||||
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties);
|
||||
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
||||
debug << "EntityItemProperties[" << "\n"
|
||||
<< " position:" << properties.getPosition() << "in meters" << "\n"
|
||||
<< " velocity:" << properties.getVelocity() << "in meters" << "\n"
|
||||
<< " last edited:" << properties.getLastEdited() << "\n"
|
||||
<< " edited ago:" << properties.getEditedAgo() << "\n"
|
||||
<< "]";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
#endif // hifi_EntityItemProperties_h
|
||||
|
|
|
@ -139,6 +139,8 @@ public:
|
|||
|
||||
void trackDeletedEntity(const EntityItemID& entityID);
|
||||
|
||||
QList<EntityItem*>& getMovingEntities() { return _movingEntities; }
|
||||
|
||||
private:
|
||||
|
||||
void updateChangingEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
|
||||
|
|
|
@ -732,9 +732,6 @@ bool findSpherePenetrationOp(OctreeElement* element, void* extraData) {
|
|||
if (!box.expandedContains(args->center, args->radius)) {
|
||||
return false;
|
||||
}
|
||||
if (!element->isLeaf()) {
|
||||
return true; // recurse on children
|
||||
}
|
||||
if (element->hasContent()) {
|
||||
glm::vec3 elementPenetration;
|
||||
if (element->findSpherePenetration(args->center, args->radius, elementPenetration, &args->penetratedObject)) {
|
||||
|
@ -744,6 +741,9 @@ bool findSpherePenetrationOp(OctreeElement* element, void* extraData) {
|
|||
args->found = true;
|
||||
}
|
||||
}
|
||||
if (!element->isLeaf()) {
|
||||
return true; // recurse on children
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -930,6 +930,9 @@ void Particle::applyHardCollision(const CollisionInfo& collisionInfo) {
|
|||
}
|
||||
|
||||
void Particle::update(const quint64& now) {
|
||||
if (_lastUpdated == 0) {
|
||||
_lastUpdated = now;
|
||||
}
|
||||
float timeElapsed = (float)(now - _lastUpdated) / (float)(USECS_PER_SECOND);
|
||||
_lastUpdated = now;
|
||||
|
||||
|
|
|
@ -72,11 +72,11 @@ void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) {
|
|||
out = qobject_cast<AudioInjector*>(object.toQObject());
|
||||
}
|
||||
|
||||
QScriptValue injectorToScriptValueInputController(QScriptEngine *engine, AbstractInputController* const &in) {
|
||||
QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) {
|
||||
return engine->newQObject(in);
|
||||
}
|
||||
|
||||
void injectorFromScriptValueInputController(const QScriptValue &object, AbstractInputController* &out) {
|
||||
void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputController* &out) {
|
||||
out = qobject_cast<AbstractInputController*>(object.toQObject());
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,7 @@ void ScriptEngine::init() {
|
|||
globalObject().setProperty("LocalVoxels", localVoxelsValue);
|
||||
|
||||
qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue);
|
||||
qScriptRegisterMetaType( this, injectorToScriptValueInputController, injectorFromScriptValueInputController);
|
||||
qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue);
|
||||
|
||||
qScriptRegisterMetaType(this, animationDetailsToScriptValue, animationDetailsFromScriptValue);
|
||||
|
||||
|
|
|
@ -51,4 +51,19 @@ Q_DECLARE_METATYPE(RayToVoxelIntersectionResult)
|
|||
QScriptValue rayToVoxelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToVoxelIntersectionResult& results);
|
||||
void rayToVoxelIntersectionResultFromScriptValue(const QScriptValue& object, RayToVoxelIntersectionResult& results);
|
||||
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const VoxelDetail& details) {
|
||||
const int TREE_SCALE = 16384; // ~10 miles.. This is the number of meters of the 0.0 to 1.0 voxel universe
|
||||
|
||||
debug << "VoxelDetail[ ("
|
||||
<< details.x * (float)TREE_SCALE << "," << details.y * (float)TREE_SCALE << "," << details.z * (float)TREE_SCALE
|
||||
<< " ) to ("
|
||||
<< details.x + details.s * (float)TREE_SCALE << "," << details.y + details.s * (float)TREE_SCALE
|
||||
<< "," << details.z + details.s * (float)TREE_SCALE << ") size: ("
|
||||
<< details.s * (float)TREE_SCALE << "," << details.s * (float)TREE_SCALE << "," << details.s * (float)TREE_SCALE << ")"
|
||||
<< " in meters]";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
#endif // hifi_VoxelDetail_h
|
||||
|
|
|
@ -5,6 +5,6 @@ setup_hifi_project(Script Network)
|
|||
include_glm()
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(animation fbx entities networking octree shared)
|
||||
link_hifi_libraries(shared octree voxels fbx metavoxels networking particles entities avatars audio animation script-engine)
|
||||
|
||||
link_shared_dependencies()
|
||||
|
|
Loading…
Reference in a new issue