From 4033baa5caac02332a30a8cb0e39a0bc86c724a6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 2 Dec 2013 12:15:43 -0800 Subject: [PATCH 01/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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 0ca23207113400a37a4ae36db64ac60d1c14dff8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 16 Dec 2013 13:44:24 -0800 Subject: [PATCH 15/24] 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 16/24] 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 07ed688a8af6363e0d885dd5d93201dd4fc23606 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 16 Dec 2013 18:13:29 -0800 Subject: [PATCH 17/24] 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 d535d3b115263f5618e92cf9c94c280362f9b579 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 17 Dec 2013 13:44:56 -0800 Subject: [PATCH 18/24] 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 c6dc93c28eb2ae8849c1542278632cb8db3933d5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 17 Dec 2013 16:08:38 -0800 Subject: [PATCH 19/24] 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 20/24] 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 21/24] 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 22/24] 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 23/24] 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 24/24] 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());