From 4033baa5caac02332a30a8cb0e39a0bc86c724a6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 2 Dec 2013 12:15:43 -0800 Subject: [PATCH 01/65] Starting work on "metavoxels." --- interface/CMakeLists.txt | 1 + libraries/metavoxels/CMakeLists.txt | 20 ++++++++++ libraries/metavoxels/src/Bitstream.cpp | 53 ++++++++++++++++++++++++++ libraries/metavoxels/src/Bitstream.h | 36 +++++++++++++++++ libraries/metavoxels/src/Metavoxel.cpp | 50 ++++++++++++++++++++++++ libraries/metavoxels/src/Metavoxel.h | 38 ++++++++++++++++++ 6 files changed, 198 insertions(+) create mode 100644 libraries/metavoxels/CMakeLists.txt create mode 100644 libraries/metavoxels/src/Bitstream.cpp create mode 100644 libraries/metavoxels/src/Bitstream.h create mode 100644 libraries/metavoxels/src/Metavoxel.cpp create mode 100644 libraries/metavoxels/src/Metavoxel.h diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 735989dfbf..fe2f8b1c89 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -84,6 +84,7 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) # link required hifi libraries link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(metavoxels ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt new file mode 100644 index 0000000000..92594af4ef --- /dev/null +++ b/libraries/metavoxels/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 2.8) + +set(ROOT_DIR ../..) +set(MACRO_DIR ${ROOT_DIR}/cmake/macros) + +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") + +set(TARGET_NAME metavoxels) + +find_package(Qt5Widgets REQUIRED) + +include(${MACRO_DIR}/SetupHifiLibrary.cmake) +setup_hifi_library(${TARGET_NAME}) + +qt5_use_modules(${TARGET_NAME} Widgets) + +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp new file mode 100644 index 0000000000..400cb4c1c6 --- /dev/null +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -0,0 +1,53 @@ +// +// Bitstream.cpp +// metavoxels +// +// Created by Andrzej Kapolka on 12/2/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include + +#include "Bitstream.h" + +Bitstream::Bitstream(QDataStream& underlying) + : _underlying(underlying), _byte(0), _position(0) { +} + +int Bitstream::write(const void* data, int bits) { + return bits; +} + +int Bitstream::read(void* data, int bits) { + return bits; +} + +void Bitstream::flush() { + if (_position != 0) { + _underlying << _byte; + _byte = 0; + _position = 0; + } +} + +Bitstream& Bitstream::operator<<(bool value) { + if (value) { + _byte |= (1 << _position); + } + const int LAST_BIT_POSITION = 7; + if (_position++ == LAST_BIT_POSITION) { + flush(); + } + return *this; +} + +Bitstream& Bitstream::operator>>(bool& value) { + if (_position == 0) { + _underlying >> _byte; + } + value = _byte & (1 << _position); + if (_position++ == 7) { + _position = 0; + } + return *this; +} diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h new file mode 100644 index 0000000000..9b4e08c858 --- /dev/null +++ b/libraries/metavoxels/src/Bitstream.h @@ -0,0 +1,36 @@ +// +// Bitstream.h +// metavoxels +// +// Created by Andrzej Kapolka on 12/2/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__Bitstream__ +#define __interface__Bitstream__ + +class QDataStream; + +/// A stream for bit-aligned data. +class Bitstream { +public: + + Bitstream(QDataStream& underlying); + + Bitstream& write(const void* data, int bits); + Bitstream& read(void* data, int bits); + + /// Flushes any unwritten bits to the underlying stream. + void flush(); + + Bitstream& operator<<(bool value); + Bitstream& operator>>(bool& value); + +private: + + QDataStream& _underlying; + char _byte; + int _position; +}; + +#endif /* defined(__interface__Bitstream__) */ diff --git a/libraries/metavoxels/src/Metavoxel.cpp b/libraries/metavoxels/src/Metavoxel.cpp new file mode 100644 index 0000000000..34332c923a --- /dev/null +++ b/libraries/metavoxels/src/Metavoxel.cpp @@ -0,0 +1,50 @@ +// +// Metavoxels.cpp +// metavoxels +// +// Created by Andrzej Kapolka on 12/2/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include "Bitstream.h" +#include "Metavoxel.h" + +bool Metavoxel::isLeaf() const { + for (int i = 0; i < CHILD_COUNT; i++) { + if (_children[i]) { + return false; + } + } + return true; +} + +Bitstream& operator<<(Bitstream& stream, const Metavoxel& voxel) { + for (int i = 0; i < Metavoxel::CHILD_COUNT; i++) { + const Metavoxel* child = voxel.getChild(i); + if (child) { + stream << true << *child; + + } else { + stream << false; + } + } + return stream; +} + +Bitstream& operator>>(Bitstream& stream, Metavoxel& voxel) { + for (int i = 0; i < Metavoxel::CHILD_COUNT; i++) { + bool childExists; + stream >> childExists; + Metavoxel* child = voxel.getChild(i); + if (childExists) { + if (!child) { + voxel.setChild(i, new Metavoxel); + } + stream >> *child; + + } else if (child) { + voxel.setChild(i, NULL); + } + } + return stream; +} diff --git a/libraries/metavoxels/src/Metavoxel.h b/libraries/metavoxels/src/Metavoxel.h new file mode 100644 index 0000000000..dcfb45309f --- /dev/null +++ b/libraries/metavoxels/src/Metavoxel.h @@ -0,0 +1,38 @@ +// +// Metavoxel.h +// metavoxels +// +// Created by Andrzej Kapolka on 12/2/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__Metavoxel__ +#define __interface__Metavoxel__ + +#include + +class Bitstream; + +/// A single node in a metavoxel tree. +class Metavoxel { +public: + + static const int CHILD_COUNT = 8; + + /// Sets the child at the specified index. Note that this object will assume ownership if non-null. + void setChild(int index, Metavoxel* child) { _children[index].reset(child); } + + const Metavoxel* getChild(int index) const { return _children[index].data(); } + Metavoxel* getChild(int index) { return _children[index].data(); } + + bool isLeaf() const; + +private: + + QScopedPointer _children[CHILD_COUNT]; +}; + +Bitstream& operator<<(Bitstream& stream, const Metavoxel& voxel); +Bitstream& operator>>(Bitstream& stream, Metavoxel& voxel); + +#endif /* defined(__interface__Metavoxel__) */ From dfbf896304bb50866e8db4eb7c5470ce106e9093 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Dec 2013 10:27:09 -0800 Subject: [PATCH 02/65] Some work on bitstreaming. --- libraries/metavoxels/src/Bitstream.cpp | 15 +++++++-------- libraries/metavoxels/src/Bitstream.h | 4 +++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 400cb4c1c6..4b20978579 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -14,12 +14,12 @@ Bitstream::Bitstream(QDataStream& underlying) : _underlying(underlying), _byte(0), _position(0) { } -int Bitstream::write(const void* data, int bits) { - return bits; +Bitstream& Bitstream::write(const void* data, int bits) { + return *this; } -int Bitstream::read(void* data, int bits) { - return bits; +Bitstream& Bitstream::read(void* data, int bits) { + return *this; } void Bitstream::flush() { @@ -30,11 +30,12 @@ void Bitstream::flush() { } } +const int LAST_BIT_POSITION = 7; + Bitstream& Bitstream::operator<<(bool value) { if (value) { _byte |= (1 << _position); } - const int LAST_BIT_POSITION = 7; if (_position++ == LAST_BIT_POSITION) { flush(); } @@ -46,8 +47,6 @@ Bitstream& Bitstream::operator>>(bool& value) { _underlying >> _byte; } value = _byte & (1 << _position); - if (_position++ == 7) { - _position = 0; - } + _position = (_position + 1) & LAST_BIT_POSITION; return *this; } diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 9b4e08c858..8aeb08baff 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -9,6 +9,8 @@ #ifndef __interface__Bitstream__ #define __interface__Bitstream__ +#include + class QDataStream; /// A stream for bit-aligned data. @@ -29,7 +31,7 @@ public: private: QDataStream& _underlying; - char _byte; + quint8 _byte; int _position; }; From 29870877a8b6dbea21d7210de3cd7d77caeec1d6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Dec 2013 17:12:29 -0800 Subject: [PATCH 03/65] More work on metavoxel bits. --- interface/src/Camera.cpp | 2 +- .../metavoxels/src/AttributeRegistry.cpp | 31 +++++++++ libraries/metavoxels/src/AttributeRegistry.h | 60 +++++++++++++++++ libraries/metavoxels/src/Bitstream.cpp | 37 +++++++++-- libraries/metavoxels/src/Bitstream.h | 11 +++- libraries/metavoxels/src/Metavoxel.cpp | 50 --------------- libraries/metavoxels/src/Metavoxel.h | 38 ----------- libraries/metavoxels/src/MetavoxelData.cpp | 11 ++++ libraries/metavoxels/src/MetavoxelData.h | 64 +++++++++++++++++++ 9 files changed, 209 insertions(+), 95 deletions(-) create mode 100644 libraries/metavoxels/src/AttributeRegistry.cpp create mode 100644 libraries/metavoxels/src/AttributeRegistry.h delete mode 100644 libraries/metavoxels/src/Metavoxel.cpp delete mode 100644 libraries/metavoxels/src/Metavoxel.h create mode 100644 libraries/metavoxels/src/MetavoxelData.cpp create mode 100644 libraries/metavoxels/src/MetavoxelData.h diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index 94bc693c2b..e65a1af7f6 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -20,7 +20,7 @@ const float CAMERA_FIRST_PERSON_MODE_TIGHTNESS = 100.0f; const float CAMERA_THIRD_PERSON_MODE_UP_SHIFT = -0.2f; const float CAMERA_THIRD_PERSON_MODE_DISTANCE = 1.5f; -const float CAMERA_THIRD_PERSON_MODE_TIGHTNESS = 8.0f; +const float CAMERA_THIRD_PERSON_MODE_TIGHTNESS = 0.0f; const float CAMERA_MIRROR_MODE_UP_SHIFT = 0.0f; const float CAMERA_MIRROR_MODE_DISTANCE = 0.17f; diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp new file mode 100644 index 0000000000..9d7e2b1210 --- /dev/null +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -0,0 +1,31 @@ +// +// AttributeRegistry.cpp +// metavoxels +// +// Created by Andrzej Kapolka on 12/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include "AttributeRegistry.h" + +AttributeRegistry AttributeRegistry::_instance; + +AttributeRegistry::AttributeRegistry() : _lastAttributeID(0) { +} + +AttributeID AttributeRegistry::getAttributeID(const QString& name) { + AttributeID& id = _attributeIDs[name]; + if (id == 0) { + id = ++_lastAttributeID; + _attributes.insert(id, Attribute(id, name)); + } + return id; +} + +Attribute AttributeRegistry::getAttribute(AttributeID id) const { + return _attributes.value(id); +} + +Attribute::Attribute(AttributeID id, const QString& name) : + _id(id), _name(name) { +} diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h new file mode 100644 index 0000000000..183efaf8b4 --- /dev/null +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -0,0 +1,60 @@ +// +// AttributeRegistry.h +// metavoxels +// +// Created by Andrzej Kapolka on 12/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__AttributeRegistry__ +#define __interface__AttributeRegistry__ + +#include +#include + +typedef int AttributeID; + +class Attribute; + +/// Maintains information about metavoxel attribute types. +class AttributeRegistry { +public: + + /// Returns a pointer to the singleton registry instance. + static AttributeRegistry* getInstance() { return &_instance; } + + AttributeRegistry(); + + /// Returns a unique id for the described attribute, creating one if necessary. + AttributeID getAttributeID(const QString& name); + + /// Returns the identified attribute, or an invalid attribute if not found. + Attribute getAttribute(AttributeID id) const; + +private: + + static AttributeRegistry _instance; + + AttributeID _lastAttributeID; + QHash _attributeIDs; + QHash _attributes; +}; + +/// Represents a registered attribute. +class Attribute { +public: + + Attribute(AttributeID id = 0, const QString& name = QString()); + + bool isValid() const { return !_name.isNull(); } + + AttributeID getID() const { return _id; } + const QString& getName() const { return _name; } + +private: + + AttributeID _id; + QString _name; +}; + +#endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 4b20978579..ac91bdf767 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -14,11 +14,41 @@ Bitstream::Bitstream(QDataStream& underlying) : _underlying(underlying), _byte(0), _position(0) { } -Bitstream& Bitstream::write(const void* data, int bits) { +const int BITS_IN_BYTE = 8; +const int LAST_BIT_POSITION = BITS_IN_BYTE - 1; + +Bitstream& Bitstream::write(const void* data, int bits, int offset) { + const quint8* source = (const quint8*)data; + while (bits > 0) { + int bitsToWrite = qMin(BITS_IN_BYTE - _position, qMin(BITS_IN_BYTE - offset, bits)); + _byte |= ((*source >> offset) & ((1 << bitsToWrite) - 1)) << _position; + if ((_position += bitsToWrite) == BITS_IN_BYTE) { + flush(); + } + if ((offset += bitsToWrite) == BITS_IN_BYTE) { + source++; + offset = 0; + } + bits -= bitsToWrite; + } return *this; } -Bitstream& Bitstream::read(void* data, int bits) { +Bitstream& Bitstream::read(void* data, int bits, int offset) { + quint8* dest = (quint8*)data; + while (bits > 0) { + if (_position == 0) { + _underlying >> _byte; + } + int bitsToRead = qMin(BITS_IN_BYTE - _position, qMin(BITS_IN_BYTE - offset, bits)); + *dest |= ((_byte >> _position) & ((1 << bitsToRead) - 1)) << offset; + _position = (_position + bitsToRead) & LAST_BIT_POSITION; + if ((offset += bitsToRead) == BITS_IN_BYTE) { + dest++; + offset = 0; + } + bits -= bitsToRead; + } return *this; } @@ -30,13 +60,12 @@ void Bitstream::flush() { } } -const int LAST_BIT_POSITION = 7; Bitstream& Bitstream::operator<<(bool value) { if (value) { _byte |= (1 << _position); } - if (_position++ == LAST_BIT_POSITION) { + if (++_position == BITS_IN_BYTE) { flush(); } return *this; diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 8aeb08baff..12a1b88886 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -19,8 +19,15 @@ public: Bitstream(QDataStream& underlying); - Bitstream& write(const void* data, int bits); - Bitstream& read(void* data, int bits); + /// Writes a set of bits to the underlying stream. + /// \param bits the number of bits to write + /// \param offset the offset of the first bit + Bitstream& write(const void* data, int bits, int offset = 0); + + /// Reads a set of bits from the underlying stream. + /// \param bits the number of bits to read + /// \param offset the offset of the first bit + Bitstream& read(void* data, int bits, int offset = 0); /// Flushes any unwritten bits to the underlying stream. void flush(); diff --git a/libraries/metavoxels/src/Metavoxel.cpp b/libraries/metavoxels/src/Metavoxel.cpp deleted file mode 100644 index 34332c923a..0000000000 --- a/libraries/metavoxels/src/Metavoxel.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// Metavoxels.cpp -// metavoxels -// -// Created by Andrzej Kapolka on 12/2/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include "Bitstream.h" -#include "Metavoxel.h" - -bool Metavoxel::isLeaf() const { - for (int i = 0; i < CHILD_COUNT; i++) { - if (_children[i]) { - return false; - } - } - return true; -} - -Bitstream& operator<<(Bitstream& stream, const Metavoxel& voxel) { - for (int i = 0; i < Metavoxel::CHILD_COUNT; i++) { - const Metavoxel* child = voxel.getChild(i); - if (child) { - stream << true << *child; - - } else { - stream << false; - } - } - return stream; -} - -Bitstream& operator>>(Bitstream& stream, Metavoxel& voxel) { - for (int i = 0; i < Metavoxel::CHILD_COUNT; i++) { - bool childExists; - stream >> childExists; - Metavoxel* child = voxel.getChild(i); - if (childExists) { - if (!child) { - voxel.setChild(i, new Metavoxel); - } - stream >> *child; - - } else if (child) { - voxel.setChild(i, NULL); - } - } - return stream; -} diff --git a/libraries/metavoxels/src/Metavoxel.h b/libraries/metavoxels/src/Metavoxel.h deleted file mode 100644 index dcfb45309f..0000000000 --- a/libraries/metavoxels/src/Metavoxel.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// Metavoxel.h -// metavoxels -// -// Created by Andrzej Kapolka on 12/2/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__Metavoxel__ -#define __interface__Metavoxel__ - -#include - -class Bitstream; - -/// A single node in a metavoxel tree. -class Metavoxel { -public: - - static const int CHILD_COUNT = 8; - - /// Sets the child at the specified index. Note that this object will assume ownership if non-null. - void setChild(int index, Metavoxel* child) { _children[index].reset(child); } - - const Metavoxel* getChild(int index) const { return _children[index].data(); } - Metavoxel* getChild(int index) { return _children[index].data(); } - - bool isLeaf() const; - -private: - - QScopedPointer _children[CHILD_COUNT]; -}; - -Bitstream& operator<<(Bitstream& stream, const Metavoxel& voxel); -Bitstream& operator>>(Bitstream& stream, Metavoxel& voxel); - -#endif /* defined(__interface__Metavoxel__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp new file mode 100644 index 0000000000..33effb45b8 --- /dev/null +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -0,0 +1,11 @@ +// +// MetavoxelData.cpp +// metavoxels +// +// Created by Andrzej Kapolka on 12/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include "MetavoxelData.h" + + diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h new file mode 100644 index 0000000000..f7b472358a --- /dev/null +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -0,0 +1,64 @@ +// +// MetavoxelData.h +// metavoxels +// +// Created by Andrzej Kapolka on 12/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__MetavoxelData__ +#define __interface__MetavoxelData__ + +#include +#include + +#include "AttributeRegistry.h" + +class MetavoxelNode; +class VoxelVisitor; + +/// The base metavoxel representation shared between server and client. +class MetavoxelData { +public: + + /// Applies the specified function to the contained voxels. + /// \param attributes the list of attributes desired + void visitVoxels(const QVector& attributes, VoxelVisitor* visitor); + +private: + + +}; + +/// A single layer of metavoxel data (a tree containing nodes of the same type). +class MetavoxelLayer { +public: + +private: + + QScopedPointer _root; +}; + +/// A single node within a metavoxel layer. +class MetavoxelNode { +public: + + static const int CHILD_COUNT = 8; + + + +private: + + QScopedPointer _children[CHILD_COUNT]; +}; + +/// Interface for visitors to voxels. +class VoxelVisitor { +public: + + /// Visits a voxel. + /// \param attributeValues the values of the desired attributes + virtual void visit(const QVector& attributeValues) = 0; +}; + +#endif /* defined(__interface__MetavoxelData__) */ From e0138257f4c04f0a18bcecad618fe0f007a55979 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 9 Dec 2013 10:49:35 -0800 Subject: [PATCH 04/65] Trivial additions related to attributes. --- libraries/metavoxels/src/MetavoxelData.cpp | 5 ++++- libraries/metavoxels/src/MetavoxelData.h | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 33effb45b8..5f1d6c5d56 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -8,4 +8,7 @@ #include "MetavoxelData.h" - +void MetavoxelData::visitVoxels(const QVector& attributes, VoxelVisitor* visitor) { + // map attributes to layers, indices + +} diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index f7b472358a..0b04cd0f86 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -14,6 +14,7 @@ #include "AttributeRegistry.h" +class MetavoxelLayer; class MetavoxelNode; class VoxelVisitor; @@ -27,7 +28,7 @@ public: private: - + QVector _layers; }; /// A single layer of metavoxel data (a tree containing nodes of the same type). @@ -36,6 +37,7 @@ public: private: + QVector _attributes; QScopedPointer _root; }; @@ -49,6 +51,7 @@ public: private: + void* _attributeValues; QScopedPointer _children[CHILD_COUNT]; }; From 6ba750a9634c7111fdc42579ee31d34a9b8e8a54 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 10 Dec 2013 15:44:48 -0800 Subject: [PATCH 05/65] More progress on generic attributes, metavoxel node management. --- interface/src/Application.cpp | 2 + interface/src/Application.h | 5 +- interface/src/renderer/MetavoxelSystem.cpp | 16 +++ interface/src/renderer/MetavoxelSystem.h | 25 ++++ .../metavoxels/src/AttributeRegistry.cpp | 72 +++++++++-- libraries/metavoxels/src/AttributeRegistry.h | 96 +++++++++++++-- libraries/metavoxels/src/MetavoxelData.cpp | 114 +++++++++++++++++- libraries/metavoxels/src/MetavoxelData.h | 69 ++++++++--- 8 files changed, 354 insertions(+), 45 deletions(-) create mode 100644 interface/src/renderer/MetavoxelSystem.cpp create mode 100644 interface/src/renderer/MetavoxelSystem.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e75c708841..a9ff0a3681 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1800,6 +1800,8 @@ void Application::init() { _voxels.setDisableFastVoxelPipeline(false); _voxels.init(); + _metavoxels.init(); + _palette.init(_glWidget->width(), _glWidget->height()); _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelAddMode), 0, 0); _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelDeleteMode), 0, 1); diff --git a/interface/src/Application.h b/interface/src/Application.h index 67cb1709c9..c1e178838b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -55,9 +55,10 @@ #include "renderer/AmbientOcclusionEffect.h" #include "renderer/GeometryCache.h" #include "renderer/GlowEffect.h" -#include "renderer/VoxelShader.h" +#include "renderer/MetavoxelSystem.h" #include "renderer/PointShader.h" #include "renderer/TextureCache.h" +#include "renderer/VoxelShader.h" #include "ui/BandwidthDialog.h" #include "ui/ChatEntry.h" #include "ui/VoxelStatsDialog.h" @@ -345,6 +346,8 @@ private: QByteArray _voxelsFilename; bool _wantToKillLocalVoxels; + MetavoxelSystem _metavoxels; + ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. Oscilloscope _audioScope; diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp new file mode 100644 index 0000000000..ef6692c2d2 --- /dev/null +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -0,0 +1,16 @@ +// +// MetavoxelSystem.cpp +// interface +// +// Created by Andrzej Kapolka on 12/10/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include + +#include "MetavoxelSystem.h" + +void MetavoxelSystem::init() { + qDebug() << "Howdy hello\n"; +} + diff --git a/interface/src/renderer/MetavoxelSystem.h b/interface/src/renderer/MetavoxelSystem.h new file mode 100644 index 0000000000..107f6f49f4 --- /dev/null +++ b/interface/src/renderer/MetavoxelSystem.h @@ -0,0 +1,25 @@ +// +// MetavoxelSystem.h +// interface +// +// Created by Andrzej Kapolka on 12/10/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__MetavoxelSystem__ +#define __interface__MetavoxelSystem__ + +#include + +/// Renders a metavoxel tree. +class MetavoxelSystem { +public: + + void init(); + +private: + + MetavoxelData _data; +}; + +#endif /* defined(__interface__MetavoxelSystem__) */ diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 9d7e2b1210..dcf5008500 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -10,22 +10,68 @@ AttributeRegistry AttributeRegistry::_instance; -AttributeRegistry::AttributeRegistry() : _lastAttributeID(0) { +AttributeRegistry::AttributeRegistry() { + registerAttribute(AttributePointer(new InlineAttribute("blerp"))); } -AttributeID AttributeRegistry::getAttributeID(const QString& name) { - AttributeID& id = _attributeIDs[name]; - if (id == 0) { - id = ++_lastAttributeID; - _attributes.insert(id, Attribute(id, name)); +AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { + AttributePointer& pointer = _attributes[attribute->getName()]; + if (!pointer) { + pointer = attribute; } - return id; + return pointer; } -Attribute AttributeRegistry::getAttribute(AttributeID id) const { - return _attributes.value(id); -} - -Attribute::Attribute(AttributeID id, const QString& name) : - _id(id), _name(name) { +AttributeValue::AttributeValue(const AttributePointer& attribute, void* const* value) : + _attribute(attribute) { + + if (_attribute) { + _value = _attribute->create(value); + } } + +AttributeValue::AttributeValue(const AttributeValue& other) : + _attribute(other._attribute) { + + if (_attribute) { + _value = _attribute->create(&other._value); + } +} + +AttributeValue::~AttributeValue() { + if (_attribute) { + _attribute->destroy(_value); + } +} + +AttributeValue& AttributeValue::operator=(const AttributeValue& other) { + if (_attribute) { + _attribute->destroy(_value); + } + if ((_attribute = other._attribute)) { + _value = _attribute->create(&other._value); + } +} + +void* AttributeValue::copy() const { + return _attribute->create(&_value); +} + +bool AttributeValue::isDefault() const { + return !_attribute || _attribute->equal(_value, _attribute->getDefaultValue()); +} + +bool AttributeValue::operator==(const AttributeValue& other) const { + return _attribute == other._attribute && (!_attribute || _attribute->equal(_value, other._value)); +} + +bool AttributeValue::operator==(void* other) const { + return _attribute && _attribute->equal(_value, other); +} + +Attribute::Attribute(const QString& name) : _name(name) { +} + +Attribute::~Attribute() { +} + diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 183efaf8b4..1ccff349c9 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -10,12 +10,15 @@ #define __interface__AttributeRegistry__ #include +#include #include -typedef int AttributeID; +#include "Bitstream.h" class Attribute; +typedef QSharedPointer AttributePointer; + /// Maintains information about metavoxel attribute types. class AttributeRegistry { public: @@ -25,36 +28,103 @@ public: AttributeRegistry(); - /// Returns a unique id for the described attribute, creating one if necessary. - AttributeID getAttributeID(const QString& name); + /// Registers an attribute with the system. + /// \return either the pointer passed as an argument, if the attribute wasn't already registered, or the existing + /// attribute + AttributePointer registerAttribute(AttributePointer attribute); - /// Returns the identified attribute, or an invalid attribute if not found. - Attribute getAttribute(AttributeID id) const; + /// Retrieves an attribute by name. + AttributePointer getAttribute(const QString& name) const { return _attributes.value(name); } private: static AttributeRegistry _instance; - AttributeID _lastAttributeID; - QHash _attributeIDs; - QHash _attributes; + QHash _attributes; +}; + +/// Pairs an attribute value with its type. +class AttributeValue { +public: + + AttributeValue(const AttributePointer& attribute = AttributePointer(), void* const* value = NULL); + AttributeValue(const AttributeValue& other); + ~AttributeValue(); + + AttributeValue& operator=(const AttributeValue& other); + + AttributePointer getAttribute() const { return _attribute; } + void* getValue() const { return _value; } + + void* copy() const; + + bool isDefault() const; + + bool operator==(const AttributeValue& other) const; + bool operator==(void* other) const; + +private: + + AttributePointer _attribute; + void* _value; }; /// Represents a registered attribute. class Attribute { public: - Attribute(AttributeID id = 0, const QString& name = QString()); + Attribute(const QString& name); + virtual ~Attribute(); - bool isValid() const { return !_name.isNull(); } - - AttributeID getID() const { return _id; } const QString& getName() const { return _name; } + virtual void* create(void* const* copy = NULL) const = 0; + virtual void destroy(void* value) const = 0; + + virtual bool read(Bitstream& in, void*& value) const = 0; + virtual bool write(Bitstream& out, void* value) const = 0; + + virtual bool equal(void* first, void* second) const = 0; + + virtual void* createAveraged(void* values[]) const = 0; + + virtual void* getDefaultValue() const = 0; + private: - AttributeID _id; QString _name; }; +/// A simple attribute class that stores its values inline. +template class InlineAttribute : public Attribute { +public: + + InlineAttribute(const QString& name, T defaultValue = T()) : Attribute(name), _defaultValue(*(void**)&defaultValue) { } + + virtual void* create(void* const* copy = NULL) const { return (copy == NULL) ? _defaultValue : *copy; } + virtual void destroy(void* value) const { /* no-op */ } + + virtual bool read(Bitstream& in, void*& value) const { value = getDefaultValue(); in.read(&value, bits); return false; } + virtual bool write(Bitstream& out, void* value) const { out.write(&value, bits); return false; } + + virtual bool equal(void* first, void* second) const { return first == second; } + + virtual void* createAveraged(void* values[]) const; + + virtual void* getDefaultValue() const { return _defaultValue; } + +private: + + void* _defaultValue; +}; + +template inline void* InlineAttribute::createAveraged(void* values[]) const { + T total = T(); + for (int i = 0; i < 8; i++) { + total += *(T*)(values + i); + } + total /= 8; + return *(void**)&total; +} + #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 5f1d6c5d56..41b2fd3317 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -8,7 +8,119 @@ #include "MetavoxelData.h" -void MetavoxelData::visitVoxels(const QVector& attributes, VoxelVisitor* visitor) { +MetavoxelData::~MetavoxelData() { + for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { + it.value()->destroy(it.key()); + delete it.value(); + } +} + +void MetavoxelData::visitVoxels(const QVector& attributes, VoxelVisitor* visitor) { // map attributes to layers, indices } + +void MetavoxelData::setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue) { + MetavoxelNode*& node = _roots[attributeValue.getAttribute()]; + if (node == NULL) { + node = new MetavoxelNode(attributeValue.getAttribute()); + } + if (node->setAttributeValue(path, 0, attributeValue)) { + node->destroy(attributeValue.getAttribute()); + delete node; + _roots.remove(attributeValue.getAttribute()); + } +} + +AttributeValue MetavoxelData::getAttributeValue(const MetavoxelPath& path, const AttributePointer& attribute) const { + MetavoxelNode* node = _roots.value(attribute); + if (node == NULL) { + return AttributeValue(attribute); + } + for (int i = 0, n = path.getSize(); i < n; i++) { + int index = path[i]; + MetavoxelNode* child = node->getChild(i); + if (child == NULL) { + return AttributeValue(attribute); + } + node = child; + } + return node->getAttributeValue(attribute); +} + +MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) { + _attributeValue = attributeValue.copy(); + for (int i = 0; i < CHILD_COUNT; i++) { + _children[i] = NULL; + } +} + +bool MetavoxelNode::setAttributeValue(const MetavoxelPath& path, int index, const AttributeValue& attributeValue) { + if (index == path.getSize()) { + setAttributeValue(attributeValue); + return attributeValue.isDefault(); + } + int element = path[index]; + if (_children[element] == NULL) { + _children[element] = new MetavoxelNode(attributeValue.getAttribute()); + } + if (_children[element]->setAttributeValue(path, index + 1, attributeValue)) { + _children[element]->destroy(attributeValue.getAttribute()); + delete _children[element]; + _children[element] = NULL; + if (allChildrenNull()) { + return true; + } + } + void* childValues[CHILD_COUNT]; + for (int i = 0; i < CHILD_COUNT; i++) { + childValues[i] = (_children[i] == NULL) ? attributeValue.getAttribute()->getDefaultValue() : + _children[i]->_attributeValue; + } + attributeValue.getAttribute()->destroy(_attributeValue); + _attributeValue = attributeValue.getAttribute()->createAveraged(childValues); + return false; +} + +void MetavoxelNode::setAttributeValue(const AttributeValue& attributeValue) { + attributeValue.getAttribute()->destroy(_attributeValue); + _attributeValue = attributeValue.copy(); +} + +AttributeValue MetavoxelNode::getAttributeValue(const AttributePointer& attribute) const { + return AttributeValue(attribute, &_attributeValue); +} + +void MetavoxelNode::destroy(const AttributePointer& attribute) { + attribute->destroy(_attributeValue); + for (int i = 0; i < CHILD_COUNT; i++) { + if (_children[i]) { + _children[i]->destroy(attribute); + delete _children[i]; + } + } +} + +bool MetavoxelNode::allChildrenNull() const { + for (int i = 0; i < CHILD_COUNT; i++) { + if (_children[i] != NULL) { + return false; + } + } + return true; +} + +int MetavoxelPath::operator[](int index) const { + return _array.at(index * BITS_PER_ELEMENT) | (_array.at(index * BITS_PER_ELEMENT + 1) << 1) | + (_array.at(index * BITS_PER_ELEMENT + 2) << 2); +} + +MetavoxelPath& MetavoxelPath::operator+=(int element) { + int offset = _array.size(); + _array.resize(offset + BITS_PER_ELEMENT); + _array.setBit(offset, element & 0x01); + _array.setBit(offset + 1, (element >> 1) & 0x01); + _array.setBit(offset + 2, element >> 2); + return *this; +} + diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 0b04cd0f86..becdc62348 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -9,36 +9,35 @@ #ifndef __interface__MetavoxelData__ #define __interface__MetavoxelData__ +#include +#include #include -#include #include "AttributeRegistry.h" -class MetavoxelLayer; class MetavoxelNode; +class MetavoxelPath; class VoxelVisitor; /// The base metavoxel representation shared between server and client. class MetavoxelData { public: + ~MetavoxelData(); + /// Applies the specified function to the contained voxels. /// \param attributes the list of attributes desired - void visitVoxels(const QVector& attributes, VoxelVisitor* visitor); + void visitVoxels(const QVector& attributes, VoxelVisitor* visitor); + + /// Sets the attribute value corresponding to the specified path. + void setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue); + + /// Retrieves the attribute value corresponding to the specified path. + AttributeValue getAttributeValue(const MetavoxelPath& path, const AttributePointer& attribute) const; private: - QVector _layers; -}; - -/// A single layer of metavoxel data (a tree containing nodes of the same type). -class MetavoxelLayer { -public: - -private: - - QVector _attributes; - QScopedPointer _root; + QHash _roots; }; /// A single node within a metavoxel layer. @@ -47,12 +46,48 @@ public: static const int CHILD_COUNT = 8; - + MetavoxelNode(const AttributeValue& attributeValue); + + /// Descends the voxel tree in order to set the value of a node. + /// \param path the path to follow + /// \param index the position in the path + /// \return whether or not the node is entirely equal to the default attribute, and can thus be collapsed + bool setAttributeValue(const MetavoxelPath& path, int index, const AttributeValue& attributeValue); + + void setAttributeValue(const AttributeValue& attributeValue); + + AttributeValue getAttributeValue(const AttributePointer& attribute) const; + + MetavoxelNode* getChild(int index) const { return _children[index]; } + void setChild(int index, MetavoxelNode* child) { _children[index] = child; } + + void destroy(const AttributePointer& attribute); private: + Q_DISABLE_COPY(MetavoxelNode) - void* _attributeValues; - QScopedPointer _children[CHILD_COUNT]; + bool allChildrenNull() const; + + void* _attributeValue; + MetavoxelNode* _children[CHILD_COUNT]; +}; + +/// A path down an octree. +class MetavoxelPath { +public: + + int getSize() const { return _array.size() / BITS_PER_ELEMENT; } + bool isEmpty() const { return _array.isEmpty(); } + + int operator[](int index) const; + + MetavoxelPath& operator+=(int element); + +private: + + static const int BITS_PER_ELEMENT = 3; + + QBitArray _array; }; /// Interface for visitors to voxels. From 88eeb17f28c21effa86121fbcb2ddedc0617fb1a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 10 Dec 2013 17:53:11 -0800 Subject: [PATCH 06/65] More progress on metavoxels with generic attributes. --- interface/src/renderer/MetavoxelSystem.cpp | 18 ++++++- libraries/metavoxels/src/AttributeRegistry.h | 14 +++-- libraries/metavoxels/src/MetavoxelData.cpp | 54 ++++++++++++++------ libraries/metavoxels/src/MetavoxelData.h | 7 ++- 4 files changed, 72 insertions(+), 21 deletions(-) diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index ef6692c2d2..fea4c374f3 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -11,6 +11,22 @@ #include "MetavoxelSystem.h" void MetavoxelSystem::init() { - qDebug() << "Howdy hello\n"; + MetavoxelPath p1; + p1 += 0; + p1 += 1; + p1 += 2; + + AttributePointer blerp = AttributeRegistry::getInstance()->getAttribute("blerp"); + + void* foo = encodeInline(5.0f); + _data.setAttributeValue(p1, AttributeValue(blerp, &foo)); + + //p1 += 0; + + MetavoxelPath p2; + + AttributeValue value = _data.getAttributeValue(p2, blerp); + + qDebug("fliggedy bloo %g\n", decodeInline(value.getValue())); } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 1ccff349c9..5ec3f2533b 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -95,11 +95,19 @@ private: QString _name; }; +template inline void* encodeInline(const T& value) { + return *(void**)const_cast(&value); +} + +template inline T decodeInline(void* value) { + return *(T*)&value; +} + /// A simple attribute class that stores its values inline. template class InlineAttribute : public Attribute { public: - InlineAttribute(const QString& name, T defaultValue = T()) : Attribute(name), _defaultValue(*(void**)&defaultValue) { } + InlineAttribute(const QString& name, T defaultValue = T()) : Attribute(name), _defaultValue(encodeInline(defaultValue)) { } virtual void* create(void* const* copy = NULL) const { return (copy == NULL) ? _defaultValue : *copy; } virtual void destroy(void* value) const { /* no-op */ } @@ -121,10 +129,10 @@ private: template inline void* InlineAttribute::createAveraged(void* values[]) const { T total = T(); for (int i = 0; i < 8; i++) { - total += *(T*)(values + i); + total += decodeInline(values[i]); } total /= 8; - return *(void**)&total; + return encodeInline(total); } #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 41b2fd3317..acedea05d1 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -25,7 +25,7 @@ void MetavoxelData::setAttributeValue(const MetavoxelPath& path, const Attribute if (node == NULL) { node = new MetavoxelNode(attributeValue.getAttribute()); } - if (node->setAttributeValue(path, 0, attributeValue)) { + if (node->setAttributeValue(path, 0, attributeValue) && attributeValue.isDefault()) { node->destroy(attributeValue.getAttribute()); delete node; _roots.remove(attributeValue.getAttribute()); @@ -41,7 +41,7 @@ AttributeValue MetavoxelData::getAttributeValue(const MetavoxelPath& path, const int index = path[i]; MetavoxelNode* child = node->getChild(i); if (child == NULL) { - return AttributeValue(attribute); + return node->getAttributeValue(attribute); } node = child; } @@ -58,39 +58,53 @@ MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) { bool MetavoxelNode::setAttributeValue(const MetavoxelPath& path, int index, const AttributeValue& attributeValue) { if (index == path.getSize()) { setAttributeValue(attributeValue); - return attributeValue.isDefault(); + return true; } int element = path[index]; if (_children[element] == NULL) { - _children[element] = new MetavoxelNode(attributeValue.getAttribute()); - } - if (_children[element]->setAttributeValue(path, index + 1, attributeValue)) { - _children[element]->destroy(attributeValue.getAttribute()); - delete _children[element]; - _children[element] = NULL; - if (allChildrenNull()) { - return true; + AttributeValue ownAttributeValue = getAttributeValue(attributeValue.getAttribute()); + for (int i = 0; i < CHILD_COUNT; i++) { + _children[i] = new MetavoxelNode(ownAttributeValue); } } + _children[element]->setAttributeValue(path, index + 1, attributeValue); + void* childValues[CHILD_COUNT]; + bool allLeaves = true; for (int i = 0; i < CHILD_COUNT; i++) { - childValues[i] = (_children[i] == NULL) ? attributeValue.getAttribute()->getDefaultValue() : - _children[i]->_attributeValue; + childValues[i] = _children[i]->_attributeValue; + allLeaves &= _children[i]->isLeaf(); } attributeValue.getAttribute()->destroy(_attributeValue); _attributeValue = attributeValue.getAttribute()->createAveraged(childValues); + + if (allLeaves && allChildrenEqual(attributeValue.getAttribute())) { + clearChildren(attributeValue.getAttribute()); + return true; + } + return false; } void MetavoxelNode::setAttributeValue(const AttributeValue& attributeValue) { attributeValue.getAttribute()->destroy(_attributeValue); _attributeValue = attributeValue.copy(); + clearChildren(attributeValue.getAttribute()); } AttributeValue MetavoxelNode::getAttributeValue(const AttributePointer& attribute) const { return AttributeValue(attribute, &_attributeValue); } +bool MetavoxelNode::isLeaf() const { + for (int i = 0; i < CHILD_COUNT; i++) { + if (_children[i]) { + return false; + } + } + return true; +} + void MetavoxelNode::destroy(const AttributePointer& attribute) { attribute->destroy(_attributeValue); for (int i = 0; i < CHILD_COUNT; i++) { @@ -101,15 +115,25 @@ void MetavoxelNode::destroy(const AttributePointer& attribute) { } } -bool MetavoxelNode::allChildrenNull() const { +bool MetavoxelNode::allChildrenEqual(const AttributePointer& attribute) const { for (int i = 0; i < CHILD_COUNT; i++) { - if (_children[i] != NULL) { + if (!attribute->equal(_attributeValue, _children[i]->_attributeValue)) { return false; } } return true; } +void MetavoxelNode::clearChildren(const AttributePointer& attribute) { + for (int i = 0; i < CHILD_COUNT; i++) { + if (_children[i]) { + _children[i]->destroy(attribute); + delete _children[i]; + _children[i] = NULL; + } + } +} + int MetavoxelPath::operator[](int index) const { return _array.at(index * BITS_PER_ELEMENT) | (_array.at(index * BITS_PER_ELEMENT + 1) << 1) | (_array.at(index * BITS_PER_ELEMENT + 2) << 2); diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index becdc62348..aafc0f6e44 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -51,7 +51,7 @@ public: /// Descends the voxel tree in order to set the value of a node. /// \param path the path to follow /// \param index the position in the path - /// \return whether or not the node is entirely equal to the default attribute, and can thus be collapsed + /// \return whether or not the node is entirely equal to the value bool setAttributeValue(const MetavoxelPath& path, int index, const AttributeValue& attributeValue); void setAttributeValue(const AttributeValue& attributeValue); @@ -61,12 +61,15 @@ public: MetavoxelNode* getChild(int index) const { return _children[index]; } void setChild(int index, MetavoxelNode* child) { _children[index] = child; } + bool isLeaf() const; + void destroy(const AttributePointer& attribute); private: Q_DISABLE_COPY(MetavoxelNode) - bool allChildrenNull() const; + bool allChildrenEqual(const AttributePointer& attribute) const; + void clearChildren(const AttributePointer& attribute); void* _attributeValue; MetavoxelNode* _children[CHILD_COUNT]; From 79a2e409a8f9500ebe9b03a0fd5e4dabf38980f1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 11 Dec 2013 13:52:52 -0800 Subject: [PATCH 07/65] Basic voxel visitation with multiple attributes. --- interface/src/renderer/MetavoxelSystem.cpp | 14 +++++++ libraries/metavoxels/src/MetavoxelData.cpp | 46 +++++++++++++++++++++- libraries/metavoxels/src/MetavoxelData.h | 14 ++++--- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index fea4c374f3..76ad824f65 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -10,6 +10,17 @@ #include "MetavoxelSystem.h" +class DebugVisitor : public MetavoxelVisitor { +public: + + virtual bool visit(const QVector& attributeValues); +}; + +bool DebugVisitor::visit(const QVector& attributeValues) { + qDebug() << decodeInline(attributeValues.at(0).getValue()) << "\n"; + return true; +} + void MetavoxelSystem::init() { MetavoxelPath p1; p1 += 0; @@ -28,5 +39,8 @@ void MetavoxelSystem::init() { AttributeValue value = _data.getAttributeValue(p2, blerp); qDebug("fliggedy bloo %g\n", decodeInline(value.getValue())); + + DebugVisitor visitor; + _data.visitVoxels(QVector() << blerp, visitor); } diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index acedea05d1..e75b51697c 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -15,9 +15,51 @@ MetavoxelData::~MetavoxelData() { } } -void MetavoxelData::visitVoxels(const QVector& attributes, VoxelVisitor* visitor) { - // map attributes to layers, indices +class Visitation { +public: + MetavoxelVisitor& visitor; + QVector nodes; + QVector attributeValues; + + void apply(); +}; + +void Visitation::apply() { + Visitation nextVisitation = { visitor, QVector(nodes.size()), attributeValues }; + for (int i = 0; i < nodes.size(); i++) { + MetavoxelNode* node = nodes.at(i); + if (node) { + nextVisitation.attributeValues[i] = node->getAttributeValue(attributeValues[i].getAttribute()); + } + } + if (!visitor.visit(nextVisitation.attributeValues)) { + return; + } + + for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + bool anyChildrenPresent = false; + for (int j = 0; j < nodes.size(); j++) { + MetavoxelNode* node = nodes.at(j); + if ((nextVisitation.nodes[j] = node ? node->getChild(i) : NULL)) { + anyChildrenPresent = true; + } + } + if (anyChildrenPresent) { + nextVisitation.apply(); + } + } +} + +void MetavoxelData::visitVoxels(const QVector& attributes, MetavoxelVisitor& visitor) { + // start with the root values/defaults + Visitation firstVisitation = { visitor, QVector(attributes.size()), + QVector(attributes.size()) }; + for (int i = 0; i < attributes.size(); i++) { + firstVisitation.nodes[i] = _roots.value(attributes[i]); + firstVisitation.attributeValues[i] = attributes[i]; + } + firstVisitation.apply(); } void MetavoxelData::setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index aafc0f6e44..11b9db2505 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -12,12 +12,13 @@ #include #include #include +#include #include "AttributeRegistry.h" class MetavoxelNode; class MetavoxelPath; -class VoxelVisitor; +class MetavoxelVisitor; /// The base metavoxel representation shared between server and client. class MetavoxelData { @@ -27,7 +28,7 @@ public: /// Applies the specified function to the contained voxels. /// \param attributes the list of attributes desired - void visitVoxels(const QVector& attributes, VoxelVisitor* visitor); + void visitVoxels(const QVector& attributes, MetavoxelVisitor& visitor); /// Sets the attribute value corresponding to the specified path. void setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue); @@ -93,13 +94,14 @@ private: QBitArray _array; }; -/// Interface for visitors to voxels. -class VoxelVisitor { +/// Interface for visitors to metavoxels. +class MetavoxelVisitor { public: - /// Visits a voxel. + /// Visits a metavoxel. /// \param attributeValues the values of the desired attributes - virtual void visit(const QVector& attributeValues) = 0; + /// \param if true, continue descending; if false, stop + virtual bool visit(const QVector& attributeValues) = 0; }; #endif /* defined(__interface__MetavoxelData__) */ From dce95992011f373eeb4e5d3f54e9fc1cb3428802 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 11 Dec 2013 16:13:36 -0800 Subject: [PATCH 08/65] More progress on generic attributes; color attributes. --- interface/src/renderer/MetavoxelSystem.cpp | 24 ++++----- .../metavoxels/src/AttributeRegistry.cpp | 23 +++++++- libraries/metavoxels/src/AttributeRegistry.h | 37 +++++++++---- libraries/metavoxels/src/MetavoxelData.cpp | 53 ++++++++++++------- libraries/metavoxels/src/MetavoxelData.h | 15 +++++- 5 files changed, 104 insertions(+), 48 deletions(-) diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index 76ad824f65..d813ac1653 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -13,11 +13,13 @@ class DebugVisitor : public MetavoxelVisitor { public: - virtual bool visit(const QVector& attributeValues); + virtual bool visit(const MetavoxelInfo& info); }; -bool DebugVisitor::visit(const QVector& attributeValues) { - qDebug() << decodeInline(attributeValues.at(0).getValue()) << "\n"; +bool DebugVisitor::visit(const MetavoxelInfo& info) { + QRgb color = info.attributeValues.at(0).getInlineValue(); + qDebug("%g %g %g %g %d %d %d %d\n", info.minimum.x, info.minimum.y, info.minimum.z, info.size, + qRed(color), qGreen(color), qBlue(color), qAlpha(color)); return true; } @@ -27,20 +29,12 @@ void MetavoxelSystem::init() { p1 += 1; p1 += 2; - AttributePointer blerp = AttributeRegistry::getInstance()->getAttribute("blerp"); + AttributePointer diffuseColor = AttributeRegistry::getInstance()->getAttribute("diffuseColor"); - void* foo = encodeInline(5.0f); - _data.setAttributeValue(p1, AttributeValue(blerp, &foo)); - - //p1 += 0; - - MetavoxelPath p2; - - AttributeValue value = _data.getAttributeValue(p2, blerp); - - qDebug("fliggedy bloo %g\n", decodeInline(value.getValue())); + void* white = encodeInline(qRgba(0xFF, 0xFF, 0xFF, 0xFF)); + _data.setAttributeValue(p1, AttributeValue(diffuseColor, &white)); DebugVisitor visitor; - _data.visitVoxels(QVector() << blerp, visitor); + _data.visitVoxels(QVector() << diffuseColor, visitor); } diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index dcf5008500..7c2a98049e 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -11,7 +11,7 @@ AttributeRegistry AttributeRegistry::_instance; AttributeRegistry::AttributeRegistry() { - registerAttribute(AttributePointer(new InlineAttribute("blerp"))); + registerAttribute(AttributePointer(new QRgbAttribute("diffuseColor"))); } AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { @@ -75,3 +75,24 @@ Attribute::Attribute(const QString& name) : _name(name) { Attribute::~Attribute() { } +QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) : + InlineAttribute(name, defaultValue) { +} + +void* QRgbAttribute::createAveraged(void* values[]) const { + int totalRed = 0; + int totalGreen = 0; + int totalBlue = 0; + int totalAlpha = 0; + for (int i = 0; i < AVERAGE_COUNT; i++) { + QRgb value = decodeInline(values[i]); + totalRed += qRed(value); + totalGreen += qGreen(value); + totalBlue += qBlue(value); + totalAlpha += qAlpha(value); + } + const int SHIFT_FACTOR = 3; + return encodeInline(qRgba(totalRed / AVERAGE_COUNT, totalGreen / AVERAGE_COUNT, + totalBlue / AVERAGE_COUNT, totalAlpha / AVERAGE_COUNT)); +} + diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 5ec3f2533b..f8eef1788d 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -9,6 +9,7 @@ #ifndef __interface__AttributeRegistry__ #define __interface__AttributeRegistry__ +#include #include #include #include @@ -43,6 +44,16 @@ private: QHash _attributes; }; +/// Converts a value to a void pointer. +template inline void* encodeInline(T value) { + return *(void**)&value; +} + +/// Extracts a value from a void pointer. +template inline T decodeInline(void* value) { + return *(T*)&value; +} + /// Pairs an attribute value with its type. class AttributeValue { public: @@ -56,6 +67,9 @@ public: AttributePointer getAttribute() const { return _attribute; } void* getValue() const { return _value; } + template void setInlineValue(T value) { _value = encodeInline(value); } + template T getInlineValue() const { return decodeInline(_value); } + void* copy() const; bool isDefault() const; @@ -73,6 +87,8 @@ private: class Attribute { public: + static const int AVERAGE_COUNT = 8; + Attribute(const QString& name); virtual ~Attribute(); @@ -95,14 +111,6 @@ private: QString _name; }; -template inline void* encodeInline(const T& value) { - return *(void**)const_cast(&value); -} - -template inline T decodeInline(void* value) { - return *(T*)&value; -} - /// A simple attribute class that stores its values inline. template class InlineAttribute : public Attribute { public: @@ -128,11 +136,20 @@ private: template inline void* InlineAttribute::createAveraged(void* values[]) const { T total = T(); - for (int i = 0; i < 8; i++) { + for (int i = 0; i < AVERAGE_COUNT; i++) { total += decodeInline(values[i]); } - total /= 8; + total /= AVERAGE_COUNT; return encodeInline(total); } +/// Provides appropriate averaging for RGBA values. +class QRgbAttribute : public InlineAttribute { +public: + + QRgbAttribute(const QString& name, QRgb defaultValue = QRgb()); + + virtual void* createAveraged(void* values[]) const; +}; + #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index e75b51697c..c99364aaa9 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -19,45 +19,58 @@ class Visitation { public: MetavoxelVisitor& visitor; QVector nodes; - QVector attributeValues; + MetavoxelInfo info; void apply(); + +protected: + + bool allNodesLeaves() const; }; +const int X_MAXIMUM_FLAG = 1; +const int Y_MAXIMUM_FLAG = 2; +const int Z_MAXIMUM_FLAG = 4; + void Visitation::apply() { - Visitation nextVisitation = { visitor, QVector(nodes.size()), attributeValues }; - for (int i = 0; i < nodes.size(); i++) { - MetavoxelNode* node = nodes.at(i); - if (node) { - nextVisitation.attributeValues[i] = node->getAttributeValue(attributeValues[i].getAttribute()); - } - } - - if (!visitor.visit(nextVisitation.attributeValues)) { + if (!visitor.visit(info) || allNodesLeaves()) { return; } - + Visitation nextVisitation = { visitor, QVector(nodes.size()), + { glm::vec3(), info.size * 0.5f, QVector(nodes.size()) } }; for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { - bool anyChildrenPresent = false; for (int j = 0; j < nodes.size(); j++) { MetavoxelNode* node = nodes.at(j); - if ((nextVisitation.nodes[j] = node ? node->getChild(i) : NULL)) { - anyChildrenPresent = true; - } + MetavoxelNode* child = node ? node->getChild(i) : NULL; + nextVisitation.info.attributeValues[j] = ((nextVisitation.nodes[j] = child)) ? + child->getAttributeValue(info.attributeValues[j].getAttribute()) : info.attributeValues[j]; } - if (anyChildrenPresent) { - nextVisitation.apply(); + nextVisitation.info.minimum = info.minimum + glm::vec3( + (i & X_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f, + (i & Y_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f, + (i & Z_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f); + nextVisitation.apply(); + } +} + +bool Visitation::allNodesLeaves() const { + foreach (MetavoxelNode* node, nodes) { + if (node != NULL && !node->isLeaf()) { + return false; } } + return true; } void MetavoxelData::visitVoxels(const QVector& attributes, MetavoxelVisitor& visitor) { // start with the root values/defaults + const float TOP_LEVEL_SIZE = 1.0f; Visitation firstVisitation = { visitor, QVector(attributes.size()), - QVector(attributes.size()) }; + { glm::vec3(), TOP_LEVEL_SIZE, QVector(attributes.size()) } }; for (int i = 0; i < attributes.size(); i++) { - firstVisitation.nodes[i] = _roots.value(attributes[i]); - firstVisitation.attributeValues[i] = attributes[i]; + MetavoxelNode* node = _roots.value(attributes[i]); + firstVisitation.nodes[i] = node; + firstVisitation.info.attributeValues[i] = node ? node->getAttributeValue(attributes[i]) : attributes[i]; } firstVisitation.apply(); } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 11b9db2505..bbdf17c99c 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -14,6 +14,8 @@ #include #include +#include + #include "AttributeRegistry.h" class MetavoxelNode; @@ -94,14 +96,23 @@ private: QBitArray _array; }; +/// Contains information about a metavoxel (explicit or procedural). +class MetavoxelInfo { +public: + + glm::vec3 minimum; ///< the minimum extent of the area covered by the voxel + float size; ///< the size of the voxel in all dimensions + QVector attributeValues; +}; + /// Interface for visitors to metavoxels. class MetavoxelVisitor { public: /// Visits a metavoxel. - /// \param attributeValues the values of the desired attributes + /// \param info the metavoxel ata /// \param if true, continue descending; if false, stop - virtual bool visit(const QVector& attributeValues) = 0; + virtual bool visit(const MetavoxelInfo& info) = 0; }; #endif /* defined(__interface__MetavoxelData__) */ From 5ec9017d3bb92135a8a58141020194e2c826f87e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 11 Dec 2013 18:00:17 -0800 Subject: [PATCH 09/65] More metavoxel bits. --- interface/src/Application.cpp | 19 +++++++++++++- interface/src/Application.h | 1 + interface/src/Menu.cpp | 3 ++- interface/src/Menu.h | 1 + interface/src/renderer/MetavoxelSystem.cpp | 26 ++++++++++++------- interface/src/renderer/MetavoxelSystem.h | 3 +++ .../metavoxels/src/AttributeRegistry.cpp | 6 ++--- libraries/metavoxels/src/AttributeRegistry.h | 13 ++++++++++ 8 files changed, 58 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2a8e7f4651..65305918d7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2320,6 +2320,15 @@ void Application::updateParticles(float deltaTime) { } } +void Application::updateMetavoxels(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()"); + + if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) { + _metavoxels.simulate(deltaTime); + } +} + void Application::updateTransmitter(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateTransmitter()"); @@ -2465,6 +2474,7 @@ void Application::update(float deltaTime) { updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); //loop through all the other avatars and simulate them... updateMyAvatarSimulation(deltaTime); // Simulate myself updateParticles(deltaTime); // Simulate particle cloud movements + updateMetavoxels(deltaTime); // update metavoxels updateTransmitter(deltaTime); // transmitter drive or pick updateCamera(deltaTime); // handle various camera tweaks like off axis projection updateDialogs(deltaTime); // update various stats dialogs if present @@ -2999,7 +3009,14 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { _voxels.render(Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures)); } } - + + // also, metavoxels + if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... metavoxels..."); + _metavoxels.render(); + } + // render the ambient occlusion effect if enabled if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), diff --git a/interface/src/Application.h b/interface/src/Application.h index c1e178838b..54f18c1080 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -269,6 +269,7 @@ private: void updateThreads(float deltaTime); void updateMyAvatarSimulation(float deltaTime); void updateParticles(float deltaTime); + void updateMetavoxels(float deltaTime); void updateTransmitter(float deltaTime); void updateCamera(float deltaTime); void updateDialogs(float deltaTime); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 13510067cd..0794522b58 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -281,7 +281,8 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ParticleCloud, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false); - + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, false); + QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index aa3b925517..b6ea1ae8b5 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -209,6 +209,7 @@ namespace MenuOption { const QString Login = "Login"; const QString LookAtIndicator = "Look-at Indicator"; const QString LookAtVectors = "Look-at Vectors"; + const QString Metavoxels = "Metavoxels"; const QString Mirror = "Mirror"; const QString MoveWithLean = "Move with Lean"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index d813ac1653..7cb5987bb7 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -10,16 +10,16 @@ #include "MetavoxelSystem.h" -class DebugVisitor : public MetavoxelVisitor { +class PointVisitor : public MetavoxelVisitor { public: virtual bool visit(const MetavoxelInfo& info); }; -bool DebugVisitor::visit(const MetavoxelInfo& info) { +bool PointVisitor::visit(const MetavoxelInfo& info) { QRgb color = info.attributeValues.at(0).getInlineValue(); - qDebug("%g %g %g %g %d %d %d %d\n", info.minimum.x, info.minimum.y, info.minimum.z, info.size, - qRed(color), qGreen(color), qBlue(color), qAlpha(color)); + QRgb normal = info.attributeValues.at(1).getInlineValue(); + return true; } @@ -29,12 +29,20 @@ void MetavoxelSystem::init() { p1 += 1; p1 += 2; - AttributePointer diffuseColor = AttributeRegistry::getInstance()->getAttribute("diffuseColor"); + AttributePointer color = AttributeRegistry::getInstance()->getAttribute("color"); void* white = encodeInline(qRgba(0xFF, 0xFF, 0xFF, 0xFF)); - _data.setAttributeValue(p1, AttributeValue(diffuseColor, &white)); - - DebugVisitor visitor; - _data.visitVoxels(QVector() << diffuseColor, visitor); + _data.setAttributeValue(p1, AttributeValue(color, &white)); } +void MetavoxelSystem::simulate(float deltaTime) { + QVector attributes; + attributes << AttributeRegistry::getInstance()->getColorAttribute(); + attributes << AttributeRegistry::getInstance()->getNormalAttribute(); + PointVisitor visitor; + _data.visitVoxels(attributes, visitor); +} + +void MetavoxelSystem::render() { + +} diff --git a/interface/src/renderer/MetavoxelSystem.h b/interface/src/renderer/MetavoxelSystem.h index 107f6f49f4..ffb73290f3 100644 --- a/interface/src/renderer/MetavoxelSystem.h +++ b/interface/src/renderer/MetavoxelSystem.h @@ -17,6 +17,9 @@ public: void init(); + void simulate(float deltaTime); + void render(); + private: MetavoxelData _data; diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 7c2a98049e..96083908bd 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -10,8 +10,9 @@ AttributeRegistry AttributeRegistry::_instance; -AttributeRegistry::AttributeRegistry() { - registerAttribute(AttributePointer(new QRgbAttribute("diffuseColor"))); +AttributeRegistry::AttributeRegistry() : + _colorAttribute(registerAttribute(new QRgbAttribute("color"))), + _normalAttribute(registerAttribute(new QRgbAttribute("normal"))) { } AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { @@ -91,7 +92,6 @@ void* QRgbAttribute::createAveraged(void* values[]) const { totalBlue += qBlue(value); totalAlpha += qAlpha(value); } - const int SHIFT_FACTOR = 3; return encodeInline(qRgba(totalRed / AVERAGE_COUNT, totalGreen / AVERAGE_COUNT, totalBlue / AVERAGE_COUNT, totalAlpha / AVERAGE_COUNT)); } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index f8eef1788d..a2e56ae3a5 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -29,6 +29,11 @@ public: AttributeRegistry(); + /// Registers an attribute with the system. The registry assumes ownership of the object. + /// \return either the pointer passed as an argument, if the attribute wasn't already registered, or the existing + /// attribute + AttributePointer registerAttribute(Attribute* attribute) { return registerAttribute(AttributePointer(attribute)); } + /// Registers an attribute with the system. /// \return either the pointer passed as an argument, if the attribute wasn't already registered, or the existing /// attribute @@ -37,11 +42,19 @@ public: /// Retrieves an attribute by name. AttributePointer getAttribute(const QString& name) const { return _attributes.value(name); } + /// Returns a reference to the standard QRgb "color" attribute. + const AttributePointer& getColorAttribute() const { return _colorAttribute; } + + /// Returns a reference to the standard QRgb "normal" attribute. + const AttributePointer& getNormalAttribute() const { return _normalAttribute; } + private: static AttributeRegistry _instance; QHash _attributes; + AttributePointer _colorAttribute; + AttributePointer _normalAttribute; }; /// Converts a value to a void pointer. From c1aec11b325bf54f394692cb5a1e9bbfc6c04229 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 12 Dec 2013 15:14:19 -0800 Subject: [PATCH 10/65] More work on rendering voxels. --- .../resources/shaders/metavoxel_point.vert | 22 ++++ interface/src/renderer/MetavoxelSystem.cpp | 101 +++++++++++++++--- interface/src/renderer/MetavoxelSystem.h | 33 +++++- libraries/metavoxels/src/MetavoxelData.cpp | 3 +- libraries/metavoxels/src/MetavoxelData.h | 1 + 5 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 interface/resources/shaders/metavoxel_point.vert diff --git a/interface/resources/shaders/metavoxel_point.vert b/interface/resources/shaders/metavoxel_point.vert new file mode 100644 index 0000000000..be04462375 --- /dev/null +++ b/interface/resources/shaders/metavoxel_point.vert @@ -0,0 +1,22 @@ +#version 120 + +// +// metavoxel_point.vert +// vertex shader +// +// Created by Andrzej Kapolka on 12/12/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +uniform float pointScale; + +void main(void) { + + // pass along the vertex color + gl_FrontColor = gl_Color; + + // extract the first four components of the vertex for position + gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0); + + gl_PointSize = pointScale * gl_Vertex.w / gl_Position.w; +} diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index 7cb5987bb7..c5c8ab327f 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -8,41 +8,112 @@ #include +#include + +#include "Application.h" #include "MetavoxelSystem.h" -class PointVisitor : public MetavoxelVisitor { -public: - - virtual bool visit(const MetavoxelInfo& info); -}; +ProgramObject MetavoxelSystem::_program; +int MetavoxelSystem::_pointScaleLocation; -bool PointVisitor::visit(const MetavoxelInfo& info) { - QRgb color = info.attributeValues.at(0).getInlineValue(); - QRgb normal = info.attributeValues.at(1).getInlineValue(); - - return true; +MetavoxelSystem::MetavoxelSystem() : + _buffer(QOpenGLBuffer::VertexBuffer), + _pointVisitor(_points) { } void MetavoxelSystem::init() { + if (!_program.isLinked()) { + switchToResourcesParentIfRequired(); + _program.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/metavoxel_point.vert"); + _program.link(); + + _pointScaleLocation = _program.uniformLocation("pointScale"); + } + MetavoxelPath p1; - p1 += 0; - p1 += 1; - p1 += 2; + p1 += 7; + p1 += 7; + p1 += 7; AttributePointer color = AttributeRegistry::getInstance()->getAttribute("color"); void* white = encodeInline(qRgba(0xFF, 0xFF, 0xFF, 0xFF)); _data.setAttributeValue(p1, AttributeValue(color, &white)); + + _buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); + _buffer.create(); } void MetavoxelSystem::simulate(float deltaTime) { + _points.clear(); + QVector attributes; attributes << AttributeRegistry::getInstance()->getColorAttribute(); attributes << AttributeRegistry::getInstance()->getNormalAttribute(); - PointVisitor visitor; - _data.visitVoxels(attributes, visitor); + _data.visitVoxels(attributes, _pointVisitor); + + _buffer.bind(); + int bytes = _points.size() * sizeof(Point); + if (_buffer.size() < bytes) { + _buffer.allocate(_points.constData(), bytes); + } else { + _buffer.write(0, _points.constData(), bytes); + } + _buffer.release(); } void MetavoxelSystem::render() { + int viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + const int VIEWPORT_WIDTH_INDEX = 2; + const int VIEWPORT_HEIGHT_INDEX = 3; + float viewportWidth = viewport[VIEWPORT_WIDTH_INDEX]; + float viewportHeight = viewport[VIEWPORT_HEIGHT_INDEX]; + float viewportDiagonal = sqrtf(viewportWidth*viewportWidth + viewportHeight*viewportHeight); + float worldDiagonal = glm::distance(Application::getInstance()->getViewFrustum()->getNearBottomLeft(), + Application::getInstance()->getViewFrustum()->getNearTopRight()); + + _program.bind(); + _program.setUniformValue(_pointScaleLocation, viewportDiagonal * + Application::getInstance()->getViewFrustum()->getNearClip() / worldDiagonal); + + _buffer.bind(); + + Point* pt = 0; + glVertexPointer(4, GL_FLOAT, sizeof(Point), &pt->vertex); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Point), &pt->color); + glNormalPointer(GL_BYTE, sizeof(Point), &pt->normal); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); + glDrawArrays(GL_POINTS, 0, _points.size()); + + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + + _buffer.release(); + + _program.release(); +} + +bool MetavoxelSystem::PointVisitor::visit(const MetavoxelInfo& info) { + if (!info.isLeaf) { + return true; + } + QRgb color = info.attributeValues.at(0).getInlineValue(); + QRgb normal = info.attributeValues.at(1).getInlineValue(); + int alpha = qAlpha(color); + if (alpha > 0) { + Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), + { qRed(color), qGreen(color), qBlue(color), alpha }, { qRed(normal), qGreen(normal), qBlue(normal) } }; + _points.append(point); + } + return false; } diff --git a/interface/src/renderer/MetavoxelSystem.h b/interface/src/renderer/MetavoxelSystem.h index ffb73290f3..4eaa4aaa95 100644 --- a/interface/src/renderer/MetavoxelSystem.h +++ b/interface/src/renderer/MetavoxelSystem.h @@ -9,20 +9,51 @@ #ifndef __interface__MetavoxelSystem__ #define __interface__MetavoxelSystem__ +#include +#include + +#include + #include +#include "ProgramObject.h" + /// Renders a metavoxel tree. class MetavoxelSystem { public: + MetavoxelSystem(); + void init(); void simulate(float deltaTime); void render(); private: + + class Point { + public: + glm::vec4 vertex; + quint8 color[4]; + quint8 normal[3]; + }; - MetavoxelData _data; + class PointVisitor : public MetavoxelVisitor { + public: + PointVisitor(QVector& points) : _points(points) { } + virtual bool visit(const MetavoxelInfo& info); + + protected: + QVector& _points; + }; + + static ProgramObject _program; + static int _pointScaleLocation; + + MetavoxelData _data; + QVector _points; + PointVisitor _pointVisitor; + QOpenGLBuffer _buffer; }; #endif /* defined(__interface__MetavoxelSystem__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index c99364aaa9..874dfbcf84 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -33,7 +33,8 @@ const int Y_MAXIMUM_FLAG = 2; const int Z_MAXIMUM_FLAG = 4; void Visitation::apply() { - if (!visitor.visit(info) || allNodesLeaves()) { + info.isLeaf = allNodesLeaves(); + if (!visitor.visit(info) || info.isLeaf) { return; } Visitation nextVisitation = { visitor, QVector(nodes.size()), diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index bbdf17c99c..adc4d1341c 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -103,6 +103,7 @@ public: glm::vec3 minimum; ///< the minimum extent of the area covered by the voxel float size; ///< the size of the voxel in all dimensions QVector attributeValues; + bool isLeaf; }; /// Interface for visitors to metavoxels. From c003a55c378875ac56d7ffb0c7273c4a3da0ccc4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 12 Dec 2013 16:19:05 -0800 Subject: [PATCH 11/65] Diffuse lighting. --- interface/resources/shaders/metavoxel_point.vert | 9 ++++++--- libraries/metavoxels/src/AttributeRegistry.cpp | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/interface/resources/shaders/metavoxel_point.vert b/interface/resources/shaders/metavoxel_point.vert index be04462375..b0472088c0 100644 --- a/interface/resources/shaders/metavoxel_point.vert +++ b/interface/resources/shaders/metavoxel_point.vert @@ -12,11 +12,14 @@ uniform float pointScale; void main(void) { - // pass along the vertex color - gl_FrontColor = gl_Color; + // standard diffuse lighting + gl_FrontColor = vec4(gl_Color.rgb * (gl_LightModel.ambient.rgb + gl_LightSource[0].ambient.rgb + + gl_LightSource[0].diffuse.rgb * max(0.0, dot(gl_NormalMatrix * gl_Normal, gl_LightSource[0].position.xyz))), + gl_Color.a); - // extract the first four components of the vertex for position + // extract the first three components of the vertex for position gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0); + // the final component is the size in world space gl_PointSize = pointScale * gl_Vertex.w / gl_Position.w; } diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 96083908bd..99076f8335 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -12,7 +12,7 @@ AttributeRegistry AttributeRegistry::_instance; AttributeRegistry::AttributeRegistry() : _colorAttribute(registerAttribute(new QRgbAttribute("color"))), - _normalAttribute(registerAttribute(new QRgbAttribute("normal"))) { + _normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) { } AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { From a10aca59f3eb16fbd2e055010e610156409b7315 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 12 Dec 2013 18:29:23 -0800 Subject: [PATCH 12/65] Visitor cleanup. --- interface/src/renderer/MetavoxelSystem.cpp | 13 +++++++----- interface/src/renderer/MetavoxelSystem.h | 4 ++-- libraries/metavoxels/src/MetavoxelData.cpp | 3 ++- libraries/metavoxels/src/MetavoxelData.h | 23 +++++++++++++++++++--- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index c5c8ab327f..757aa89ade 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -46,11 +46,7 @@ void MetavoxelSystem::init() { void MetavoxelSystem::simulate(float deltaTime) { _points.clear(); - - QVector attributes; - attributes << AttributeRegistry::getInstance()->getColorAttribute(); - attributes << AttributeRegistry::getInstance()->getNormalAttribute(); - _data.visitVoxels(attributes, _pointVisitor); + _data.traverse(_pointVisitor); _buffer.bind(); int bytes = _points.size() * sizeof(Point); @@ -103,6 +99,13 @@ void MetavoxelSystem::render() { _program.release(); } +MetavoxelSystem::PointVisitor::PointVisitor(QVector& points) : + MetavoxelVisitor(QVector() << + AttributeRegistry::getInstance()->getColorAttribute() << + AttributeRegistry::getInstance()->getNormalAttribute()), + _points(points) { +} + bool MetavoxelSystem::PointVisitor::visit(const MetavoxelInfo& info) { if (!info.isLeaf) { return true; diff --git a/interface/src/renderer/MetavoxelSystem.h b/interface/src/renderer/MetavoxelSystem.h index 4eaa4aaa95..1b4a749581 100644 --- a/interface/src/renderer/MetavoxelSystem.h +++ b/interface/src/renderer/MetavoxelSystem.h @@ -40,10 +40,10 @@ private: class PointVisitor : public MetavoxelVisitor { public: - PointVisitor(QVector& points) : _points(points) { } + PointVisitor(QVector& points); virtual bool visit(const MetavoxelInfo& info); - protected: + private: QVector& _points; }; diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 874dfbcf84..e7ac378ec2 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -63,9 +63,10 @@ bool Visitation::allNodesLeaves() const { return true; } -void MetavoxelData::visitVoxels(const QVector& attributes, MetavoxelVisitor& visitor) { +void MetavoxelData::traverse(MetavoxelVisitor& visitor) { // start with the root values/defaults const float TOP_LEVEL_SIZE = 1.0f; + const QVector& attributes = visitor.getAttributes(); Visitation firstVisitation = { visitor, QVector(attributes.size()), { glm::vec3(), TOP_LEVEL_SIZE, QVector(attributes.size()) } }; for (int i = 0; i < attributes.size(); i++) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index adc4d1341c..df42e73a21 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -28,9 +29,8 @@ public: ~MetavoxelData(); - /// Applies the specified function to the contained voxels. - /// \param attributes the list of attributes desired - void visitVoxels(const QVector& attributes, MetavoxelVisitor& visitor); + /// Applies the specified visitor to the contained voxels. + void traverse(MetavoxelVisitor& visitor); /// Sets the attribute value corresponding to the specified path. void setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue); @@ -110,10 +110,27 @@ public: class MetavoxelVisitor { public: + MetavoxelVisitor(const QVector& attributes) : _attributes(attributes) { } + + /// Returns a reference to the list of attributes desired. + const QVector& getAttributes() const { return _attributes; } + /// Visits a metavoxel. /// \param info the metavoxel ata /// \param if true, continue descending; if false, stop virtual bool visit(const MetavoxelInfo& info) = 0; + +protected: + + QVector _attributes; +}; + +/// Interface for objects that host metavoxel visitors. +class MetavoxelTraverser : public QSharedData { +public: + + /// Applies the specified visitor to the contained voxels. + virtual void traverse(MetavoxelVisitor& visitor) = 0; }; #endif /* defined(__interface__MetavoxelData__) */ From 50e469156863f45987a68829fedbaf586bc4dc87 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 13 Dec 2013 14:33:18 -0800 Subject: [PATCH 13/65] Pointer attributes, cleanup. --- interface/src/renderer/MetavoxelSystem.cpp | 10 ++- .../metavoxels/src/AttributeRegistry.cpp | 63 +++++++++--------- libraries/metavoxels/src/AttributeRegistry.h | 64 ++++++++++++++++--- libraries/metavoxels/src/MetavoxelData.cpp | 2 +- 4 files changed, 98 insertions(+), 41 deletions(-) diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index 757aa89ade..26f722f65c 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -37,8 +37,10 @@ void MetavoxelSystem::init() { AttributePointer color = AttributeRegistry::getInstance()->getAttribute("color"); - void* white = encodeInline(qRgba(0xFF, 0xFF, 0xFF, 0xFF)); - _data.setAttributeValue(p1, AttributeValue(color, &white)); + _data.setAttributeValue(p1, AttributeValue(color, encodeInline(qRgba(0xFF, 0xFF, 0xFF, 0xFF)))); + + bool blerp = true; + _data.setAttributeValue(p1, AttributeValue(AttributeRegistry::getInstance()->getAttribute("voxelizer"), &blerp)); _buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); _buffer.create(); @@ -102,7 +104,8 @@ void MetavoxelSystem::render() { MetavoxelSystem::PointVisitor::PointVisitor(QVector& points) : MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getColorAttribute() << - AttributeRegistry::getInstance()->getNormalAttribute()), + AttributeRegistry::getInstance()->getNormalAttribute() << + AttributeRegistry::getInstance()->getVoxelizerAttribute()), _points(points) { } @@ -112,6 +115,7 @@ bool MetavoxelSystem::PointVisitor::visit(const MetavoxelInfo& info) { } QRgb color = info.attributeValues.at(0).getInlineValue(); QRgb normal = info.attributeValues.at(1).getInlineValue(); + bool blerp = *info.attributeValues.at(2).getPointerValue(); int alpha = qAlpha(color); if (alpha > 0) { Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 99076f8335..71ffe358ae 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -12,7 +12,8 @@ AttributeRegistry AttributeRegistry::_instance; AttributeRegistry::AttributeRegistry() : _colorAttribute(registerAttribute(new QRgbAttribute("color"))), - _normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) { + _normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))), + _voxelizerAttribute(registerAttribute(new PointerAttribute("voxelizer", false))) { } AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { @@ -23,39 +24,16 @@ AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute return pointer; } -AttributeValue::AttributeValue(const AttributePointer& attribute, void* const* value) : - _attribute(attribute) { - - if (_attribute) { - _value = _attribute->create(value); - } +AttributeValue::AttributeValue(const AttributePointer& attribute) : + _attribute(attribute), _value(attribute ? attribute->getDefaultValue() : NULL) { } -AttributeValue::AttributeValue(const AttributeValue& other) : - _attribute(other._attribute) { - - if (_attribute) { - _value = _attribute->create(&other._value); - } -} - -AttributeValue::~AttributeValue() { - if (_attribute) { - _attribute->destroy(_value); - } -} - -AttributeValue& AttributeValue::operator=(const AttributeValue& other) { - if (_attribute) { - _attribute->destroy(_value); - } - if ((_attribute = other._attribute)) { - _value = _attribute->create(&other._value); - } +AttributeValue::AttributeValue(const AttributePointer& attribute, void* value) : + _attribute(attribute), _value(value) { } void* AttributeValue::copy() const { - return _attribute->create(&_value); + return _attribute->create(_value); } bool AttributeValue::isDefault() const { @@ -70,6 +48,33 @@ bool AttributeValue::operator==(void* other) const { return _attribute && _attribute->equal(_value, other); } +OwnedAttributeValue::OwnedAttributeValue(const AttributePointer& attribute) : + AttributeValue(attribute, attribute ? attribute->create() : NULL) { +} + +OwnedAttributeValue::OwnedAttributeValue(const AttributePointer& attribute, void* value) : + AttributeValue(attribute, attribute ? attribute->create(value) : NULL) { +} + +OwnedAttributeValue::OwnedAttributeValue(const AttributeValue& other) : + AttributeValue(other.getAttribute(), other.getAttribute() ? other.copy() : NULL) { +} + +OwnedAttributeValue::~OwnedAttributeValue() { + if (_attribute) { + _attribute->destroy(_value); + } +} + +OwnedAttributeValue& OwnedAttributeValue::operator=(const AttributeValue& other) { + if (_attribute) { + _attribute->destroy(_value); + } + if ((_attribute = other.getAttribute())) { + _value = _attribute->create(other.getValue()); + } +} + Attribute::Attribute(const QString& name) : _name(name) { } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index a2e56ae3a5..cf00d4d5fe 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -48,6 +48,9 @@ public: /// Returns a reference to the standard QRgb "normal" attribute. const AttributePointer& getNormalAttribute() const { return _normalAttribute; } + /// Returns a reference to the standard "voxelizer" attribute. + const AttributePointer& getVoxelizerAttribute() const { return _voxelizerAttribute; } + private: static AttributeRegistry _instance; @@ -55,6 +58,7 @@ private: QHash _attributes; AttributePointer _colorAttribute; AttributePointer _normalAttribute; + AttributePointer _voxelizerAttribute; }; /// Converts a value to a void pointer. @@ -71,11 +75,8 @@ template inline T decodeInline(void* value) { class AttributeValue { public: - AttributeValue(const AttributePointer& attribute = AttributePointer(), void* const* value = NULL); - AttributeValue(const AttributeValue& other); - ~AttributeValue(); - - AttributeValue& operator=(const AttributeValue& other); + AttributeValue(const AttributePointer& attribute = AttributePointer()); + AttributeValue(const AttributePointer& attribute, void* value); AttributePointer getAttribute() const { return _attribute; } void* getValue() const { return _value; } @@ -83,6 +84,8 @@ public: template void setInlineValue(T value) { _value = encodeInline(value); } template T getInlineValue() const { return decodeInline(_value); } + template T* getPointerValue() const { return static_cast(_value); } + void* copy() const; bool isDefault() const; @@ -90,12 +93,24 @@ public: bool operator==(const AttributeValue& other) const; bool operator==(void* other) const; -private: +protected: AttributePointer _attribute; void* _value; }; +// Assumes ownership of an attribute value. +class OwnedAttributeValue : public AttributeValue { +public: + + OwnedAttributeValue(const AttributePointer& attribute = AttributePointer()); + OwnedAttributeValue(const AttributePointer& attribute, void* value); + OwnedAttributeValue(const AttributeValue& other); + ~OwnedAttributeValue(); + + OwnedAttributeValue& operator=(const AttributeValue& other); +}; + /// Represents a registered attribute. class Attribute { public: @@ -107,7 +122,8 @@ public: const QString& getName() const { return _name; } - virtual void* create(void* const* copy = NULL) const = 0; + void* create() const { return create(getDefaultValue()); } + virtual void* create(void* copy) const = 0; virtual void destroy(void* value) const = 0; virtual bool read(Bitstream& in, void*& value) const = 0; @@ -130,7 +146,7 @@ public: InlineAttribute(const QString& name, T defaultValue = T()) : Attribute(name), _defaultValue(encodeInline(defaultValue)) { } - virtual void* create(void* const* copy = NULL) const { return (copy == NULL) ? _defaultValue : *copy; } + virtual void* create(void* copy) const { return copy; } virtual void destroy(void* value) const { /* no-op */ } virtual bool read(Bitstream& in, void*& value) const { value = getDefaultValue(); in.read(&value, bits); return false; } @@ -165,4 +181,36 @@ public: virtual void* createAveraged(void* values[]) const; }; +/// An attribute class that stores pointers to its values. +template class PointerAttribute : public Attribute { +public: + + PointerAttribute(const QString& name, T defaultValue = T()) : Attribute(name), _defaultValue(defaultValue) { } + + virtual void* create(void* copy) const { new T(*static_cast(copy)); } + virtual void destroy(void* value) const { delete static_cast(value); } + + virtual bool read(Bitstream& in, void*& value) const { in >> *static_cast(value); return true; } + virtual bool write(Bitstream& out, void* value) const { out << *static_cast(value); return true; } + + virtual bool equal(void* first, void* second) const { return *static_cast(first) == *static_cast(second); } + + virtual void* createAveraged(void* values[]) const; + + virtual void* getDefaultValue() const { return const_cast((void*)&_defaultValue); } + +private: + + T _defaultValue; +}; + +template inline void* PointerAttribute::createAveraged(void* values[]) const { + T* total = new T(); + for (int i = 0; i < AVERAGE_COUNT; i++) { + *total += *static_cast(values[i]); + } + *total /= AVERAGE_COUNT; + return total; +} + #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index e7ac378ec2..5f7ad48876 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -150,7 +150,7 @@ void MetavoxelNode::setAttributeValue(const AttributeValue& attributeValue) { } AttributeValue MetavoxelNode::getAttributeValue(const AttributePointer& attribute) const { - return AttributeValue(attribute, &_attributeValue); + return AttributeValue(attribute, _attributeValue); } bool MetavoxelNode::isLeaf() const { From 5458e7a5550488388e7767ba3f868499be4f078d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 16 Dec 2013 12:05:16 -0800 Subject: [PATCH 14/65] Working on polymorphic attributes, average -> merge. --- .../metavoxels/src/AttributeRegistry.cpp | 40 +++++-- libraries/metavoxels/src/AttributeRegistry.h | 100 +++++++++++++----- libraries/metavoxels/src/MetavoxelData.cpp | 5 +- libraries/metavoxels/src/MetavoxelData.h | 4 +- 4 files changed, 104 insertions(+), 45 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 71ffe358ae..7eb295490d 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -13,7 +13,7 @@ AttributeRegistry AttributeRegistry::_instance; AttributeRegistry::AttributeRegistry() : _colorAttribute(registerAttribute(new QRgbAttribute("color"))), _normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))), - _voxelizerAttribute(registerAttribute(new PointerAttribute("voxelizer", false))) { + _voxelizerAttribute(registerAttribute(new SimplePointerAttribute("voxelizer", false))) { } AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { @@ -82,22 +82,40 @@ Attribute::~Attribute() { } QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) : - InlineAttribute(name, defaultValue) { + InlineAttribute(name, defaultValue) { } -void* QRgbAttribute::createAveraged(void* values[]) const { - int totalRed = 0; - int totalGreen = 0; - int totalBlue = 0; - int totalAlpha = 0; - for (int i = 0; i < AVERAGE_COUNT; i++) { - QRgb value = decodeInline(values[i]); +bool QRgbAttribute::merge(void*& parent, void* children[]) const { + QRgb firstValue = decodeInline(children[0]); + int totalRed = qRed(firstValue); + int totalGreen = qGreen(firstValue); + int totalBlue = qBlue(firstValue); + int totalAlpha = qAlpha(firstValue); + bool allChildrenEqual = true; + for (int i = 1; i < Attribute::MERGE_COUNT; i++) { + QRgb value = decodeInline(children[i]); totalRed += qRed(value); totalGreen += qGreen(value); totalBlue += qBlue(value); totalAlpha += qAlpha(value); + allChildrenEqual &= (firstValue == value); } - return encodeInline(qRgba(totalRed / AVERAGE_COUNT, totalGreen / AVERAGE_COUNT, - totalBlue / AVERAGE_COUNT, totalAlpha / AVERAGE_COUNT)); + parent = encodeInline(qRgba(totalRed / MERGE_COUNT, totalGreen / MERGE_COUNT, + totalBlue / MERGE_COUNT, totalAlpha / MERGE_COUNT)); + return allChildrenEqual; } +PolymorphicData::~PolymorphicData() { +} + +template<> PolymorphicData* QSharedDataPointer::clone() { + return d->clone(); +} + +PolymorphicAttribute::PolymorphicAttribute(const QString& name, const PolymorphicDataPointer& defaultValue) : + InlineAttribute(name, defaultValue) { +} + +bool PolymorphicAttribute::merge(void*& parent, void* children[]) const { + return false; +} diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index cf00d4d5fe..e956be078b 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include @@ -115,7 +117,7 @@ public: class Attribute { public: - static const int AVERAGE_COUNT = 8; + static const int MERGE_COUNT = 8; Attribute(const QString& name); virtual ~Attribute(); @@ -131,7 +133,9 @@ public: virtual bool equal(void* first, void* second) const = 0; - virtual void* createAveraged(void* values[]) const = 0; + /// Merges the value of a parent and its children. + /// \return whether or not the children and parent values are all equal + virtual bool merge(void*& parent, void* children[]) const = 0; virtual void* getDefaultValue() const = 0; @@ -141,44 +145,54 @@ private: }; /// A simple attribute class that stores its values inline. -template class InlineAttribute : public Attribute { +template class InlineAttribute : public Attribute { public: - InlineAttribute(const QString& name, T defaultValue = T()) : Attribute(name), _defaultValue(encodeInline(defaultValue)) { } + InlineAttribute(const QString& name, const T& defaultValue = T()) : Attribute(name), _defaultValue(defaultValue) { } - virtual void* create(void* copy) const { return copy; } - virtual void destroy(void* value) const { /* no-op */ } + virtual void* create(void* copy) const { void* value; new (&value) T(*(T*)©); return value; } + virtual void destroy(void* value) const { ((T*)&value)->~T(); } virtual bool read(Bitstream& in, void*& value) const { value = getDefaultValue(); in.read(&value, bits); return false; } virtual bool write(Bitstream& out, void* value) const { out.write(&value, bits); return false; } - virtual bool equal(void* first, void* second) const { return first == second; } + virtual bool equal(void* first, void* second) const { return decodeInline(first) == decodeInline(second); } - virtual void* createAveraged(void* values[]) const; - - virtual void* getDefaultValue() const { return _defaultValue; } + virtual void* getDefaultValue() const { return encodeInline(_defaultValue); } private: - void* _defaultValue; + T _defaultValue; }; -template inline void* InlineAttribute::createAveraged(void* values[]) const { - T total = T(); - for (int i = 0; i < AVERAGE_COUNT; i++) { - total += decodeInline(values[i]); +/// Provides merging using the =, ==, += and /= operators. +template class SimpleInlineAttribute : public InlineAttribute { +public: + + SimpleInlineAttribute(const QString& name, T defaultValue = T()) : InlineAttribute(name, defaultValue) { } + + virtual bool merge(void*& parent, void* children[]) const; +}; + +template inline bool SimpleInlineAttribute::merge(void*& parent, void* children[]) const { + T& merged = *(T*)&parent; + merged = decodeInline(children[0]); + bool allChildrenEqual = true; + for (int i = 1; i < Attribute::MERGE_COUNT; i++) { + merged += decodeInline(children[i]); + allChildrenEqual &= (decodeInline(children[0]) == decodeInline(children[i])); } - total /= AVERAGE_COUNT; - return encodeInline(total); + merged /= Attribute::MERGE_COUNT; + return allChildrenEqual; } /// Provides appropriate averaging for RGBA values. -class QRgbAttribute : public InlineAttribute { +class QRgbAttribute : public InlineAttribute { public: QRgbAttribute(const QString& name, QRgb defaultValue = QRgb()); - virtual void* createAveraged(void* values[]) const; + virtual bool merge(void*& parent, void* children[]) const; }; /// An attribute class that stores pointers to its values. @@ -195,8 +209,6 @@ public: virtual bool equal(void* first, void* second) const { return *static_cast(first) == *static_cast(second); } - virtual void* createAveraged(void* values[]) const; - virtual void* getDefaultValue() const { return const_cast((void*)&_defaultValue); } private: @@ -204,13 +216,47 @@ private: T _defaultValue; }; -template inline void* PointerAttribute::createAveraged(void* values[]) const { - T* total = new T(); - for (int i = 0; i < AVERAGE_COUNT; i++) { - *total += *static_cast(values[i]); +/// Provides merging using the =, ==, += and /= operators. +template class SimplePointerAttribute : public PointerAttribute { +public: + + SimplePointerAttribute(const QString& name, T defaultValue = T()) : PointerAttribute(name, defaultValue) { } + + virtual bool merge(void*& parent, void* children[]) const; +}; + +template inline bool SimplePointerAttribute::merge(void*& parent, void* children[]) const { + T& merged = *static_cast(parent); + merged = *static_cast(children[0]); + bool allChildrenEqual = true; + for (int i = 1; i < Attribute::MERGE_COUNT; i++) { + merged += *static_cast(children[i]); + allChildrenEqual &= (*static_cast(children[0]) == *static_cast(children[i])); } - *total /= AVERAGE_COUNT; - return total; + merged /= Attribute::MERGE_COUNT; + return allChildrenEqual; } +/// Base class for polymorphic attribute data. +class PolymorphicData : public QSharedData { +public: + + virtual ~PolymorphicData(); + + /// Creates a new clone of this object. + virtual PolymorphicData* clone() const = 0; +}; + +template<> PolymorphicData* QSharedDataPointer::clone(); + +typedef QSharedDataPointer PolymorphicDataPointer; + +/// Provides polymorphic streaming and averaging. +class PolymorphicAttribute : public InlineAttribute { + + PolymorphicAttribute(const QString& name, const PolymorphicDataPointer& defaultValue = PolymorphicDataPointer()); + + virtual bool merge(void*& parent, void* children[]) const; +}; + #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 5f7ad48876..d128e06296 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -132,10 +132,7 @@ bool MetavoxelNode::setAttributeValue(const MetavoxelPath& path, int index, cons childValues[i] = _children[i]->_attributeValue; allLeaves &= _children[i]->isLeaf(); } - attributeValue.getAttribute()->destroy(_attributeValue); - _attributeValue = attributeValue.getAttribute()->createAveraged(childValues); - - if (allLeaves && allChildrenEqual(attributeValue.getAttribute())) { + if (attributeValue.getAttribute()->merge(_attributeValue, childValues) && allLeaves) { clearChildren(attributeValue.getAttribute()); return true; } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index df42e73a21..dc3ff133d3 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -11,8 +11,6 @@ #include #include -#include -#include #include #include @@ -126,7 +124,7 @@ protected: }; /// Interface for objects that host metavoxel visitors. -class MetavoxelTraverser : public QSharedData { +class MetavoxelTraverser : public PolymorphicData { public: /// Applies the specified visitor to the contained voxels. From e788d746d480d1afc26f570a1ca01b1db1233e75 Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Mon, 16 Dec 2013 22:43:17 +0100 Subject: [PATCH 15/65] added dialog for log data - importing Inconsolata.otf on application level - style sheet for dialog - changed menu behaviour for log data --- interface/resources/styles/Inconsolata.otf | Bin 0 -> 58464 bytes interface/resources/styles/log_dialog.qss | 10 +++ interface/src/Application.cpp | 35 +++++------ interface/src/Menu.cpp | 28 ++++++++- interface/src/Menu.h | 6 ++ interface/src/ui/LogDialog.cpp | 70 +++++++++++++++++++++ interface/src/ui/LogDialog.h | 41 ++++++++++++ 7 files changed, 170 insertions(+), 20 deletions(-) create mode 100644 interface/resources/styles/Inconsolata.otf create mode 100644 interface/resources/styles/log_dialog.qss create mode 100644 interface/src/ui/LogDialog.cpp create mode 100644 interface/src/ui/LogDialog.h diff --git a/interface/resources/styles/Inconsolata.otf b/interface/resources/styles/Inconsolata.otf new file mode 100644 index 0000000000000000000000000000000000000000..348889828d894b9b57fb6435497d5c034448cb1b GIT binary patch literal 58464 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%0Aw$I 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 z*E*Y3`WXYIvka0CappendLogLine(message.toLocal8Bit().constData()); } Application::Application(int& argc, char** argv, timeval &startup_time) : @@ -142,10 +142,21 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _pasteMode(false) { _applicationStartupTime = startup_time; + +#ifdef Q_OS_MAC + QString resourcesPath = QCoreApplication::applicationDirPath() + "/../Resources"; +#else + QString resourcesPath = QCoreApplication::applicationDirPath() + "/resources"; +#endif + + QFontDatabase::addApplicationFont(resourcesPath + "/styles/Inconsolata.otf"); _window->setWindowTitle("Interface"); + // call Menu getInstance static method to set up the menu + _window->setMenuBar(Menu::getInstance()); + qInstallMessageHandler(messageHandler); - + unsigned int listenPort = 0; // bind to an ephemeral port by default const char** constArgv = const_cast(argv); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); @@ -170,14 +181,7 @@ 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); @@ -190,9 +194,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : 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. @@ -243,6 +244,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; @@ -3323,11 +3327,6 @@ void Application::displayOverlay() { if (Menu::getInstance()->isOptionChecked(MenuOption::CoverageMap)) { renderCoverageMap(); } - - - if (Menu::getInstance()->isOptionChecked(MenuOption::Log)) { - LogDisplay::instance.render(_glWidget->width(), _glWidget->height()); - } // Show chat entry field if (_chatEntryOn) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 13510067cd..83fb70cee3 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -69,7 +69,8 @@ Menu::Menu() : _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _boundaryLevelAdjust(0), - _maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS) + _maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS), + _logDialog(NULL) { Application *appInstance = Application::getInstance(); @@ -261,7 +262,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, this, SLOT(showLogDialog())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails())); @@ -1007,6 +1008,29 @@ void Menu::pasteToVoxel() { sendFakeEnterEvent(); } +void Menu::appendLogLine(QString logLine) { + if (_logDialog) { + _logDialog->appendLogLine(logLine); + } +} + +void Menu::showLogDialog() { + if (! _logDialog) { + _logDialog = new LogDialog(Application::getInstance()->getGLWidget()); + connect(_logDialog, SIGNAL(closed()), SLOT(logDialogClosed())); + + _logDialog->show(); + } + _logDialog->raise(); +} + +void Menu::logDialogClosed() { + if (_logDialog) { + delete _logDialog; + _logDialog = NULL; + } +} + void Menu::bandwidthDetails() { if (! _bandwidthDialog) { _bandwidthDialog = new BandwidthDialog(Application::getInstance()->getGLWidget(), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index aa3b925517..0ef507ca8b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -13,6 +13,8 @@ #include #include +#include "ui/LogDialog.h" + enum FrustumDrawMode { FRUSTUM_DRAW_MODE_ALL, FRUSTUM_DRAW_MODE_VECTORS, @@ -47,6 +49,7 @@ public: void triggerOption(const QString& menuOption); QAction* getActionForOption(const QString& menuOption); bool isVoxelModeActionChecked(); + void appendLogLine(QString logLine); float getAudioJitterBufferSamples() const { return _audioJitterBufferSamples; } float getFieldOfView() const { return _fieldOfView; } @@ -81,6 +84,7 @@ public slots: void exportSettings(); void goToUser(); void pasteToVoxel(); + void showLogDialog(); private slots: void aboutApp(); @@ -96,6 +100,7 @@ private slots: void chooseVoxelPaintColor(); void runTests(); void resetSwatchColors(); + void logDialogClosed(); private: static Menu* _instance; @@ -141,6 +146,7 @@ private: int _boundaryLevelAdjust; QAction* _useVoxelShader; int _maxVoxelPacketsPerSecond; + LogDialog* _logDialog; }; namespace MenuOption { diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp new file mode 100644 index 0000000000..7edffd2f83 --- /dev/null +++ b/interface/src/ui/LogDialog.cpp @@ -0,0 +1,70 @@ +// +// LogDialog.cpp +// interface +// +// Created by Stojce Slavkovski on 12/12/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include +#include +#include + +#include "SharedUtil.h" +#include "ui/LogDialog.h" + +#define INITIAL_WIDTH_RATIO 0.3 +#define INITIAL_HEIGHT_RATIO 0.6 + +int cursorMeta = qRegisterMetaType("QTextCursor"); +int blockMeta = qRegisterMetaType("QTextBlock"); + +LogDialog::LogDialog(QWidget* parent) : + QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) { + + 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 = new QDesktopWidget(); + QRect screen = desktop->screenGeometry(); + resize((int)(screen.width() * INITIAL_WIDTH_RATIO), (int)(screen.height() * INITIAL_HEIGHT_RATIO)); + move(screen.center() - rect().center()); + delete desktop; +} + +LogDialog::~LogDialog() { + delete _logTextBox; +} + +void LogDialog::showEvent(QShowEvent *e) { + _logTextBox->clear(); +} + +void LogDialog::resizeEvent(QResizeEvent *e) { + _logTextBox->resize(width(), height()); +} + +void LogDialog::appendLogLine(QString logLine) { + if (isVisible()) { + _logTextBox->appendPlainText(logLine.simplified()); + _logTextBox->ensureCursorVisible(); + } +} + +void LogDialog::reject() { + this->QDialog::close(); +} + +void LogDialog::closeEvent(QCloseEvent* event) { + emit closed(); +} diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h new file mode 100644 index 0000000000..6b847cd66f --- /dev/null +++ b/interface/src/ui/LogDialog.h @@ -0,0 +1,41 @@ +// +// 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 +#include + +class LogDialog : public QDialog { + Q_OBJECT + +public: + LogDialog(QWidget* parent); + ~LogDialog(); + void appendLogLine(QString logLine); + +signals: + void closed(); + +public slots: + void reject(); + +protected: + // Emits a 'closed' signal when this dialog is closed. + void closeEvent(QCloseEvent* e); + void resizeEvent(QResizeEvent* e); + void showEvent(QShowEvent* e); + +private: + QPlainTextEdit* _logTextBox; + +}; + +#endif + From 0ca23207113400a37a4ae36db64ac60d1c14dff8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 16 Dec 2013 13:44:24 -0800 Subject: [PATCH 16/65] Working on guide/script support. --- interface/src/renderer/MetavoxelSystem.cpp | 9 +--- libraries/metavoxels/CMakeLists.txt | 2 +- .../metavoxels/src/AttributeRegistry.cpp | 5 ++- libraries/metavoxels/src/AttributeRegistry.h | 11 ++--- libraries/metavoxels/src/MetavoxelData.cpp | 18 +++++++- libraries/metavoxels/src/MetavoxelData.h | 41 ++++++++++++++++--- 6 files changed, 65 insertions(+), 21 deletions(-) diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index 26f722f65c..18fb6de2ab 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -39,16 +39,13 @@ void MetavoxelSystem::init() { _data.setAttributeValue(p1, AttributeValue(color, encodeInline(qRgba(0xFF, 0xFF, 0xFF, 0xFF)))); - bool blerp = true; - _data.setAttributeValue(p1, AttributeValue(AttributeRegistry::getInstance()->getAttribute("voxelizer"), &blerp)); - _buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); _buffer.create(); } void MetavoxelSystem::simulate(float deltaTime) { _points.clear(); - _data.traverse(_pointVisitor); + _data.guide(_pointVisitor); _buffer.bind(); int bytes = _points.size() * sizeof(Point); @@ -104,8 +101,7 @@ void MetavoxelSystem::render() { MetavoxelSystem::PointVisitor::PointVisitor(QVector& points) : MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getColorAttribute() << - AttributeRegistry::getInstance()->getNormalAttribute() << - AttributeRegistry::getInstance()->getVoxelizerAttribute()), + AttributeRegistry::getInstance()->getNormalAttribute()), _points(points) { } @@ -115,7 +111,6 @@ bool MetavoxelSystem::PointVisitor::visit(const MetavoxelInfo& info) { } QRgb color = info.attributeValues.at(0).getInlineValue(); QRgb normal = info.attributeValues.at(1).getInlineValue(); - bool blerp = *info.attributeValues.at(2).getPointerValue(); int alpha = qAlpha(color); if (alpha > 0) { Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index 92594af4ef..0f9c1c695c 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -13,7 +13,7 @@ find_package(Qt5Widgets REQUIRED) include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -qt5_use_modules(${TARGET_NAME} Widgets) +qt5_use_modules(${TARGET_NAME} Widgets Script) include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} ${ROOT_DIR}) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 7eb295490d..2b1875223e 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -7,13 +7,14 @@ // #include "AttributeRegistry.h" +#include "MetavoxelData.h" AttributeRegistry AttributeRegistry::_instance; AttributeRegistry::AttributeRegistry() : + _guideAttribute(registerAttribute(new PolymorphicAttribute("guide", PolymorphicDataPointer(new DefaultMetavoxelGuide())))), _colorAttribute(registerAttribute(new QRgbAttribute("color"))), - _normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))), - _voxelizerAttribute(registerAttribute(new SimplePointerAttribute("voxelizer", false))) { + _normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) { } AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index e956be078b..f905c08eb0 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -44,23 +44,23 @@ public: /// Retrieves an attribute by name. AttributePointer getAttribute(const QString& name) const { return _attributes.value(name); } + /// Returns a reference to the standard PolymorphicDataPointer "guide" attribute. + const AttributePointer& getGuideAttribute() const { return _guideAttribute; } + /// Returns a reference to the standard QRgb "color" attribute. const AttributePointer& getColorAttribute() const { return _colorAttribute; } /// Returns a reference to the standard QRgb "normal" attribute. const AttributePointer& getNormalAttribute() const { return _normalAttribute; } - /// Returns a reference to the standard "voxelizer" attribute. - const AttributePointer& getVoxelizerAttribute() const { return _voxelizerAttribute; } - private: static AttributeRegistry _instance; QHash _attributes; + AttributePointer _guideAttribute; AttributePointer _colorAttribute; AttributePointer _normalAttribute; - AttributePointer _voxelizerAttribute; }; /// Converts a value to a void pointer. @@ -253,7 +253,8 @@ typedef QSharedDataPointer PolymorphicDataPointer; /// Provides polymorphic streaming and averaging. class PolymorphicAttribute : public InlineAttribute { - +public: + PolymorphicAttribute(const QString& name, const PolymorphicDataPointer& defaultValue = PolymorphicDataPointer()); virtual bool merge(void*& parent, void* children[]) const; diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index d128e06296..0eb7b55165 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -63,7 +63,7 @@ bool Visitation::allNodesLeaves() const { return true; } -void MetavoxelData::traverse(MetavoxelVisitor& visitor) { +void MetavoxelData::guide(MetavoxelVisitor& visitor) { // start with the root values/defaults const float TOP_LEVEL_SIZE = 1.0f; const QVector& attributes = visitor.getAttributes(); @@ -202,3 +202,19 @@ MetavoxelPath& MetavoxelPath::operator+=(int element) { return *this; } +PolymorphicData* DefaultMetavoxelGuide::clone() const { + return new DefaultMetavoxelGuide(); +} + +void DefaultMetavoxelGuide::guide(MetavoxelTour& tour) const { +} + +ScriptedMetavoxelGuide::ScriptedMetavoxelGuide(const QScriptValue& guideFunction) : _guideFunction(guideFunction) { +} + +PolymorphicData* ScriptedMetavoxelGuide::clone() const { + return new ScriptedMetavoxelGuide(_guideFunction); +} + +void ScriptedMetavoxelGuide::guide(MetavoxelTour& tour) const { +} diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index dc3ff133d3..b43292bf0b 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -19,6 +20,7 @@ class MetavoxelNode; class MetavoxelPath; +class MetavoxelTour; class MetavoxelVisitor; /// The base metavoxel representation shared between server and client. @@ -28,7 +30,7 @@ public: ~MetavoxelData(); /// Applies the specified visitor to the contained voxels. - void traverse(MetavoxelVisitor& visitor); + void guide(MetavoxelVisitor& visitor); /// Sets the attribute value corresponding to the specified path. void setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue); @@ -123,12 +125,41 @@ protected: QVector _attributes; }; -/// Interface for objects that host metavoxel visitors. -class MetavoxelTraverser : public PolymorphicData { +/// Interface for objects that guide metavoxel visitors. +class MetavoxelGuide : public PolymorphicData { public: - /// Applies the specified visitor to the contained voxels. - virtual void traverse(MetavoxelVisitor& visitor) = 0; + /// Guides the specified visitor to the contained voxels. + virtual void guide(MetavoxelTour& tour) const = 0; +}; + +/// Guides visitors through the explicit content of the system. +class DefaultMetavoxelGuide : public MetavoxelGuide { +public: + + virtual PolymorphicData* clone() const; + + virtual void guide(MetavoxelTour& tour) const; +}; + +/// Represents a guide implemented in Javascript. +class ScriptedMetavoxelGuide : public MetavoxelGuide { +public: + + ScriptedMetavoxelGuide(const QScriptValue& guideFunction); + + virtual PolymorphicData* clone() const; + + virtual void guide(MetavoxelTour& tour) const; + +private: + + QScriptValue _guideFunction; +}; + +/// Contains the state associated with a tour of a metavoxel system. +class MetavoxelTour { + }; #endif /* defined(__interface__MetavoxelData__) */ From 6385a73379a1d850df72289d52353d25c885e6e5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 16 Dec 2013 17:53:53 -0800 Subject: [PATCH 17/65] Working on scripty bits. --- interface/CMakeLists.txt | 2 +- interface/src/renderer/MetavoxelSystem.cpp | 7 + interface/src/renderer/MetavoxelSystem.h | 2 + .../metavoxels/src/AttributeRegistry.cpp | 2 +- libraries/metavoxels/src/AttributeRegistry.h | 6 +- libraries/metavoxels/src/MetavoxelData.cpp | 142 ++++++++++-------- libraries/metavoxels/src/MetavoxelData.h | 29 +++- 7 files changed, 114 insertions(+), 76 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 7f22495c8a..e62db989ee 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -135,7 +135,7 @@ if (LIBOVR_FOUND AND NOT DISABLE_LIBOVR) target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR) -qt5_use_modules(${TARGET_NAME} Core Gui Multimedia Network OpenGL Svg WebKit WebKitWidgets) +qt5_use_modules(${TARGET_NAME} Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets) # include headers for interface and InterfaceConfig. include_directories( diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index 18fb6de2ab..065fd10ef5 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -39,6 +39,13 @@ void MetavoxelSystem::init() { _data.setAttributeValue(p1, AttributeValue(color, encodeInline(qRgba(0xFF, 0xFF, 0xFF, 0xFF)))); + QScriptValue guideFunction = _scriptEngine.evaluate( + "(function(visitation) { " + " visitation.visitor.visit(visitation.info);" + "})"); + _data.setAttributeValue(MetavoxelPath(), AttributeValue(AttributeRegistry::getInstance()->getGuideAttribute(), + encodeInline(PolymorphicDataPointer(new ScriptedMetavoxelGuide(guideFunction))))); + _buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); _buffer.create(); } diff --git a/interface/src/renderer/MetavoxelSystem.h b/interface/src/renderer/MetavoxelSystem.h index 1b4a749581..b8617d99a4 100644 --- a/interface/src/renderer/MetavoxelSystem.h +++ b/interface/src/renderer/MetavoxelSystem.h @@ -10,6 +10,7 @@ #define __interface__MetavoxelSystem__ #include +#include #include #include @@ -50,6 +51,7 @@ private: static ProgramObject _program; static int _pointScaleLocation; + QScriptEngine _scriptEngine; MetavoxelData _data; QVector _points; PointVisitor _pointVisitor; diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 2b1875223e..a113162efa 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -109,7 +109,7 @@ bool QRgbAttribute::merge(void*& parent, void* children[]) const { PolymorphicData::~PolymorphicData() { } -template<> PolymorphicData* QSharedDataPointer::clone() { +template<> PolymorphicData* QExplicitlySharedDataPointer::clone() { return d->clone(); } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index f905c08eb0..41b1005ad0 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -10,9 +10,9 @@ #define __interface__AttributeRegistry__ #include +#include #include #include -#include #include #include @@ -247,9 +247,9 @@ public: virtual PolymorphicData* clone() const = 0; }; -template<> PolymorphicData* QSharedDataPointer::clone(); +template<> PolymorphicData* QExplicitlySharedDataPointer::clone(); -typedef QSharedDataPointer PolymorphicDataPointer; +typedef QExplicitlySharedDataPointer PolymorphicDataPointer; /// Provides polymorphic streaming and averaging. class PolymorphicAttribute : public InlineAttribute { diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 0eb7b55165..76a405b38a 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -6,6 +6,9 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +#include +#include + #include "MetavoxelData.h" MetavoxelData::~MetavoxelData() { @@ -15,66 +18,23 @@ MetavoxelData::~MetavoxelData() { } } -class Visitation { -public: - MetavoxelVisitor& visitor; - QVector nodes; - MetavoxelInfo info; - - void apply(); - -protected: - - bool allNodesLeaves() const; -}; - -const int X_MAXIMUM_FLAG = 1; -const int Y_MAXIMUM_FLAG = 2; -const int Z_MAXIMUM_FLAG = 4; - -void Visitation::apply() { - info.isLeaf = allNodesLeaves(); - if (!visitor.visit(info) || info.isLeaf) { - return; - } - Visitation nextVisitation = { visitor, QVector(nodes.size()), - { glm::vec3(), info.size * 0.5f, QVector(nodes.size()) } }; - for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { - for (int j = 0; j < nodes.size(); j++) { - MetavoxelNode* node = nodes.at(j); - MetavoxelNode* child = node ? node->getChild(i) : NULL; - nextVisitation.info.attributeValues[j] = ((nextVisitation.nodes[j] = child)) ? - child->getAttributeValue(info.attributeValues[j].getAttribute()) : info.attributeValues[j]; - } - nextVisitation.info.minimum = info.minimum + glm::vec3( - (i & X_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f, - (i & Y_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f, - (i & Z_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f); - nextVisitation.apply(); - } -} - -bool Visitation::allNodesLeaves() const { - foreach (MetavoxelNode* node, nodes) { - if (node != NULL && !node->isLeaf()) { - return false; - } - } - return true; -} - void MetavoxelData::guide(MetavoxelVisitor& visitor) { - // start with the root values/defaults + // start with the root values/defaults (plus the guide attribute) const float TOP_LEVEL_SIZE = 1.0f; const QVector& attributes = visitor.getAttributes(); - Visitation firstVisitation = { visitor, QVector(attributes.size()), - { glm::vec3(), TOP_LEVEL_SIZE, QVector(attributes.size()) } }; + MetavoxelVisitation firstVisitation = { visitor, QVector(attributes.size() + 1), + { glm::vec3(), TOP_LEVEL_SIZE, QVector(attributes.size() + 1) } }; for (int i = 0; i < attributes.size(); i++) { MetavoxelNode* node = _roots.value(attributes[i]); firstVisitation.nodes[i] = node; firstVisitation.info.attributeValues[i] = node ? node->getAttributeValue(attributes[i]) : attributes[i]; } - firstVisitation.apply(); + AttributePointer guideAttribute = AttributeRegistry::getInstance()->getGuideAttribute(); + MetavoxelNode* node = _roots.value(guideAttribute); + firstVisitation.nodes.last() = node; + firstVisitation.info.attributeValues.last() = node ? node->getAttributeValue(guideAttribute) : guideAttribute; + static_cast(firstVisitation.info.attributeValues.last().getInlineValue< + PolymorphicDataPointer>().data())->guide(firstVisitation); } void MetavoxelData::setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue) { @@ -169,15 +129,6 @@ void MetavoxelNode::destroy(const AttributePointer& attribute) { } } -bool MetavoxelNode::allChildrenEqual(const AttributePointer& attribute) const { - for (int i = 0; i < CHILD_COUNT; i++) { - if (!attribute->equal(_attributeValue, _children[i]->_attributeValue)) { - return false; - } - } - return true; -} - void MetavoxelNode::clearChildren(const AttributePointer& attribute) { for (int i = 0; i < CHILD_COUNT; i++) { if (_children[i]) { @@ -206,15 +157,78 @@ PolymorphicData* DefaultMetavoxelGuide::clone() const { return new DefaultMetavoxelGuide(); } -void DefaultMetavoxelGuide::guide(MetavoxelTour& tour) const { +const int X_MAXIMUM_FLAG = 1; +const int Y_MAXIMUM_FLAG = 2; +const int Z_MAXIMUM_FLAG = 4; + +void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { + visitation.info.isLeaf = visitation.allNodesLeaves(); + if (!visitation.visitor.visit(visitation.info) || visitation.info.isLeaf) { + return; + } + MetavoxelVisitation nextVisitation = { visitation.visitor, QVector(visitation.nodes.size()), + { glm::vec3(), visitation.info.size * 0.5f, QVector(visitation.nodes.size()) } }; + for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + for (int j = 0; j < visitation.nodes.size(); j++) { + MetavoxelNode* node = visitation.nodes.at(j); + MetavoxelNode* child = node ? node->getChild(i) : NULL; + nextVisitation.info.attributeValues[j] = ((nextVisitation.nodes[j] = child)) ? + child->getAttributeValue(visitation.info.attributeValues[j].getAttribute()) : + visitation.info.attributeValues[j]; + } + nextVisitation.info.minimum = visitation.info.minimum + glm::vec3( + (i & X_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f, + (i & Y_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f, + (i & Z_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f); + static_cast(nextVisitation.info.attributeValues.last().getInlineValue< + PolymorphicDataPointer>().data())->guide(nextVisitation); + } } -ScriptedMetavoxelGuide::ScriptedMetavoxelGuide(const QScriptValue& guideFunction) : _guideFunction(guideFunction) { +QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngine* engine) { + qDebug() << context->callee().data().toVariant() << " oh hi thar\n"; + + MetavoxelInfo info; + QScriptValue infoValue = context->argument(0); + + + + return QScriptValue(); +} + +ScriptedMetavoxelGuide::ScriptedMetavoxelGuide(const QScriptValue& guideFunction) : + _guideFunction(guideFunction), + _sizeHandle(guideFunction.engine()->toStringHandle("size")), + _visitFunction(guideFunction.engine()->newFunction(visit, 1)), + _info(guideFunction.engine()->newObject()), + _minimum(guideFunction.engine()->newArray(3)) { + + _arguments.append(guideFunction.engine()->newObject()); + QScriptValue visitor = guideFunction.engine()->newObject(); + visitor.setProperty("visit", _visitFunction); + _arguments[0].setProperty("visitor", visitor); + _arguments[0].setProperty("info", _info); + _info.setProperty("minimum", _minimum); } PolymorphicData* ScriptedMetavoxelGuide::clone() const { return new ScriptedMetavoxelGuide(_guideFunction); } -void ScriptedMetavoxelGuide::guide(MetavoxelTour& tour) const { +void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) { + _visitFunction.setData(_guideFunction.engine()->newVariant(QVariant::fromValue(this))); + _minimum.setProperty(0, visitation.info.minimum.x); + _minimum.setProperty(1, visitation.info.minimum.y); + _minimum.setProperty(2, visitation.info.minimum.z); + _info.setProperty(_sizeHandle, visitation.info.size); + _guideFunction.call(QScriptValue(), _arguments); +} + +bool MetavoxelVisitation::allNodesLeaves() const { + foreach (MetavoxelNode* node, nodes) { + if (node != NULL && !node->isLeaf()) { + return false; + } + } + return true; } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index b43292bf0b..6e90da4b86 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -18,9 +19,11 @@ #include "AttributeRegistry.h" +class QScriptContext; + class MetavoxelNode; class MetavoxelPath; -class MetavoxelTour; +class MetavoxelVisitation; class MetavoxelVisitor; /// The base metavoxel representation shared between server and client. @@ -71,7 +74,6 @@ public: private: Q_DISABLE_COPY(MetavoxelNode) - bool allChildrenEqual(const AttributePointer& attribute) const; void clearChildren(const AttributePointer& attribute); void* _attributeValue; @@ -130,7 +132,7 @@ class MetavoxelGuide : public PolymorphicData { public: /// Guides the specified visitor to the contained voxels. - virtual void guide(MetavoxelTour& tour) const = 0; + virtual void guide(MetavoxelVisitation& visitation) = 0; }; /// Guides visitors through the explicit content of the system. @@ -139,7 +141,7 @@ public: virtual PolymorphicData* clone() const; - virtual void guide(MetavoxelTour& tour) const; + virtual void guide(MetavoxelVisitation& visitation); }; /// Represents a guide implemented in Javascript. @@ -150,16 +152,29 @@ public: virtual PolymorphicData* clone() const; - virtual void guide(MetavoxelTour& tour) const; + virtual void guide(MetavoxelVisitation& visitation); private: + static QScriptValue visit(QScriptContext* context, QScriptEngine* engine); + QScriptValue _guideFunction; + QScriptString _sizeHandle; + QScriptValueList _arguments; + QScriptValue _visitFunction; + QScriptValue _info; + QScriptValue _minimum; }; -/// Contains the state associated with a tour of a metavoxel system. -class MetavoxelTour { +/// Contains the state associated with a visit to a metavoxel system. +class MetavoxelVisitation { +public: + + MetavoxelVisitor& visitor; + QVector nodes; + MetavoxelInfo info; + bool allNodesLeaves() const; }; #endif /* defined(__interface__MetavoxelData__) */ From cc6f7ed4cc1a8e77a5312bac8b3389c5d99ea8ab Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Tue, 17 Dec 2013 03:07:57 +0100 Subject: [PATCH 18/65] display all log data on load --- interface/src/Application.cpp | 5 +++-- interface/src/LogDisplay.cpp | 1 + interface/src/LogDisplay.h | 9 ++++++++- interface/src/Menu.cpp | 6 ------ interface/src/Menu.h | 1 - interface/src/ui/LogDialog.cpp | 17 +++++++++++++++-- interface/src/ui/LogDialog.h | 3 ++- 7 files changed, 29 insertions(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ce9fcdb434..7bc74843ff 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -87,7 +87,7 @@ const float MIRROR_REARVIEW_BODY_DISTANCE = 1.f; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) { fprintf(stdout, "%s", message.toLocal8Bit().constData()); - Menu::getInstance()->appendLogLine(message.toLocal8Bit().constData()); + LogDisplay::instance.addMessage(message.toLocal8Bit().constData()); } Application::Application(int& argc, char** argv, timeval &startup_time) : @@ -153,9 +153,10 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : QFontDatabase::addApplicationFont(resourcesPath + "/styles/Inconsolata.otf"); _window->setWindowTitle("Interface"); + qInstallMessageHandler(messageHandler); + // call Menu getInstance static method to set up the menu _window->setMenuBar(Menu::getInstance()); - qInstallMessageHandler(messageHandler); qDebug( "[VERSION] Build sequence: %i", BUILD_VERSION); diff --git a/interface/src/LogDisplay.cpp b/interface/src/LogDisplay.cpp index 247ea4beb5..bc674059d3 100644 --- a/interface/src/LogDisplay.cpp +++ b/interface/src/LogDisplay.cpp @@ -90,6 +90,7 @@ void LogDisplay::setCharacterSize(unsigned width, unsigned height) { void LogDisplay::addMessage(const char* ptr) { + emit logReceived(ptr); pthread_mutex_lock(& _mutex); // T-pipe, if requested diff --git a/interface/src/LogDisplay.h b/interface/src/LogDisplay.h index 6f90df3724..29080d075e 100644 --- a/interface/src/LogDisplay.h +++ b/interface/src/LogDisplay.h @@ -14,7 +14,8 @@ #include "ui/TextRenderer.h" -class LogDisplay { +class LogDisplay : public QObject { + Q_OBJECT public: static LogDisplay instance; @@ -43,6 +44,12 @@ 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 + char** getLogData() { return _lines; }; + char** getLastLinePos() { return _lastLinePos; } + +signals: + void logReceived(QString message); + private: // use static 'instance' to access the single instance LogDisplay(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 059286a52a..98a40cb836 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1014,12 +1014,6 @@ void Menu::pasteToVoxel() { sendFakeEnterEvent(); } -void Menu::appendLogLine(QString logLine) { - if (_logDialog) { - _logDialog->appendLogLine(logLine); - } -} - void Menu::showLogDialog() { if (! _logDialog) { _logDialog = new LogDialog(Application::getInstance()->getGLWidget()); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index a24ca87c9f..948c0c9bea 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -49,7 +49,6 @@ public: void triggerOption(const QString& menuOption); QAction* getActionForOption(const QString& menuOption); bool isVoxelModeActionChecked(); - void appendLogLine(QString logLine); float getAudioJitterBufferSamples() const { return _audioJitterBufferSamples; } float getFieldOfView() const { return _fieldOfView; } diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index ed6bdb840a..5717521d90 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -12,6 +12,7 @@ #include "SharedUtil.h" #include "ui/LogDialog.h" +#include "LogDisplay.h" #define INITIAL_WIDTH_RATIO 0.3 #define INITIAL_HEIGHT_RATIO 0.6 @@ -37,7 +38,7 @@ LogDialog::LogDialog(QWidget* parent) : QDesktopWidget* desktop = new QDesktopWidget(); QRect screen = desktop->screenGeometry(); - resize((int)(screen.width() * INITIAL_WIDTH_RATIO), (int)(screen.height() * INITIAL_HEIGHT_RATIO)); + resize(static_cast(screen.width() * INITIAL_WIDTH_RATIO), static_cast(screen.height() * INITIAL_HEIGHT_RATIO)); move(screen.center() - rect().center()); delete desktop; } @@ -49,6 +50,18 @@ LogDialog::~LogDialog() { void LogDialog::showEvent(QShowEvent *e) { _logTextBox->clear(); + pthread_mutex_lock(& _mutex); + char** _lines = LogDisplay::instance.getLogData(); + char** _lastLinePos = LogDisplay::instance.getLastLinePos(); + + int i = 0; + while (_lines[i] != *_lastLinePos) { + appendLogLine(_lines[i]); + i++; + } + + connect(&LogDisplay::instance, &LogDisplay::logReceived, this, &LogDialog::appendLogLine); + pthread_mutex_unlock(& _mutex); } void LogDialog::resizeEvent(QResizeEvent *e) { @@ -63,7 +76,7 @@ void LogDialog::appendLogLine(QString logLine) { } void LogDialog::reject() { - this->QDialog::close(); + close(); } void LogDialog::closeEvent(QCloseEvent* event) { diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h index 6b847cd66f..7b445b6f4f 100644 --- a/interface/src/ui/LogDialog.h +++ b/interface/src/ui/LogDialog.h @@ -18,13 +18,13 @@ class LogDialog : public QDialog { public: LogDialog(QWidget* parent); ~LogDialog(); - void appendLogLine(QString logLine); signals: void closed(); public slots: void reject(); + void appendLogLine(QString logLine); protected: // Emits a 'closed' signal when this dialog is closed. @@ -34,6 +34,7 @@ protected: private: QPlainTextEdit* _logTextBox; + pthread_mutex_t _mutex; }; From 07ed688a8af6363e0d885dd5d93201dd4fc23606 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 16 Dec 2013 18:13:29 -0800 Subject: [PATCH 19/65] A few more script bits. --- libraries/metavoxels/src/MetavoxelData.cpp | 19 +++++++++++++------ libraries/metavoxels/src/MetavoxelData.h | 4 ++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 76a405b38a..945289c151 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -186,19 +186,24 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { } QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngine* engine) { - qDebug() << context->callee().data().toVariant() << " oh hi thar\n"; - + ScriptedMetavoxelGuide* guide = static_cast(context->callee().data().toVariant().value()); + MetavoxelInfo info; QScriptValue infoValue = context->argument(0); + QScriptValue minimumValue = infoValue.property(guide->_minimumHandle); + info.minimum = glm::vec3(minimumValue.property(0).toNumber(), minimumValue.property(1).toNumber(), + minimumValue.property(2).toNumber()); + info.size = infoValue.property(guide->_sizeHandle).toNumber(); + info.isLeaf = infoValue.property(guide->_isLeafHandle).toBool(); - - - return QScriptValue(); + return guide->_visitor->visit(info); } ScriptedMetavoxelGuide::ScriptedMetavoxelGuide(const QScriptValue& guideFunction) : _guideFunction(guideFunction), + _minimumHandle(guideFunction.engine()->toStringHandle("minimum")), _sizeHandle(guideFunction.engine()->toStringHandle("size")), + _isLeafHandle(guideFunction.engine()->toStringHandle("isLeaf")), _visitFunction(guideFunction.engine()->newFunction(visit, 1)), _info(guideFunction.engine()->newObject()), _minimum(guideFunction.engine()->newArray(3)) { @@ -208,7 +213,7 @@ ScriptedMetavoxelGuide::ScriptedMetavoxelGuide(const QScriptValue& guideFunction visitor.setProperty("visit", _visitFunction); _arguments[0].setProperty("visitor", visitor); _arguments[0].setProperty("info", _info); - _info.setProperty("minimum", _minimum); + _info.setProperty(_minimumHandle, _minimum); } PolymorphicData* ScriptedMetavoxelGuide::clone() const { @@ -221,6 +226,8 @@ void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) { _minimum.setProperty(1, visitation.info.minimum.y); _minimum.setProperty(2, visitation.info.minimum.z); _info.setProperty(_sizeHandle, visitation.info.size); + _info.setProperty(_isLeafHandle, visitation.info.isLeaf); + _visitor = &visitation.visitor; _guideFunction.call(QScriptValue(), _arguments); } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 6e90da4b86..0af6fba582 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -159,11 +159,15 @@ private: static QScriptValue visit(QScriptContext* context, QScriptEngine* engine); QScriptValue _guideFunction; + QScriptString _minimumHandle; QScriptString _sizeHandle; + QScriptString _isLeafHandle; QScriptValueList _arguments; QScriptValue _visitFunction; QScriptValue _info; QScriptValue _minimum; + + MetavoxelVisitor* _visitor; }; /// Contains the state associated with a visit to a metavoxel system. From 95639c7ce799483767414eeb942c9de9e14d9dad Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 17 Dec 2013 10:58:36 -0800 Subject: [PATCH 20/65] first cut, not working yet --- assignment-client/CMakeLists.txt | 14 ++++ assignment-client/src/Agent.cpp | 73 ++------------------ assignment-client/src/Agent.h | 2 + libraries/scriptengine/src/ScriptEngine.cpp | 16 ++++- libraries/scriptengine/src/ScriptEngine.h | 8 ++- libraries/shared/CMakeLists.txt | 3 + libraries/shared/src/AbstractMenuInterface.h | 7 ++ 7 files changed, 53 insertions(+), 70 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 5bc4829117..1d2fb866bb 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -8,12 +8,25 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros) # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") +set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} $ENV{QT_CMAKE_PREFIX_PATH}) + +find_package(Qt5Core REQUIRED) +find_package(Qt5Gui REQUIRED) find_package(Qt5Network REQUIRED) +#find_package(Qt5Multimedia REQUIRED) +#find_package(Qt5Network REQUIRED) +#find_package(Qt5OpenGL REQUIRED) +#find_package(Qt5Svg REQUIRED) +#find_package(Qt5WebKit REQUIRED) +#find_package(Qt5WebKitWidgets REQUIRED) + + include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) qt5_use_modules(${TARGET_NAME} Network) +qt5_use_modules(${TARGET_NAME} Gui) # include glm include(${MACRO_DIR}/IncludeGLM.cmake) @@ -30,6 +43,7 @@ link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(octree-server ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(particle-server ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(voxel-server ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(scriptengine ${TARGET_NAME} ${ROOT_DIR}) #testing include_directories(${ROOT_DIR}/externals/civetweb/include) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 8f02ed9a2e..9fbe464a9e 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -76,28 +76,6 @@ void Agent::run() { loop.exec(); QString scriptContents(reply->readAll()); - QScriptEngine engine; - - // register meta-type for glm::vec3 conversions - registerMetaTypes(&engine); - - QScriptValue agentValue = engine.newQObject(this); - engine.globalObject().setProperty("Agent", agentValue); - - QScriptValue voxelScripterValue = engine.newQObject(&_voxelScriptingInterface); - engine.globalObject().setProperty("Voxels", voxelScripterValue); - - QScriptValue particleScripterValue = engine.newQObject(&_particleScriptingInterface); - engine.globalObject().setProperty("Particles", particleScripterValue); - - QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); - engine.globalObject().setProperty("TREE_SCALE", treeScaleValue); - - const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; - - // let the VoxelPacketSender know how frequently we plan to call it - _voxelScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); - _particleScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); qDebug() << "Downloaded script:" << scriptContents << "\n"; QScriptValue result = engine.evaluate(scriptContents); @@ -124,50 +102,13 @@ void Agent::run() { QTimer* pingNodesTimer = new QTimer(this); connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes())); pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000); + + const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; + // let the VoxelPacketSender know how frequently we plan to call it + _voxelScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); + _particleScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); - while (!_isFinished) { - - int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * VISUAL_DATA_CALLBACK_USECS) - usecTimestampNow(); - if (usecToSleep > 0) { - usleep(usecToSleep); - } - - QCoreApplication::processEvents(); - - bool willSendVisualDataCallBack = false; - - if (_voxelScriptingInterface.getVoxelPacketSender()->voxelServersExist()) { - // allow the scripter's call back to setup visual data - willSendVisualDataCallBack = true; - - // release the queue of edit voxel messages. - _voxelScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages(); - - // since we're in non-threaded mode, call process so that the packets are sent - _voxelScriptingInterface.getVoxelPacketSender()->process(); - } + _scriptEngine.setScriptContents(scriptContents); - if (_particleScriptingInterface.getParticlePacketSender()->serversExist()) { - // allow the scripter's call back to setup visual data - willSendVisualDataCallBack = true; - - // release the queue of edit voxel messages. - _particleScriptingInterface.getParticlePacketSender()->releaseQueuedMessages(); - - // since we're in non-threaded mode, call process so that the packets are sent - _particleScriptingInterface.getParticlePacketSender()->process(); - } - - if (willSendVisualDataCallBack) { - emit willSendVisualDataCallback(); - } - - - if (engine.hasUncaughtException()) { - int line = engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; - } - - - } + _scriptEngine.run(); } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 1c2be08662..e6e7eb84b1 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -35,6 +36,7 @@ signals: private: VoxelScriptingInterface _voxelScriptingInterface; ParticleScriptingInterface _particleScriptingInterface; + ScriptEngine _scriptEngine; }; #endif /* defined(__hifi__Agent__) */ diff --git a/libraries/scriptengine/src/ScriptEngine.cpp b/libraries/scriptengine/src/ScriptEngine.cpp index 7e5f414dee..7d34a4edf6 100644 --- a/libraries/scriptengine/src/ScriptEngine.cpp +++ b/libraries/scriptengine/src/ScriptEngine.cpp @@ -28,6 +28,9 @@ ScriptEngine::ScriptEngine(QString scriptContents, bool wantMenuItems, const char* scriptMenuName, AbstractMenuInterface* menu) { _scriptContents = scriptContents; _isFinished = false; + _isRunning = false; + + // some clients will use these menu features _wantMenuItems = wantMenuItems; if (scriptMenuName) { _scriptMenuName = "Stop "; @@ -57,10 +60,16 @@ void ScriptEngine::cleanMenuItems() { } } -void ScriptEngine::run() { +bool ScriptEngine::setScriptContents(QString scriptContents) { + if (_isRunning) { + return false; + } + _scriptContents = scriptContents; + return true; +} - //setupMenuItems(); - +void ScriptEngine::run() { + _isRunning = true; QScriptEngine engine; _voxelScriptingInterface.init(); @@ -161,6 +170,7 @@ void ScriptEngine::run() { } emit finished(); + _isRunning = false; } void ScriptEngine::stop() { diff --git a/libraries/scriptengine/src/ScriptEngine.h b/libraries/scriptengine/src/ScriptEngine.h index 772b0a146f..605c4ce7e8 100644 --- a/libraries/scriptengine/src/ScriptEngine.h +++ b/libraries/scriptengine/src/ScriptEngine.h @@ -19,10 +19,12 @@ #include #include +const QString NO_SCRIPT(""); + class ScriptEngine : public QObject { Q_OBJECT public: - ScriptEngine(QString scriptContents, bool wantMenuItems = false, + ScriptEngine(QString scriptContents = NO_SCRIPT, bool wantMenuItems = false, const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL); ~ScriptEngine(); @@ -33,6 +35,9 @@ public: /// Access the ParticleScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener ParticleScriptingInterface* getParticleScriptingInterface() { return &_particleScriptingInterface; } + /// sets the script contents, will return false if failed, will fail if script is already running + bool setScriptContents(QString scriptContents); + void setupMenuItems(); void cleanMenuItems(); @@ -47,6 +52,7 @@ signals: protected: QString _scriptContents; bool _isFinished; + bool _isRunning; private: diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 8c05b1ff8f..8de7e3f594 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -6,12 +6,15 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros) set(TARGET_NAME shared) project(${TARGET_NAME}) +find_package(Qt5Core REQUIRED) +find_package(Qt5Gui REQUIRED) find_package(Qt5Network REQUIRED) include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) qt5_use_modules(${TARGET_NAME} Network) +qt5_use_modules(${TARGET_NAME} Gui) # include GLM include(${MACRO_DIR}/IncludeGLM.cmake) diff --git a/libraries/shared/src/AbstractMenuInterface.h b/libraries/shared/src/AbstractMenuInterface.h index 6af0ea2d00..c3857c456a 100644 --- a/libraries/shared/src/AbstractMenuInterface.h +++ b/libraries/shared/src/AbstractMenuInterface.h @@ -14,6 +14,13 @@ //#include //#include +//class QMenu; +//class QString; +//class QObject; +//class QKeySequence; +//class QAction; +//extern enum QAction::MenuRole; + class AbstractMenuInterface { public: virtual QMenu* getActiveScriptsMenu() = 0; From 18295809ce317e62de1dc7751f3ea7abe63f27ae Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Tue, 17 Dec 2013 21:44:44 +0100 Subject: [PATCH 21/65] log dialog style changes --- interface/resources/styles/log_dialog.qss | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/interface/resources/styles/log_dialog.qss b/interface/resources/styles/log_dialog.qss index 5fe6e1ba66..c5601a9ab6 100644 --- a/interface/resources/styles/log_dialog.qss +++ b/interface/resources/styles/log_dialog.qss @@ -1,10 +1,7 @@ -QWidget { - background-color: none; -} - -QPlainTextEdit { - font-family: Inconsolata, Lucida Console, Andale Mono, Monaco; - font-size: 16px; - padding: 28px; - color: #333333; +QPlainTextEdit { + font-family: Inconsolata, Lucida Console, Andale Mono, Monaco; + font-size: 16px; + padding-left: 28px; + color: #333333; + background-color: #FFFFFF; } From 57b4148867b78732d2c9fbd6876447b13c49322a Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Tue, 17 Dec 2013 22:12:24 +0100 Subject: [PATCH 22/65] Dialog position / toggle --- interface/resources/styles/log_dialog.qss | 2 +- interface/src/Menu.cpp | 4 ++-- interface/src/ui/LogDialog.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/styles/log_dialog.qss b/interface/resources/styles/log_dialog.qss index c5601a9ab6..fe3675f682 100644 --- a/interface/resources/styles/log_dialog.qss +++ b/interface/resources/styles/log_dialog.qss @@ -1,5 +1,5 @@ QPlainTextEdit { - font-family: Inconsolata, Lucida Console, Andale Mono, Monaco; + font-family: Inconsolata, Lucida Console, Andale Mono, Monaco; font-size: 16px; padding-left: 28px; color: #333333; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f14106bf49..5ea9bc8810 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1032,10 +1032,10 @@ void Menu::showLogDialog() { if (! _logDialog) { _logDialog = new LogDialog(Application::getInstance()->getGLWidget()); connect(_logDialog, SIGNAL(closed()), SLOT(logDialogClosed())); - _logDialog->show(); + } else { + _logDialog->close(); } - _logDialog->raise(); } void Menu::logDialogClosed() { diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 5717521d90..09e66eac75 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -21,7 +21,7 @@ int cursorMeta = qRegisterMetaType("QTextCursor"); int blockMeta = qRegisterMetaType("QTextBlock"); LogDialog::LogDialog(QWidget* parent) : - QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) { + QDialog(parent, Qt::Dialog | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) { setWindowTitle("Log"); From 456611417582c9c847314b237f99f8782a5d75dc Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Tue, 17 Dec 2013 22:25:26 +0100 Subject: [PATCH 23/65] Log dialog geometry --- interface/src/ui/LogDialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 09e66eac75..cca76fde11 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -14,14 +14,14 @@ #include "ui/LogDialog.h" #include "LogDisplay.h" -#define INITIAL_WIDTH_RATIO 0.3 +#define INITIAL_WIDTH_RATIO 0.6 #define INITIAL_HEIGHT_RATIO 0.6 int cursorMeta = qRegisterMetaType("QTextCursor"); int blockMeta = qRegisterMetaType("QTextBlock"); LogDialog::LogDialog(QWidget* parent) : - QDialog(parent, Qt::Dialog | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) { + QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint) { setWindowTitle("Log"); From 9d3cc9a5b499bbb046e59b9fd0663b5c133bc3c9 Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Tue, 17 Dec 2013 22:32:36 +0100 Subject: [PATCH 24/65] 70% initial width --- interface/src/ui/LogDialog.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index cca76fde11..4d938bcd06 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -14,14 +14,13 @@ #include "ui/LogDialog.h" #include "LogDisplay.h" -#define INITIAL_WIDTH_RATIO 0.6 +#define INITIAL_WIDTH_RATIO 0.7 #define INITIAL_HEIGHT_RATIO 0.6 int cursorMeta = qRegisterMetaType("QTextCursor"); int blockMeta = qRegisterMetaType("QTextBlock"); -LogDialog::LogDialog(QWidget* parent) : - QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint) { +LogDialog::LogDialog(QWidget* parent) : QDialog(parent, Qt::Dialog) { setWindowTitle("Log"); From 36109c090ebe3cbd9d163d73c0f5856d157802f8 Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Tue, 17 Dec 2013 22:41:38 +0100 Subject: [PATCH 25/65] 720px width --- interface/src/ui/LogDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 4d938bcd06..1ada9df2ca 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -37,7 +37,7 @@ LogDialog::LogDialog(QWidget* parent) : QDialog(parent, Qt::Dialog) { QDesktopWidget* desktop = new QDesktopWidget(); QRect screen = desktop->screenGeometry(); - resize(static_cast(screen.width() * INITIAL_WIDTH_RATIO), static_cast(screen.height() * INITIAL_HEIGHT_RATIO)); + resize(720, static_cast(screen.height() * INITIAL_HEIGHT_RATIO)); move(screen.center() - rect().center()); delete desktop; } From d535d3b115263f5618e92cf9c94c280362f9b579 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 17 Dec 2013 13:44:56 -0800 Subject: [PATCH 26/65] More progress on getting values in and out of scripts. --- interface/src/renderer/MetavoxelSystem.cpp | 9 +++ .../metavoxels/src/AttributeRegistry.cpp | 22 ++++++- libraries/metavoxels/src/AttributeRegistry.h | 24 ++++++-- libraries/metavoxels/src/MetavoxelData.cpp | 59 ++++++++++++++++--- libraries/metavoxels/src/MetavoxelData.h | 5 +- 5 files changed, 102 insertions(+), 17 deletions(-) diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index 065fd10ef5..6820cbfece 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -30,6 +30,8 @@ void MetavoxelSystem::init() { _pointScaleLocation = _program.uniformLocation("pointScale"); } + AttributeRegistry::getInstance()->configureScriptEngine(&_scriptEngine); + MetavoxelPath p1; p1 += 7; p1 += 7; @@ -41,6 +43,13 @@ void MetavoxelSystem::init() { QScriptValue guideFunction = _scriptEngine.evaluate( "(function(visitation) { " + " var attributes = visitation.visitor.getAttributes();" + " var colorIndex = attributes.indexOf(AttributeRegistry.colorAttribute);" + " var normalIndex = attributes.indexOf(AttributeRegistry.normalAttribute);" + " for (var i = 0; i < attributes.length; i++) {" + " print(attributes[i].getName() + ' ');" + " }" + " print('\\n');" " visitation.visitor.visit(visitation.info);" "})"); _data.setAttributeValue(MetavoxelPath(), AttributeValue(AttributeRegistry::getInstance()->getGuideAttribute(), diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index a113162efa..d91e7cb994 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -6,6 +6,8 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +#include + #include "AttributeRegistry.h" #include "MetavoxelData.h" @@ -17,6 +19,14 @@ AttributeRegistry::AttributeRegistry() : _normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) { } +void AttributeRegistry::configureScriptEngine(QScriptEngine* engine) { + QScriptValue registry = engine->newObject(); + registry.setProperty("colorAttribute", engine->newQObject(_colorAttribute.data())); + registry.setProperty("normalAttribute", engine->newQObject(_normalAttribute.data())); + registry.setProperty("getAttribute", engine->newFunction(getAttribute, 1)); + engine->globalObject().setProperty("AttributeRegistry", registry); +} + AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { AttributePointer& pointer = _attributes[attribute->getName()]; if (!pointer) { @@ -25,6 +35,11 @@ AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute return pointer; } +QScriptValue AttributeRegistry::getAttribute(QScriptContext* context, QScriptEngine* engine) { + return engine->newQObject(_instance.getAttribute(context->argument(0).toString()).data(), QScriptEngine::QtOwnership, + QScriptEngine::PreferExistingWrapperObject); +} + AttributeValue::AttributeValue(const AttributePointer& attribute) : _attribute(attribute), _value(attribute ? attribute->getDefaultValue() : NULL) { } @@ -76,7 +91,8 @@ OwnedAttributeValue& OwnedAttributeValue::operator=(const AttributeValue& other) } } -Attribute::Attribute(const QString& name) : _name(name) { +Attribute::Attribute(const QString& name) { + setObjectName(name); } Attribute::~Attribute() { @@ -106,6 +122,10 @@ bool QRgbAttribute::merge(void*& parent, void* children[]) const { return allChildrenEqual; } +void* QRgbAttribute::createFromScript(const QScriptValue& value, QScriptEngine* engine) const { + return encodeInline((QRgb)value.toUInt32()); +} + PolymorphicData::~PolymorphicData() { } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 41b1005ad0..a5f9c08f8b 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -12,12 +12,17 @@ #include #include #include +#include #include #include #include #include "Bitstream.h" +class QScriptContext; +class QScriptEngine; +class QScriptValue; + class Attribute; typedef QSharedPointer AttributePointer; @@ -31,6 +36,9 @@ public: AttributeRegistry(); + /// Configures the supplied script engine with the global AttributeRegistry property. + void configureScriptEngine(QScriptEngine* engine); + /// Registers an attribute with the system. The registry assumes ownership of the object. /// \return either the pointer passed as an argument, if the attribute wasn't already registered, or the existing /// attribute @@ -55,6 +63,8 @@ public: private: + static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine); + static AttributeRegistry _instance; QHash _attributes; @@ -114,15 +124,17 @@ public: }; /// Represents a registered attribute. -class Attribute { +class Attribute : public QObject { + Q_OBJECT + public: - + static const int MERGE_COUNT = 8; Attribute(const QString& name); virtual ~Attribute(); - const QString& getName() const { return _name; } + Q_INVOKABLE QString getName() const { return objectName(); } void* create() const { return create(getDefaultValue()); } virtual void* create(void* copy) const = 0; @@ -139,9 +151,7 @@ public: virtual void* getDefaultValue() const = 0; -private: - - QString _name; + virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const { return create(); } }; /// A simple attribute class that stores its values inline. @@ -193,6 +203,8 @@ public: QRgbAttribute(const QString& name, QRgb defaultValue = QRgb()); virtual bool merge(void*& parent, void* children[]) const; + + virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const; }; /// An attribute class that stores pointers to its values. diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 945289c151..cc06c64051 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -185,31 +185,67 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { } } +QScriptValue ScriptedMetavoxelGuide::getAttributes(QScriptContext* context, QScriptEngine* engine) { + ScriptedMetavoxelGuide* guide = static_cast(context->callee().data().toVariant().value()); + + const QVector& attributes = guide->_visitation->visitor.getAttributes(); + QScriptValue attributesValue = engine->newArray(attributes.size()); + for (int i = 0; i < attributes.size(); i++) { + attributesValue.setProperty(i, engine->newQObject(attributes.at(i).data(), QScriptEngine::QtOwnership, + QScriptEngine::PreferExistingWrapperObject)); + } + + return attributesValue; +} + QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngine* engine) { ScriptedMetavoxelGuide* guide = static_cast(context->callee().data().toVariant().value()); - MetavoxelInfo info; + // start with the basics, including inherited attribute values QScriptValue infoValue = context->argument(0); - QScriptValue minimumValue = infoValue.property(guide->_minimumHandle); - info.minimum = glm::vec3(minimumValue.property(0).toNumber(), minimumValue.property(1).toNumber(), - minimumValue.property(2).toNumber()); - info.size = infoValue.property(guide->_sizeHandle).toNumber(); - info.isLeaf = infoValue.property(guide->_isLeafHandle).toBool(); + QScriptValue minimum = infoValue.property(guide->_minimumHandle); + MetavoxelInfo info = { + glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()), + infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.attributeValues, + infoValue.property(guide->_isLeafHandle).toBool() }; - return guide->_visitor->visit(info); + // extract and convert the values provided by the script + QScriptValue attributeValues = infoValue.property(guide->_attributeValuesHandle); + const QVector& attributes = guide->_visitation->visitor.getAttributes(); + for (int i = 0; i < attributes.size(); i++) { + QScriptValue attributeValue = attributeValues.property(i); + if (attributeValue.isValid()) { + info.attributeValues[i] = AttributeValue(attributes.at(i), + attributes.at(i)->createFromScript(attributeValue, engine)); + } + } + + QScriptValue result = guide->_visitation->visitor.visit(info); + + // destroy any created values + for (int i = 0; i < attributes.size(); i++) { + if (attributeValues.property(i).isValid()) { + info.attributeValues[i].getAttribute()->destroy(info.attributeValues[i].getValue()); + } + } + + return result; } ScriptedMetavoxelGuide::ScriptedMetavoxelGuide(const QScriptValue& guideFunction) : _guideFunction(guideFunction), _minimumHandle(guideFunction.engine()->toStringHandle("minimum")), _sizeHandle(guideFunction.engine()->toStringHandle("size")), + _attributeValuesHandle(guideFunction.engine()->toStringHandle("attributeValues")), _isLeafHandle(guideFunction.engine()->toStringHandle("isLeaf")), + _getAttributesFunction(guideFunction.engine()->newFunction(getAttributes, 0)), _visitFunction(guideFunction.engine()->newFunction(visit, 1)), _info(guideFunction.engine()->newObject()), _minimum(guideFunction.engine()->newArray(3)) { _arguments.append(guideFunction.engine()->newObject()); QScriptValue visitor = guideFunction.engine()->newObject(); + visitor.setProperty("getAttributes", _getAttributesFunction); visitor.setProperty("visit", _visitFunction); _arguments[0].setProperty("visitor", visitor); _arguments[0].setProperty("info", _info); @@ -221,14 +257,19 @@ PolymorphicData* ScriptedMetavoxelGuide::clone() const { } void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) { - _visitFunction.setData(_guideFunction.engine()->newVariant(QVariant::fromValue(this))); + QScriptValue data = _guideFunction.engine()->newVariant(QVariant::fromValue(this)); + _getAttributesFunction.setData(data); + _visitFunction.setData(data); _minimum.setProperty(0, visitation.info.minimum.x); _minimum.setProperty(1, visitation.info.minimum.y); _minimum.setProperty(2, visitation.info.minimum.z); _info.setProperty(_sizeHandle, visitation.info.size); _info.setProperty(_isLeafHandle, visitation.info.isLeaf); - _visitor = &visitation.visitor; + _visitation = &visitation; _guideFunction.call(QScriptValue(), _arguments); + if (_guideFunction.engine()->hasUncaughtException()) { + qDebug() << "Script error: " << _guideFunction.engine()->uncaughtException().toString() << "\n"; + } } bool MetavoxelVisitation::allNodesLeaves() const { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 0af6fba582..fc7045cff4 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -156,18 +156,21 @@ public: private: + static QScriptValue getAttributes(QScriptContext* context, QScriptEngine* engine); static QScriptValue visit(QScriptContext* context, QScriptEngine* engine); QScriptValue _guideFunction; QScriptString _minimumHandle; QScriptString _sizeHandle; + QScriptString _attributeValuesHandle; QScriptString _isLeafHandle; QScriptValueList _arguments; + QScriptValue _getAttributesFunction; QScriptValue _visitFunction; QScriptValue _info; QScriptValue _minimum; - MetavoxelVisitor* _visitor; + MetavoxelVisitation* _visitation; }; /// Contains the state associated with a visit to a metavoxel system. From ccd6058412dcf17df31d64b16297f1231387445c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 17 Dec 2013 13:55:17 -0800 Subject: [PATCH 27/65] get abstract menu class to work --- assignment-client/CMakeLists.txt | 11 ---------- assignment-client/src/Agent.cpp | 9 -------- interface/src/Menu.cpp | 8 +++---- interface/src/Menu.h | 4 ++-- libraries/shared/CMakeLists.txt | 3 --- libraries/shared/src/AbstractMenuInterface.h | 22 ++++++++++---------- 6 files changed, 17 insertions(+), 40 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 1d2fb866bb..9df3f2455a 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -10,23 +10,12 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} $ENV{QT_CMAKE_PREFIX_PATH}) -find_package(Qt5Core REQUIRED) -find_package(Qt5Gui REQUIRED) find_package(Qt5Network REQUIRED) -#find_package(Qt5Multimedia REQUIRED) -#find_package(Qt5Network REQUIRED) -#find_package(Qt5OpenGL REQUIRED) -#find_package(Qt5Svg REQUIRED) -#find_package(Qt5WebKit REQUIRED) -#find_package(Qt5WebKitWidgets REQUIRED) - - include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) qt5_use_modules(${TARGET_NAME} Network) -qt5_use_modules(${TARGET_NAME} Gui) # include glm include(${MACRO_DIR}/IncludeGLM.cmake) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 9fbe464a9e..a5fc32881f 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -78,19 +78,10 @@ void Agent::run() { QString scriptContents(reply->readAll()); qDebug() << "Downloaded script:" << scriptContents << "\n"; - QScriptValue result = engine.evaluate(scriptContents); - qDebug() << "Evaluated script.\n"; - - if (engine.hasUncaughtException()) { - int line = engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; - } timeval startTime; gettimeofday(&startTime, NULL); - int thisFrame = 0; - QTimer* domainServerTimer = new QTimer(this); connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d81e22d818..20afe38e67 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -689,10 +689,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) { @@ -701,7 +701,7 @@ QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu, action = destinationMenu->addAction(actionName); action->setShortcut(shortcut); } - action->setMenuRole(role); + action->setMenuRole((QAction::MenuRole)role); _actionHash.insert(actionName, action); @@ -714,7 +714,7 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu, const bool checked, const QObject* receiver, const char* member) { - QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member); + QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, (QKEYSEQUENCE&)shortcut, receiver, member); action->setCheckable(true); action->setChecked(checked); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b62f49abe4..f896423b00 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -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 = QAction::NoRole); + QACTION_MENUROLE role = NO_ROLE); virtual void removeAction(QMenu* menu, const QString& actionName); public slots: diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 8de7e3f594..8c05b1ff8f 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -6,15 +6,12 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros) set(TARGET_NAME shared) project(${TARGET_NAME}) -find_package(Qt5Core REQUIRED) -find_package(Qt5Gui REQUIRED) find_package(Qt5Network REQUIRED) include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) qt5_use_modules(${TARGET_NAME} Network) -qt5_use_modules(${TARGET_NAME} Gui) # include GLM include(${MACRO_DIR}/IncludeGLM.cmake) diff --git a/libraries/shared/src/AbstractMenuInterface.h b/libraries/shared/src/AbstractMenuInterface.h index c3857c456a..39c378f40b 100644 --- a/libraries/shared/src/AbstractMenuInterface.h +++ b/libraries/shared/src/AbstractMenuInterface.h @@ -10,26 +10,26 @@ #ifndef __hifi__AbstractMenuInterface__ #define __hifi__AbstractMenuInterface__ -#include -//#include -//#include +class QMenu; +class QString; +class QObject; +class QKeySequence; +class QAction; -//class QMenu; -//class QString; -//class QObject; -//class QKeySequence; -//class QAction; -//extern enum QAction::MenuRole; +// 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 = QAction::NoRole) = 0; + QACTION_MENUROLE role = NO_ROLE) = 0; virtual void removeAction(QMenu* menu, const QString& actionName) = 0; }; From 43054ad89388c94ffbfbe946e700563eb2009016 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 17 Dec 2013 13:56:07 -0800 Subject: [PATCH 28/65] cleanup --- assignment-client/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 9df3f2455a..e308a3eece 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -8,8 +8,6 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros) # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") -set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} $ENV{QT_CMAKE_PREFIX_PATH}) - find_package(Qt5Network REQUIRED) include(${MACRO_DIR}/SetupHifiProject.cmake) From 7b3a778fb4de0225abf05f06b0b2abe2800a4993 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 17 Dec 2013 14:13:16 -0800 Subject: [PATCH 29/65] get Agent working with ScriptEngine --- assignment-client/src/Agent.cpp | 14 +++++++------- assignment-client/src/Agent.h | 4 ++-- libraries/scriptengine/src/ScriptEngine.cpp | 14 ++++++++------ libraries/shared/src/GenericThread.h | 4 ++-- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index a5fc32881f..16bd5256f8 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -24,8 +24,8 @@ Agent::Agent(const unsigned char* dataBuffer, int numBytes) : ThreadedAssignment(dataBuffer, numBytes) { - _particleScriptingInterface.init(); - _voxelScriptingInterface.init(); + //_particleScriptingInterface.init(); + //_voxelScriptingInterface.init(); } void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { @@ -34,12 +34,12 @@ void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& // PACKET_TYPE_JURISDICTION, first byte is the node type... switch (dataByteArray[headerBytes]) { case NODE_TYPE_VOXEL_SERVER: - _voxelScriptingInterface.getJurisdictionListener()->queueReceivedPacket(senderSockAddr, + _scriptEngine.getVoxelScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); break; case NODE_TYPE_PARTICLE_SERVER: - _particleScriptingInterface.getJurisdictionListener()->queueReceivedPacket(senderSockAddr, + _scriptEngine.getParticleScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); break; @@ -94,10 +94,10 @@ void Agent::run() { connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes())); pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000); - const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; + //const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; // let the VoxelPacketSender know how frequently we plan to call it - _voxelScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); - _particleScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); + //_voxelScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); + //_particleScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); _scriptEngine.setScriptContents(scriptContents); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index e6e7eb84b1..8f77141a30 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -34,8 +34,8 @@ signals: void willSendAudioDataCallback(); void willSendVisualDataCallback(); private: - VoxelScriptingInterface _voxelScriptingInterface; - ParticleScriptingInterface _particleScriptingInterface; + //VoxelScriptingInterface _voxelScriptingInterface; + //ParticleScriptingInterface _particleScriptingInterface; ScriptEngine _scriptEngine; }; diff --git a/libraries/scriptengine/src/ScriptEngine.cpp b/libraries/scriptengine/src/ScriptEngine.cpp index 7d34a4edf6..3bffa35929 100644 --- a/libraries/scriptengine/src/ScriptEngine.cpp +++ b/libraries/scriptengine/src/ScriptEngine.cpp @@ -116,16 +116,14 @@ void ScriptEngine::run() { if (usecToSleep > 0) { usleep(usecToSleep); } - + if (_isFinished) { - //qDebug() << "line: " << __LINE__ << " _isFinished... breaking loop\n"; break; } QCoreApplication::processEvents(); if (_isFinished) { - //qDebug() << "line: " << __LINE__ << " _isFinished... breaking loop\n"; break; } @@ -138,7 +136,9 @@ void ScriptEngine::run() { _voxelScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages(); // since we're in non-threaded mode, call process so that the packets are sent - //_voxelScriptingInterface.getVoxelPacketSender()->process(); + if (!_voxelScriptingInterface.getVoxelPacketSender()->isThreaded()) { + _voxelScriptingInterface.getVoxelPacketSender()->process(); + } } if (_particleScriptingInterface.getParticlePacketSender()->serversExist()) { @@ -149,14 +149,15 @@ void ScriptEngine::run() { _particleScriptingInterface.getParticlePacketSender()->releaseQueuedMessages(); // since we're in non-threaded mode, call process so that the packets are sent - //_particleScriptingInterface.getParticlePacketSender()->process(); + if (!_particleScriptingInterface.getParticlePacketSender()->isThreaded()) { + _particleScriptingInterface.getParticlePacketSender()->process(); + } } if (willSendVisualDataCallBack) { emit willSendVisualDataCallback(); } - if (engine.hasUncaughtException()) { int line = engine.uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; @@ -177,3 +178,4 @@ void ScriptEngine::stop() { _isFinished = true; } + diff --git a/libraries/shared/src/GenericThread.h b/libraries/shared/src/GenericThread.h index 013b7a7936..2de9112204 100644 --- a/libraries/shared/src/GenericThread.h +++ b/libraries/shared/src/GenericThread.h @@ -33,6 +33,8 @@ public: /// Override this function to do whatever your class actually does, return false to exit thread early. virtual bool process() = 0; + bool isThreaded() const { return _isThreaded; } + protected: /// Locks all the resources of the thread. @@ -43,8 +45,6 @@ protected: bool isStillRunning() const { return !_stopThread; } - bool isThreaded() const { return _isThreaded; } - private: pthread_mutex_t _mutex; From 88c319a0daa279fdf404a3868460d79910f50629 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 17 Dec 2013 14:15:34 -0800 Subject: [PATCH 30/65] remove dead code --- assignment-client/src/Agent.cpp | 8 -------- assignment-client/src/Agent.h | 2 -- 2 files changed, 10 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 16bd5256f8..e8bffc8eb2 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -24,8 +24,6 @@ Agent::Agent(const unsigned char* dataBuffer, int numBytes) : ThreadedAssignment(dataBuffer, numBytes) { - //_particleScriptingInterface.init(); - //_voxelScriptingInterface.init(); } void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { @@ -94,12 +92,6 @@ void Agent::run() { connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes())); pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000); - //const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; - // let the VoxelPacketSender know how frequently we plan to call it - //_voxelScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); - //_particleScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); - _scriptEngine.setScriptContents(scriptContents); - _scriptEngine.run(); } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 8f77141a30..0bcd1af78e 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -34,8 +34,6 @@ signals: void willSendAudioDataCallback(); void willSendVisualDataCallback(); private: - //VoxelScriptingInterface _voxelScriptingInterface; - //ParticleScriptingInterface _particleScriptingInterface; ScriptEngine _scriptEngine; }; From 4509b8dbe5c85d8c19e09f30b7e7243c2d5e1948 Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Tue, 17 Dec 2013 23:16:16 +0100 Subject: [PATCH 31/65] don't cut long lines --- interface/src/Application.cpp | 3 +-- interface/src/LogDisplay.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f5e5f06b53..13d7a9f37f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -158,7 +158,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : // call Menu getInstance static method to set up the menu _window->setMenuBar(Menu::getInstance()); - qDebug( "[VERSION] Build sequence: %i", BUILD_VERSION); + qDebug("[VERSION] Build sequence: %i", BUILD_VERSION); unsigned int listenPort = 0; // bind to an ephemeral port by default const char** constArgv = const_cast(argv); @@ -185,7 +185,6 @@ 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 // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings applicationInfo(resourcesPath + "/info/ApplicationInfo.ini", QSettings::IniFormat); diff --git a/interface/src/LogDisplay.cpp b/interface/src/LogDisplay.cpp index bc674059d3..dcfbbff626 100644 --- a/interface/src/LogDisplay.cpp +++ b/interface/src/LogDisplay.cpp @@ -119,7 +119,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; @@ -149,7 +149,6 @@ void LogDisplay::addMessage(const char* ptr) { // remember start position in character buffer for next line and reset character count _writeLineStartPos = _writePos; - _writtenInLine = 0; } } From f469553b8ca5f22e15985d826d06d409b56909a1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 17 Dec 2013 14:27:54 -0800 Subject: [PATCH 32/65] CR feedback --- assignment-client/CMakeLists.txt | 2 +- interface/CMakeLists.txt | 2 +- libraries/{scriptengine => script-engine}/CMakeLists.txt | 2 +- .../{scriptengine => script-engine}/src/ScriptEngine.cpp | 4 ++-- libraries/{scriptengine => script-engine}/src/ScriptEngine.h | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) rename libraries/{scriptengine => script-engine}/CMakeLists.txt (96%) rename libraries/{scriptengine => script-engine}/src/ScriptEngine.cpp (97%) rename libraries/{scriptengine => script-engine}/src/ScriptEngine.h (92%) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index e308a3eece..464728f7e0 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -30,7 +30,7 @@ link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(octree-server ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(particle-server ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(voxel-server ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(scriptengine ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(script-engine ${TARGET_NAME} ${ROOT_DIR}) #testing include_directories(${ROOT_DIR}/externals/civetweb/include) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index c447bfa1a5..9d56764ffa 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -96,7 +96,7 @@ link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(scriptengine ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(script-engine ${TARGET_NAME} ${ROOT_DIR}) # find required libraries find_package(Faceshift) diff --git a/libraries/scriptengine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt similarity index 96% rename from libraries/scriptengine/CMakeLists.txt rename to libraries/script-engine/CMakeLists.txt index 593feab014..59f41b8cbe 100644 --- a/libraries/scriptengine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -6,7 +6,7 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros) # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") -set(TARGET_NAME scriptengine) +set(TARGET_NAME script-engine) find_package(Qt5Widgets REQUIRED) diff --git a/libraries/scriptengine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp similarity index 97% rename from libraries/scriptengine/src/ScriptEngine.cpp rename to libraries/script-engine/src/ScriptEngine.cpp index 3bffa35929..35585ad6ef 100644 --- a/libraries/scriptengine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -24,7 +24,7 @@ int ScriptEngine::_scriptNumber = 1; -ScriptEngine::ScriptEngine(QString scriptContents, bool wantMenuItems, +ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, const char* scriptMenuName, AbstractMenuInterface* menu) { _scriptContents = scriptContents; _isFinished = false; @@ -60,7 +60,7 @@ void ScriptEngine::cleanMenuItems() { } } -bool ScriptEngine::setScriptContents(QString scriptContents) { +bool ScriptEngine::setScriptContents(const QString& scriptContents) { if (_isRunning) { return false; } diff --git a/libraries/scriptengine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h similarity index 92% rename from libraries/scriptengine/src/ScriptEngine.h rename to libraries/script-engine/src/ScriptEngine.h index 605c4ce7e8..2e0d7fcc40 100644 --- a/libraries/scriptengine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -24,7 +24,7 @@ const QString NO_SCRIPT(""); class ScriptEngine : public QObject { Q_OBJECT public: - ScriptEngine(QString scriptContents = NO_SCRIPT, bool wantMenuItems = false, + ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false, const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL); ~ScriptEngine(); @@ -36,7 +36,7 @@ public: ParticleScriptingInterface* getParticleScriptingInterface() { return &_particleScriptingInterface; } /// sets the script contents, will return false if failed, will fail if script is already running - bool setScriptContents(QString scriptContents); + bool setScriptContents(const QString& scriptContents); void setupMenuItems(); void cleanMenuItems(); From a6e6205a57fc79d6c26d595f460d15e2d4578b23 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 17 Dec 2013 15:23:09 -0800 Subject: [PATCH 33/65] first cut at scriptable controller --- interface/src/Application.cpp | 3 +- interface/src/Application.h | 4 ++ .../InterfaceControllerScriptingInterface.cpp | 45 +++++++++++++++++++ .../InterfaceControllerScriptingInterface.h | 28 ++++++++++++ libraries/avatars/src/HandData.h | 44 +++++++++--------- libraries/scriptengine/src/ScriptEngine.cpp | 11 ++++- libraries/scriptengine/src/ScriptEngine.h | 7 ++- libraries/shared/src/RegisteredMetaTypes.cpp | 14 ++++++ libraries/shared/src/RegisteredMetaTypes.h | 6 +++ 9 files changed, 137 insertions(+), 25 deletions(-) create mode 100644 interface/src/InterfaceControllerScriptingInterface.cpp create mode 100644 interface/src/InterfaceControllerScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3cb806c7f8..ad27a6e427 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4432,7 +4432,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 diff --git a/interface/src/Application.h b/interface/src/Application.h index f9ffc33781..67291c8ba8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -68,6 +68,8 @@ #include "ui/LodToolsDialog.h" #include "ParticleTreeRenderer.h" #include "ParticleEditHandle.h" +#include "InterfaceControllerScriptingInterface.h" + class QAction; class QActionGroup; @@ -498,6 +500,8 @@ private: std::vector _voxelFades; std::vector _avatarFades; + + InterfaceControllerScriptingInterface _controllerScriptingInterface; }; #endif /* defined(__interface__Application__) */ diff --git a/interface/src/InterfaceControllerScriptingInterface.cpp b/interface/src/InterfaceControllerScriptingInterface.cpp new file mode 100644 index 0000000000..a301120d8c --- /dev/null +++ b/interface/src/InterfaceControllerScriptingInterface.cpp @@ -0,0 +1,45 @@ +// +// InterfaceControllerScriptingInterface.h +// hifi +// +// Created by Brad Hefta-Gaub on 12/17/13 +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#include +#include "Application.h" +#include "InterfaceControllerScriptingInterface.h" + +const PalmData* InterfaceControllerScriptingInterface::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; +} + +bool InterfaceControllerScriptingInterface::isPrimaryButtonPressed() const { + const PalmData* primaryPalm = getPrimaryPalm(); + if (primaryPalm) { + if (primaryPalm->getControllerButtons() & BUTTON_FWD) { + return true; + } + } + + return false; +} + +glm::vec2 InterfaceControllerScriptingInterface::getPrimaryJoystickPosition() const { + const PalmData* primaryPalm = getPrimaryPalm(); + if (primaryPalm) { + return glm::vec2(primaryPalm->getJoystickX(), primaryPalm->getJoystickY()); + } + + return glm::vec2(0); +} + diff --git a/interface/src/InterfaceControllerScriptingInterface.h b/interface/src/InterfaceControllerScriptingInterface.h new file mode 100644 index 0000000000..1a9f2ea119 --- /dev/null +++ b/interface/src/InterfaceControllerScriptingInterface.h @@ -0,0 +1,28 @@ +// +// InterfaceControllerScriptingInterface.h +// hifi +// +// Created by Brad Hefta-Gaub on 12/17/13 +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__InterfaceControllerScriptingInterface__ +#define __hifi__InterfaceControllerScriptingInterface__ + +#include + +#include + +/// handles scripting of input controller commands from JS +class InterfaceControllerScriptingInterface : public ControllerScriptingInterface { + Q_OBJECT + +public slots: + virtual bool isPrimaryButtonPressed() const; + virtual glm::vec2 getPrimaryJoystickPosition() const; + +private: + const PalmData* getPrimaryPalm() const; +}; + +#endif /* defined(__hifi__InterfaceControllerScriptingInterface__) */ diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 00797881fe..49bdd3791d 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -53,9 +53,10 @@ public: glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const; glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const; - std::vector& getPalms() { return _palms; } - size_t getNumPalms() { return _palms.size(); } - PalmData& addNewPalm(); + std::vector& getPalms() { return _palms; } + const std::vector& getPalms() const { return _palms; } + size_t getNumPalms() { 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& getFingers() { return _fingers; } - size_t getNumFingers() { return _fingers.size(); } + std::vector& getFingers() { return _fingers; } + const std::vector& 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; } @@ -162,26 +164,28 @@ 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() const { return _isCollidingWithPalm; } + void setIsCollidingWithPalm(bool isCollidingWithPalm) { _isCollidingWithPalm = isCollidingWithPalm; } private: std::vector _fingers; glm::quat _rawRotation; diff --git a/libraries/scriptengine/src/ScriptEngine.cpp b/libraries/scriptengine/src/ScriptEngine.cpp index 7e5f414dee..d4f6d5a630 100644 --- a/libraries/scriptengine/src/ScriptEngine.cpp +++ b/libraries/scriptengine/src/ScriptEngine.cpp @@ -24,8 +24,9 @@ int ScriptEngine::_scriptNumber = 1; -ScriptEngine::ScriptEngine(QString scriptContents, bool wantMenuItems, - const char* scriptMenuName, AbstractMenuInterface* menu) { +ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, + const char* scriptMenuName, AbstractMenuInterface* menu, + ControllerScriptingInterface* controllerScriptingInterface) { _scriptContents = scriptContents; _isFinished = false; _wantMenuItems = wantMenuItems; @@ -38,6 +39,7 @@ ScriptEngine::ScriptEngine(QString scriptContents, bool wantMenuItems, _scriptMenuName.append(_scriptNumber); } _menu = menu; + _controllerScriptingInterface = controllerScriptingInterface; } ScriptEngine::~ScriptEngine() { @@ -78,6 +80,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); diff --git a/libraries/scriptengine/src/ScriptEngine.h b/libraries/scriptengine/src/ScriptEngine.h index 772b0a146f..3001aebeaa 100644 --- a/libraries/scriptengine/src/ScriptEngine.h +++ b/libraries/scriptengine/src/ScriptEngine.h @@ -18,12 +18,14 @@ #include #include #include +#include "ControllerScriptingInterface.h" class ScriptEngine : public QObject { Q_OBJECT public: - ScriptEngine(QString scriptContents, bool wantMenuItems = false, - const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL); + ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false, + const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL, + ControllerScriptingInterface* controllerScriptingInterface = NULL); ~ScriptEngine(); @@ -52,6 +54,7 @@ protected: private: VoxelScriptingInterface _voxelScriptingInterface; ParticleScriptingInterface _particleScriptingInterface; + ControllerScriptingInterface* _controllerScriptingInterface; bool _wantMenuItems; QString _scriptMenuName; AbstractMenuInterface* _menu; diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index de9fcae781..9a099b4171 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -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); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 51a4562c87..b5d3d80e2f 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -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); From 4b3fd2166d32042d3c6b86268a95cb391618e900 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 17 Dec 2013 15:28:29 -0800 Subject: [PATCH 34/65] make getNumPalms() const --- libraries/avatars/src/HandData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 8df286cd44..a0c8fed980 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -55,7 +55,7 @@ public: std::vector& getPalms() { return _palms; } const std::vector& getPalms() const { return _palms; } - size_t getNumPalms() { return _palms.size(); } + 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 From f08354c853e2a186d6d8e10f4a9c8b0d4df88504 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 17 Dec 2013 15:36:26 -0800 Subject: [PATCH 35/65] higher speed collisions to trigger a bounce sound --- interface/src/avatar/Hand.cpp | 4 ++-- libraries/particles/src/ParticleCollisionSystem.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index bd3a0a1fac..7f8e3ffe52 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -24,11 +24,11 @@ using namespace std; const float FINGERTIP_VOXEL_SIZE = 0.05; const int TOY_BALL_HAND = 1; const float TOY_BALL_RADIUS = 0.05f; -const float TOY_BALL_DAMPING = 0.99f; +const float TOY_BALL_DAMPING = 0.999f; const glm::vec3 NO_VELOCITY = glm::vec3(0,0,0); const glm::vec3 NO_GRAVITY = glm::vec3(0,0,0); const float NO_DAMPING = 0.f; -const glm::vec3 TOY_BALL_GRAVITY = glm::vec3(0,-0.5,0); +const glm::vec3 TOY_BALL_GRAVITY = glm::vec3(0,-2.0,0); const QString TOY_BALL_UPDATE_SCRIPT(""); const float PALM_COLLISION_RADIUS = 0.03f; const float CATCH_RADIUS = 0.2f; diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index 1a21d1231e..313c4d7045 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -206,7 +206,7 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm:: void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency) { // consider whether to have the collision make a sound - const float AUDIBLE_COLLISION_THRESHOLD = 0.02f; + const float AUDIBLE_COLLISION_THRESHOLD = 0.1f; const float COLLISION_LOUDNESS = 1.f; const float DURATION_SCALING = 0.004f; const float NOISE_SCALING = 0.1f; From c6dc93c28eb2ae8849c1542278632cb8db3933d5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 17 Dec 2013 16:08:38 -0800 Subject: [PATCH 36/65] fix for 8 channel output devices (HDMI capture) --- interface/src/Audio.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 25a5f01d06..400ff534df 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -174,9 +174,8 @@ void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples, if (sourceAudioFormat == destinationAudioFormat) { memcpy(destinationSamples, sourceSamples, numSourceSamples * sizeof(int16_t)); } else { - int destinationChannels = (destinationAudioFormat.channelCount() >= 2) ? 2 : destinationAudioFormat.channelCount(); float sourceToDestinationFactor = (sourceAudioFormat.sampleRate() / (float) destinationAudioFormat.sampleRate()) - * (sourceAudioFormat.channelCount() / (float) destinationChannels); + * (sourceAudioFormat.channelCount() / (float) destinationAudioFormat.channelCount()); // take into account the number of channels in source and destination // accomodate for the case where have an output with > 2 channels @@ -203,14 +202,15 @@ void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples, // upsample from 24 to 48 // for now this only supports a stereo to stereo conversion - this is our case for network audio to output int sourceIndex = 0; - int destinationToSourceFactor = (1 / sourceToDestinationFactor); int dtsSampleRateFactor = (destinationAudioFormat.sampleRate() / sourceAudioFormat.sampleRate()); + int sampleShift = destinationAudioFormat.channelCount() * dtsSampleRateFactor; + int destinationToSourceFactor = (1 / sourceToDestinationFactor); - for (int i = 0; i < numDestinationSamples; i += destinationAudioFormat.channelCount() * dtsSampleRateFactor) { + for (int i = 0; i < numDestinationSamples; i += sampleShift) { sourceIndex = (i / destinationToSourceFactor); // fill the L/R channels and make the rest silent - for (int j = i; j < i + (dtsSampleRateFactor * destinationAudioFormat.channelCount()); j++) { + for (int j = i; j < i + sampleShift; j++) { if (j % destinationAudioFormat.channelCount() == 0) { // left channel destinationSamples[j] = sourceSamples[sourceIndex]; From e6a41b2003a756a8ce14a2c25d9202b83bce628a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 17 Dec 2013 16:56:52 -0800 Subject: [PATCH 37/65] Proof of concept sphere thing for metavoxels. --- interface/resources/scripts/sphere.js | 171 +++++++++++++++++++++ interface/src/renderer/MetavoxelSystem.cpp | 16 +- 2 files changed, 176 insertions(+), 11 deletions(-) create mode 100644 interface/resources/scripts/sphere.js diff --git a/interface/resources/scripts/sphere.js b/interface/resources/scripts/sphere.js new file mode 100644 index 0000000000..4e235883d4 --- /dev/null +++ b/interface/resources/scripts/sphere.js @@ -0,0 +1,171 @@ +// +// sphere.js +// interface +// +// Created by Andrzej Kapolka on 12/17/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +function strictIndexOf(array, element) { + for (var i = 0; i < array.length; i++) { + if (array[i] == element) { + return i; + } + } + return -1; +} + +var colorIndex; +var normalIndex; +var visitor; +var info; + +var MAX_DEPTH = 5; + +var sphereCenter = [ 0.5, 0.5, 0.5 ]; +var sphereColor = 0xFFFF00FF; +var sphereRadius = 0.25; +var sphereRadiusSquared = sphereRadius * sphereRadius; + +function lengthSquared(x, y, z) { + return x*x + y*y + z*z; +} + +function setNormal(vector) { + if (normalIndex != -1) { + var length = Math.sqrt(lengthSquared(vector[0], vector[1], vector[2])); + if (length == 0.0) { + info.attributeValues[normalIndex] = 0x007F00; + + } else { + var scale = 127.0 / length; + info.attributeValues[normalIndex] = + (Math.floor(vector[0] * scale) & 0xFF) << 16 | + (Math.floor(vector[1] * scale) & 0xFF) << 8 | + Math.floor(vector[2] * scale) & 0xFF; + } + } +} + +function guide(minimum, size, depth) { + info.minimum = minimum; + info.size = size; + + // start with a relative fast bounding volume test to find most non-intersecting states + var maximum = [ minimum[0] + size, minimum[1] + size, minimum[2] + size ]; + if (minimum[0] >= sphereCenter[0] + sphereRadius || + minimum[1] >= sphereCenter[1] + sphereRadius || + minimum[2] >= sphereCenter[2] + sphereRadius || + maximum[0] <= sphereCenter[0] - sphereRadius || + maximum[1] <= sphereCenter[1] - sphereRadius || + maximum[2] <= sphereCenter[2] - sphereRadius) { + info.isLeaf = true; + if (colorIndex != -1) { + info.attributeValues[colorIndex] = 0x0; + } + visitor.visit(info); + return; + } + + var halfSize = size / 2; + var center = [ minimum[0] + halfSize, minimum[1] + halfSize, minimum[2] + halfSize ]; + var vector = [ center[0] - sphereCenter[0], center[1] - sphereCenter[1], center[2] - sphereCenter[2] ]; + + // count the number of points inside the sphere + var inside = 0; + if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - minimum[2]) <= + sphereRadiusSquared) { + inside++; + } + if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - minimum[2]) <= + sphereRadiusSquared) { + inside++; + } + if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - minimum[2]) <= + sphereRadiusSquared) { + inside++; + } + if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - minimum[2]) <= + sphereRadiusSquared) { + inside++; + } + if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - maximum[2]) <= + sphereRadiusSquared) { + inside++; + } + if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - maximum[2]) <= + sphereRadiusSquared) { + inside++; + } + if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - maximum[2]) <= + sphereRadiusSquared) { + inside++; + } + if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - maximum[2]) <= + sphereRadiusSquared) { + inside++; + } + + // see if all points are in the sphere + if (inside == 8) { + info.isLeaf = true; + if (colorIndex != -1) { + info.attributeValues[colorIndex] = sphereColor; + } + setNormal(vector); + visitor.visit(info); + return; + } + + // if we've reached max depth, compute alpha using a volume estimate + if (depth == MAX_DEPTH) { + info.isLeaf = true; + if (inside >= 3) { + if (colorIndex != -1) { + info.attributeValues[colorIndex] = sphereColor; + } + setNormal(vector); + + } else { + if (colorIndex != -1) { + info.attributeValues[colorIndex] = 0x0; + } + } + visitor.visit(info); + return; + } + + // recurse + info.isLeaf = false; + if (!visitor.visit(info)) { + return; + } + depth += 1; + guide(minimum, halfSize, depth); + guide([ center[0], minimum[1], minimum[2] ], halfSize, depth); + guide([ minimum[0], center[1], minimum[2] ], halfSize, depth); + guide([ center[0], center[1], minimum[2] ], halfSize, depth); + guide([ minimum[0], minimum[1], center[2] ], halfSize, depth); + guide([ center[0], minimum[1], center[2] ], halfSize, depth); + guide([ minimum[0], center[1], center[2] ], halfSize, depth); + guide([ center[0], center[1], center[2] ], halfSize, depth); +} + +(function(visitation) { + var attributes = visitation.visitor.getAttributes(); + colorIndex = strictIndexOf(attributes, AttributeRegistry.colorAttribute); + normalIndex = strictIndexOf(attributes, AttributeRegistry.normalAttribute); + visitor = visitation.visitor; + info = { attributeValues: new Array(attributes.length) }; + + // have the sphere orbit the center and pulse in size + var time = new Date().getTime(); + var ROTATE_PERIOD = 400.0; + sphereCenter[0] = 0.5 + 0.25 * Math.cos(time / ROTATE_PERIOD); + sphereCenter[2] = 0.5 + 0.25 * Math.sin(time / ROTATE_PERIOD); + var PULSE_PERIOD = 300.0; + sphereRadius = 0.25 + 0.0625 * Math.cos(time / PULSE_PERIOD); + sphereRadiusSquared = sphereRadius * sphereRadius; + + guide(visitation.info.minimum, visitation.info.size, 0); +}) diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index 6820cbfece..46afa6cade 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -6,6 +6,8 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +#include +#include #include #include @@ -41,17 +43,9 @@ void MetavoxelSystem::init() { _data.setAttributeValue(p1, AttributeValue(color, encodeInline(qRgba(0xFF, 0xFF, 0xFF, 0xFF)))); - QScriptValue guideFunction = _scriptEngine.evaluate( - "(function(visitation) { " - " var attributes = visitation.visitor.getAttributes();" - " var colorIndex = attributes.indexOf(AttributeRegistry.colorAttribute);" - " var normalIndex = attributes.indexOf(AttributeRegistry.normalAttribute);" - " for (var i = 0; i < attributes.length; i++) {" - " print(attributes[i].getName() + ' ');" - " }" - " print('\\n');" - " visitation.visitor.visit(visitation.info);" - "})"); + QFile scriptFile("resources/scripts/sphere.js"); + scriptFile.open(QIODevice::ReadOnly); + QScriptValue guideFunction = _scriptEngine.evaluate(QTextStream(&scriptFile).readAll()); _data.setAttributeValue(MetavoxelPath(), AttributeValue(AttributeRegistry::getInstance()->getGuideAttribute(), encodeInline(PolymorphicDataPointer(new ScriptedMetavoxelGuide(guideFunction))))); From 8ddf6297a591920f762379631dfff8eb1b0c199b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 17 Dec 2013 17:13:41 -0800 Subject: [PATCH 38/65] Fixed Xcode warnings. --- interface/src/renderer/MetavoxelSystem.cpp | 4 ++-- libraries/metavoxels/src/AttributeRegistry.cpp | 1 + libraries/metavoxels/src/MetavoxelData.cpp | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index 46afa6cade..366e9eb743 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -19,8 +19,8 @@ ProgramObject MetavoxelSystem::_program; int MetavoxelSystem::_pointScaleLocation; MetavoxelSystem::MetavoxelSystem() : - _buffer(QOpenGLBuffer::VertexBuffer), - _pointVisitor(_points) { + _pointVisitor(_points), + _buffer(QOpenGLBuffer::VertexBuffer) { } void MetavoxelSystem::init() { diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index d91e7cb994..5fb03035da 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -89,6 +89,7 @@ OwnedAttributeValue& OwnedAttributeValue::operator=(const AttributeValue& other) if ((_attribute = other.getAttribute())) { _value = _attribute->create(other.getValue()); } + return *this; } Attribute::Attribute(const QString& name) { diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index cc06c64051..636982b63a 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -55,8 +55,7 @@ AttributeValue MetavoxelData::getAttributeValue(const MetavoxelPath& path, const return AttributeValue(attribute); } for (int i = 0, n = path.getSize(); i < n; i++) { - int index = path[i]; - MetavoxelNode* child = node->getChild(i); + MetavoxelNode* child = node->getChild(path[i]); if (child == NULL) { return node->getAttributeValue(attribute); } From ff2b77d31188a709bec2fa5f76bc4ae89d017466 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 17 Dec 2013 17:16:09 -0800 Subject: [PATCH 39/65] Back to a more modest depth. --- interface/resources/scripts/sphere.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/scripts/sphere.js b/interface/resources/scripts/sphere.js index 4e235883d4..403374e812 100644 --- a/interface/resources/scripts/sphere.js +++ b/interface/resources/scripts/sphere.js @@ -20,7 +20,7 @@ var normalIndex; var visitor; var info; -var MAX_DEPTH = 5; +var MAX_DEPTH = 4; var sphereCenter = [ 0.5, 0.5, 0.5 ]; var sphereColor = 0xFFFF00FF; From f7aa464bf2b1506569a2926471aab392fb52b645 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 17 Dec 2013 17:21:56 -0800 Subject: [PATCH 40/65] Somehow, I overwrote this value in Camera. --- interface/src/Camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index e65a1af7f6..94bc693c2b 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -20,7 +20,7 @@ const float CAMERA_FIRST_PERSON_MODE_TIGHTNESS = 100.0f; const float CAMERA_THIRD_PERSON_MODE_UP_SHIFT = -0.2f; const float CAMERA_THIRD_PERSON_MODE_DISTANCE = 1.5f; -const float CAMERA_THIRD_PERSON_MODE_TIGHTNESS = 0.0f; +const float CAMERA_THIRD_PERSON_MODE_TIGHTNESS = 8.0f; const float CAMERA_MIRROR_MODE_UP_SHIFT = 0.0f; const float CAMERA_MIRROR_MODE_DISTANCE = 0.17f; From 45c31cece35d5138783f85c85847e750035a5c19 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 17 Dec 2013 18:23:12 -0800 Subject: [PATCH 41/65] Removed insertion test code. --- interface/src/renderer/MetavoxelSystem.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp index 366e9eb743..543a8b6301 100644 --- a/interface/src/renderer/MetavoxelSystem.cpp +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -34,15 +34,6 @@ void MetavoxelSystem::init() { AttributeRegistry::getInstance()->configureScriptEngine(&_scriptEngine); - MetavoxelPath p1; - p1 += 7; - p1 += 7; - p1 += 7; - - AttributePointer color = AttributeRegistry::getInstance()->getAttribute("color"); - - _data.setAttributeValue(p1, AttributeValue(color, encodeInline(qRgba(0xFF, 0xFF, 0xFF, 0xFF)))); - QFile scriptFile("resources/scripts/sphere.js"); scriptFile.open(QIODevice::ReadOnly); QScriptValue guideFunction = _scriptEngine.evaluate(QTextStream(&scriptFile).readAll()); From e6847961f5553b95bb05ed3787c6a749389fbdca Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 17 Dec 2013 20:11:53 -0800 Subject: [PATCH 42/65] reduced damping for thrown balls, turned off screen flash --- interface/src/avatar/Hand.cpp | 2 +- libraries/particles/src/ParticleCollisionSystem.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 7f8e3ffe52..c276b9baca 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -24,7 +24,7 @@ using namespace std; const float FINGERTIP_VOXEL_SIZE = 0.05; const int TOY_BALL_HAND = 1; const float TOY_BALL_RADIUS = 0.05f; -const float TOY_BALL_DAMPING = 0.999f; +const float TOY_BALL_DAMPING = 0.1f; const glm::vec3 NO_VELOCITY = glm::vec3(0,0,0); const glm::vec3 NO_GRAVITY = glm::vec3(0,0,0); const float NO_DAMPING = 0.f; diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index 313c4d7045..8281deb12d 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -235,6 +235,6 @@ void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f), frequency * (1.f + velocityTangentToCollision / velocityTowardCollision), fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f), - 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision, true); + 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision, false); } } \ No newline at end of file From 13be1ea825b5c67e963812e5f9d144adc8bb74e9 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 17 Dec 2013 22:08:52 -0800 Subject: [PATCH 43/65] added catch, throw, new ball sounds. Tuned ball speed for handball. --- interface/src/avatar/Hand.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index c276b9baca..2fa59ee43f 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -98,7 +98,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f // update the particle with it's new state... #ifdef DEBUG_HAND - qDebug("Update caught particle!\n"); + qDebug("Caught!\n"); #endif caughtParticle->updateParticle(newPosition, closestParticle->getRadius(), @@ -108,6 +108,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f NO_DAMPING, IN_HAND, // we just grabbed it! closestParticle->getUpdateScript()); + // now tell our hand about us having caught it... _toyBallInHand[handID] = true; @@ -115,6 +116,11 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f //printf(">>>>>>> caught... handID:%d particle ID:%d _toyBallInHand[handID] = true\n", handID, closestParticle->getID()); _ballParticleEditHandles[handID] = caughtParticle; caughtParticle = NULL; + // Play a catch sound! + Application::getInstance()->getAudio()->startDrumSound(1.0, + 300, + 0.5, + 0.05); } } @@ -158,11 +164,17 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f TOY_BALL_DAMPING, IN_HAND, TOY_BALL_UPDATE_SCRIPT); + // Play a new ball sound + Application::getInstance()->getAudio()->startDrumSound(1.0, + 2000, + 0.5, + 0.02); + } } else { // Ball is in hand #ifdef DEBUG_HAND - qDebug("Ball in hand\n"); + //qDebug("Ball in hand\n"); #endif glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; _ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE, @@ -178,13 +190,14 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f // If toy ball just released, add velocity to it! if (_toyBallInHand[handID]) { + const float THROWN_VELOCITY_SCALING = 1.5f; _toyBallInHand[handID] = false; glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; glm::vec3 ballVelocity = ballFromHand ? palm.getRawVelocity() : palm.getTipVelocity(); glm::quat avatarRotation = _owningAvatar->getOrientation(); ballVelocity = avatarRotation * ballVelocity; + ballVelocity *= THROWN_VELOCITY_SCALING; - // ball is no longer in hand... #ifdef DEBUG_HAND qDebug("Threw ball, v = %.3f\n", glm::length(ballVelocity)); #endif @@ -201,6 +214,13 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f // note: deleting the edit handle doesn't effect the actual particle delete _ballParticleEditHandles[handID]; _ballParticleEditHandles[handID] = NULL; + + // Play a throw sound + Application::getInstance()->getAudio()->startDrumSound(1.0, + 3000, + 0.5, + 0.02); + } } From 397eb1368026b372cdf57a5e3431070b1ad90429 Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Wed, 18 Dec 2013 08:05:34 +0100 Subject: [PATCH 44/65] removed legacy resources path locator --- interface/src/Application.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 069870a898..3d6078d541 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -144,13 +144,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : { _applicationStartupTime = startup_time; -#ifdef Q_OS_MAC - QString resourcesPath = QCoreApplication::applicationDirPath() + "/../Resources"; -#else - QString resourcesPath = QCoreApplication::applicationDirPath() + "/resources"; -#endif - - QFontDatabase::addApplicationFont(resourcesPath + "/styles/Inconsolata.otf"); + switchToResourcesParentIfRequired(); + QFontDatabase::addApplicationFont("resources/styles/Inconsolata.otf"); _window->setWindowTitle("Interface"); qInstallMessageHandler(messageHandler); @@ -186,7 +181,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _enableProcessVoxelsThread = _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking"); // 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"); From 70e9781ad9ae7a1bdb49ea3da0b2d8692adcb445 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 08:42:34 -0800 Subject: [PATCH 45/65] CR feedback new class names --- interface/src/Application.h | 4 ++-- ...gInterface.cpp => ControllerScriptingInterface.cpp} | 10 +++++----- ...ptingInterface.h => ControllerScriptingInterface.h} | 6 +++--- ...erface.h => AbstractControllerScriptingInterface.h} | 10 +++++----- libraries/script-engine/src/ScriptEngine.cpp | 2 +- libraries/script-engine/src/ScriptEngine.h | 6 +++--- 6 files changed, 19 insertions(+), 19 deletions(-) rename interface/src/{InterfaceControllerScriptingInterface.cpp => ControllerScriptingInterface.cpp} (72%) rename interface/src/{InterfaceControllerScriptingInterface.h => ControllerScriptingInterface.h} (77%) rename libraries/script-engine/src/{ControllerScriptingInterface.h => AbstractControllerScriptingInterface.h} (57%) diff --git a/interface/src/Application.h b/interface/src/Application.h index 71281659d0..2683d679ed 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -69,7 +69,7 @@ #include "ui/LodToolsDialog.h" #include "ParticleTreeRenderer.h" #include "ParticleEditHandle.h" -#include "InterfaceControllerScriptingInterface.h" +#include "ControllerScriptingInterface.h" class QAction; @@ -506,7 +506,7 @@ private: std::vector _voxelFades; std::vector _avatarFades; - InterfaceControllerScriptingInterface _controllerScriptingInterface; + ControllerScriptingInterface _controllerScriptingInterface; }; #endif /* defined(__interface__Application__) */ diff --git a/interface/src/InterfaceControllerScriptingInterface.cpp b/interface/src/ControllerScriptingInterface.cpp similarity index 72% rename from interface/src/InterfaceControllerScriptingInterface.cpp rename to interface/src/ControllerScriptingInterface.cpp index a301120d8c..774b671899 100644 --- a/interface/src/InterfaceControllerScriptingInterface.cpp +++ b/interface/src/ControllerScriptingInterface.cpp @@ -1,5 +1,5 @@ // -// InterfaceControllerScriptingInterface.h +// ControllerScriptingInterface.h // hifi // // Created by Brad Hefta-Gaub on 12/17/13 @@ -8,9 +8,9 @@ #include #include "Application.h" -#include "InterfaceControllerScriptingInterface.h" +#include "ControllerScriptingInterface.h" -const PalmData* InterfaceControllerScriptingInterface::getPrimaryPalm() const { +const PalmData* ControllerScriptingInterface::getPrimaryPalm() const { int leftPalmIndex, rightPalmIndex; const HandData* handData = Application::getInstance()->getAvatar()->getHandData(); @@ -23,7 +23,7 @@ const PalmData* InterfaceControllerScriptingInterface::getPrimaryPalm() const { return NULL; } -bool InterfaceControllerScriptingInterface::isPrimaryButtonPressed() const { +bool ControllerScriptingInterface::isPrimaryButtonPressed() const { const PalmData* primaryPalm = getPrimaryPalm(); if (primaryPalm) { if (primaryPalm->getControllerButtons() & BUTTON_FWD) { @@ -34,7 +34,7 @@ bool InterfaceControllerScriptingInterface::isPrimaryButtonPressed() const { return false; } -glm::vec2 InterfaceControllerScriptingInterface::getPrimaryJoystickPosition() const { +glm::vec2 ControllerScriptingInterface::getPrimaryJoystickPosition() const { const PalmData* primaryPalm = getPrimaryPalm(); if (primaryPalm) { return glm::vec2(primaryPalm->getJoystickX(), primaryPalm->getJoystickY()); diff --git a/interface/src/InterfaceControllerScriptingInterface.h b/interface/src/ControllerScriptingInterface.h similarity index 77% rename from interface/src/InterfaceControllerScriptingInterface.h rename to interface/src/ControllerScriptingInterface.h index 1a9f2ea119..5657a243a8 100644 --- a/interface/src/InterfaceControllerScriptingInterface.h +++ b/interface/src/ControllerScriptingInterface.h @@ -1,5 +1,5 @@ // -// InterfaceControllerScriptingInterface.h +// ControllerScriptingInterface.h // hifi // // Created by Brad Hefta-Gaub on 12/17/13 @@ -11,10 +11,10 @@ #include -#include +#include /// handles scripting of input controller commands from JS -class InterfaceControllerScriptingInterface : public ControllerScriptingInterface { +class ControllerScriptingInterface : public AbstractControllerScriptingInterface { Q_OBJECT public slots: diff --git a/libraries/script-engine/src/ControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h similarity index 57% rename from libraries/script-engine/src/ControllerScriptingInterface.h rename to libraries/script-engine/src/AbstractControllerScriptingInterface.h index 10124e588b..37cea60c72 100644 --- a/libraries/script-engine/src/ControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -1,19 +1,19 @@ // -// ControllerScriptingInterface.h +// AbstractControllerScriptingInterface.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__ +#ifndef __hifi__AbstractControllerScriptingInterface__ +#define __hifi__AbstractControllerScriptingInterface__ #include #include /// handles scripting of input controller commands from JS -class ControllerScriptingInterface : public QObject { +class AbstractControllerScriptingInterface : public QObject { Q_OBJECT public slots: @@ -21,4 +21,4 @@ public slots: virtual glm::vec2 getPrimaryJoystickPosition() const = 0; }; -#endif /* defined(__hifi__ControllerScriptingInterface__) */ +#endif /* defined(__hifi__AbstractControllerScriptingInterface__) */ diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index bae63f1a4c..24c4fcf1d9 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -26,7 +26,7 @@ int ScriptEngine::_scriptNumber = 1; ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, const char* scriptMenuName, AbstractMenuInterface* menu, - ControllerScriptingInterface* controllerScriptingInterface) { + AbstractControllerScriptingInterface* controllerScriptingInterface) { _scriptContents = scriptContents; _isFinished = false; _isRunning = false; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 39ea0d276b..c5172a5772 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -18,7 +18,7 @@ #include #include #include -#include "ControllerScriptingInterface.h" +#include "AbstractControllerScriptingInterface.h" const QString NO_SCRIPT(""); @@ -27,7 +27,7 @@ class ScriptEngine : public QObject { public: ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false, const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL, - ControllerScriptingInterface* controllerScriptingInterface = NULL); + AbstractControllerScriptingInterface* controllerScriptingInterface = NULL); ~ScriptEngine(); @@ -60,7 +60,7 @@ protected: private: VoxelScriptingInterface _voxelScriptingInterface; ParticleScriptingInterface _particleScriptingInterface; - ControllerScriptingInterface* _controllerScriptingInterface; + AbstractControllerScriptingInterface* _controllerScriptingInterface; bool _wantMenuItems; QString _scriptMenuName; AbstractMenuInterface* _menu; From efdef1ad358b0c17a1e7d85a6adff85e43dbdfeb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 09:33:48 -0800 Subject: [PATCH 46/65] added all buttons triggers and joysticks --- .../src/ControllerScriptingInterface.cpp | 97 +++++++++++++++++++ interface/src/ControllerScriptingInterface.h | 26 ++++- .../AbstractControllerScriptingInterface.h | 12 +++ 3 files changed, 132 insertions(+), 3 deletions(-) diff --git a/interface/src/ControllerScriptingInterface.cpp b/interface/src/ControllerScriptingInterface.cpp index 774b671899..0f436a6785 100644 --- a/interface/src/ControllerScriptingInterface.cpp +++ b/interface/src/ControllerScriptingInterface.cpp @@ -23,6 +23,38 @@ const PalmData* ControllerScriptingInterface::getPrimaryPalm() const { 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) { @@ -43,3 +75,68 @@ glm::vec2 ControllerScriptingInterface::getPrimaryJoystickPosition() const { 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 { + return glm::vec3(0); // not yet implemented +} + + + diff --git a/interface/src/ControllerScriptingInterface.h b/interface/src/ControllerScriptingInterface.h index 5657a243a8..f1f763790d 100644 --- a/interface/src/ControllerScriptingInterface.h +++ b/interface/src/ControllerScriptingInterface.h @@ -6,8 +6,8 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // -#ifndef __hifi__InterfaceControllerScriptingInterface__ -#define __hifi__InterfaceControllerScriptingInterface__ +#ifndef __hifi__ControllerScriptingInterface__ +#define __hifi__ControllerScriptingInterface__ #include @@ -21,8 +21,28 @@ 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; + 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 = 0; + const int NUMBER_OF_JOYSTICKS_PER_PALM = 1; + const int NUMBER_OF_TRIGGERS_PER_PALM = 1; + const int NUMBER_OF_BUTTONS_PER_PALM = 6; }; -#endif /* defined(__hifi__InterfaceControllerScriptingInterface__) */ +#endif /* defined(__hifi__ControllerScriptingInterface__) */ diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 37cea60c72..3ad2cc3845 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -19,6 +19,18 @@ class AbstractControllerScriptingInterface : public QObject { 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; }; #endif /* defined(__hifi__AbstractControllerScriptingInterface__) */ From 8549894ff864104b7a5847bc7fde582aa3d724eb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 09:53:47 -0800 Subject: [PATCH 47/65] add support for palm and tip spatial data to JS interface --- .../src/ControllerScriptingInterface.cpp | 46 ++++++++++++++++++- interface/src/ControllerScriptingInterface.h | 5 +- .../AbstractControllerScriptingInterface.h | 2 + 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/interface/src/ControllerScriptingInterface.cpp b/interface/src/ControllerScriptingInterface.cpp index 0f436a6785..493892e042 100644 --- a/interface/src/ControllerScriptingInterface.cpp +++ b/interface/src/ControllerScriptingInterface.cpp @@ -134,8 +134,52 @@ int ControllerScriptingInterface::getNumberOfSpatialControls() const { return getNumberOfActivePalms() * NUMBER_OF_SPATIALCONTROLS_PER_PALM; } +const int PALM_SPATIALCONTROL = 0; +const int TIP_SPATIALCONTROL = 1; + glm::vec3 ControllerScriptingInterface::getSpatialControlPosition(int controlIndex) const { - return glm::vec3(0); // not yet implemented + 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 } diff --git a/interface/src/ControllerScriptingInterface.h b/interface/src/ControllerScriptingInterface.h index f1f763790d..f5b8143032 100644 --- a/interface/src/ControllerScriptingInterface.h +++ b/interface/src/ControllerScriptingInterface.h @@ -32,6 +32,8 @@ public slots: 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; @@ -39,7 +41,8 @@ private: int getNumberOfActivePalms() const; const PalmData* getActivePalm(int palmIndex) const; - const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 0; + 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; diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 3ad2cc3845..5c791af0a4 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -31,6 +31,8 @@ public slots: 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__) */ From 4f3f6c032735557c8895968bc1626bc3a0631988 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 10:42:35 -0800 Subject: [PATCH 48/65] fixed build buster --- interface/src/ControllerScriptingInterface.cpp | 3 --- interface/src/ControllerScriptingInterface.h | 13 +++++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/interface/src/ControllerScriptingInterface.cpp b/interface/src/ControllerScriptingInterface.cpp index 493892e042..fd27eb2428 100644 --- a/interface/src/ControllerScriptingInterface.cpp +++ b/interface/src/ControllerScriptingInterface.cpp @@ -134,9 +134,6 @@ int ControllerScriptingInterface::getNumberOfSpatialControls() const { return getNumberOfActivePalms() * NUMBER_OF_SPATIALCONTROLS_PER_PALM; } -const int PALM_SPATIALCONTROL = 0; -const int TIP_SPATIALCONTROL = 1; - glm::vec3 ControllerScriptingInterface::getSpatialControlPosition(int controlIndex) const { int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; diff --git a/interface/src/ControllerScriptingInterface.h b/interface/src/ControllerScriptingInterface.h index f5b8143032..d0e032d52f 100644 --- a/interface/src/ControllerScriptingInterface.h +++ b/interface/src/ControllerScriptingInterface.h @@ -40,12 +40,13 @@ private: 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 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__) */ From 45d926da41be3ff91322f0b98f2183475d34f75f Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Wed, 18 Dec 2013 20:37:45 +0100 Subject: [PATCH 49/65] CR fixes --- interface/src/Application.cpp | 9 ++++++ interface/src/Application.h | 6 +++- interface/src/LogDisplay.cpp | 14 +++++++- interface/src/LogDisplay.h | 3 +- interface/src/Menu.cpp | 22 ++----------- interface/src/Menu.h | 4 --- interface/src/ui/LogDialog.cpp | 58 +++++++++++++++------------------- interface/src/ui/LogDialog.h | 8 ++--- 8 files changed, 59 insertions(+), 65 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3d6078d541..efe2193629 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4478,3 +4478,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(); + } +} diff --git a/interface/src/Application.h b/interface/src/Application.h index 5f8aaffd23..7680388e9f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,7 @@ #include "ui/VoxelStatsDialog.h" #include "ui/RearMirrorTools.h" #include "ui/LodToolsDialog.h" +#include "ui/LogDialog.h" #include "ParticleTreeRenderer.h" #include "ParticleEditHandle.h" @@ -222,7 +224,7 @@ public slots: void decreaseVoxelSize(); void increaseVoxelSize(); void loadScript(); - + void toggleLogDialog(); private slots: @@ -503,6 +505,8 @@ private: std::vector _voxelFades; std::vector _avatarFades; + + QPointer _logDialog; }; #endif /* defined(__interface__Application__) */ diff --git a/interface/src/LogDisplay.cpp b/interface/src/LogDisplay.cpp index dcfbbff626..84a1abd364 100644 --- a/interface/src/LogDisplay.cpp +++ b/interface/src/LogDisplay.cpp @@ -90,8 +90,8 @@ void LogDisplay::setCharacterSize(unsigned width, unsigned height) { void LogDisplay::addMessage(const char* ptr) { - emit logReceived(ptr); pthread_mutex_lock(& _mutex); + emit logReceived(ptr); // T-pipe, if requested if (_stream != 0l) { @@ -155,6 +155,18 @@ void LogDisplay::addMessage(const char* ptr) { 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 // diff --git a/interface/src/LogDisplay.h b/interface/src/LogDisplay.h index 29080d075e..285325b180 100644 --- a/interface/src/LogDisplay.h +++ b/interface/src/LogDisplay.h @@ -44,8 +44,7 @@ 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 - char** getLogData() { return _lines; }; - char** getLastLinePos() { return _lastLinePos; } + QStringList getLogData(); signals: void logReceived(QString message); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0cfe7928b4..38f4ae3bae 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -69,8 +69,7 @@ Menu::Menu() : _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _boundaryLevelAdjust(0), - _maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS), - _logDialog(NULL) + _maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS) { Application *appInstance = Application::getInstance(); @@ -266,7 +265,7 @@ Menu::Menu() : addDisabledActionAndSeparator(viewMenu, "Stats"); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash); - addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, this, SLOT(showLogDialog())); + 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())); @@ -1029,23 +1028,6 @@ void Menu::pasteToVoxel() { sendFakeEnterEvent(); } -void Menu::showLogDialog() { - if (! _logDialog) { - _logDialog = new LogDialog(Application::getInstance()->getGLWidget()); - connect(_logDialog, SIGNAL(closed()), SLOT(logDialogClosed())); - _logDialog->show(); - } else { - _logDialog->close(); - } -} - -void Menu::logDialogClosed() { - if (_logDialog) { - delete _logDialog; - _logDialog = NULL; - } -} - void Menu::bandwidthDetails() { if (! _bandwidthDialog) { _bandwidthDialog = new BandwidthDialog(Application::getInstance()->getGLWidget(), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 8b31d50578..c5742cc570 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -13,7 +13,6 @@ #include #include -#include "ui/LogDialog.h" #include enum FrustumDrawMode { @@ -93,7 +92,6 @@ public slots: void exportSettings(); void goToUser(); void pasteToVoxel(); - void showLogDialog(); private slots: void aboutApp(); @@ -109,7 +107,6 @@ private slots: void chooseVoxelPaintColor(); void runTests(); void resetSwatchColors(); - void logDialogClosed(); private: static Menu* _instance; @@ -149,7 +146,6 @@ private: int _boundaryLevelAdjust; QAction* _useVoxelShader; int _maxVoxelPacketsPerSecond; - LogDialog* _logDialog; QMenu* _activeScriptsMenu; }; diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 1ada9df2ca..013c60d993 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -14,52 +14,50 @@ #include "ui/LogDialog.h" #include "LogDisplay.h" -#define INITIAL_WIDTH_RATIO 0.7 -#define INITIAL_HEIGHT_RATIO 0.6 +const int INITIAL_WIDTH = 720; +const float INITIAL_HEIGHT_RATIO = 0.6f; int cursorMeta = qRegisterMetaType("QTextCursor"); int blockMeta = qRegisterMetaType("QTextBlock"); LogDialog::LogDialog(QWidget* parent) : QDialog(parent, Qt::Dialog) { - setWindowTitle("Log"); + setWindowTitle("Log"); - _logTextBox = new QPlainTextEdit(this); - _logTextBox->setReadOnly(true); - _logTextBox->show(); + _logTextBox = new QPlainTextEdit(this); + _logTextBox->setReadOnly(true); + _logTextBox->show(); - switchToResourcesParentIfRequired(); - QFile styleSheet("resources/styles/log_dialog.qss"); + switchToResourcesParentIfRequired(); + QFile styleSheet("resources/styles/log_dialog.qss"); - if (styleSheet.open(QIODevice::ReadOnly)) { - setStyleSheet(styleSheet.readAll()); - } + if (styleSheet.open(QIODevice::ReadOnly)) { + setStyleSheet(styleSheet.readAll()); + } - QDesktopWidget* desktop = new QDesktopWidget(); - QRect screen = desktop->screenGeometry(); - resize(720, static_cast(screen.height() * INITIAL_HEIGHT_RATIO)); - move(screen.center() - rect().center()); - delete desktop; + QDesktopWidget desktop; + QRect screen = desktop.screenGeometry(); + resize(INITIAL_WIDTH, static_cast(screen.height() * INITIAL_HEIGHT_RATIO)); + move(screen.center() - rect().center()); + + setAttribute(Qt::WA_DeleteOnClose); } LogDialog::~LogDialog() { deleteLater(); - delete _logTextBox; } void LogDialog::showEvent(QShowEvent *e) { _logTextBox->clear(); - pthread_mutex_lock(& _mutex); - char** _lines = LogDisplay::instance.getLogData(); - char** _lastLinePos = LogDisplay::instance.getLastLinePos(); - int i = 0; - while (_lines[i] != *_lastLinePos) { - appendLogLine(_lines[i]); - i++; - } + 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); } @@ -69,15 +67,9 @@ void LogDialog::resizeEvent(QResizeEvent *e) { void LogDialog::appendLogLine(QString logLine) { if (isVisible()) { + pthread_mutex_lock(& _mutex); _logTextBox->appendPlainText(logLine.simplified()); + pthread_mutex_unlock(& _mutex); _logTextBox->ensureCursorVisible(); } } - -void LogDialog::reject() { - close(); -} - -void LogDialog::closeEvent(QCloseEvent* event) { - emit closed(); -} diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h index 7b445b6f4f..8146bc29e6 100644 --- a/interface/src/ui/LogDialog.h +++ b/interface/src/ui/LogDialog.h @@ -19,16 +19,16 @@ public: LogDialog(QWidget* parent); ~LogDialog(); -signals: - void closed(); +//signals: +// void closed(); public slots: - void reject(); +// void reject(); void appendLogLine(QString logLine); protected: // Emits a 'closed' signal when this dialog is closed. - void closeEvent(QCloseEvent* e); +// void closeEvent(QCloseEvent* e); void resizeEvent(QResizeEvent* e); void showEvent(QShowEvent* e); From d72c4e4f65cf50a28c141784f0eff8054f7429a8 Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Wed, 18 Dec 2013 20:40:15 +0100 Subject: [PATCH 50/65] removed commented code --- interface/src/ui/LogDialog.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h index 8146bc29e6..808ac4a485 100644 --- a/interface/src/ui/LogDialog.h +++ b/interface/src/ui/LogDialog.h @@ -19,16 +19,10 @@ public: LogDialog(QWidget* parent); ~LogDialog(); -//signals: -// void closed(); - -public slots: -// void reject(); +public slots: void appendLogLine(QString logLine); protected: - // Emits a 'closed' signal when this dialog is closed. -// void closeEvent(QCloseEvent* e); void resizeEvent(QResizeEvent* e); void showEvent(QShowEvent* e); From 3f0b5aa748b22ad75694dd17ff92b53970bcaf00 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 18 Dec 2013 13:56:30 -0800 Subject: [PATCH 51/65] Build fix. --- interface/src/LogDisplay.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/LogDisplay.cpp b/interface/src/LogDisplay.cpp index 84a1abd364..dc365a9ea0 100644 --- a/interface/src/LogDisplay.cpp +++ b/interface/src/LogDisplay.cpp @@ -6,12 +6,13 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#include "LogDisplay.h" - #include #include #include +#include + +#include "LogDisplay.h" #include "Util.h" using namespace std; From 17f35ce97ba0c322023ddc241c448ec2d83a44c4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 18 Dec 2013 16:37:15 -0800 Subject: [PATCH 52/65] Fix to see other people animate hydra hands --- libraries/avatars/src/HandData.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index cf91af902a..e8b2c97ff0 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -169,6 +169,9 @@ int HandData::decodeRemoteData(unsigned char* sourceBuffer) { palm.setRawNormal(handNormal); palm.setActive(true); + // For received data, set the sixense controller ID to match the order initialized and sent - 0 Left, 1 Right + palm.setSixenseID(handIndex); + for (unsigned int fingerIndex = 0; fingerIndex < numFingers; ++fingerIndex) { if (fingerIndex < palm.getNumFingers()) { FingerData& finger = palm.getFingers()[fingerIndex]; From 6b0d7c30f0857cef3437c09a08399681a7f32cc5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 16:58:49 -0800 Subject: [PATCH 53/65] added debugging option for forced clock skew --- interface/src/main.cpp | 11 +++++++++++ libraries/shared/src/SharedUtil.cpp | 3 ++- libraries/shared/src/SharedUtil.h | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 07788fefe0..c348ab6dc3 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -19,11 +19,22 @@ #include #include +#include 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* TIME_ADJUST = "--usecTimestampNowAdjust"; + const char* timeAdjustOption = getCmdOption(argc, argv, TIME_ADJUST); + if (timeAdjustOption) { + ::usecTimestampNowAdjust = atoi(timeAdjustOption); + qDebug("timeAdjustOption=%s usecTimestampNowAdjust=%d\n", timeAdjustOption, ::usecTimestampNowAdjust); + } + int exitCode; { Application app(argc, const_cast(argv), startup_time); diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 9a6bb8b4c3..3d79e7fcc2 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -30,10 +30,11 @@ uint64_t usecTimestamp(const timeval *time) { return (time->tv_sec * 1000000 + time->tv_usec); } +int usecTimestampNowAdjust = 0; 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 () { diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index cd6444624f..7752e2e72c 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -56,6 +56,7 @@ static const uint64_t USECS_PER_SECOND = 1000 * 1000; uint64_t usecTimestamp(const timeval *time); uint64_t usecTimestampNow(); +extern int usecTimestampNowAdjust; float randFloat(); int randIntInRange (int min, int max); From 1badc8dc5df5e5c0e7a1afdc82662817eb59195c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 16:59:36 -0800 Subject: [PATCH 54/65] first pass at removing timestamps from particles removed _lastUpdated/getLastUpdated() --- libraries/octree-server/src/OctreeServer.cpp | 10 ++++++ libraries/particles/src/Particle.cpp | 31 ++++--------------- libraries/particles/src/Particle.h | 6 ++-- .../particles/src/ParticleEditHandle.cpp | 4 +-- .../src/ParticleScriptingInterface.cpp | 2 +- .../particles/src/ParticleTreeElement.cpp | 10 ++++-- libraries/shared/src/PacketHeaders.cpp | 2 +- 7 files changed, 30 insertions(+), 35 deletions(-) diff --git a/libraries/octree-server/src/OctreeServer.cpp b/libraries/octree-server/src/OctreeServer.cpp index ffb5f9c976..7ab0705d40 100644 --- a/libraries/octree-server/src/OctreeServer.cpp +++ b/libraries/octree-server/src/OctreeServer.cpp @@ -656,6 +656,16 @@ 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* TIME_ADJUST = "--usecTimestampNowAdjust"; + const char* timeAdjustOption = getCmdOption(_argc, _argv, TIME_ADJUST); + if (timeAdjustOption) { + ::usecTimestampNowAdjust = atoi(timeAdjustOption); + qDebug("timeAdjustOption=%s usecTimestampNowAdjust=%d\n", timeAdjustOption, ::usecTimestampNowAdjust); + } // Check to see if the user passed in a command line option for setting packet send rate const char* PACKETS_PER_SECOND = "--packetsPerSecond"; diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index fb5d603d7d..beb8203b66 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -42,8 +42,9 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 } else { _id = id; } - _lastUpdated = usecTimestampNow(); - _lastEdited = _lastUpdated; + uint64_t now = usecTimestampNow(); + _lastEdited = now; + _lastSimulated = now; _position = position; _radius = radius; @@ -65,9 +66,6 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const { if (success) { success = packetData->appendValue(getCreated()); } - if (success) { - success = packetData->appendValue(getLastUpdated()); - } if (success) { success = packetData->appendValue(getLastEdited()); } @@ -124,11 +122,6 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef dataAt += sizeof(_created); bytesRead += sizeof(_created); - // lastupdated - memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated)); - dataAt += sizeof(_lastUpdated); - bytesRead += sizeof(_lastUpdated); - // _lastEdited memcpy(&_lastEdited, dataAt, sizeof(_lastEdited)); dataAt += sizeof(_lastEdited); @@ -186,7 +179,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; @@ -224,11 +217,6 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe 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); @@ -292,7 +280,6 @@ 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(" position:%f,%f,%f\n", _position.x, _position.y, _position.z); printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z); @@ -347,11 +334,6 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, 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); @@ -405,7 +387,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); } } @@ -419,7 +400,7 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, void Particle::update() { uint64_t now = usecTimestampNow(); - uint64_t elapsed = now - _lastUpdated; + uint64_t elapsed = now - _lastSimulated; uint64_t USECS_PER_SECOND = 1000 * 1000; float timeElapsed = (float)((float)elapsed/(float)USECS_PER_SECOND); @@ -454,7 +435,7 @@ void Particle::update() { //printf("applying damping to Particle timeElapsed=%f\n",timeElapsed); } - _lastUpdated = now; + _lastSimulated = now; } void Particle::runScript() { diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 33e8960670..68e2b10174 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -25,7 +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; @@ -70,7 +69,6 @@ public: 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; } uint32_t getID() const { return _id; } bool getShouldDie() const { return _shouldDie; } @@ -116,7 +114,6 @@ protected: rgbColor _color; float _radius; glm::vec3 _velocity; - uint64_t _lastUpdated; uint64_t _created; uint64_t _lastEdited; uint32_t _id; @@ -129,6 +126,9 @@ protected: uint32_t _creatorTokenID; bool _newlyCreated; + + uint64_t _lastSimulated; + }; class ParticleScriptObject : public QObject { diff --git a/libraries/particles/src/ParticleEditHandle.cpp b/libraries/particles/src/ParticleEditHandle.cpp index 28356ce63e..88d3143a0f 100644 --- a/libraries/particles/src/ParticleEditHandle.cpp +++ b/libraries/particles/src/ParticleEditHandle.cpp @@ -45,7 +45,7 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); - ParticleDetail addParticleDetail = { NEW_PARTICLE, now, now, + ParticleDetail addParticleDetail = { NEW_PARTICLE, now, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, inHand, updateScript, _creatorTokenID }; @@ -71,7 +71,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, now, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, inHand, updateScript, _creatorTokenID }; diff --git a/libraries/particles/src/ParticleScriptingInterface.cpp b/libraries/particles/src/ParticleScriptingInterface.cpp index ec8209208c..8edfae3b88 100644 --- a/libraries/particles/src/ParticleScriptingInterface.cpp +++ b/libraries/particles/src/ParticleScriptingInterface.cpp @@ -23,7 +23,7 @@ unsigned int ParticleScriptingInterface::queueParticleAdd(glm::vec3 position, fl // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); - ParticleDetail addParticleDetail = { NEW_PARTICLE, now, now, + ParticleDetail addParticleDetail = { NEW_PARTICLE, now, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, inHand, updateScript, creatorTokenID }; diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index a631eae926..9ab0a2b4e9 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -119,18 +119,20 @@ 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(); + //int difference = _particles[i].getLastUpdated() - particle.getLastUpdated(); + //bool localOlder = _particles[i].getLastUpdated() < particle.getLastUpdated(); bool changedOnServer = _particles[i].getLastEdited() < particle.getLastEdited(); - bool localOlder = _particles[i].getLastUpdated() < particle.getLastUpdated(); - if (changedOnServer || localOlder) { + if (changedOnServer /*|| localOlder*/) { if (wantDebug) { + /** printf("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n", particle.getID(), (changedOnServer ? "CHANGED" : "same"), (localOlder ? "OLDER" : "NEWER"), difference, debug::valueOf(particle.isNewlyCreated()) ); + **/ } uint64_t actuallyCreated = particle.getCreated(); @@ -141,11 +143,13 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) { _particles[i].setCreated(actuallyCreated); } else { if (wantDebug) { + /** printf(">>> NO CHANGE <<< -- local particle [id:%d] %s and %s than server particle by %d, " "particle.isNewlyCreated()=%s\n", particle.getID(), (changedOnServer ? "CHANGED" : "same"), (localOlder ? "OLDER" : "NEWER"), difference, debug::valueOf(particle.isNewlyCreated()) ); + **/ } } return true; diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index e7c16367aa..24865fff5c 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -54,7 +54,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { return 2; case PACKET_TYPE_PARTICLE_DATA: - return 3; + return 4; default: return 0; From 8b1c39a47168d726b4d72f5a8fd0e232f9d8539d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 17:03:53 -0800 Subject: [PATCH 55/65] more lastUpdated-ectomy --- .../particles/src/ParticleTreeElement.cpp | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index 9ab0a2b4e9..6905bb7021 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -119,20 +119,12 @@ 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 localOlder = _particles[i].getLastUpdated() < particle.getLastUpdated(); - bool changedOnServer = _particles[i].getLastEdited() < particle.getLastEdited(); - - if (changedOnServer /*|| localOlder*/) { - + 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(); @@ -143,13 +135,9 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) { _particles[i].setCreated(actuallyCreated); } 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; From f10dccb1b8d6fa462ca0891b0247ff133a00c8b0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 18 Dec 2013 17:28:21 -0800 Subject: [PATCH 56/65] Fix for menu shortcuts; just include widget library rather than using awkward workaround. --- assignment-client/CMakeLists.txt | 3 ++- interface/src/Menu.cpp | 8 ++++---- interface/src/Menu.h | 4 ++-- libraries/shared/CMakeLists.txt | 3 ++- libraries/shared/src/AbstractMenuInterface.h | 14 +++++--------- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 464728f7e0..c7b8ab5732 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -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) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 38f4ae3bae..98b807fea2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -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); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c5742cc570..73bb0472b4 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -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: diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 8c05b1ff8f..1923d906bb 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -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) diff --git a/libraries/shared/src/AbstractMenuInterface.h b/libraries/shared/src/AbstractMenuInterface.h index 39c378f40b..66083e4ed4 100644 --- a/libraries/shared/src/AbstractMenuInterface.h +++ b/libraries/shared/src/AbstractMenuInterface.h @@ -10,27 +10,23 @@ #ifndef __hifi__AbstractMenuInterface__ #define __hifi__AbstractMenuInterface__ +#include + 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__) */ \ No newline at end of file +#endif /* defined(__hifi__AbstractMenuInterface__) */ From c68a226094763c45b6d0c32b9cb5950210e8a475 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 17:43:48 -0800 Subject: [PATCH 57/65] removing of created timestamp from wire format, still supports lifetime --- libraries/particles/src/Particle.cpp | 55 ++++++++++--------- libraries/particles/src/Particle.h | 12 ++-- .../particles/src/ParticleTreeElement.cpp | 6 +- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index beb8203b66..d68a55ce3b 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -36,7 +36,6 @@ 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 { @@ -45,7 +44,8 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 uint64_t now = usecTimestampNow(); _lastEdited = now; _lastSimulated = now; - + _created = now; // will get updated as appropriate in setLifetime() + _position = position; _radius = radius; memcpy(_color, color, sizeof(_color)); @@ -64,7 +64,7 @@ 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(getLastEdited()); @@ -101,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(uint64_t) // lastedited + + 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; } @@ -117,10 +125,12 @@ 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); // _lastEdited memcpy(&_lastEdited, dataAt, sizeof(_lastEdited)); @@ -207,16 +217,14 @@ 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); - // lastEdited memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited)); dataAt += sizeof(newParticle._lastEdited); @@ -279,7 +287,7 @@ 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(" lifetime:%f\n", getLifetime()); printf(" last edited:%llu\n", _lastEdited); printf(" position:%f,%f,%f\n", _position.x, _position.y, _position.z); printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z); @@ -312,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)); @@ -325,15 +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); - // lastEdited memcpy(copyAt, &details[i].lastEdited, sizeof(details[i].lastEdited)); copyAt += sizeof(details[i].lastEdited); @@ -413,7 +413,7 @@ void Particle::update() { bool isInHand = getInHand(); bool shouldDie = !isInHand && !isStillMoving && isReallyOld; setShouldDie(shouldDie); - + runScript(); // allow the javascript to alter our state // If the ball is in hand, it doesn't move or have gravity effect it @@ -465,3 +465,8 @@ void Particle::runScript() { } } } + +void Particle::setLifetime(float lifetime) { + uint64_t lifetimeInUsecs = lifetime * USECS_PER_SECOND; + _created = usecTimestampNow() - lifetimeInUsecs; +} diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 68e2b10174..aa884762ad 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -67,8 +67,10 @@ 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; } + + /// lifetime of the particle in seconds + float getLifetime() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } + uint64_t getLastEdited() const { return _lastEdited; } uint32_t getID() const { return _id; } bool getShouldDie() const { return _shouldDie; } @@ -91,7 +93,7 @@ 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; } + void setLifetime(float lifetime); bool appendParticleData(OctreePacketData* packetData) const; int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); @@ -144,8 +146,8 @@ 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 getCreated() const { return ((float)_particle->getCreated() / (float)USECS_PER_SECOND); } + float getLifetime() const { return _particle->getLifetime(); } void setPosition(glm::vec3 value) { _particle->setPosition(value); } diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index 6905bb7021..3d9f208408 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -127,12 +127,12 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) { debug::valueOf(particle.isNewlyCreated()) ); } - uint64_t actuallyCreated = particle.getCreated(); + float actualLifetime = particle.getLifetime(); if (!particle.isNewlyCreated()) { - actuallyCreated = _particles[i].getCreated(); + actualLifetime = _particles[i].getLifetime(); } _particles[i] = particle; - _particles[i].setCreated(actuallyCreated); + _particles[i].setLifetime(actualLifetime); } else { if (wantDebug) { printf(">>> NO CHANGE <<< -- local particle [id:%d] %s particle.isNewlyCreated()=%s\n", From 920ef65ccbbeffca4f570c766cff152554f02fa1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 19:01:42 -0800 Subject: [PATCH 58/65] removed _lastedEdited changed to editedAgo --- libraries/particles/src/Particle.cpp | 51 +++++++++++-------- libraries/particles/src/Particle.h | 20 +++++--- .../particles/src/ParticleEditHandle.cpp | 6 +-- .../src/ParticleScriptingInterface.cpp | 3 +- .../particles/src/ParticleTreeElement.cpp | 10 +--- 5 files changed, 49 insertions(+), 41 deletions(-) diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index d68a55ce3b..3f231ac483 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -42,7 +42,7 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 _id = id; } uint64_t now = usecTimestampNow(); - _lastEdited = now; + _edited = now; _lastSimulated = now; _created = now; // will get updated as appropriate in setLifetime() @@ -67,7 +67,7 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const { success = packetData->appendValue(getLifetime()); } if (success) { - success = packetData->appendValue(getLastEdited()); + success = packetData->appendValue(getEditedAgo()); } if (success) { success = packetData->appendValue(getRadius()); @@ -103,7 +103,7 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const { int Particle::expectedBytes() { int expectedBytes = sizeof(uint32_t) // id + sizeof(float) // lifetime - + sizeof(uint64_t) // lastedited + + sizeof(float) // edited ago + sizeof(float) // radius + sizeof(glm::vec3) // position + sizeof(rgbColor) // color @@ -132,10 +132,12 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef bytesRead += sizeof(lifetime); setLifetime(lifetime); - // _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)); @@ -225,11 +227,9 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe newParticle._newlyCreated = false; } - // 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); @@ -288,7 +288,7 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe void Particle::debugDump() const { printf("Particle id :%u\n", _id); printf(" lifetime:%f\n", getLifetime()); - printf(" last edited:%llu\n", _lastEdited); + 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); @@ -334,11 +334,6 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, sizeOut += sizeof(details[i].creatorTokenID); } - // 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); @@ -399,20 +394,25 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, void Particle::update() { + uint64_t now = usecTimestampNow(); uint64_t elapsed = now - _lastSimulated; - uint64_t USECS_PER_SECOND = 1000 * 1000; 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 = 300.0f; // 300 seconds bool isReallyOld = (getLifetime() > REALLY_OLD); bool isInHand = getInHand(); bool shouldDie = !isInHand && !isStillMoving && isReallyOld; setShouldDie(shouldDie); + +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 @@ -470,3 +470,14 @@ 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); +} diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index aa884762ad..e818a2e91d 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -25,7 +25,6 @@ const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF; class ParticleDetail { public: uint32_t id; - uint64_t lastEdited; glm::vec3 position; float radius; rgbColor color; @@ -70,8 +69,8 @@ public: /// lifetime of the particle in seconds float getLifetime() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } - - uint64_t getLastEdited() const { return _lastEdited; } + /// 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 setLifetime(float lifetime); bool appendParticleData(OctreePacketData* packetData) const; int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); @@ -105,19 +103,24 @@ public: void update(); void debugDump() const; + + // similar to an assignment, but it handles no breaking lifetime and editedAgo + 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 _created; - uint64_t _lastEdited; uint32_t _id; static uint32_t _nextID; bool _shouldDie; @@ -128,8 +131,11 @@ protected: uint32_t _creatorTokenID; bool _newlyCreated; - + + // these are never included in wire time uint64_t _lastSimulated; + uint64_t _created; + uint64_t _edited; }; diff --git a/libraries/particles/src/ParticleEditHandle.cpp b/libraries/particles/src/ParticleEditHandle.cpp index 88d3143a0f..d8466816c4 100644 --- a/libraries/particles/src/ParticleEditHandle.cpp +++ b/libraries/particles/src/ParticleEditHandle.cpp @@ -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, + 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, + ParticleDetail newParticleDetail = { _id, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, inHand, updateScript, _creatorTokenID }; diff --git a/libraries/particles/src/ParticleScriptingInterface.cpp b/libraries/particles/src/ParticleScriptingInterface.cpp index 8edfae3b88..758b50035d 100644 --- a/libraries/particles/src/ParticleScriptingInterface.cpp +++ b/libraries/particles/src/ParticleScriptingInterface.cpp @@ -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, + ParticleDetail addParticleDetail = { NEW_PARTICLE, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, inHand, updateScript, creatorTokenID }; diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index 3d9f208408..b142c1f568 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -119,20 +119,14 @@ 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()) { - bool changedOnServer = _particles[i].getLastEdited() < particle.getLastEdited(); + bool changedOnServer = _particles[i].getEditedAgo() > particle.getEditedAgo(); if (changedOnServer) { if (wantDebug) { printf("local particle [id:%d] %s, particle.isNewlyCreated()=%s\n", particle.getID(), (changedOnServer ? "CHANGED" : "same"), debug::valueOf(particle.isNewlyCreated()) ); } - - float actualLifetime = particle.getLifetime(); - if (!particle.isNewlyCreated()) { - actualLifetime = _particles[i].getLifetime(); - } - _particles[i] = particle; - _particles[i].setLifetime(actualLifetime); + _particles[i].copyChangedProperties(particle); } else { if (wantDebug) { printf(">>> NO CHANGE <<< -- local particle [id:%d] %s particle.isNewlyCreated()=%s\n", From c6933239d9c2c1419c845f70194f2ff33ff8c554 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 19:21:30 -0800 Subject: [PATCH 59/65] fixed comment --- libraries/particles/src/Particle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index e818a2e91d..051f9bf59d 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -104,7 +104,7 @@ public: void debugDump() const; - // similar to an assignment, but it handles no breaking lifetime and editedAgo + // similar to assignment/copy, but it handles keeping lifetime accurate void copyChangedProperties(const Particle& other); protected: From 6e2c0032b5c6ed1189ebcbd11a32b748eac2eadc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 19:22:15 -0800 Subject: [PATCH 60/65] removed dead code --- libraries/particles/src/Particle.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 051f9bf59d..995a8675ce 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -152,10 +152,8 @@ 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 _particle->getLifetime(); } - void setPosition(glm::vec3 value) { _particle->setPosition(value); } void setVelocity(glm::vec3 value) { _particle->setVelocity(value); } void setGravity(glm::vec3 value) { _particle->setGravity(value); } From 5b36953e8187359fdeea140ac8767df6df97f43e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 19:33:52 -0800 Subject: [PATCH 61/65] cleanup clockSkew debug options and remove some chatty logs --- interface/src/main.cpp | 11 ++++++----- libraries/octree-server/src/OctreeServer.cpp | 11 ++++++----- libraries/particles/src/Particle.cpp | 12 ++++++++---- libraries/shared/src/SharedUtil.cpp | 6 +++++- libraries/shared/src/SharedUtil.h | 2 +- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index c348ab6dc3..7a5703a881 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -28,11 +28,12 @@ int main(int argc, const char * argv[]) { // 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* TIME_ADJUST = "--usecTimestampNowAdjust"; - const char* timeAdjustOption = getCmdOption(argc, argv, TIME_ADJUST); - if (timeAdjustOption) { - ::usecTimestampNowAdjust = atoi(timeAdjustOption); - qDebug("timeAdjustOption=%s usecTimestampNowAdjust=%d\n", timeAdjustOption, ::usecTimestampNowAdjust); + 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; diff --git a/libraries/octree-server/src/OctreeServer.cpp b/libraries/octree-server/src/OctreeServer.cpp index 7ab0705d40..a8010cefaf 100644 --- a/libraries/octree-server/src/OctreeServer.cpp +++ b/libraries/octree-server/src/OctreeServer.cpp @@ -660,11 +660,12 @@ void OctreeServer::run() { // 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* TIME_ADJUST = "--usecTimestampNowAdjust"; - const char* timeAdjustOption = getCmdOption(_argc, _argv, TIME_ADJUST); - if (timeAdjustOption) { - ::usecTimestampNowAdjust = atoi(timeAdjustOption); - qDebug("timeAdjustOption=%s usecTimestampNowAdjust=%d\n", timeAdjustOption, ::usecTimestampNowAdjust); + 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 diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 3f231ac483..c2f86c7b75 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -409,11 +409,15 @@ void Particle::update() { bool isInHand = getInHand(); bool shouldDie = !isInHand && !isStillMoving && isReallyOld; setShouldDie(shouldDie); - -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)); + 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 diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 3d79e7fcc2..4d178a6ee9 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -31,10 +31,14 @@ uint64_t usecTimestamp(const timeval *time) { } 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) + usecTimestampNowAdjust; + return (now.tv_sec * 1000000 + now.tv_usec) + ::usecTimestampNowAdjust; } float randFloat () { diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 7752e2e72c..893922ec28 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -56,7 +56,7 @@ static const uint64_t USECS_PER_SECOND = 1000 * 1000; uint64_t usecTimestamp(const timeval *time); uint64_t usecTimestampNow(); -extern int usecTimestampNowAdjust; +void usecTimestampNowForceClockSkew(int clockSkew); float randFloat(); int randIntInRange (int min, int max); From 95df772707b77b371f66f81a9b4592ff90ca0944 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 19:36:34 -0800 Subject: [PATCH 62/65] make really old 30 seconds not 300 --- libraries/particles/src/Particle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index c2f86c7b75..9248bf540f 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -404,7 +404,7 @@ void Particle::update() { float velocityScalar = glm::length(getVelocity()); const float STILL_MOVING = 0.05 / TREE_SCALE; bool isStillMoving = (velocityScalar > STILL_MOVING); - const float REALLY_OLD = 300.0f; // 300 seconds + const float REALLY_OLD = 30.0f; // 30 seconds bool isReallyOld = (getLifetime() > REALLY_OLD); bool isInHand = getInHand(); bool shouldDie = !isInHand && !isStillMoving && isReallyOld; From d430558ea9ea437bd46997b6d2397847195e42bf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 18 Dec 2013 21:08:34 -0800 Subject: [PATCH 63/65] fix expectedBytes() mismatch between edit packets and normal packets --- libraries/particles/src/Particle.cpp | 15 ++++++++++++++- libraries/particles/src/Particle.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 9248bf540f..ec0783d0d9 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -115,6 +115,19 @@ int Particle::expectedBytes() { return expectedBytes; } +int Particle::expectedEditMessageBytes() { + int expectedBytes = sizeof(uint32_t) // id + + 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; +} + int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { int bytesRead = 0; if (bytesLeftToRead >= expectedBytes()) { @@ -308,7 +321,7 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, int octets = numberOfThreeBitSectionsInCode(octcode); int lengthOfOctcode = bytesRequiredForCodeLength(octets); - int lenfthOfEditData = lengthOfOctcode + expectedBytes(); + int lenfthOfEditData = lengthOfOctcode + expectedEditMessageBytes(); // make sure we have room to copy this particle if (sizeOut + lenfthOfEditData > sizeIn) { diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 995a8675ce..5090828724 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -96,6 +96,7 @@ public: bool appendParticleData(OctreePacketData* packetData) const; int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); static int expectedBytes(); + static int expectedEditMessageBytes(); static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details, unsigned char* bufferOut, int sizeIn, int& sizeOut); From c3b222cfc218ff09784869eabf211a52c197b910 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 19 Dec 2013 11:23:55 -0600 Subject: [PATCH 64/65] Print assignment request details to log --- domain-server/src/DomainServer.cpp | 6 ++++-- interface/src/avatar/Avatar.cpp | 4 ---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index ec955f5fb4..47b0295941 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -220,12 +220,12 @@ void DomainServer::readAvailableDatagrams() { } } else if (packetData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) { - qDebug("Received a request for assignment.\n"); - if (_assignmentQueue.size() > 0) { // construct the requested assignment from the packet data Assignment requestAssignment(packetData, receivedBytes); + qDebug("Received a request for assignment type %i from %s.\n", requestAssignment.getType() ,qPrintable(senderSockAddr.getAddress().toString())); + Assignment* assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); if (assignmentToDeploy) { @@ -243,6 +243,8 @@ void DomainServer::readAvailableDatagrams() { } } + } else { + qDebug("Received an invalid assignment request from %s.\n", qPrintable(senderSockAddr.getAddress().toString())); } } } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f4a09ad069..7762f5afbc 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -338,8 +338,6 @@ void Avatar::render(bool forceRenderHead) { } } - - // returns true if the Leap controls any of the avatar's hands. bool Avatar::updateLeapHandPositions() { bool returnValue = false; @@ -443,8 +441,6 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { return glm::angleAxis(angle * proportion, axis); } - - void Avatar::renderBody(bool forceRenderHead) { if (_head.getVideoFace().isFullFrame()) { From 57bf31e1a6c22b7bc3049d48660efd644c01de7e Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 19 Dec 2013 11:25:51 -0600 Subject: [PATCH 65/65] Wrong spacing --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 47b0295941..ee6caaaf9b 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -224,7 +224,7 @@ void DomainServer::readAvailableDatagrams() { // construct the requested assignment from the packet data Assignment requestAssignment(packetData, receivedBytes); - qDebug("Received a request for assignment type %i from %s.\n", requestAssignment.getType() ,qPrintable(senderSockAddr.getAddress().toString())); + qDebug("Received a request for assignment type %i from %s.\n", requestAssignment.getType(), qPrintable(senderSockAddr.getAddress().toString())); Assignment* assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);