Beispiel #1
0
void testPropertyFlags(uint32_t value) {
    EntityPropertyFlags original;
    original.clear();
    auto enumSize = sizeof(EntityPropertyList);
    for (size_t i = 0; i < enumSize * 8; ++i) {
        original.setHasProperty((EntityPropertyList)i);
    }
    QByteArray encoded = original.encode();
    #ifndef QT_NO_DEBUG
    int originalSize = encoded.size();
    #endif
    for (size_t i = 0; i < enumSize; ++i) {
        encoded.append(qrand());
    }

    EntityPropertyFlags decodeOld, decodeNew;
    {
        decodeOld.decode(encoded);
        Q_ASSERT(decodeOld == original);
    }

    {
        #ifndef QT_NO_DEBUG
        int decodeSize = decodeNew.decode((const uint8_t*)encoded.data(), encoded.size());
        #endif
        Q_ASSERT(originalSize == decodeSize);
        Q_ASSERT(decodeNew == original);
    }
}
EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) {
    EntityItemProperties results;
    if (_entityTree) {
        _entityTree->withReadLock([&] {
            EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity));
            if (entity) {
                if (desiredProperties.getHasProperty(PROP_POSITION) ||
                    desiredProperties.getHasProperty(PROP_ROTATION) ||
                    desiredProperties.getHasProperty(PROP_LOCAL_POSITION) ||
                    desiredProperties.getHasProperty(PROP_LOCAL_ROTATION)) {
                    // if we are explicitly getting position or rotation, we need parent information to make sense of them.
                    desiredProperties.setHasProperty(PROP_PARENT_ID);
                    desiredProperties.setHasProperty(PROP_PARENT_JOINT_INDEX);
                }

                if (desiredProperties.isEmpty()) {
                    // these are left out of EntityItem::getEntityProperties so that localPosition and localRotation
                    // don't end up in json saves, etc.  We still want them here, though.
                    EncodeBitstreamParams params; // unknown
                    desiredProperties = entity->getEntityProperties(params);
                    desiredProperties.setHasProperty(PROP_LOCAL_POSITION);
                    desiredProperties.setHasProperty(PROP_LOCAL_ROTATION);
                 }

                results = entity->getProperties(desiredProperties);

                // TODO: improve sitting points and naturalDimensions in the future,
                //       for now we've included the old sitting points model behavior for entity types that are models
                //        we've also added this hack for setting natural dimensions of models
                if (entity->getType() == EntityTypes::Model) {
                    const FBXGeometry* geometry = _entityTree->getGeometryForEntity(entity);
                    if (geometry) {
                        results.setSittingPoints(geometry->sittingPoints);
                        Extents meshExtents = geometry->getUnscaledMeshExtents();
                        results.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum);
                        results.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum);
                    }
                }

            }
        });
    }

    return convertLocationToScriptSemantics(results);
}
Beispiel #3
0
void OctreeTests::propertyFlagsTests() {
    bool verbose = true;
    
    qDebug() << "FIXME: this test is broken and needs to be fixed.";
    qDebug() << "We're disabling this so that ALL_BUILD works";
    return;

    if (verbose) {
        qDebug() << "******************************************************************************************";
    }
    
    qDebug() << "OctreeTests::propertyFlagsTests()";

    {
        if (verbose) {
            qDebug() << "Test 1: EntityProperties: using setHasProperty()";
        }

        EntityPropertyFlags props;
        props.setHasProperty(PROP_VISIBLE);
        props.setHasProperty(PROP_POSITION);
        props.setHasProperty(PROP_RADIUS);
        props.setHasProperty(PROP_MODEL_URL);
        props.setHasProperty(PROP_COMPOUND_SHAPE_URL);
        props.setHasProperty(PROP_ROTATION);
    
        QByteArray encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 13 }));

    }

    {    
        if (verbose) {
            qDebug() << "Test 2: ExamplePropertyFlags: using setHasProperty()";
        }

        EntityPropertyFlags props2;
        props2.setHasProperty(PROP_VISIBLE);
        props2.setHasProperty(PROP_ANIMATION_URL);
        props2.setHasProperty(PROP_ANIMATION_FPS);
        props2.setHasProperty(PROP_ANIMATION_FRAME_INDEX);
        props2.setHasProperty(PROP_ANIMATION_PLAYING);
    
        QByteArray encoded = props2.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 196, 15, 2 }));

        if (verbose) {
            qDebug() << "Test 2b: remove flag with setHasProperty() PROP_PAUSE_SIMULATION";
        }

        encoded = props2.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 136, 30 }));
    }

    {    
        if (verbose) {
            qDebug() << "Test 3: ExamplePropertyFlags: using | operator";
        }
        
        ExamplePropertyFlags props;

        props = ExamplePropertyFlags(EXAMPLE_PROP_VISIBLE) 
                    | ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_URL)
                    | ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FPS)
                    | ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FRAME_INDEX)
                    | ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_PLAYING) 
                    | ExamplePropertyFlags(EXAMPLE_PROP_PAUSE_SIMULATION);
    
        QByteArray encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 196, 15, 2 }));


        if (verbose) {
            qDebug() << "Test 3b: remove flag with -= EXAMPLE_PROP_PAUSE_SIMULATION";
        }
        
        props -= EXAMPLE_PROP_PAUSE_SIMULATION;
    
        encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 136, 30 }));
    }

    {    
        if (verbose) {
            qDebug() << "Test 3c: ExamplePropertyFlags: using |= operator";
        }

        ExamplePropertyFlags props;

        props |= EXAMPLE_PROP_VISIBLE;
        props |= EXAMPLE_PROP_ANIMATION_URL;
        props |= EXAMPLE_PROP_ANIMATION_FPS;
        props |= EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
        props |= EXAMPLE_PROP_ANIMATION_PLAYING;
        props |= EXAMPLE_PROP_PAUSE_SIMULATION;

        QByteArray encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 196, 15, 2 }));
    }

    {    
        if (verbose) {
            qDebug() << "Test 4: ExamplePropertyFlags: using + operator";
        }

        ExamplePropertyFlags props;

        props = ExamplePropertyFlags(EXAMPLE_PROP_VISIBLE) 
                    + ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_URL)
                    + ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FPS)
                    + ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FRAME_INDEX)
                    + ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_PLAYING) 
                    + ExamplePropertyFlags(EXAMPLE_PROP_PAUSE_SIMULATION);
    
        QByteArray encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 196, 15, 2 }));
    }

    {    
        if (verbose) {
            qDebug() << "Test 5: ExamplePropertyFlags: using += operator";
        }
        ExamplePropertyFlags props;

        props += EXAMPLE_PROP_VISIBLE;
        props += EXAMPLE_PROP_ANIMATION_URL;
        props += EXAMPLE_PROP_ANIMATION_FPS;
        props += EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
        props += EXAMPLE_PROP_ANIMATION_PLAYING;
        props += EXAMPLE_PROP_PAUSE_SIMULATION;
    
        QByteArray encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 196, 15, 2 }));
    }

    {    
        if (verbose) {
            qDebug() << "Test 6: ExamplePropertyFlags: using = ... << operator";
        }
        
        ExamplePropertyFlags props;

        props = ExamplePropertyFlags(EXAMPLE_PROP_VISIBLE) 
                    << ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_URL)
                    << ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FPS)
                    << ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FRAME_INDEX)
                    << ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_PLAYING) 
                    << ExamplePropertyFlags(EXAMPLE_PROP_PAUSE_SIMULATION);
    
        QByteArray encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 196, 15, 2 }));
    }

    {
        if (verbose) {
            qDebug() << "Test 7: ExamplePropertyFlags: using <<= operator";
        }
        
        ExamplePropertyFlags props;

        props <<= EXAMPLE_PROP_VISIBLE;
        props <<= EXAMPLE_PROP_ANIMATION_URL;
        props <<= EXAMPLE_PROP_ANIMATION_FPS;
        props <<= EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
        props <<= EXAMPLE_PROP_ANIMATION_PLAYING;
        props <<= EXAMPLE_PROP_PAUSE_SIMULATION;
    
        QByteArray encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 196, 15, 2 }));
    }

    {
        if (verbose) {
            qDebug() << "Test 8: ExamplePropertyFlags: using << enum operator";
        }
        
        ExamplePropertyFlags props;

        props << EXAMPLE_PROP_VISIBLE;
        props << EXAMPLE_PROP_ANIMATION_URL;
        props << EXAMPLE_PROP_ANIMATION_FPS;
        props << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
        props << EXAMPLE_PROP_ANIMATION_PLAYING;
        props << EXAMPLE_PROP_PAUSE_SIMULATION;

        QByteArray encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 196, 15, 2 }));
    }

    {
        if (verbose) {
            qDebug() << "Test 9: ExamplePropertyFlags: using << flags operator ";
        }

        ExamplePropertyFlags props;
        ExamplePropertyFlags props2;

        props << EXAMPLE_PROP_VISIBLE;
        props << EXAMPLE_PROP_ANIMATION_URL;
        props << EXAMPLE_PROP_ANIMATION_FPS;

        props2 << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
        props2 << EXAMPLE_PROP_ANIMATION_PLAYING;
        props2 << EXAMPLE_PROP_PAUSE_SIMULATION;

        props << props2;

        QByteArray encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 196, 15, 2 }));
    }
  
    {
        if (verbose) {
            qDebug() << "Test 10: ExamplePropertyFlags comparison";
        }
        ExamplePropertyFlags propsA;

        if (verbose) {
            qDebug() << "!propsA:" << (!propsA) << "{ expect true }";
        }
        QCOMPARE(!propsA, true);

        propsA << EXAMPLE_PROP_VISIBLE;
        propsA << EXAMPLE_PROP_ANIMATION_URL;
        propsA << EXAMPLE_PROP_ANIMATION_FPS;
        propsA << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
        propsA << EXAMPLE_PROP_ANIMATION_PLAYING;
        propsA << EXAMPLE_PROP_PAUSE_SIMULATION;

        QCOMPARE(!propsA, false);

        ExamplePropertyFlags propsB;
        propsB << EXAMPLE_PROP_VISIBLE;
        propsB << EXAMPLE_PROP_ANIMATION_URL;
        propsB << EXAMPLE_PROP_ANIMATION_FPS;
        propsB << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
        propsB << EXAMPLE_PROP_ANIMATION_PLAYING;
        propsB << EXAMPLE_PROP_PAUSE_SIMULATION;

        if (verbose) {
            qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect true }";
            qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect false }";
        }
        QCOMPARE(propsA == propsB, true);
        QCOMPARE(propsA != propsB, false);
        
        if (verbose) {
            qDebug() << "AFTER propsB -= EXAMPLE_PROP_PAUSE_SIMULATION...";
        }
        
        propsB -= EXAMPLE_PROP_PAUSE_SIMULATION;

        QCOMPARE(propsA == propsB, false);
        if (verbose) {
            qDebug() << "AFTER propsB = propsA...";
        }
        propsB = propsA;
        QCOMPARE(propsA == propsB, true);
    }

    {
        if (verbose) {
            qDebug() << "Test 11: ExamplePropertyFlags testing individual properties";
        }
        ExamplePropertyFlags props;

        if (verbose) {
            qDebug() << "ExamplePropertyFlags props;";
        }
        
        QByteArray encoded = props.encode();

        if (verbose) {
            qDebug() << "Test 11b: props.getHasProperty(EXAMPLE_PROP_VISIBLE)" << (props.getHasProperty(EXAMPLE_PROP_VISIBLE)) 
                        << "{ expect false }";
        }
        QCOMPARE(props.getHasProperty(EXAMPLE_PROP_VISIBLE), false);

        if (verbose) {
            qDebug() << "props << EXAMPLE_PROP_VISIBLE;";
        }
        props << EXAMPLE_PROP_VISIBLE;
        QCOMPARE(props.getHasProperty(EXAMPLE_PROP_VISIBLE), true);

        encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 16 }));
        if (verbose) {
            qDebug() << "props << EXAMPLE_PROP_ANIMATION_URL;";
        }
        props << EXAMPLE_PROP_ANIMATION_URL;
    
        encoded = props.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 136, 16}));
        QCOMPARE(props.getHasProperty(EXAMPLE_PROP_VISIBLE), true);

        if (verbose) {
            qDebug() << "props << ... more ...";
        }
        props << EXAMPLE_PROP_ANIMATION_FPS;
        props << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
        props << EXAMPLE_PROP_ANIMATION_PLAYING;
        props << EXAMPLE_PROP_PAUSE_SIMULATION;

        encoded = props.encode();
        QCOMPARE(props.getHasProperty(EXAMPLE_PROP_VISIBLE), true);

        if (verbose) {
            qDebug() << "ExamplePropertyFlags propsB = props & EXAMPLE_PROP_VISIBLE;";
        }
        ExamplePropertyFlags propsB = props & EXAMPLE_PROP_VISIBLE;

        QCOMPARE(propsB.getHasProperty(EXAMPLE_PROP_VISIBLE), true);

        encoded = propsB.encode();
        QCOMPARE(encoded, makeQByteArray({ (char) 16 }));

        if (verbose) {
            qDebug() << "ExamplePropertyFlags propsC = ~propsB;";
        }
        ExamplePropertyFlags propsC = ~propsB;
        
        QCOMPARE(propsC.getHasProperty(EXAMPLE_PROP_VISIBLE), false);

        encoded = propsC.encode();
        if (verbose) {
            qDebug() << "propsC... encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }
    }
    
    {
        if (verbose) {
            qDebug() << "Test 12: ExamplePropertyFlags: decode tests";
        }
        ExamplePropertyFlags props;

        props << EXAMPLE_PROP_VISIBLE;
        props << EXAMPLE_PROP_ANIMATION_URL;
        props << EXAMPLE_PROP_ANIMATION_FPS;
        props << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
        props << EXAMPLE_PROP_ANIMATION_PLAYING;
        props << EXAMPLE_PROP_PAUSE_SIMULATION;

        QByteArray encoded = props.encode();
        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
            qDebug() << "encoded.size()=" << encoded.size();
        }

        ExamplePropertyFlags propsDecoded;
        propsDecoded.decode(encoded);
        
        QCOMPARE(propsDecoded, props);

        QByteArray encodedAfterDecoded = propsDecoded.encode();

        QCOMPARE(encoded, encodedAfterDecoded);

        if (verbose) {
            qDebug() << "fill encoded byte array with extra garbage (as if it was bitstream with more content)";
        }
        QByteArray extraContent;
        extraContent.fill(0xbaU, 10);
        encoded.append(extraContent);

        if (verbose) {
            qDebug() << "encoded.size()=" << encoded.size() << "includes extra garbage";
        }

        ExamplePropertyFlags propsDecodedExtra;
        propsDecodedExtra.decode(encoded);
        
        QCOMPARE(propsDecodedExtra, props);

        QByteArray encodedAfterDecodedExtra = propsDecodedExtra.encode();

        if (verbose) {
            qDebug() << "encodedAfterDecodedExtra=";
            outputBufferBits((const unsigned char*)encodedAfterDecodedExtra.constData(), encodedAfterDecodedExtra.size());
        }
    }
    
    {
        if (verbose) {
            qDebug() << "Test 13: ExamplePropertyFlags: QByteArray << / >> tests";
        }
        ExamplePropertyFlags props;

        props << EXAMPLE_PROP_VISIBLE;
        props << EXAMPLE_PROP_ANIMATION_URL;
        props << EXAMPLE_PROP_ANIMATION_FPS;
        props << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
        props << EXAMPLE_PROP_ANIMATION_PLAYING;
        props << EXAMPLE_PROP_PAUSE_SIMULATION;

        if (verbose) {
            qDebug() << "testing encoded << props";
        }
        QByteArray encoded;
        encoded << props;

        if (verbose) {
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        ExamplePropertyFlags propsDecoded;
        if (verbose) {
            qDebug() << "testing encoded >> propsDecoded";
        }
        encoded >> propsDecoded;
        
        
        QCOMPARE(propsDecoded, props);
    }

    if (verbose) {
        qDebug() << "******************************************************************************************";
    }
}
Beispiel #4
0
void OctreeTests::propertyFlagsTests(bool verbose) {
    int testsTaken = 0;
    int testsPassed = 0;
    int testsFailed = 0;

    if (verbose) {
        qDebug() << "******************************************************************************************";
    }
    
    qDebug() << "OctreeTests::propertyFlagsTests()";

    {
        if (verbose) {
            qDebug() << "Test 1: EntityProperties: using setHasProperty()";
        }
        testsTaken++;

        EntityPropertyFlags 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();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }
        
        char expectedBytes[] = { 31 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 1: EntityProperties: using setHasProperty()";
        }

    }

    {    
        if (verbose) {
            qDebug() << "Test 2: ParticlePropertyFlags: using setHasProperty()";
        }
        testsTaken++;

        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();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        char expectedBytes[] = { (char)196, (char)15, (char)2 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 2: ParticlePropertyFlags: using setHasProperty()";
        }

        
        if (verbose) {
            qDebug() << "Test 2b: remove flag with setHasProperty() PARTICLE_PROP_PAUSE_SIMULATION";
        }
        testsTaken++;

        props2.setHasProperty(PARTICLE_PROP_PAUSE_SIMULATION, false);
    
        encoded = props2.encode();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        char expectedBytesB[] = { (char)136, (char)30 };
        QByteArray expectedResultB(expectedBytesB, sizeof(expectedBytesB)/sizeof(expectedBytesB[0]));
        
        if (encoded == expectedResultB) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 2b: remove flag with setHasProperty() PARTICLE_PROP_PAUSE_SIMULATION";
        }
    }

    {    
        if (verbose) {
            qDebug() << "Test 3: ParticlePropertyFlags: using | operator";
        }
        testsTaken++;
        
        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();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }
        char expectedBytes[] = { (char)196, (char)15, (char)2 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 3: ParticlePropertyFlags: using | operator";
        }


        if (verbose) {
            qDebug() << "Test 3b: remove flag with -= PARTICLE_PROP_PAUSE_SIMULATION";
        }
        testsTaken++;
        
        props -= PARTICLE_PROP_PAUSE_SIMULATION;
    
        encoded = props.encode();
    
        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }
        
        char expectedBytesB[] = { (char)136, (char)30 };
        QByteArray expectedResultB(expectedBytesB, sizeof(expectedBytesB)/sizeof(expectedBytesB[0]));
        
        if (encoded == expectedResultB) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 3b: remove flag with -= PARTICLE_PROP_PAUSE_SIMULATION";
        }
        
    }

    {    
        if (verbose) {
            qDebug() << "Test 3c: ParticlePropertyFlags: using |= operator";
        }
        testsTaken++;

        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();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        char expectedBytes[] = { (char)196, (char)15, (char)2 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - 3c: ParticlePropertyFlags: using |= operator";
        }
    }

    {    
        if (verbose) {
            qDebug() << "Test 4: ParticlePropertyFlags: using + operator";
        }
        testsTaken++;

        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();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        char expectedBytes[] = { (char)196, (char)15, (char)2 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 4: ParticlePropertyFlags: using + operator";
        }
    }

    {    
        if (verbose) {
            qDebug() << "Test 5: ParticlePropertyFlags: using += operator";
        }
        testsTaken++;
        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();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        char expectedBytes[] = { (char)196, (char)15, (char)2 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 5: ParticlePropertyFlags: using += operator";
        }
    }

    {    
        if (verbose) {
            qDebug() << "Test 6: ParticlePropertyFlags: using = ... << operator";
        }
        testsTaken++;
        
        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();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        char expectedBytes[] = { (char)196, (char)15, (char)2 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 6: ParticlePropertyFlags: using = ... << operator";
        }
    }

    {
        if (verbose) {
            qDebug() << "Test 7: ParticlePropertyFlags: using <<= operator";
        }
        testsTaken++;
        
        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();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        char expectedBytes[] = { (char)196, (char)15, (char)2 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 7: ParticlePropertyFlags: using <<= operator";
        }
    }

    {
        if (verbose) {
            qDebug() << "Test 8: ParticlePropertyFlags: using << enum operator";
        }
        testsTaken++;
        
        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();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        char expectedBytes[] = { (char)196, (char)15, (char)2 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 8: ParticlePropertyFlags: using << enum operator";
        }
    }

    {
        if (verbose) {
            qDebug() << "Test 9: ParticlePropertyFlags: using << flags operator ";
        }
        testsTaken++;

        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();

        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        char expectedBytes[] = { (char)196, (char)15, (char)2 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 9: ParticlePropertyFlags: using << flags operator";
        }
    }
  
    {
        if (verbose) {
            qDebug() << "Test 10: ParticlePropertyFlags comparison";
        }
        ParticlePropertyFlags propsA;

        if (verbose) {
            qDebug() << "!propsA:" << (!propsA) << "{ expect true }";
        }
        testsTaken++;
        bool resultA = (!propsA);
        bool expectedA = true;
        if (resultA == expectedA) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 10a: ParticlePropertyFlags comparison, uninitialized !propsA";
        }

        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;

        if (verbose) {
            qDebug() << "!propsA:" << (!propsA) << "{ expect false }";
        }
        testsTaken++;
        bool resultB = (!propsA);
        bool expectedB = false;
        if (resultB == expectedB) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 10b: ParticlePropertyFlags comparison, initialized !propsA";
        }

        ParticlePropertyFlags propsB;
        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;

        if (verbose) {
            qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect true }";
            qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect false }";
        }
        testsTaken++;
        bool resultC = (propsA == propsB);
        bool expectedC = true;
        if (resultC == expectedC) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 10c: ParticlePropertyFlags comparison, propsA == propsB";
        }

        testsTaken++;
        bool resultD = (propsA != propsB);
        bool expectedD = false;
        if (resultD == expectedD) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 10d: ParticlePropertyFlags comparison, propsA != propsB";
        }
        
        if (verbose) {
            qDebug() << "AFTER propsB -= PARTICLE_PROP_PAUSE_SIMULATION...";
        }
        
        propsB -= PARTICLE_PROP_PAUSE_SIMULATION;

        if (verbose) {
            qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect false }";
            qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect true }";
        }
        testsTaken++;
        bool resultE = (propsA == propsB);
        bool expectedE = false;
        if (resultE == expectedE) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 10e: ParticlePropertyFlags comparison, AFTER propsB -= PARTICLE_PROP_PAUSE_SIMULATION";
        }
        
        if (verbose) {
            qDebug() << "AFTER propsB = propsA...";
        }
        propsB = propsA;
        if (verbose) {
            qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect true }";
            qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect false }";
        }
        testsTaken++;
        bool resultF = (propsA == propsB);
        bool expectedF = true;
        if (resultF == expectedF) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 10f: ParticlePropertyFlags comparison, AFTER propsB = propsA";
        }
    }

    {
        if (verbose) {
            qDebug() << "Test 11: ParticlePropertyFlags testing individual properties";
        }
        ParticlePropertyFlags props;

        if (verbose) {
            qDebug() << "ParticlePropertyFlags props;";
        }
        
        QByteArray encoded = props.encode();

        if (verbose) {
            qDebug() << "props... encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        char expectedBytes[] = { 0 };
        QByteArray expectedResult(expectedBytes, sizeof(expectedBytes)/sizeof(expectedBytes[0]));
        
        testsTaken++;
        if (encoded == expectedResult) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 11a: ParticlePropertyFlags testing individual properties";
        }


        if (verbose) {
            qDebug() << "Test 11b: props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) 
                        << "{ expect false }";
        }
        testsTaken++;
        bool resultB = props.getHasProperty(PARTICLE_PROP_VISIBLE);
        bool expectedB = false;
        if (resultB == expectedB) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 11b: props.getHasProperty(PARTICLE_PROP_VISIBLE)";
        }

        if (verbose) {
            qDebug() << "props << PARTICLE_PROP_VISIBLE;";
        }
        props << PARTICLE_PROP_VISIBLE;
        testsTaken++;
        bool resultC = props.getHasProperty(PARTICLE_PROP_VISIBLE);
        bool expectedC = true;
        if (resultC == expectedC) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 11c: props.getHasProperty(PARTICLE_PROP_VISIBLE) after props << PARTICLE_PROP_VISIBLE";
        }

        encoded = props.encode();

        if (verbose) {
            qDebug() << "props... encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
            qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) 
                            << "{ expect true }";
        }

        char expectedBytesC[] = { 16 };
        QByteArray expectedResultC(expectedBytesC, sizeof(expectedBytesC)/sizeof(expectedBytesC[0]));
        
        testsTaken++;
        if (encoded == expectedResultC) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 11c: ParticlePropertyFlags testing individual properties";
        }

        if (verbose) {
            qDebug() << "props << PARTICLE_PROP_ANIMATION_URL;";
        }
        props << PARTICLE_PROP_ANIMATION_URL;

        encoded = props.encode();
        if (verbose) {
            qDebug() << "props... encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
            qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) 
                            << "{ expect true }";
        }
        char expectedBytesD[] = { (char)136, (char)16 };
        QByteArray expectedResultD(expectedBytesD, sizeof(expectedBytesD)/sizeof(expectedBytesD[0]));
        
        testsTaken++;
        if (encoded == expectedResultD) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 11d: ParticlePropertyFlags testing individual properties";
        }
        testsTaken++;
        bool resultE = props.getHasProperty(PARTICLE_PROP_VISIBLE);
        bool expectedE = true;
        if (resultE == expectedE) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 11e: props.getHasProperty(PARTICLE_PROP_VISIBLE) after props << PARTICLE_PROP_ANIMATION_URL";
        }


        if (verbose) {
            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();
        if (verbose) {
            qDebug() << "props... encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
            qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) 
                            << "{ expect true }";
        }
        testsTaken++;
        bool resultF = props.getHasProperty(PARTICLE_PROP_VISIBLE);
        bool expectedF = true;
        if (resultF == expectedF) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 11f: props.getHasProperty(PARTICLE_PROP_VISIBLE) after props << more";
        }

        if (verbose) {
            qDebug() << "ParticlePropertyFlags propsB = props & PARTICLE_PROP_VISIBLE;";
        }
        ParticlePropertyFlags propsB = props & PARTICLE_PROP_VISIBLE;

        if (verbose) {
            qDebug() << "propsB.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsB.getHasProperty(PARTICLE_PROP_VISIBLE)) 
                        << "{ expect true }";
        }
        testsTaken++;
        bool resultG = propsB.getHasProperty(PARTICLE_PROP_VISIBLE);
        bool expectedG = true;
        if (resultG == expectedG) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 11g: propsB = props & PARTICLE_PROP_VISIBLE";
        }

        encoded = propsB.encode();
        if (verbose) {
            qDebug() << "propsB... encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }
        char expectedBytesH[] = { 16 };
        QByteArray expectedResultH(expectedBytesC, sizeof(expectedBytesH)/sizeof(expectedBytesH[0]));
        
        testsTaken++;
        if (encoded == expectedResultH) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 11h: ParticlePropertyFlags testing individual properties";
        }

        if (verbose) {
            qDebug() << "ParticlePropertyFlags propsC = ~propsB;";
        }
        ParticlePropertyFlags propsC = ~propsB;
        
        if (verbose) {
            qDebug() << "propsC.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsC.getHasProperty(PARTICLE_PROP_VISIBLE))
                        << "{ expect false }";
        }
        testsTaken++;
        bool resultI = propsC.getHasProperty(PARTICLE_PROP_VISIBLE);
        bool expectedI = false;
        if (resultI == expectedI) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 11i: propsC = ~propsB";
        }

        encoded = propsC.encode();
        if (verbose) {
            qDebug() << "propsC... encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }
    }
    
    {
        if (verbose) {
            qDebug() << "Test 12: 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();
        if (verbose) {
            qDebug() << "encoded=";
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
            qDebug() << "encoded.size()=" << encoded.size();
        }

        ParticlePropertyFlags propsDecoded;
        propsDecoded.decode(encoded);
        
        if (verbose) {
            qDebug() << "propsDecoded == props:" << (propsDecoded == props) << "{ expect true }";
        }
        testsTaken++;
        bool resultA = (propsDecoded == props);
        bool expectedA = true;
        if (resultA == expectedA) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 12a: propsDecoded == props";
        }

        QByteArray encodedAfterDecoded = propsDecoded.encode();

        if (verbose) {
            qDebug() << "encodedAfterDecoded=";
            outputBufferBits((const unsigned char*)encodedAfterDecoded.constData(), encodedAfterDecoded.size());
        }
        testsTaken++;
        bool resultB = (encoded == encodedAfterDecoded);
        bool expectedB = true;
        if (resultB == expectedB) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 12b: (encoded == encodedAfterDecoded)";
        }

        if (verbose) {
            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);

        if (verbose) {
            qDebug() << "encoded.size()=" << encoded.size() << "includes extra garbage";
        }

        ParticlePropertyFlags propsDecodedExtra;
        propsDecodedExtra.decode(encoded);
        
        if (verbose) {
            qDebug() << "propsDecodedExtra == props:" << (propsDecodedExtra == props) << "{ expect true }";
        }
        testsTaken++;
        bool resultC = (propsDecodedExtra == props);
        bool expectedC = true;
        if (resultC == expectedC) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 12c: (propsDecodedExtra == props)";
        }

        QByteArray encodedAfterDecodedExtra = propsDecodedExtra.encode();

        if (verbose) {
            qDebug() << "encodedAfterDecodedExtra=";
            outputBufferBits((const unsigned char*)encodedAfterDecodedExtra.constData(), encodedAfterDecodedExtra.size());
        }
    }
    
    {
        if (verbose) {
            qDebug() << "Test 13: ParticlePropertyFlags: QByteArray << / >> 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;

        if (verbose) {
            qDebug() << "testing encoded << props";
        }
        QByteArray encoded;
        encoded << props;

        if (verbose) {
            outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
        }

        ParticlePropertyFlags propsDecoded;
        if (verbose) {
            qDebug() << "testing encoded >> propsDecoded";
        }
        encoded >> propsDecoded;

        if (verbose) {
            qDebug() << "propsDecoded==props" << (propsDecoded==props);
        }

        testsTaken++;
        bool resultA = (propsDecoded == props);
        bool expectedA = true;
        if (resultA == expectedA) {
            testsPassed++;
        } else {
            testsFailed++;
            qDebug() << "FAILED - Test 13: ParticlePropertyFlags: QByteArray << / >> tests";
        }
    }

    qDebug() << "   tests passed:" << testsPassed << "out of" << testsTaken;
    if (verbose) {
        qDebug() << "******************************************************************************************";
    }
}