Beispiel #1
0
void OctreeTests::modelItemTests() {
#if 0 // TODO - repair/replace these
    bool verbose = true;

    //verbose = true;
    EntityTreeElementExtraEncodeData modelTreeElementExtraEncodeData;
    int testsTaken = 0;
    int testsPassed = 0;
    int testsFailed = 0;

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

    EncodeBitstreamParams params;
    OctreePacketData packetData;
    EntityItem entityItem;
    
    entityItem.setID(1042);
    entityItem.setModelURL("http://foo.com/foo.fbx");

    bool appendResult = entityItem.appendEntityData(&packetData, params, &modelTreeElementExtraEncodeData);
    int bytesWritten = packetData.getUncompressedSize();
    if (verbose) {
        qDebug() << "Test 1: bytesRead == bytesWritten ...";
        qDebug() << "appendResult=" << appendResult;
        qDebug() << "bytesWritten=" << bytesWritten;
    }

    {
        ReadBitstreamToTreeParams args;
        EntityItem modelItemFromBuffer;
        const unsigned char* data = packetData.getUncompressedData();
        int bytesLeftToRead = packetData.getUncompressedSize();
    
        int bytesRead =  modelItemFromBuffer.readEntityDataFromBuffer(data, bytesLeftToRead, args);
        if (verbose) {
            qDebug() << "bytesRead=" << bytesRead;
            qDebug() << "modelItemFromBuffer.getID()=" << modelItemFromBuffer.getID();
            qDebug() << "modelItemFromBuffer.getModelURL()=" << modelItemFromBuffer.getModelURL();
        }

        QCOMPARE(bytesRead, bytesWritten);

        if (verbose) {
            qDebug() << "Test 2: modelItemFromBuffer.getModelURL() == 'http://foo.com/foo.fbx'";
        }
    
        QCOMPARE(modelItemFromBuffer.getModelURL(), "http://foo.com/foo.fbx");
    }
    
    // TEST 3:
    // Reset the packet, fill it with data so that EntityItem header won't fit, and verify that we don't let it fit
    {
        packetData.reset();
        int remainingSpace = 10;
        int almostFullOfData = MAX_OCTREE_UNCOMRESSED_PACKET_SIZE - remainingSpace;
        QByteArray garbageData(almostFullOfData, 0);
        packetData.appendValue(garbageData);

        appendResult = entityItem.appendEntityData(&packetData, params, &modelTreeElementExtraEncodeData);
        bytesWritten = packetData.getUncompressedSize() - almostFullOfData;
        if (verbose) {
            qDebug() << "Test 3: attempt to appendEntityData in nearly full packetData ...";
            qDebug() << "appendResult=" << appendResult;
            qDebug() << "bytesWritten=" << bytesWritten;
        }
        QCOMPARE(appendResult, false);
        QCOMPARE(bytesWritten, 0);
    }
    
    // TEST 4:
    // Reset the packet, fill it with data so that some of EntityItem won't fit, and verify that we write what can fit
    {
        packetData.reset();
        int remainingSpace = 50;
        int almostFullOfData = MAX_OCTREE_UNCOMRESSED_PACKET_SIZE - remainingSpace;
        QByteArray garbageData(almostFullOfData, 0);
        packetData.appendValue(garbageData);

        appendResult = entityItem.appendEntityData(&packetData, params, &modelTreeElementExtraEncodeData);
        bytesWritten = packetData.getUncompressedSize() - almostFullOfData;
        if (verbose) {
            qDebug() << "Test 4: attempt to appendEntityData in nearly full packetData which some should fit ...";
            qDebug() << "appendResult=" << appendResult;
            qDebug() << "bytesWritten=" << bytesWritten;
        }
        
        QCOMPARE(appendResult, true);

        ReadBitstreamToTreeParams args;
        EntityItem modelItemFromBuffer;
        const unsigned char* data = packetData.getUncompressedData() + almostFullOfData;
        int bytesLeftToRead = packetData.getUncompressedSize() - almostFullOfData;
    
        int bytesRead =  modelItemFromBuffer.readEntityDataFromBuffer(data, bytesLeftToRead, args);
        if (verbose) {
            qDebug() << "Test 5: partial EntityItem written ... bytesRead == bytesWritten...";
            qDebug() << "bytesRead=" << bytesRead;
            qDebug() << "modelItemFromBuffer.getID()=" << modelItemFromBuffer.getID();
            qDebug() << "modelItemFromBuffer.getModelURL()=" << modelItemFromBuffer.getModelURL();
        }

        QCOMPARE(bytesRead, bytesWritten);

        if (verbose) {
            qDebug() << "Test 6: partial EntityItem written ... getModelURL() NOT SET ...";
        }
    
        QCOMPARE(modelItemFromBuffer.getModelURL(), "");
    }
    
    if (verbose) {
        qDebug() << "******************************************************************************************";
    }
    
    QCOMPARE(testsPassed, testsTaken);
    if (verbose) {
        qDebug() << "******************************************************************************************";
    }
    
#endif 
}
Beispiel #2
0
OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData* packetData, 
                                                                    EncodeBitstreamParams& params) const {

    OctreeElement::AppendState appendElementState = OctreeElement::COMPLETED; // assume the best...
    
    // first, check the params.extraEncodeData to see if there's any partial re-encode data for this element
    OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData;
    EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData = NULL;
    bool hadElementExtraData = false;
    if (extraEncodeData && extraEncodeData->contains(this)) {
        entityTreeElementExtraEncodeData = static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
        hadElementExtraData = true;
    } else {
        // if there wasn't one already, then create one
        entityTreeElementExtraEncodeData = new EntityTreeElementExtraEncodeData();
        entityTreeElementExtraEncodeData->elementCompleted = (_entityItems->size() == 0);

        for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
            EntityTreeElement* child = getChildAtIndex(i);
            if (!child) {
                entityTreeElementExtraEncodeData->childCompleted[i] = true; // if no child exists, it is completed
            } else {
                if (child->hasEntities()) {
                    entityTreeElementExtraEncodeData->childCompleted[i] = false;
                } else {
                    entityTreeElementExtraEncodeData->childCompleted[i] = true; // if the child doesn't have enities, it is completed
                }
            }
        }
        for (uint16_t i = 0; i < _entityItems->size(); i++) {
            EntityItem* entity = (*_entityItems)[i];
            entityTreeElementExtraEncodeData->entities.insert(entity->getEntityItemID(), entity->getEntityProperties(params));
        }
    }

    //assert(extraEncodeData);
    //assert(extraEncodeData->contains(this));
    //entityTreeElementExtraEncodeData = static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));

    LevelDetails elementLevel = packetData->startLevel();

    // write our entities out... first determine which of the entities are in view based on our params
    uint16_t numberOfEntities = 0;
    uint16_t actualNumberOfEntities = 0;
    QVector<uint16_t> indexesOfEntitiesToInclude;

    // It's possible that our element has been previous completed. In this case we'll simply not include any of our
    // entities for encoding. This is needed because we encode the element data at the "parent" level, and so we 
    // need to handle the case where our sibling elements need encoding but we don't.
    if (!entityTreeElementExtraEncodeData->elementCompleted) {
        for (uint16_t i = 0; i < _entityItems->size(); i++) {
            EntityItem* entity = (*_entityItems)[i];
            bool includeThisEntity = true;
            
            if (!params.forceSendScene && entity->getLastChangedOnServer() < params.lastViewFrustumSent) {
                includeThisEntity = false;
            }
        
            if (hadElementExtraData) {
                includeThisEntity = includeThisEntity && 
                                        entityTreeElementExtraEncodeData->entities.contains(entity->getEntityItemID());
            }
        
            if (includeThisEntity && params.viewFrustum) {
            
                // we want to use the maximum possible box for this, so that we don't have to worry about the nuance of
                // simulation changing what's visible. consider the case where the entity contains an angular velocity
                // the entity may not be in view and then in view a frame later, let the client side handle it's view
                // frustum culling on rendering.
                AACube entityCube = entity->getMaximumAACube();
                entityCube.scale(TREE_SCALE);
                if (params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) {
                    includeThisEntity = false; // out of view, don't include it
                }
            }
        
            if (includeThisEntity) {
                indexesOfEntitiesToInclude << i;
                numberOfEntities++;
            }
        }
    }

    int numberOfEntitiesOffset = packetData->getUncompressedByteOffset();
    bool successAppendEntityCount = packetData->appendValue(numberOfEntities);

    if (successAppendEntityCount) {
        foreach (uint16_t i, indexesOfEntitiesToInclude) {
            EntityItem* entity = (*_entityItems)[i];
            LevelDetails entityLevel = packetData->startLevel();
            OctreeElement::AppendState appendEntityState = entity->appendEntityData(packetData, 
                                                                        params, entityTreeElementExtraEncodeData);

            // If none of this entity data was able to be appended, then discard it
            // and don't include it in our entity count
            if (appendEntityState == OctreeElement::NONE) {
                packetData->discardLevel(entityLevel);
            } else {
                // If either ALL or some of it got appended, then end the level (commit it)
                // and include the entity in our final count of entities
                packetData->endLevel(entityLevel);
                actualNumberOfEntities++;
            }
            
            // If the entity item got completely appended, then we can remove it from the extra encode data
            if (appendEntityState == OctreeElement::COMPLETED) {
                entityTreeElementExtraEncodeData->entities.remove(entity->getEntityItemID());
            }

            // If any part of the entity items didn't fit, then the element is considered partial
            // NOTE: if the entity item didn't fit or only partially fit, then the entity item should have
            // added itself to the extra encode data.
            if (appendEntityState != OctreeElement::COMPLETED) {
                appendElementState = OctreeElement::PARTIAL;
            }
        }
    } else {