diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index b87557d073..b0c7e125b4 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -50,11 +50,16 @@ ModelTreeElement* ModelTreeElement::addChildAtIndex(int index) { } +// TODO: This will attempt to store as many models as will fit in the packetData, if an individual model won't +// fit, but some models did fit, then the element outputs what can fit. Once the general Octree::encodeXXX() +// process supports partial encoding of an octree element, this will need to be updated to handle spanning its +// contents across multiple packets. bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { bool success = true; // assume the best... // write our models out... first determine which of the models are in view based on our params uint16_t numberOfModels = 0; + uint16_t actualNumberOfModels = 0; QVector indexesOfModelsToInclude; for (uint16_t i = 0; i < _modelItems->size(); i++) { @@ -72,17 +77,33 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBit } } + int numberOfModelsOffset = packetData->getUncompressedByteOffset(); success = packetData->appendValue(numberOfModels); if (success) { foreach (uint16_t i, indexesOfModelsToInclude) { const ModelItem& model = (*_modelItems)[i]; + + LevelDetails modelLevel = packetData->startLevel(); + success = model.appendModelData(packetData); + + if (success) { + packetData->endLevel(modelLevel); + actualNumberOfModels++; + } if (!success) { + packetData->discardLevel(modelLevel); break; } } } + + if (!success) { + success = packetData->updatePriorBytes(numberOfModelsOffset, + (const unsigned char*)&actualNumberOfModels, sizeof(actualNumberOfModels)); + } + return success; } @@ -433,6 +454,7 @@ int ModelTreeElement::readElementDataFromBuffer(const unsigned char* data, int b if (bytesLeftToRead >= (int)sizeof(numberOfModels)) { // read our models in.... numberOfModels = *(uint16_t*)dataAt; + dataAt += sizeof(numberOfModels); bytesLeftToRead -= (int)sizeof(numberOfModels); bytesRead += sizeof(numberOfModels); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 3ec1871023..cbdc4753dc 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -602,7 +602,6 @@ public: bool findRayIntersectionOp(OctreeElement* element, void* extraData) { RayArgs* args = static_cast(extraData); - bool keepSearching = true; if (element->findRayIntersection(args->origin, args->direction, keepSearching, args->element, args->distance, args->face, args->intersectedObject)) { @@ -1336,14 +1335,23 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, } } - // write the color data... + // write the child element data... if (continueThisLevel && params.includeColor) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { OctreeElement* childElement = element->getChildAtIndex(i); if (childElement) { + int bytesBeforeChild = packetData->getUncompressedSize(); + + // TODO: we want to support the ability for a childElement to "partially" write it's data. + // for example, consider the case of the model server where the entire contents of the + // element may be larger than can fit in a single MTU/packetData. In this case, we want + // to allow the appendElementData() to respond that it produced partial data, which should be + // written, but that the childElement needs to be reprocessed in an additional pass or passes + // to be completed. In the case that an element was partially written, we need to continueThisLevel = childElement->appendElementData(packetData, params); + int bytesAfterChild = packetData->getUncompressedSize(); if (!continueThisLevel) { diff --git a/libraries/shared/src/PropertyFlags.h b/libraries/shared/src/PropertyFlags.h new file mode 100644 index 0000000000..b9253379c6 --- /dev/null +++ b/libraries/shared/src/PropertyFlags.h @@ -0,0 +1,418 @@ +// +// PropertyFlags.h +// libraries/shared/src +// +// Created by Brad Hefta-Gaub on 6/3/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// +// TODO: +// * consider adding iterator to enumerate the properties that have been set? + +#ifndef hifi_PropertyFlags_h +#define hifi_PropertyFlags_h + +#include +#include + +#include +#include + +#include + +templateclass PropertyFlags { +public: + typedef Enum enum_type; + inline PropertyFlags() : + _maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false) { }; + inline PropertyFlags(const PropertyFlags& other) : + _flags(other._flags), _maxFlag(other._maxFlag), _minFlag(other._minFlag), + _trailingFlipped(other._trailingFlipped) {} + inline PropertyFlags(Enum flag) : + _maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false) { setHasProperty(flag); } + + void clear() { _flags.clear(); _maxFlag = INT_MIN; _minFlag = INT_MAX; _trailingFlipped = false; } + + Enum firstFlag() const { return (Enum)_minFlag; } + Enum lastFlag() const { return (Enum)_maxFlag; } + + void setHasProperty(Enum flag, bool value = true); + bool getHasProperty(Enum flag); + QByteArray encode(); + void decode(const QByteArray& fromEncoded); + + + bool operator==(const PropertyFlags& other) const { return _flags == other._flags; } + bool operator!=(const PropertyFlags& other) const { return _flags != other._flags; } + bool operator!() const { return _flags.size() == 0; } + + PropertyFlags& operator=(const PropertyFlags& other); + + PropertyFlags& operator|=(PropertyFlags other); + PropertyFlags& operator|=(Enum flag); + + PropertyFlags& operator&=(PropertyFlags other); + PropertyFlags& operator&=(Enum flag); + + PropertyFlags& operator+=(PropertyFlags other); + PropertyFlags& operator+=(Enum flag); + + PropertyFlags& operator-=(PropertyFlags other); + PropertyFlags& operator-=(Enum flag); + + PropertyFlags& operator<<=(PropertyFlags other); + PropertyFlags& operator<<=(Enum flag); + + PropertyFlags operator|(PropertyFlags other) const; + PropertyFlags operator|(Enum flag) const; + + PropertyFlags operator&(PropertyFlags other) const; + PropertyFlags operator&(Enum flag) const; + + PropertyFlags operator+(PropertyFlags other) const; + PropertyFlags operator+(Enum flag) const; + + PropertyFlags operator-(PropertyFlags other) const; + PropertyFlags operator-(Enum flag) const; + + PropertyFlags operator<<(PropertyFlags other) const; + PropertyFlags operator<<(Enum flag) const; + + // NOTE: due to the nature of the compact storage of these property flags, and the fact that the upper bound of the + // enum is not know, these operators will only perform their bitwise operations on the set of properties that have + // been previously set + PropertyFlags& operator^=(PropertyFlags other); + PropertyFlags& operator^=(Enum flag); + PropertyFlags operator^(PropertyFlags other) const; + PropertyFlags operator^(Enum flag) const; + PropertyFlags operator~() const; + + void debugDumpBits(); + + +private: + void shinkIfNeeded(); + + QBitArray _flags; + int _maxFlag; + int _minFlag; + bool _trailingFlipped; /// are the trailing properties flipping in their state (e.g. assumed true, instead of false) +}; + +template PropertyFlags& operator<<(PropertyFlags& out, const PropertyFlags& other) { + return out <<= other; +} + +template PropertyFlags& operator<<(PropertyFlags& out, Enum flag) { + return out <<= flag; +} + + +template inline void PropertyFlags::setHasProperty(Enum flag, bool value) { + // keep track of our min flag + if (flag < _minFlag) { + if (value) { + _minFlag = flag; + } + } + if (flag > _maxFlag) { + if (value) { + _maxFlag = flag; + _flags.resize(_maxFlag + 1); + } else { + return; // bail early, we're setting a flag outside of our current _maxFlag to false, which is already the default + } + } + _flags.setBit(flag, value); + + if (flag == _maxFlag && !value) { + shinkIfNeeded(); + } +} + +template inline bool PropertyFlags::getHasProperty(Enum flag) { + if (flag > _maxFlag) { + return _trailingFlipped; // usually false + } + return _flags.testBit(flag); +} + +const int BITS_PER_BYTE = 8; + +template inline QByteArray PropertyFlags::encode() { + QByteArray output; + + if (_maxFlag < _minFlag) { + output.fill(0, 1); + return output; // no flags... nothing to encode + } + + // we should size the array to the correct size. + int lengthInBytes = (_maxFlag / (BITS_PER_BYTE - 1)) + 1; + + output.fill(0, lengthInBytes); + + // next pack the number of header bits in, the first N-1 to be set to 1, the last to be set to 0 + for(int i = 0; i < lengthInBytes; i++) { + int outputIndex = i; + int bitValue = (i < (lengthInBytes - 1) ? 1 : 0); + char original = output.at(outputIndex / BITS_PER_BYTE); + int shiftBy = BITS_PER_BYTE - ((outputIndex % BITS_PER_BYTE) + 1); + char thisBit = ( bitValue << shiftBy); + output[i / BITS_PER_BYTE] = (original | thisBit); + } + + // finally pack the the actual bits from the bit array + for(int i = lengthInBytes; i < (lengthInBytes + _maxFlag + 1); i++) { + int flagIndex = i - lengthInBytes; + int outputIndex = i; + int bitValue = ( _flags[flagIndex] ? 1 : 0); + char original = output.at(outputIndex / BITS_PER_BYTE); + int shiftBy = BITS_PER_BYTE - ((outputIndex % BITS_PER_BYTE) + 1); + char thisBit = ( bitValue << shiftBy); + output[i / BITS_PER_BYTE] = (original | thisBit); + } + return output; +} + +template inline void PropertyFlags::decode(const QByteArray& fromEncodedBytes) { + + clear(); // we are cleared out! + + // first convert the ByteArray into a BitArray... + QBitArray encodedBits; + int bitCount = BITS_PER_BYTE * fromEncodedBytes.count(); + encodedBits.resize(bitCount); + + for(int byte = 0; byte < fromEncodedBytes.count(); byte++) { + char originalByte = fromEncodedBytes.at(byte); + for(int bit = 0; bit < BITS_PER_BYTE; bit++) { + int shiftBy = BITS_PER_BYTE - (bit + 1); + char maskBit = ( 1 << shiftBy); + bool bitValue = originalByte & maskBit; + encodedBits.setBit(byte * BITS_PER_BYTE + bit, bitValue); + } + } + + // next, read the leading bits to determine the correct number of bytes to decode (may not match the QByteArray) + int encodedByteCount = 0; + int bitAt; + for (bitAt = 0; bitAt < bitCount; bitAt++) { + if (encodedBits.at(bitAt)) { + encodedByteCount++; + } else { + break; + } + } + encodedByteCount++; // always at least one byte + int expectedBitCount = encodedByteCount * BITS_PER_BYTE; + + // Now, keep reading... + int flagsStartAt = bitAt + 1; + for (bitAt = flagsStartAt; bitAt < expectedBitCount; bitAt++) { + if (encodedBits.at(bitAt)) { + setHasProperty((Enum)(bitAt - flagsStartAt)); + } + } +} + +template inline void PropertyFlags::debugDumpBits() { + qDebug() << "_minFlag=" << _minFlag; + qDebug() << "_maxFlag=" << _maxFlag; + qDebug() << "_trailingFlipped=" << _trailingFlipped; + for(int i = 0; i < _flags.size(); i++) { + qDebug() << "bit[" << i << "]=" << _flags.at(i); + } +} + + +template inline PropertyFlags& PropertyFlags::operator=(const PropertyFlags& other) { + _flags = other._flags; + _maxFlag = other._maxFlag; + _minFlag = other._minFlag; + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator|=(PropertyFlags other) { + _flags |= other._flags; + _maxFlag = std::max(_maxFlag, other._maxFlag); + _minFlag = std::min(_minFlag, other._minFlag); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator|=(Enum flag) { + PropertyFlags other(flag); + _flags |= other._flags; + _maxFlag = std::max(_maxFlag, other._maxFlag); + _minFlag = std::min(_minFlag, other._minFlag); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator&=(PropertyFlags other) { + _flags &= other._flags; + shinkIfNeeded(); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator&=(Enum flag) { + PropertyFlags other(flag); + _flags &= other._flags; + shinkIfNeeded(); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator^=(PropertyFlags other) { + _flags ^= other._flags; + shinkIfNeeded(); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator^=(Enum flag) { + PropertyFlags other(flag); + _flags ^= other._flags; + shinkIfNeeded(); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator+=(PropertyFlags other) { + for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { + if (other.getHasProperty((Enum)flag)) { + setHasProperty((Enum)flag, true); + } + } + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator+=(Enum flag) { + setHasProperty(flag, true); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator-=(PropertyFlags other) { + for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { + if (other.getHasProperty((Enum)flag)) { + setHasProperty((Enum)flag, false); + } + } + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator-=(Enum flag) { + setHasProperty(flag, false); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator<<=(PropertyFlags other) { + for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { + if (other.getHasProperty((Enum)flag)) { + setHasProperty((Enum)flag, true); + } + } + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator<<=(Enum flag) { + setHasProperty(flag, true); + return *this; +} + +template inline PropertyFlags PropertyFlags::operator|(PropertyFlags other) const { + PropertyFlags result(*this); + result |= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator|(Enum flag) const { + PropertyFlags result(*this); + PropertyFlags other(flag); + result |= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator&(PropertyFlags other) const { + PropertyFlags result(*this); + result &= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator&(Enum flag) const { + PropertyFlags result(*this); + PropertyFlags other(flag); + result &= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator^(PropertyFlags other) const { + PropertyFlags result(*this); + result ^= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator^(Enum flag) const { + PropertyFlags result(*this); + PropertyFlags other(flag); + result ^= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator+(PropertyFlags other) const { + PropertyFlags result(*this); + result += other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator+(Enum flag) const { + PropertyFlags result(*this); + result.setHasProperty(flag, true); + return result; +} + +template inline PropertyFlags PropertyFlags::operator-(PropertyFlags other) const { + PropertyFlags result(*this); + result -= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator-(Enum flag) const { + PropertyFlags result(*this); + result.setHasProperty(flag, false); + return result; +} + +template inline PropertyFlags PropertyFlags::operator<<(PropertyFlags other) const { + PropertyFlags result(*this); + result <<= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator<<(Enum flag) const { + PropertyFlags result(*this); + result.setHasProperty(flag, true); + return result; +} + +template inline PropertyFlags PropertyFlags::operator~() const { + PropertyFlags result(*this); + result._flags = ~_flags; + result._trailingFlipped = !_trailingFlipped; + return result; +} + +template inline void PropertyFlags::shinkIfNeeded() { + bool maxFlagWas = _maxFlag; + while (_maxFlag >= 0) { + if (_flags.testBit(_maxFlag)) { + break; + } + _maxFlag--; + } + if (maxFlagWas != _maxFlag) { + _flags.resize(_maxFlag + 1); + } +} + +#endif // hifi_PropertyFlags_h + diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt new file mode 100644 index 0000000000..cbdfd02054 --- /dev/null +++ b/tests/octree/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 2.8) + +if (WIN32) + cmake_policy (SET CMP0020 NEW) +endif (WIN32) + +set(TARGET_NAME octree-tests) + +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/") + +#find_package(Qt5Network REQUIRED) +#find_package(Qt5Script REQUIRED) +#find_package(Qt5Widgets REQUIRED) + +include(${MACRO_DIR}/SetupHifiProject.cmake) +setup_hifi_project(${TARGET_NAME} TRUE) + +include(${MACRO_DIR}/AutoMTC.cmake) +auto_mtc(${TARGET_NAME} ${ROOT_DIR}) + +#qt5_use_modules(${TARGET_NAME} Network Script Widgets) + +#include glm +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + +# link in the shared libraries +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) + +IF (WIN32) + #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) +ENDIF(WIN32) + diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp new file mode 100644 index 0000000000..ddc3f2c74d --- /dev/null +++ b/tests/octree/src/OctreeTests.cpp @@ -0,0 +1,416 @@ +// +// OctreeTests.h +// tests/physics/src +// +// Created by Brad Hefta-Gaub on 06/04/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include +#include + +#include "OctreeTests.h" + +enum ModelPropertyList { + PROP_PAGED_PROPERTY, + PROP_CUSTOM_PROPERTIES_INCLUDED, + PROP_VISIBLE, + PROP_POSITION, + PROP_RADIUS, + PROP_MODEL_URL, + PROP_ROTATION, + PROP_COLOR, + PROP_SCRIPT, + PROP_ANIMATION_URL, + PROP_ANIMATION_FPS, + PROP_ANIMATION_FRAME_INDEX, + PROP_ANIMATION_PLAYING, + PROP_SHOULD_BE_DELETED +}; + +typedef PropertyFlags ModelPropertyFlags; + +enum ParticlePropertyList { + PARTICLE_PROP_PAGED_PROPERTY, + PARTICLE_PROP_CUSTOM_PROPERTIES_INCLUDED, + PARTICLE_PROP_VISIBLE, + PARTICLE_PROP_POSITION, + PARTICLE_PROP_RADIUS, + PARTICLE_PROP_MODEL_URL, + PARTICLE_PROP_ROTATION, + PARTICLE_PROP_COLOR, + PARTICLE_PROP_SCRIPT, + PARTICLE_PROP_ANIMATION_URL, + PARTICLE_PROP_ANIMATION_FPS, + PARTICLE_PROP_ANIMATION_FRAME_INDEX, + PARTICLE_PROP_ANIMATION_PLAYING, + PARTICLE_PROP_SHOULD_BE_DELETED, + PARTICLE_PROP_VELOCITY, + PARTICLE_PROP_GRAVITY, + PARTICLE_PROP_DAMPING, + PARTICLE_PROP_MASS, + PARTICLE_PROP_LIFETIME, + PARTICLE_PROP_PAUSE_SIMULATION, +}; + +typedef PropertyFlags ParticlePropertyFlags; + + +void OctreeTests::propertyFlagsTests() { + qDebug() << "******************************************************************************************"; + qDebug() << "OctreeTests::propertyFlagsTests()"; + + { + qDebug() << "Test 1: ModelProperties: using setHasProperty()"; + ModelPropertyFlags props; + props.setHasProperty(PROP_VISIBLE); + props.setHasProperty(PROP_POSITION); + props.setHasProperty(PROP_RADIUS); + props.setHasProperty(PROP_MODEL_URL); + props.setHasProperty(PROP_ROTATION); + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 2: ParticlePropertyFlags: using setHasProperty()"; + ParticlePropertyFlags props2; + props2.setHasProperty(PARTICLE_PROP_VISIBLE); + props2.setHasProperty(PARTICLE_PROP_ANIMATION_URL); + props2.setHasProperty(PARTICLE_PROP_ANIMATION_FPS); + props2.setHasProperty(PARTICLE_PROP_ANIMATION_FRAME_INDEX); + props2.setHasProperty(PARTICLE_PROP_ANIMATION_PLAYING); + props2.setHasProperty(PARTICLE_PROP_PAUSE_SIMULATION); + + QByteArray encoded = props2.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "Test 2b: remove flag with setHasProperty() PARTICLE_PROP_PAUSE_SIMULATION"; + + props2.setHasProperty(PARTICLE_PROP_PAUSE_SIMULATION, false); + + encoded = props2.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + } + + { + qDebug() << "Test 3: ParticlePropertyFlags: using | operator"; + ParticlePropertyFlags props; + + props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE) + | ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL) + | ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS) + | ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX) + | ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING) + | ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION); + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "Test 3b: remove flag with -= PARTICLE_PROP_PAUSE_SIMULATION"; + props -= PARTICLE_PROP_PAUSE_SIMULATION; + + encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 3c: ParticlePropertyFlags: using |= operator"; + ParticlePropertyFlags props; + + props |= PARTICLE_PROP_VISIBLE; + props |= PARTICLE_PROP_ANIMATION_URL; + props |= PARTICLE_PROP_ANIMATION_FPS; + props |= PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props |= PARTICLE_PROP_ANIMATION_PLAYING; + props |= PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 4: ParticlePropertyFlags: using + operator"; + ParticlePropertyFlags props; + + props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING) + + ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION); + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 4b: ParticlePropertyFlags: using += operator"; + ParticlePropertyFlags props; + + props += PARTICLE_PROP_VISIBLE; + props += PARTICLE_PROP_ANIMATION_URL; + props += PARTICLE_PROP_ANIMATION_FPS; + props += PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props += PARTICLE_PROP_ANIMATION_PLAYING; + props += PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5: ParticlePropertyFlags: using = ... << operator"; + ParticlePropertyFlags props; + + props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING) + << ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION); + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5b: ParticlePropertyFlags: using <<= operator"; + ParticlePropertyFlags props; + + props <<= PARTICLE_PROP_VISIBLE; + props <<= PARTICLE_PROP_ANIMATION_URL; + props <<= PARTICLE_PROP_ANIMATION_FPS; + props <<= PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props <<= PARTICLE_PROP_ANIMATION_PLAYING; + props <<= PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5c: ParticlePropertyFlags: using << enum operator"; + ParticlePropertyFlags props; + + props << PARTICLE_PROP_VISIBLE; + props << PARTICLE_PROP_ANIMATION_URL; + props << PARTICLE_PROP_ANIMATION_FPS; + props << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props << PARTICLE_PROP_ANIMATION_PLAYING; + props << PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5d: ParticlePropertyFlags: using << flags operator "; + ParticlePropertyFlags props; + ParticlePropertyFlags props2; + + props << PARTICLE_PROP_VISIBLE; + props << PARTICLE_PROP_ANIMATION_URL; + props << PARTICLE_PROP_ANIMATION_FPS; + + props2 << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props2 << PARTICLE_PROP_ANIMATION_PLAYING; + props2 << PARTICLE_PROP_PAUSE_SIMULATION; + + props << props2; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 6: ParticlePropertyFlags comparison"; + ParticlePropertyFlags propsA; + + qDebug() << "!propsA:" << (!propsA) << "{ expect true }"; + + propsA << PARTICLE_PROP_VISIBLE; + propsA << PARTICLE_PROP_ANIMATION_URL; + propsA << PARTICLE_PROP_ANIMATION_FPS; + propsA << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + propsA << PARTICLE_PROP_ANIMATION_PLAYING; + propsA << PARTICLE_PROP_PAUSE_SIMULATION; + + qDebug() << "!propsA:" << (!propsA) << "{ expect false }"; + + ParticlePropertyFlags propsB; + qDebug() << "!propsB:" << (!propsB) << "{ expect true }"; + + + propsB << PARTICLE_PROP_VISIBLE; + propsB << PARTICLE_PROP_ANIMATION_URL; + propsB << PARTICLE_PROP_ANIMATION_FPS; + propsB << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + propsB << PARTICLE_PROP_ANIMATION_PLAYING; + propsB << PARTICLE_PROP_PAUSE_SIMULATION; + + qDebug() << "!propsB:" << (!propsB) << "{ expect false }"; + + qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect true }"; + qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect false }"; + + + qDebug() << "AFTER propsB -= PARTICLE_PROP_PAUSE_SIMULATION..."; + propsB -= PARTICLE_PROP_PAUSE_SIMULATION; + + qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect false }"; + qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect true }"; + + qDebug() << "AFTER propsB = propsA..."; + propsB = propsA; + + qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect true }"; + qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect false }"; + + } + + { + qDebug() << "Test 7: ParticlePropertyFlags testing individual properties"; + ParticlePropertyFlags props; + + qDebug() << "ParticlePropertyFlags props;"; + QByteArray encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect false }"; + + qDebug() << "props << PARTICLE_PROP_VISIBLE;"; + props << PARTICLE_PROP_VISIBLE; + + encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + qDebug() << "props << PARTICLE_PROP_ANIMATION_URL;"; + props << PARTICLE_PROP_ANIMATION_URL; + + encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + qDebug() << "props << ... more ..."; + props << PARTICLE_PROP_ANIMATION_FPS; + props << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props << PARTICLE_PROP_ANIMATION_PLAYING; + props << PARTICLE_PROP_PAUSE_SIMULATION; + + encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + qDebug() << "ParticlePropertyFlags propsB = props & PARTICLE_PROP_VISIBLE;"; + ParticlePropertyFlags propsB = props & PARTICLE_PROP_VISIBLE; + + qDebug() << "propsB.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsB.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + encoded = propsB.encode(); + qDebug() << "propsB... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "ParticlePropertyFlags propsC = ~propsB;"; + ParticlePropertyFlags propsC = ~propsB; + + qDebug() << "propsC.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsC.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect false }"; + + encoded = propsC.encode(); + qDebug() << "propsC... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 8: ParticlePropertyFlags: decode tests"; + ParticlePropertyFlags props; + + props << PARTICLE_PROP_VISIBLE; + props << PARTICLE_PROP_ANIMATION_URL; + props << PARTICLE_PROP_ANIMATION_FPS; + props << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props << PARTICLE_PROP_ANIMATION_PLAYING; + props << PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "encoded.size()=" << encoded.size(); + + ParticlePropertyFlags propsDecoded; + propsDecoded.decode(encoded); + + qDebug() << "propsDecoded == props:" << (propsDecoded == props) << "{ expect true }"; + + QByteArray encodedAfterDecoded = propsDecoded.encode(); + + qDebug() << "encodedAfterDecoded="; + outputBufferBits((const unsigned char*)encodedAfterDecoded.constData(), encodedAfterDecoded.size()); + + qDebug() << "fill encoded byte array with extra garbage (as if it was bitstream with more content)"; + QByteArray extraContent; + extraContent.fill(0xba, 10); + encoded.append(extraContent); + qDebug() << "encoded.size()=" << encoded.size() << "includes extra garbage"; + + ParticlePropertyFlags propsDecodedExtra; + propsDecodedExtra.decode(encoded); + + qDebug() << "propsDecodedExtra == props:" << (propsDecodedExtra == props) << "{ expect true }"; + + QByteArray encodedAfterDecodedExtra = propsDecodedExtra.encode(); + + qDebug() << "encodedAfterDecodedExtra="; + outputBufferBits((const unsigned char*)encodedAfterDecodedExtra.constData(), encodedAfterDecodedExtra.size()); + + } + + qDebug() << "******************************************************************************************"; +} + +void OctreeTests::runAllTests() { + propertyFlagsTests(); +} diff --git a/tests/octree/src/OctreeTests.h b/tests/octree/src/OctreeTests.h new file mode 100644 index 0000000000..53b0d9fb83 --- /dev/null +++ b/tests/octree/src/OctreeTests.h @@ -0,0 +1,22 @@ +// +// OctreeTests.h +// tests/physics/src +// +// Created by Brad Hefta-Gaub on 06/04/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_OctreeTests_h +#define hifi_OctreeTests_h + +namespace OctreeTests { + + void propertyFlagsTests(); + + void runAllTests(); +} + +#endif // hifi_OctreeTests_h diff --git a/tests/octree/src/main.cpp b/tests/octree/src/main.cpp new file mode 100644 index 0000000000..ec3dc19e01 --- /dev/null +++ b/tests/octree/src/main.cpp @@ -0,0 +1,16 @@ +// +// main.cpp +// tests/octree/src +// +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "OctreeTests.h" + +int main(int argc, char** argv) { + OctreeTests::runAllTests(); + return 0; +}