Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Philip Rosedale 2013-12-18 20:55:57 -08:00
commit abd0951696
31 changed files with 648 additions and 175 deletions

View file

@ -9,11 +9,12 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
find_package(Qt5Network REQUIRED)
find_package(Qt5Widgets REQUIRED)
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME} TRUE)
qt5_use_modules(${TARGET_NAME} Network)
qt5_use_modules(${TARGET_NAME} Network Widgets)
# include glm
include(${MACRO_DIR}/IncludeGLM.cmake)

Binary file not shown.

View file

@ -0,0 +1,7 @@
QPlainTextEdit {
font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;
font-size: 16px;
padding-left: 28px;
color: #333333;
background-color: #FFFFFF;
}

View file

@ -143,11 +143,17 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_pasteMode(false)
{
_applicationStartupTime = startup_time;
switchToResourcesParentIfRequired();
QFontDatabase::addApplicationFont("resources/styles/Inconsolata.otf");
_window->setWindowTitle("Interface");
qDebug( "[VERSION] Build sequence: %i", BUILD_VERSION);
qInstallMessageHandler(messageHandler);
// call Menu getInstance static method to set up the menu
_window->setMenuBar(Menu::getInstance());
qDebug("[VERSION] Build sequence: %i", BUILD_VERSION);
unsigned int listenPort = 0; // bind to an ephemeral port by default
const char** constArgv = const_cast<const char**>(argv);
@ -173,16 +179,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
// network receive thread and voxel parsing thread are both controlled by the --nonblocking command line
_enableProcessVoxelsThread = _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking");
// setup QSettings
#ifdef Q_OS_MAC
QString resourcesPath = QCoreApplication::applicationDirPath() + "/../Resources";
#else
QString resourcesPath = QCoreApplication::applicationDirPath() + "/resources";
#endif
// read the ApplicationInfo.ini file for Name/Version/Domain information
QSettings applicationInfo(resourcesPath + "/info/ApplicationInfo.ini", QSettings::IniFormat);
QSettings applicationInfo("resources/info/ApplicationInfo.ini", QSettings::IniFormat);
// set the associated application properties
applicationInfo.beginGroup("INFO");
@ -191,11 +190,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
setApplicationVersion(applicationInfo.value("version").toString());
setOrganizationName(applicationInfo.value("organizationName").toString());
setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
_settings = new QSettings(this);
// call Menu getInstance static method to set up the menu
_window->setMenuBar(Menu::getInstance());
// Check to see if the user passed in a command line option for loading a local
// Voxel File.
@ -251,6 +247,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
}
Application::~Application() {
qInstallMessageHandler(NULL);
// make sure we don't call the idle timer any more
delete idleTimer;
@ -4462,7 +4461,8 @@ void Application::loadScript() {
bool wantMenuItems = true; // tells the ScriptEngine object to add menu items for itself
ScriptEngine* scriptEngine = new ScriptEngine(script, wantMenuItems, fileName, Menu::getInstance());
ScriptEngine* scriptEngine = new ScriptEngine(script, wantMenuItems, fileName, Menu::getInstance(),
&_controllerScriptingInterface);
scriptEngine->setupMenuItems();
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
@ -4490,3 +4490,12 @@ void Application::loadScript() {
// restore the main window's active state
_window->activateWindow();
}
void Application::toggleLogDialog() {
if (! _logDialog) {
_logDialog = new LogDialog(_glWidget);
_logDialog->show();
} else {
_logDialog->close();
}
}

View file

@ -18,6 +18,7 @@
#include <QSettings>
#include <QTouchEvent>
#include <QList>
#include <QPointer>
#include <NetworkPacket.h>
#include <NodeList.h>
@ -67,8 +68,11 @@
#include "ui/VoxelStatsDialog.h"
#include "ui/RearMirrorTools.h"
#include "ui/LodToolsDialog.h"
#include "ui/LogDialog.h"
#include "ParticleTreeRenderer.h"
#include "ParticleEditHandle.h"
#include "ControllerScriptingInterface.h"
class QAction;
class QActionGroup;
@ -222,7 +226,7 @@ public slots:
void decreaseVoxelSize();
void increaseVoxelSize();
void loadScript();
void toggleLogDialog();
private slots:
@ -503,6 +507,8 @@ private:
std::vector<VoxelFade> _voxelFades;
std::vector<Avatar*> _avatarFades;
ControllerScriptingInterface _controllerScriptingInterface;
QPointer<LogDialog> _logDialog;
};
#endif /* defined(__interface__Application__) */

View file

@ -0,0 +1,183 @@
//
// ControllerScriptingInterface.h
// hifi
//
// Created by Brad Hefta-Gaub on 12/17/13
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#include <HandData.h>
#include "Application.h"
#include "ControllerScriptingInterface.h"
const PalmData* ControllerScriptingInterface::getPrimaryPalm() const {
int leftPalmIndex, rightPalmIndex;
const HandData* handData = Application::getInstance()->getAvatar()->getHandData();
handData->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
if (rightPalmIndex != -1) {
return &handData->getPalms()[rightPalmIndex];
}
return NULL;
}
int ControllerScriptingInterface::getNumberOfActivePalms() const {
const HandData* handData = Application::getInstance()->getAvatar()->getHandData();
int numberOfPalms = handData->getNumPalms();
int numberOfActivePalms = 0;
for (int i = 0; i < numberOfPalms; i++) {
if (getPalm(i)->isActive()) {
numberOfActivePalms++;
}
}
return numberOfActivePalms;
}
const PalmData* ControllerScriptingInterface::getPalm(int palmIndex) const {
const HandData* handData = Application::getInstance()->getAvatar()->getHandData();
return &handData->getPalms()[palmIndex];
}
const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const {
const HandData* handData = Application::getInstance()->getAvatar()->getHandData();
int numberOfPalms = handData->getNumPalms();
int numberOfActivePalms = 0;
for (int i = 0; i < numberOfPalms; i++) {
if (getPalm(i)->isActive()) {
if (numberOfActivePalms == palmIndex) {
return &handData->getPalms()[i];
}
numberOfActivePalms++;
}
}
return NULL;
}
bool ControllerScriptingInterface::isPrimaryButtonPressed() const {
const PalmData* primaryPalm = getPrimaryPalm();
if (primaryPalm) {
if (primaryPalm->getControllerButtons() & BUTTON_FWD) {
return true;
}
}
return false;
}
glm::vec2 ControllerScriptingInterface::getPrimaryJoystickPosition() const {
const PalmData* primaryPalm = getPrimaryPalm();
if (primaryPalm) {
return glm::vec2(primaryPalm->getJoystickX(), primaryPalm->getJoystickY());
}
return glm::vec2(0);
}
int ControllerScriptingInterface::getNumberOfButtons() const {
return getNumberOfActivePalms() * NUMBER_OF_BUTTONS_PER_PALM;
}
bool ControllerScriptingInterface::isButtonPressed(int buttonIndex) const {
int palmIndex = buttonIndex / NUMBER_OF_BUTTONS_PER_PALM;
int buttonOnPalm = buttonIndex % NUMBER_OF_BUTTONS_PER_PALM;
const PalmData* palmData = getActivePalm(palmIndex);
if (palmData) {
switch (buttonOnPalm) {
case 0:
return palmData->getControllerButtons() & BUTTON_0;
case 1:
return palmData->getControllerButtons() & BUTTON_1;
case 2:
return palmData->getControllerButtons() & BUTTON_2;
case 3:
return palmData->getControllerButtons() & BUTTON_3;
case 4:
return palmData->getControllerButtons() & BUTTON_4;
case 5:
return palmData->getControllerButtons() & BUTTON_FWD;
}
}
return false;
}
int ControllerScriptingInterface::getNumberOfTriggers() const {
return getNumberOfActivePalms() * NUMBER_OF_TRIGGERS_PER_PALM;
}
float ControllerScriptingInterface::getTriggerValue(int triggerIndex) const {
// we know there's one trigger per palm, so the triggerIndex is the palm Index
int palmIndex = triggerIndex;
const PalmData* palmData = getActivePalm(palmIndex);
if (palmData) {
return palmData->getTrigger();
}
return 0.0f;
}
int ControllerScriptingInterface::getNumberOfJoysticks() const {
return getNumberOfActivePalms() * NUMBER_OF_JOYSTICKS_PER_PALM;
}
glm::vec2 ControllerScriptingInterface::getJoystickPosition(int joystickIndex) const {
// we know there's one joystick per palm, so the joystickIndex is the palm Index
int palmIndex = joystickIndex;
const PalmData* palmData = getActivePalm(palmIndex);
if (palmData) {
return glm::vec2(palmData->getJoystickX(), palmData->getJoystickY());
}
return glm::vec2(0);
}
int ControllerScriptingInterface::getNumberOfSpatialControls() const {
return getNumberOfActivePalms() * NUMBER_OF_SPATIALCONTROLS_PER_PALM;
}
glm::vec3 ControllerScriptingInterface::getSpatialControlPosition(int controlIndex) const {
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
const PalmData* palmData = getActivePalm(palmIndex);
if (palmData) {
switch (controlOfPalm) {
case PALM_SPATIALCONTROL:
return palmData->getPosition();
case TIP_SPATIALCONTROL:
return palmData->getTipPosition();
}
}
return glm::vec3(0); // bad index
}
glm::vec3 ControllerScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
const PalmData* palmData = getActivePalm(palmIndex);
if (palmData) {
switch (controlOfPalm) {
case PALM_SPATIALCONTROL:
return palmData->getVelocity();
case TIP_SPATIALCONTROL:
return palmData->getTipVelocity();
}
}
return glm::vec3(0); // bad index
}
glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex) const {
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
const PalmData* palmData = getActivePalm(palmIndex);
if (palmData) {
switch (controlOfPalm) {
case PALM_SPATIALCONTROL:
return palmData->getNormal();
case TIP_SPATIALCONTROL:
return palmData->getNormal(); // currently the tip doesn't have a unique normal, use the palm normal
}
}
return glm::vec3(0); // bad index
}

View file

@ -0,0 +1,52 @@
//
// ControllerScriptingInterface.h
// hifi
//
// Created by Brad Hefta-Gaub on 12/17/13
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__ControllerScriptingInterface__
#define __hifi__ControllerScriptingInterface__
#include <QtCore/QObject>
#include <AbstractControllerScriptingInterface.h>
/// handles scripting of input controller commands from JS
class ControllerScriptingInterface : public AbstractControllerScriptingInterface {
Q_OBJECT
public slots:
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;
private:
const PalmData* getPrimaryPalm() const;
const PalmData* getPalm(int palmIndex) const;
int getNumberOfActivePalms() const;
const PalmData* getActivePalm(int palmIndex) const;
};
const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip
const int NUMBER_OF_JOYSTICKS_PER_PALM = 1;
const int NUMBER_OF_TRIGGERS_PER_PALM = 1;
const int NUMBER_OF_BUTTONS_PER_PALM = 6;
const int PALM_SPATIALCONTROL = 0;
const int TIP_SPATIALCONTROL = 1;
#endif /* defined(__hifi__ControllerScriptingInterface__) */

View file

@ -6,12 +6,13 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "LogDisplay.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <QStringList>
#include "LogDisplay.h"
#include "Util.h"
using namespace std;
@ -91,6 +92,7 @@ void LogDisplay::setCharacterSize(unsigned width, unsigned height) {
void LogDisplay::addMessage(const char* ptr) {
pthread_mutex_lock(& _mutex);
emit logReceived(ptr);
// T-pipe, if requested
if (_stream != 0l) {
@ -118,7 +120,7 @@ void LogDisplay::addMessage(const char* ptr) {
_writePos = _chars;
}
if (++_writtenInLine >= _lineLength || c == '\0') {
if (c == '\0') {
// new line? store its start to the line buffer and mark next line as empty
++_lastLinePos;
@ -148,13 +150,24 @@ void LogDisplay::addMessage(const char* ptr) {
// remember start position in character buffer for next line and reset character count
_writeLineStartPos = _writePos;
_writtenInLine = 0;
}
}
pthread_mutex_unlock(& _mutex);
}
QStringList LogDisplay::getLogData() {
// wait for adding new log data whilr iterating over _lines
pthread_mutex_lock(& _mutex);
QStringList list;
int i = 0;
while (_lines[i] != *_lastLinePos) {
list.append(_lines[i++]);
}
pthread_mutex_unlock(& _mutex);
return list;
}
//
// Rendering
//

View file

@ -14,7 +14,8 @@
#include "ui/TextRenderer.h"
class LogDisplay {
class LogDisplay : public QObject {
Q_OBJECT
public:
static LogDisplay instance;
@ -43,6 +44,11 @@ public:
static unsigned const LINE_BUFFER_SIZE = 256; // number of lines that are buffered
static unsigned const MAX_MESSAGE_LENGTH = 512; // maximum number of characters for a message
QStringList getLogData();
signals:
void logReceived(QString message);
private:
// use static 'instance' to access the single instance
LogDisplay();

View file

@ -265,7 +265,7 @@ Menu::Menu() :
addDisabledActionAndSeparator(viewMenu, "Stats");
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L);
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, appInstance, SLOT(toggleLogDialog()));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, true);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true);
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails()));
@ -690,10 +690,10 @@ void Menu::addDisabledActionAndSeparator(QMenu* destinationMenu, const QString&
QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu,
const QString actionName,
const QKEYSEQUENCE& shortcut,
const QKeySequence& shortcut,
const QObject* receiver,
const char* member,
QACTION_MENUROLE role) {
QAction::MenuRole role) {
QAction* action;
if (receiver && member) {
@ -702,7 +702,7 @@ QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu,
action = destinationMenu->addAction(actionName);
action->setShortcut(shortcut);
}
action->setMenuRole((QAction::MenuRole)role);
action->setMenuRole(role);
_actionHash.insert(actionName, action);
@ -715,7 +715,7 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
const bool checked,
const QObject* receiver,
const char* member) {
QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, (QKEYSEQUENCE&)shortcut, receiver, member);
QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member);
action->setCheckable(true);
action->setChecked(checked);

View file

@ -76,10 +76,10 @@ public:
virtual QMenu* getActiveScriptsMenu() { return _activeScriptsMenu;}
virtual QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu,
const QString actionName,
const QKEYSEQUENCE& shortcut = 0,
const QKeySequence& shortcut = 0,
const QObject* receiver = NULL,
const char* member = NULL,
QACTION_MENUROLE role = NO_ROLE);
QAction::MenuRole role = QAction::NoRole);
virtual void removeAction(QMenu* menu, const QString& actionName);
public slots:
@ -146,7 +146,6 @@ private:
int _boundaryLevelAdjust;
QAction* _useVoxelShader;
int _maxVoxelPacketsPerSecond;
QMenu* _activeScriptsMenu;
};

View file

@ -19,11 +19,23 @@
#include <QDebug>
#include <QDir>
#include <SharedUtil.h>
int main(int argc, const char * argv[]) {
timeval startup_time;
gettimeofday(&startup_time, NULL);
// Debug option to demonstrate that the client's local time does not
// need to be in sync with any other network node. This forces clock
// skew for the individual client
const char* CLOCK_SKEW = "--clockSkew";
const char* clockSkewOption = getCmdOption(argc, argv, CLOCK_SKEW);
if (clockSkewOption) {
int clockSkew = atoi(clockSkewOption);
usecTimestampNowForceClockSkew(clockSkew);
qDebug("clockSkewOption=%s clockSkew=%d\n", clockSkewOption, clockSkew);
}
int exitCode;
{
Application app(argc, const_cast<char**>(argv), startup_time);

View file

@ -0,0 +1,75 @@
//
// LogDialog.cpp
// interface
//
// Created by Stojce Slavkovski on 12/12/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <QDesktopWidget>
#include <QTextBlock>
#include <QtGui>
#include "SharedUtil.h"
#include "ui/LogDialog.h"
#include "LogDisplay.h"
const int INITIAL_WIDTH = 720;
const float INITIAL_HEIGHT_RATIO = 0.6f;
int cursorMeta = qRegisterMetaType<QTextCursor>("QTextCursor");
int blockMeta = qRegisterMetaType<QTextBlock>("QTextBlock");
LogDialog::LogDialog(QWidget* parent) : QDialog(parent, Qt::Dialog) {
setWindowTitle("Log");
_logTextBox = new QPlainTextEdit(this);
_logTextBox->setReadOnly(true);
_logTextBox->show();
switchToResourcesParentIfRequired();
QFile styleSheet("resources/styles/log_dialog.qss");
if (styleSheet.open(QIODevice::ReadOnly)) {
setStyleSheet(styleSheet.readAll());
}
QDesktopWidget desktop;
QRect screen = desktop.screenGeometry();
resize(INITIAL_WIDTH, static_cast<int>(screen.height() * INITIAL_HEIGHT_RATIO));
move(screen.center() - rect().center());
setAttribute(Qt::WA_DeleteOnClose);
}
LogDialog::~LogDialog() {
deleteLater();
}
void LogDialog::showEvent(QShowEvent *e) {
_logTextBox->clear();
pthread_mutex_lock(& _mutex);
QStringList _logData = LogDisplay::instance.getLogData();
connect(&LogDisplay::instance, &LogDisplay::logReceived, this, &LogDialog::appendLogLine);
for(int i = 0; i < _logData.size(); ++i) {
appendLogLine(_logData[i]);
}
pthread_mutex_unlock(& _mutex);
}
void LogDialog::resizeEvent(QResizeEvent *e) {
_logTextBox->resize(width(), height());
}
void LogDialog::appendLogLine(QString logLine) {
if (isVisible()) {
pthread_mutex_lock(& _mutex);
_logTextBox->appendPlainText(logLine.simplified());
pthread_mutex_unlock(& _mutex);
_logTextBox->ensureCursorVisible();
}
}

View file

@ -0,0 +1,36 @@
//
// LogDialog.h
// interface
//
// Created by Stojce Slavkovski on 12/12/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__LogDialog__
#define __interface__LogDialog__
#include <QDialog>
#include <QPlainTextEdit>
class LogDialog : public QDialog {
Q_OBJECT
public:
LogDialog(QWidget* parent);
~LogDialog();
public slots:
void appendLogLine(QString logLine);
protected:
void resizeEvent(QResizeEvent* e);
void showEvent(QShowEvent* e);
private:
QPlainTextEdit* _logTextBox;
pthread_mutex_t _mutex;
};
#endif

View file

@ -53,9 +53,10 @@ public:
glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const;
glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const;
std::vector<PalmData>& getPalms() { return _palms; }
size_t getNumPalms() { return _palms.size(); }
PalmData& addNewPalm();
std::vector<PalmData>& getPalms() { return _palms; }
const std::vector<PalmData>& getPalms() const { return _palms; }
size_t getNumPalms() const { return _palms.size(); }
PalmData& addNewPalm();
/// Finds the indices of the left and right palms according to their locations, or -1 if either or
/// both is not found.
@ -137,17 +138,18 @@ public:
const glm::vec3& getRawPosition() const { return _rawPosition; }
const glm::vec3& getRawNormal() const { return _rawNormal; }
bool isActive() const { return _isActive; }
int getLeapID() const { return _leapID; }
int getSixenseID() const { return _sixenseID; }
bool isActive() const { return _isActive; }
int getLeapID() const { return _leapID; }
int getSixenseID() const { return _sixenseID; }
std::vector<FingerData>& getFingers() { return _fingers; }
size_t getNumFingers() { return _fingers.size(); }
std::vector<FingerData>& getFingers() { return _fingers; }
const std::vector<FingerData>& getFingers() const { return _fingers; }
size_t getNumFingers() const { return _fingers.size(); }
void setActive(bool active) { _isActive = active; }
void setLeapID(int id) { _leapID = id; }
void setSixenseID(int id) { _sixenseID = id; }
void setActive(bool active) { _isActive = active; }
void setLeapID(int id) { _leapID = id; }
void setSixenseID(int id) { _sixenseID = id; }
void setRawRotation(const glm::quat rawRotation) { _rawRotation = rawRotation; };
glm::quat getRawRotation() const { return _rawRotation; }
@ -164,27 +166,27 @@ public:
const glm::vec3& getTipVelocity() const { return _tipVelocity; }
void setTipVelocity(const glm::vec3& velocity) { _tipVelocity = velocity; }
void incrementFramesWithoutData() { _numFramesWithoutData++; }
void resetFramesWithoutData() { _numFramesWithoutData = 0; }
int getFramesWithoutData() const { return _numFramesWithoutData; }
void incrementFramesWithoutData() { _numFramesWithoutData++; }
void resetFramesWithoutData() { _numFramesWithoutData = 0; }
int getFramesWithoutData() const { return _numFramesWithoutData; }
// Controller buttons
void setControllerButtons(int controllerButtons) { _controllerButtons = controllerButtons; }
void setLastControllerButtons(int controllerButtons) { _lastControllerButtons = controllerButtons; }
int getControllerButtons() { return _controllerButtons; }
int getLastControllerButtons() { return _lastControllerButtons; }
int getControllerButtons() const { return _controllerButtons; }
int getLastControllerButtons() const { return _lastControllerButtons; }
void setTrigger(float trigger) { _trigger = trigger; }
float getTrigger() { return _trigger; }
float getTrigger() const { return _trigger; }
void setJoystick(float joystickX, float joystickY) { _joystickX = joystickX; _joystickY = joystickY; }
float getJoystickX() { return _joystickX; }
float getJoystickY() { return _joystickY; }
float getJoystickX() const { return _joystickX; }
float getJoystickY() const { return _joystickY; }
bool getIsCollidingWithVoxel() { return _isCollidingWithVoxel; }
bool getIsCollidingWithVoxel() const { return _isCollidingWithVoxel; }
void setIsCollidingWithVoxel(bool isCollidingWithVoxel) { _isCollidingWithVoxel = isCollidingWithVoxel; }
bool getIsCollidingWithPalm() { return _isCollidingWithPalm; }
bool getIsCollidingWithPalm() const { return _isCollidingWithPalm; }
void setIsCollidingWithPalm(bool isCollidingWithPalm) { _isCollidingWithPalm = isCollidingWithPalm; }
private:

View file

@ -656,6 +656,17 @@ void OctreeServer::run() {
_persistThread->initialize(true);
}
}
// Debug option to demonstrate that the server's local time does not
// need to be in sync with any other network node. This forces clock
// skew for the individual server node
const char* CLOCK_SKEW = "--clockSkew";
const char* clockSkewOption = getCmdOption(_argc, _argv, CLOCK_SKEW);
if (clockSkewOption) {
int clockSkew = atoi(clockSkewOption);
usecTimestampNowForceClockSkew(clockSkew);
qDebug("clockSkewOption=%s clockSkew=%d\n", clockSkewOption, clockSkew);
}
// Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND = "--packetsPerSecond";

View file

@ -36,15 +36,16 @@ Particle::~Particle() {
void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity,
float damping, bool inHand, QString updateScript, uint32_t id) {
if (id == NEW_PARTICLE) {
_created = usecTimestampNow();
_id = _nextID;
_nextID++;
} else {
_id = id;
}
_lastUpdated = usecTimestampNow();
_lastEdited = _lastUpdated;
uint64_t now = usecTimestampNow();
_edited = now;
_lastSimulated = now;
_created = now; // will get updated as appropriate in setLifetime()
_position = position;
_radius = radius;
memcpy(_color, color, sizeof(_color));
@ -63,13 +64,10 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
//printf("Particle::appendParticleData()... getID()=%d\n", getID());
if (success) {
success = packetData->appendValue(getCreated());
success = packetData->appendValue(getLifetime());
}
if (success) {
success = packetData->appendValue(getLastUpdated());
}
if (success) {
success = packetData->appendValue(getLastEdited());
success = packetData->appendValue(getEditedAgo());
}
if (success) {
success = packetData->appendValue(getRadius());
@ -103,9 +101,17 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
}
int Particle::expectedBytes() {
int expectedBytes = sizeof(uint32_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(float) +
sizeof(glm::vec3) + sizeof(rgbColor) + sizeof(glm::vec3) +
sizeof(glm::vec3) + sizeof(float) + sizeof(bool);
int expectedBytes = sizeof(uint32_t) // id
+ sizeof(float) // lifetime
+ sizeof(float) // edited ago
+ sizeof(float) // radius
+ sizeof(glm::vec3) // position
+ sizeof(rgbColor) // color
+ sizeof(glm::vec3) // velocity
+ sizeof(glm::vec3) // gravity
+ sizeof(float) // damping
+ sizeof(bool); // inhand
// potentially more...
return expectedBytes;
}
@ -119,20 +125,19 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += sizeof(_id);
bytesRead += sizeof(_id);
// created
memcpy(&_created, dataAt, sizeof(_created));
dataAt += sizeof(_created);
bytesRead += sizeof(_created);
// lifetime
float lifetime;
memcpy(&lifetime, dataAt, sizeof(lifetime));
dataAt += sizeof(lifetime);
bytesRead += sizeof(lifetime);
setLifetime(lifetime);
// lastupdated
memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated));
dataAt += sizeof(_lastUpdated);
bytesRead += sizeof(_lastUpdated);
// _lastEdited
memcpy(&_lastEdited, dataAt, sizeof(_lastEdited));
dataAt += sizeof(_lastEdited);
bytesRead += sizeof(_lastEdited);
// edited ago
float editedAgo;
memcpy(&editedAgo, dataAt, sizeof(editedAgo));
dataAt += sizeof(editedAgo);
bytesRead += sizeof(editedAgo);
setEditedAgo(editedAgo);
// radius
memcpy(&_radius, dataAt, sizeof(_radius));
@ -186,7 +191,7 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes) {
Particle newParticle; // id and lastUpdated will get set here...
Particle newParticle; // id and _lastSimulated will get set here...
unsigned char* dataAt = data;
processedBytes = 0;
@ -214,26 +219,17 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
processedBytes += sizeof(creatorTokenID);
newParticle.setCreatorTokenID(creatorTokenID);
newParticle._newlyCreated = true;
newParticle.setLifetime(0); // this guy is new!
} else {
newParticle._id = editID;
newParticle._newlyCreated = false;
}
// created
memcpy(&newParticle._created, dataAt, sizeof(newParticle._created));
dataAt += sizeof(newParticle._created);
processedBytes += sizeof(newParticle._created);
// lastUpdated
memcpy(&newParticle._lastUpdated, dataAt, sizeof(newParticle._lastUpdated));
dataAt += sizeof(newParticle._lastUpdated);
processedBytes += sizeof(newParticle._lastUpdated);
// lastEdited
memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited));
dataAt += sizeof(newParticle._lastEdited);
processedBytes += sizeof(newParticle._lastEdited);
// clearly we just edited it
newParticle.setEditedAgo(0);
// radius
memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius));
dataAt += sizeof(newParticle._radius);
@ -291,9 +287,8 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
void Particle::debugDump() const {
printf("Particle id :%u\n", _id);
printf(" created:%llu\n", _created);
printf(" last updated:%llu\n", _lastUpdated);
printf(" last edited:%llu\n", _lastEdited);
printf(" lifetime:%f\n", getLifetime());
printf(" edited ago:%f\n", getEditedAgo());
printf(" position:%f,%f,%f\n", _position.x, _position.y, _position.z);
printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z);
printf(" gravity:%f,%f,%f\n", _gravity.x, _gravity.y, _gravity.z);
@ -325,7 +320,6 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
sizeOut += lengthOfOctcode;
// Now add our edit content details...
uint64_t created = usecTimestampNow();
// id
memcpy(copyAt, &details[i].id, sizeof(details[i].id));
@ -338,25 +332,8 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
memcpy(copyAt, &details[i].creatorTokenID, sizeof(details[i].creatorTokenID));
copyAt += sizeof(details[i].creatorTokenID);
sizeOut += sizeof(details[i].creatorTokenID);
} else {
created = 0;
}
// created
memcpy(copyAt, &created, sizeof(created));
copyAt += sizeof(created);
sizeOut += sizeof(created);
// lastUpdated
memcpy(copyAt, &details[i].lastUpdated, sizeof(details[i].lastUpdated));
copyAt += sizeof(details[i].lastUpdated);
sizeOut += sizeof(details[i].lastUpdated);
// lastEdited
memcpy(copyAt, &details[i].lastEdited, sizeof(details[i].lastEdited));
copyAt += sizeof(details[i].lastEdited);
sizeOut += sizeof(details[i].lastEdited);
// radius
memcpy(copyAt, &details[i].radius, sizeof(details[i].radius));
copyAt += sizeof(details[i].radius);
@ -405,7 +382,6 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
if (wantDebugging) {
printf("encodeParticleEditMessageDetails()....\n");
printf("Particle id :%u\n", details[i].id);
printf(" last updated:%llu\n", details[i].lastUpdated);
printf(" nextID:%u\n", _nextID);
}
}
@ -418,21 +394,30 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
void Particle::update() {
uint64_t now = usecTimestampNow();
uint64_t elapsed = now - _lastUpdated;
uint64_t USECS_PER_SECOND = 1000 * 1000;
uint64_t elapsed = now - _lastSimulated;
float timeElapsed = (float)((float)elapsed/(float)USECS_PER_SECOND);
// calculate our default shouldDie state... then allow script to change it if it wants...
float velocityScalar = glm::length(getVelocity());
const float STILL_MOVING = 0.05 / TREE_SCALE;
bool isStillMoving = (velocityScalar > STILL_MOVING);
const uint64_t REALLY_OLD = 30 * 1000 * 1000;
const float REALLY_OLD = 30.0f; // 30 seconds
bool isReallyOld = (getLifetime() > REALLY_OLD);
bool isInHand = getInHand();
bool shouldDie = !isInHand && !isStillMoving && isReallyOld;
setShouldDie(shouldDie);
bool wantDebug = false;
if (wantDebug) {
printf("Particle::update()... timeElapsed: %f lifeTime:%f editedAgo:%f "
"isInHand:%s isStillMoveing:%s isReallyOld:%s shouldDie:%s\n",
timeElapsed, getLifetime(), getEditedAgo(), debug::valueOf(isInHand), debug::valueOf(isStillMoving),
debug::valueOf(isReallyOld), debug::valueOf(shouldDie));
}
runScript(); // allow the javascript to alter our state
// If the ball is in hand, it doesn't move or have gravity effect it
@ -454,7 +439,7 @@ void Particle::update() {
//printf("applying damping to Particle timeElapsed=%f\n",timeElapsed);
}
_lastUpdated = now;
_lastSimulated = now;
}
void Particle::runScript() {
@ -484,3 +469,19 @@ void Particle::runScript() {
}
}
}
void Particle::setLifetime(float lifetime) {
uint64_t lifetimeInUsecs = lifetime * USECS_PER_SECOND;
_created = usecTimestampNow() - lifetimeInUsecs;
}
void Particle::setEditedAgo(float editedAgo) {
uint64_t editedAgoInUsecs = editedAgo * USECS_PER_SECOND;
_edited = usecTimestampNow() - editedAgoInUsecs;
}
void Particle::copyChangedProperties(const Particle& other) {
float lifetime = getLifetime();
*this = other;
setLifetime(lifetime);
}

View file

@ -25,8 +25,6 @@ const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF;
class ParticleDetail {
public:
uint32_t id;
uint64_t lastUpdated;
uint64_t lastEdited;
glm::vec3 position;
float radius;
rgbColor color;
@ -68,10 +66,11 @@ public:
const glm::vec3& getGravity() const { return _gravity; }
bool getInHand() const { return _inHand; }
float getDamping() const { return _damping; }
uint64_t getCreated() const { return _created; }
uint64_t getLifetime() const { return usecTimestampNow() - _created; }
uint64_t getLastUpdated() const { return _lastUpdated; }
uint64_t getLastEdited() const { return _lastEdited; }
/// lifetime of the particle in seconds
float getLifetime() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
/// seconds since last edited
float getEditedAgo() const { return (float)(usecTimestampNow() - _edited) / (float)USECS_PER_SECOND; }
uint32_t getID() const { return _id; }
bool getShouldDie() const { return _shouldDie; }
QString getUpdateScript() const { return _updateScript; }
@ -93,7 +92,6 @@ public:
void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; }
void setUpdateScript(QString updateScript) { _updateScript = updateScript; }
void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; }
void setCreated(uint64_t created) { _created = created; }
bool appendParticleData(OctreePacketData* packetData) const;
int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
@ -105,20 +103,24 @@ public:
void update();
void debugDump() const;
// similar to assignment/copy, but it handles keeping lifetime accurate
void copyChangedProperties(const Particle& other);
protected:
void runScript();
static QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3);
static void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3);
static QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color);
static void xColorFromScriptValue(const QScriptValue &object, xColor& color);
void setLifetime(float lifetime);
void setEditedAgo(float editedAgo);
glm::vec3 _position;
rgbColor _color;
float _radius;
glm::vec3 _velocity;
uint64_t _lastUpdated;
uint64_t _created;
uint64_t _lastEdited;
uint32_t _id;
static uint32_t _nextID;
bool _shouldDie;
@ -129,6 +131,12 @@ protected:
uint32_t _creatorTokenID;
bool _newlyCreated;
// these are never included in wire time
uint64_t _lastSimulated;
uint64_t _created;
uint64_t _edited;
};
class ParticleScriptObject : public QObject {
@ -144,9 +152,7 @@ public slots:
float getDamping() const { return _particle->getDamping(); }
float getRadius() const { return _particle->getRadius(); }
bool getShouldDie() { return _particle->getShouldDie(); }
float getCreated() const { return ((float)_particle->getCreated() / (float)USECS_PER_SECOND); }
float getLifetime() const { return ((float)_particle->getLifetime() / (float)USECS_PER_SECOND); }
float getLifetime() const { return _particle->getLifetime(); }
void setPosition(glm::vec3 value) { _particle->setPosition(value); }
void setVelocity(glm::vec3 value) { _particle->setVelocity(value); }

View file

@ -44,8 +44,7 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor
glm::vec3 gravity, float damping, bool inHand, QString updateScript) {
// setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow();
ParticleDetail addParticleDetail = { NEW_PARTICLE, now, now,
ParticleDetail addParticleDetail = { NEW_PARTICLE,
position, radius, {color.red, color.green, color.blue },
velocity, gravity, damping, inHand, updateScript, _creatorTokenID };
@ -70,8 +69,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor
}
// setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow();
ParticleDetail newParticleDetail = { _id, now, now,
ParticleDetail newParticleDetail = { _id,
position, radius, {color.red, color.green, color.blue },
velocity, gravity, damping, inHand, updateScript, _creatorTokenID };

View file

@ -22,8 +22,7 @@ unsigned int ParticleScriptingInterface::queueParticleAdd(glm::vec3 position, fl
_nextCreatorTokenID++;
// setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow();
ParticleDetail addParticleDetail = { NEW_PARTICLE, now, now,
ParticleDetail addParticleDetail = { NEW_PARTICLE,
position, radius, {color.red, color.green, color.blue }, velocity,
gravity, damping, inHand, updateScript, creatorTokenID };

View file

@ -119,33 +119,19 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) {
uint16_t numberOfParticles = _particles.size();
for (uint16_t i = 0; i < numberOfParticles; i++) {
if (_particles[i].getID() == particle.getID()) {
int difference = _particles[i].getLastUpdated() - particle.getLastUpdated();
bool changedOnServer = _particles[i].getLastEdited() < particle.getLastEdited();
bool localOlder = _particles[i].getLastUpdated() < particle.getLastUpdated();
if (changedOnServer || localOlder) {
bool changedOnServer = _particles[i].getEditedAgo() > particle.getEditedAgo();
if (changedOnServer) {
if (wantDebug) {
printf("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n",
printf("local particle [id:%d] %s, particle.isNewlyCreated()=%s\n",
particle.getID(), (changedOnServer ? "CHANGED" : "same"),
(localOlder ? "OLDER" : "NEWER"),
difference, debug::valueOf(particle.isNewlyCreated()) );
debug::valueOf(particle.isNewlyCreated()) );
}
uint64_t actuallyCreated = particle.getCreated();
if (!particle.isNewlyCreated()) {
actuallyCreated = _particles[i].getCreated();
}
_particles[i] = particle;
_particles[i].setCreated(actuallyCreated);
_particles[i].copyChangedProperties(particle);
} else {
if (wantDebug) {
printf(">>> NO CHANGE <<< -- local particle [id:%d] %s and %s than server particle by %d, "
"particle.isNewlyCreated()=%s\n",
printf(">>> NO CHANGE <<< -- local particle [id:%d] %s particle.isNewlyCreated()=%s\n",
particle.getID(), (changedOnServer ? "CHANGED" : "same"),
(localOlder ? "OLDER" : "NEWER"),
difference, debug::valueOf(particle.isNewlyCreated()) );
debug::valueOf(particle.isNewlyCreated()) );
}
}
return true;

View file

@ -0,0 +1,38 @@
//
// AbstractControllerScriptingInterface.h
// hifi
//
// Created by Brad Hefta-Gaub on 12/17/13
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__AbstractControllerScriptingInterface__
#define __hifi__AbstractControllerScriptingInterface__
#include <QtCore/QObject>
#include <glm/glm.hpp>
/// handles scripting of input controller commands from JS
class AbstractControllerScriptingInterface : public QObject {
Q_OBJECT
public slots:
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;
};
#endif /* defined(__hifi__AbstractControllerScriptingInterface__) */

View file

@ -25,7 +25,8 @@
int ScriptEngine::_scriptNumber = 1;
ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems,
const char* scriptMenuName, AbstractMenuInterface* menu) {
const char* scriptMenuName, AbstractMenuInterface* menu,
AbstractControllerScriptingInterface* controllerScriptingInterface) {
_scriptContents = scriptContents;
_isFinished = false;
_isRunning = false;
@ -41,6 +42,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems,
_scriptMenuName.append(_scriptNumber);
}
_menu = menu;
_controllerScriptingInterface = controllerScriptingInterface;
}
ScriptEngine::~ScriptEngine() {
@ -87,6 +89,11 @@ void ScriptEngine::run() {
QScriptValue particleScripterValue = engine.newQObject(&_particleScriptingInterface);
engine.globalObject().setProperty("Particles", particleScripterValue);
if (_controllerScriptingInterface) {
QScriptValue controllerScripterValue = engine.newQObject(_controllerScriptingInterface);
engine.globalObject().setProperty("Controller", controllerScripterValue);
}
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
engine.globalObject().setProperty("TREE_SCALE", treeScaleValue);

View file

@ -18,6 +18,7 @@
#include <AbstractMenuInterface.h>
#include <ParticleScriptingInterface.h>
#include <VoxelScriptingInterface.h>
#include "AbstractControllerScriptingInterface.h"
const QString NO_SCRIPT("");
@ -25,7 +26,8 @@ class ScriptEngine : public QObject {
Q_OBJECT
public:
ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false,
const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL);
const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL,
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
~ScriptEngine();
@ -58,6 +60,7 @@ protected:
private:
VoxelScriptingInterface _voxelScriptingInterface;
ParticleScriptingInterface _particleScriptingInterface;
AbstractControllerScriptingInterface* _controllerScriptingInterface;
bool _wantMenuItems;
QString _scriptMenuName;
AbstractMenuInterface* _menu;

View file

@ -7,11 +7,12 @@ set(TARGET_NAME shared)
project(${TARGET_NAME})
find_package(Qt5Network REQUIRED)
find_package(Qt5Widgets REQUIRED)
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
setup_hifi_library(${TARGET_NAME})
qt5_use_modules(${TARGET_NAME} Network)
qt5_use_modules(${TARGET_NAME} Network Widgets)
# include GLM
include(${MACRO_DIR}/IncludeGLM.cmake)

View file

@ -10,27 +10,23 @@
#ifndef __hifi__AbstractMenuInterface__
#define __hifi__AbstractMenuInterface__
#include <QAction>
class QMenu;
class QString;
class QObject;
class QKeySequence;
class QAction;
// these are actually class scoped enums, but we don't want to depend on the class for this abstract interface
const int NO_ROLE = 0;
typedef int QACTION_MENUROLE;
typedef int QKEYSEQUENCE;
class AbstractMenuInterface {
public:
virtual QMenu* getActiveScriptsMenu() = 0;
virtual QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu,
const QString actionName,
const QKEYSEQUENCE& shortcut = 0,
const QKeySequence& shortcut = 0,
const QObject* receiver = NULL,
const char* member = NULL,
QACTION_MENUROLE role = NO_ROLE) = 0;
QAction::MenuRole role = QAction::NoRole) = 0;
virtual void removeAction(QMenu* menu, const QString& actionName) = 0;
};
#endif /* defined(__hifi__AbstractMenuInterface__) */
#endif /* defined(__hifi__AbstractMenuInterface__) */

View file

@ -54,7 +54,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
return 2;
case PACKET_TYPE_PARTICLE_DATA:
return 3;
return 4;
default:
return 0;

View file

@ -12,6 +12,7 @@
void registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue);
qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue);
}
@ -29,6 +30,19 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) {
vec3.z = object.property("z").toVariant().toFloat();
}
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) {
QScriptValue obj = engine->newObject();
obj.setProperty("x", vec2.x);
obj.setProperty("y", vec2.y);
return obj;
}
void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2) {
vec2.x = object.property("x").toVariant().toFloat();
vec2.y = object.property("y").toVariant().toFloat();
}
QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color) {
QScriptValue obj = engine->newObject();
obj.setProperty("red", color.red);

View file

@ -17,11 +17,17 @@
#include "SharedUtil.h"
Q_DECLARE_METATYPE(glm::vec3)
Q_DECLARE_METATYPE(glm::vec2)
Q_DECLARE_METATYPE(xColor)
void registerMetaTypes(QScriptEngine* engine);
QScriptValue vec3toScriptValue(QScriptEngine* engine, const glm::vec3 &vec3);
void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3);
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2);
void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2);
QScriptValue xColorToScriptValue(QScriptEngine* engine, const xColor& color);
void xColorFromScriptValue(const QScriptValue &object, xColor& color);

View file

@ -30,10 +30,15 @@ uint64_t usecTimestamp(const timeval *time) {
return (time->tv_sec * 1000000 + time->tv_usec);
}
int usecTimestampNowAdjust = 0;
void usecTimestampNowForceClockSkew(int clockSkew) {
::usecTimestampNowAdjust = clockSkew;
}
uint64_t usecTimestampNow() {
timeval now;
gettimeofday(&now, NULL);
return (now.tv_sec * 1000000 + now.tv_usec);
return (now.tv_sec * 1000000 + now.tv_usec) + ::usecTimestampNowAdjust;
}
float randFloat () {

View file

@ -56,6 +56,7 @@ static const uint64_t USECS_PER_SECOND = 1000 * 1000;
uint64_t usecTimestamp(const timeval *time);
uint64_t usecTimestampNow();
void usecTimestampNowForceClockSkew(int clockSkew);
float randFloat();
int randIntInRange (int min, int max);