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 }
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 {