コード例 #1
0
ファイル: VoxelTreeCommands.cpp プロジェクト: Adrianl3d/hifi
bool sendVoxelsOperation(OctreeElement* element, void* extraData) {
    VoxelTreeElement* voxel = static_cast<VoxelTreeElement*>(element);
    SendVoxelsOperationArgs* args = static_cast<SendVoxelsOperationArgs*>(extraData);
    if (voxel->isColored()) {
        const unsigned char* nodeOctalCode = voxel->getOctalCode();
        unsigned char* codeColorBuffer = NULL;
        int codeLength  = 0;
        int bytesInCode = 0;
        int codeAndColorLength;
        
        // If the newBase is NULL, then don't rebase
        if (args->newBaseOctCode) {
            codeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true);
            codeLength  = numberOfThreeBitSectionsInCode(codeColorBuffer);
            bytesInCode = bytesRequiredForCodeLength(codeLength);
            codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA;
        } else {
            codeLength  = numberOfThreeBitSectionsInCode(nodeOctalCode);
            bytesInCode = bytesRequiredForCodeLength(codeLength);
            codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA;
            codeColorBuffer = new unsigned char[codeAndColorLength];
            memcpy(codeColorBuffer, nodeOctalCode, bytesInCode);
        }
        
        // copy the colors over
        codeColorBuffer[bytesInCode + RED_INDEX] = voxel->getColor()[RED_INDEX];
        codeColorBuffer[bytesInCode + GREEN_INDEX] = voxel->getColor()[GREEN_INDEX];
        codeColorBuffer[bytesInCode + BLUE_INDEX] = voxel->getColor()[BLUE_INDEX];
        args->packetSender->queueVoxelEditMessage(PacketTypeVoxelSetDestructive,
                                                  codeColorBuffer, codeAndColorLength);
        
        delete[] codeColorBuffer;
    }
    return true; // keep going
}
コード例 #2
0
ファイル: OctreeSceneStats.cpp プロジェクト: CryptArc/hifi
int OctreeSceneStats::packIntoPacket() {
    _statsPacket->reset();

    _statsPacket->writePrimitive(_start);
    _statsPacket->writePrimitive(_end);
    _statsPacket->writePrimitive(_elapsed);
    _statsPacket->writePrimitive(_totalEncodeTime);
    _statsPacket->writePrimitive(_isFullScene);
    _statsPacket->writePrimitive(_isMoving);
    _statsPacket->writePrimitive(_packets);
    _statsPacket->writePrimitive(_bytes);

    _statsPacket->writePrimitive(_totalInternal);
    _statsPacket->writePrimitive(_totalLeaves);
    _statsPacket->writePrimitive(_internal);
    _statsPacket->writePrimitive(_leaves);
    _statsPacket->writePrimitive(_internalSkippedDistance);
    _statsPacket->writePrimitive(_leavesSkippedDistance);
    _statsPacket->writePrimitive(_internalSkippedOutOfView);
    _statsPacket->writePrimitive(_leavesSkippedOutOfView);
    _statsPacket->writePrimitive(_internalSkippedWasInView);
    _statsPacket->writePrimitive(_leavesSkippedWasInView);
    _statsPacket->writePrimitive(_internalSkippedNoChange);
    _statsPacket->writePrimitive(_leavesSkippedNoChange);
    _statsPacket->writePrimitive(_internalSkippedOccluded);
    _statsPacket->writePrimitive(_leavesSkippedOccluded);
    _statsPacket->writePrimitive(_internalColorSent);
    _statsPacket->writePrimitive(_leavesColorSent);
    _statsPacket->writePrimitive(_internalDidntFit);
    _statsPacket->writePrimitive(_leavesDidntFit);
    _statsPacket->writePrimitive(_colorBitsWritten);
    _statsPacket->writePrimitive(_existsBitsWritten);
    _statsPacket->writePrimitive(_existsInPacketBitsWritten);
    _statsPacket->writePrimitive(_treesRemoved);

    // add the root jurisdiction
    if (_jurisdictionRoot) {
        // copy the
        int bytes = (int)bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_jurisdictionRoot));
        _statsPacket->writePrimitive(bytes);
        _statsPacket->write(reinterpret_cast<char*>(_jurisdictionRoot), bytes);

        // if and only if there's a root jurisdiction, also include the end elements
        int endNodeCount = (int)_jurisdictionEndNodes.size();

        _statsPacket->writePrimitive(endNodeCount);

        for (int i=0; i < endNodeCount; i++) {
            unsigned char* endNodeCode = _jurisdictionEndNodes[i];
            auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode));
            _statsPacket->writePrimitive(bytes);
            _statsPacket->write(reinterpret_cast<char*>(endNodeCode), bytes);
        }
    } else {
        int bytes = 0;
        _statsPacket->writePrimitive(bytes);
    }

    return _statsPacket->getPayloadSize();
}
コード例 #3
0
ファイル: ModelItem.cpp プロジェクト: Adrianl3d/hifi
// adjust any internal timestamps to fix clock skew for this server
void ModelItem::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) {
    unsigned char* dataAt = codeColorBuffer;
    int octets = numberOfThreeBitSectionsInCode(dataAt);
    int lengthOfOctcode = bytesRequiredForCodeLength(octets);
    dataAt += lengthOfOctcode;

    // id
    uint32_t id;
    memcpy(&id, dataAt, sizeof(id));
    dataAt += sizeof(id);
    // special case for handling "new" modelItems
    if (id == NEW_MODEL) {
        // If this is a NEW_MODEL, then we assume that there's an additional uint32_t creatorToken, that
        // we want to send back to the creator as an map to the actual id
        dataAt += sizeof(uint32_t);
    }

    // lastEdited
    quint64 lastEditedInLocalTime;
    memcpy(&lastEditedInLocalTime, dataAt, sizeof(lastEditedInLocalTime));
    quint64 lastEditedInServerTime = lastEditedInLocalTime + clockSkew;
    memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime));
    const bool wantDebug = false;
    if (wantDebug) {
        qDebug("ModelItem::adjustEditPacketForClockSkew()...");
        qDebug() << "     lastEditedInLocalTime: " << lastEditedInLocalTime;
        qDebug() << "                 clockSkew: " << clockSkew;
        qDebug() << "    lastEditedInServerTime: " << lastEditedInServerTime;
    }
}
コード例 #4
0
ファイル: OctreeSceneStats.cpp プロジェクト: CryptArc/hifi
void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, OctreeElementPointer root,
                                    JurisdictionMap* jurisdictionMap) {
    reset(); // resets packet and octree stats
    _isStarted = true;
    _start = usecTimestampNow();

    _totalElements = OctreeElement::getNodeCount();
    _totalInternal = OctreeElement::getInternalNodeCount();
    _totalLeaves   = OctreeElement::getLeafNodeCount();

    _isFullScene = isFullScene;
    _isMoving = isMoving;

    if (_jurisdictionRoot) {
        delete[] _jurisdictionRoot;
        _jurisdictionRoot = NULL;
    }
    // clear existing endNodes before copying new ones...
    for (size_t i=0; i < _jurisdictionEndNodes.size(); i++) {
        if (_jurisdictionEndNodes[i]) {
            delete[] _jurisdictionEndNodes[i];
        }
    }
    _jurisdictionEndNodes.clear();

    // setup jurisdictions
    if (jurisdictionMap) {
        unsigned char* jurisdictionRoot = jurisdictionMap->getRootOctalCode();
        if (jurisdictionRoot) {
            auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(jurisdictionRoot));
            _jurisdictionRoot = new unsigned char[bytes];
            memcpy(_jurisdictionRoot, jurisdictionRoot, bytes);
        }

        // copy new endNodes...
        for (int i = 0; i < jurisdictionMap->getEndNodeCount(); i++) {
            unsigned char* endNodeCode = jurisdictionMap->getEndNodeOctalCode(i);
            if (endNodeCode) {
                auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode));
                unsigned char* endNodeCodeCopy = new unsigned char[bytes];
                memcpy(endNodeCodeCopy, endNodeCode, bytes);
                _jurisdictionEndNodes.push_back(endNodeCodeCopy);
            }
        }
    }
}
コード例 #5
0
ファイル: VoxelTree.cpp プロジェクト: harrisonpartch/hifi
void VoxelTree::readCodeColorBufferToTree(const unsigned char* codeColorBuffer, bool destructive) {
    ReadCodeColorBufferToTreeArgs args;
    args.codeColorBuffer = codeColorBuffer;
    args.lengthOfCode = numberOfThreeBitSectionsInCode(codeColorBuffer);
    args.destructive = destructive;
    args.pathChanged = false;
    VoxelTreeElement* node = getRoot();
    readCodeColorBufferToTreeRecursion(node, args);
}
コード例 #6
0
ファイル: OctreeElement.cpp プロジェクト: MarcelEdward/hifi
void OctreeElement::calculateAACube() {
    // copy corner into cube
    glm::vec3 corner;
    copyFirstVertexForCode(getOctalCode(), (float*)&corner);

    // this tells you the "size" of the voxel
    float voxelScale = (float)TREE_SCALE / powf(2.0f, numberOfThreeBitSectionsInCode(getOctalCode()));
    corner *= (float)TREE_SCALE;
    _cube.setBox(corner, voxelScale);
}
コード例 #7
0
ファイル: JurisdictionMap.cpp プロジェクト: digi-chris/hifi
void JurisdictionMap::copyContents(unsigned char* rootCodeIn, const std::vector<unsigned char*>& endNodesIn) {
    unsigned char* rootCode;
    std::vector<unsigned char*> endNodes;
    if (rootCodeIn) {
        int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(rootCodeIn));
        rootCode = new unsigned char[bytes];
        memcpy(rootCode, rootCodeIn, bytes);
    } else {
        rootCode = new unsigned char[1];
        *rootCode = 0;
    }
    
    for (int i = 0; i < endNodesIn.size(); i++) {
        if (endNodesIn[i]) {
            int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodesIn[i]));
            unsigned char* endNodeCode = new unsigned char[bytes];
            memcpy(endNodeCode, endNodesIn[i], bytes);
            endNodes.push_back(endNodeCode);
        }
    }
    init(rootCode, endNodes);
}
コード例 #8
0
ファイル: OctreeElement.cpp プロジェクト: rabedik/hifi
OctreeElement::~OctreeElement() {
    notifyDeleteHooks();
    _voxelNodeCount--;
    if (isLeaf()) {
        _voxelNodeLeafCount--;
    }

    if (_octcodePointer) {
        _octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode()));
        delete[] _octalCode.pointer;
    }

    // delete all of this node's children, this also takes care of all population tracking data
    deleteAllChildren();
}
コード例 #9
0
ファイル: OctreeElement.cpp プロジェクト: Giugiogia/hifi
void OctreeElement::init(unsigned char * octalCode) {
    if (!octalCode) {
        octalCode = new unsigned char[1];
        *octalCode = 0;
    }
    _voxelNodeCount++;
    _voxelNodeLeafCount++; // all nodes start as leaf nodes


    size_t octalCodeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode));
    if (octalCodeLength > sizeof(_octalCode)) {
        _octalCode.pointer = octalCode;
        _octcodePointer = true;
        _octcodeMemoryUsage += octalCodeLength;
    } else {
        _octcodePointer = false;
        memcpy(_octalCode.buffer, octalCode, octalCodeLength);
        delete[] octalCode;
    }

    // set up the _children union
    _childBitmask = 0;
    _childrenExternal = false;


    _childrenCount[0]++;

    // default pointers to child nodes to NULL
#ifdef SIMPLE_CHILD_ARRAY
    for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
        _simpleChildArray[i] = NULL;
    }
#endif

#ifdef SIMPLE_EXTERNAL_CHILDREN
    _childrenSingle.reset();
#endif

    for (int i = 0; i < NUMBER_OF_CHILDREN; i ++) {
        _externalChildren[i].reset();
    }

    _isDirty = true;
    _shouldRender = false;
    _sourceUUIDKey = 0;
    calculateAACube();
    markWithChangedTime();
}
コード例 #10
0
ファイル: OctreeElement.cpp プロジェクト: Giugiogia/hifi
OctreeElement::~OctreeElement() {
    // We can't call notifyDeleteHooks from here:
    //   notifyDeleteHooks();
    // see comment in EntityTreeElement::createNewElement.
    assert(_deleteHooksNotified);
    _voxelNodeCount--;
    if (isLeaf()) {
        _voxelNodeLeafCount--;
    }

    if (_octcodePointer) {
        _octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode()));
        delete[] _octalCode.pointer;
    }

    // delete all of this node's children, this also takes care of all population tracking data
    deleteAllChildren();
}
コード例 #11
0
ファイル: EntityItem.cpp プロジェクト: jjbunbury/hifi
// adjust any internal timestamps to fix clock skew for this server
void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, size_t length, int clockSkew) {
    unsigned char* dataAt = editPacketBuffer;
    int octets = numberOfThreeBitSectionsInCode(dataAt);
    int lengthOfOctcode = bytesRequiredForCodeLength(octets);
    dataAt += lengthOfOctcode;

    // lastEdited
    quint64 lastEditedInLocalTime;
    memcpy(&lastEditedInLocalTime, dataAt, sizeof(lastEditedInLocalTime));
    quint64 lastEditedInServerTime = lastEditedInLocalTime + clockSkew;
    memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime));
    const bool wantDebug = false;
    if (wantDebug) {
        qDebug("EntityItem::adjustEditPacketForClockSkew()...");
        qDebug() << "     lastEditedInLocalTime: " << lastEditedInLocalTime;
        qDebug() << "                 clockSkew: " << clockSkew;
        qDebug() << "    lastEditedInServerTime: " << lastEditedInServerTime;
    }
}
コード例 #12
0
ファイル: VoxelTree.cpp プロジェクト: harrisonpartch/hifi
int VoxelTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* packetData, int packetLength,
                    unsigned char* editData, int maxLength, Node* senderNode) {

    int processedBytes = 0;
    // we handle these types of "edit" packets
    switch (packetType) {
        case PACKET_TYPE_VOXEL_SET:
        case PACKET_TYPE_VOXEL_SET_DESTRUCTIVE: {
            bool destructive = (packetType == PACKET_TYPE_VOXEL_SET_DESTRUCTIVE);
            int octets = numberOfThreeBitSectionsInCode(editData, maxLength);
            
            if (octets == OVERFLOWED_OCTCODE_BUFFER) {
                printf("WARNING! Got voxel edit record that would overflow buffer in numberOfThreeBitSectionsInCode(), ");
                printf("bailing processing of packet!\n");
                return processedBytes;
            }

            const int COLOR_SIZE_IN_BYTES = 3;
            int voxelCodeSize = bytesRequiredForCodeLength(octets);
            int voxelDataSize = voxelCodeSize + COLOR_SIZE_IN_BYTES;

            if (voxelDataSize > maxLength) {
                printf("WARNING! Got voxel edit record that would overflow buffer, bailing processing of packet!\n");
                printf("bailing processing of packet!\n");
                return processedBytes;
            }
            
            readCodeColorBufferToTree(editData, destructive);
            
            return voxelDataSize;
        } break;
            
        case PACKET_TYPE_VOXEL_ERASE:
            processRemoveOctreeElementsBitstream((unsigned char*)packetData, packetLength);
            return maxLength;
    }
    return processedBytes;
}
コード例 #13
0
ファイル: OctreePacketData.cpp プロジェクト: Lhasamencur/hifi
bool OctreePacketData::startSubTree(const unsigned char* octcode) {
    _bytesOfOctalCodesCurrentSubTree = _bytesOfOctalCodes;
    bool success = false;
    int possibleStartAt = _bytesInUse;
    int length = 0;
    if (octcode) {
        length = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octcode));
        success = append(octcode, length); // handles checking compression
    } else {
        // NULL case, means root node, which is 0
        unsigned char byte = 0;
        length = 1;
        success = append(byte); // handles checking compression
    }
    if (success) {
        _subTreeAt = possibleStartAt;
    }
    if (success) {
        _bytesOfOctalCodes += length;
        _totalBytesOfOctalCodes += length;
    }
    return success;
}
コード例 #14
0
ファイル: ModelItem.cpp プロジェクト: Adrianl3d/hifi
ModelItem ModelItem::fromEditPacket(const unsigned char* data, int length, int& processedBytes, ModelTree* tree, bool& valid) {
    ModelItem newModelItem; // id and _lastUpdated will get set here...
    const unsigned char* dataAt = data;
    processedBytes = 0;

    // the first part of the data is our octcode...
    int octets = numberOfThreeBitSectionsInCode(data);
    int lengthOfOctcode = bytesRequiredForCodeLength(octets);

    // we don't actually do anything with this octcode...
    dataAt += lengthOfOctcode;
    processedBytes += lengthOfOctcode;

    // id
    uint32_t editID;
    memcpy(&editID, dataAt, sizeof(editID));
    dataAt += sizeof(editID);
    processedBytes += sizeof(editID);

    bool isNewModelItem = (editID == NEW_MODEL);

    // special case for handling "new" modelItems
    if (isNewModelItem) {
        // If this is a NEW_MODEL, then we assume that there's an additional uint32_t creatorToken, that
        // we want to send back to the creator as an map to the actual id
        uint32_t creatorTokenID;
        memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID));
        dataAt += sizeof(creatorTokenID);
        processedBytes += sizeof(creatorTokenID);

        newModelItem.setCreatorTokenID(creatorTokenID);
        newModelItem._newlyCreated = true;
        valid = true;

    } else {
        // look up the existing modelItem
        const ModelItem* existingModelItem = tree->findModelByID(editID, true);

        // copy existing properties before over-writing with new properties
        if (existingModelItem) {
            newModelItem = *existingModelItem;
            valid = true;
        } else {
            // the user attempted to edit a modelItem that doesn't exist
            qDebug() << "user attempted to edit a modelItem that doesn't exist... editID=" << editID;

            // NOTE: even though this is a bad editID, we have to consume the edit details, so that
            // the buffer doesn't get corrupted for further processing...
            valid = false;
        }
        newModelItem._id = editID;
        newModelItem._newlyCreated = false;
    }
    
    // lastEdited
    memcpy(&newModelItem._lastEdited, dataAt, sizeof(newModelItem._lastEdited));
    dataAt += sizeof(newModelItem._lastEdited);
    processedBytes += sizeof(newModelItem._lastEdited);

    // All of the remaining items are optional, and may or may not be included based on their included values in the
    // properties included bits
    uint16_t packetContainsBits = 0;
    if (!isNewModelItem) {
        memcpy(&packetContainsBits, dataAt, sizeof(packetContainsBits));
        dataAt += sizeof(packetContainsBits);
        processedBytes += sizeof(packetContainsBits);
    }


    // radius
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_RADIUS) == MODEL_PACKET_CONTAINS_RADIUS)) {
        memcpy(&newModelItem._radius, dataAt, sizeof(newModelItem._radius));
        dataAt += sizeof(newModelItem._radius);
        processedBytes += sizeof(newModelItem._radius);
    }

    // position
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_POSITION) == MODEL_PACKET_CONTAINS_POSITION)) {
        memcpy(&newModelItem._position, dataAt, sizeof(newModelItem._position));
        dataAt += sizeof(newModelItem._position);
        processedBytes += sizeof(newModelItem._position);
    }

    // color
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_COLOR) == MODEL_PACKET_CONTAINS_COLOR)) {
        memcpy(newModelItem._color, dataAt, sizeof(newModelItem._color));
        dataAt += sizeof(newModelItem._color);
        processedBytes += sizeof(newModelItem._color);
    }

    // shouldDie
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_SHOULDDIE) == MODEL_PACKET_CONTAINS_SHOULDDIE)) {
        memcpy(&newModelItem._shouldDie, dataAt, sizeof(newModelItem._shouldDie));
        dataAt += sizeof(newModelItem._shouldDie);
        processedBytes += sizeof(newModelItem._shouldDie);
    }

    // modelURL
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_MODEL_URL) == MODEL_PACKET_CONTAINS_MODEL_URL)) {
        uint16_t modelURLLength;
        memcpy(&modelURLLength, dataAt, sizeof(modelURLLength));
        dataAt += sizeof(modelURLLength);
        processedBytes += sizeof(modelURLLength);
        QString tempString((const char*)dataAt);
        newModelItem._modelURL = tempString;
        dataAt += modelURLLength;
        processedBytes += modelURLLength;
    }

    // modelRotation
    if (isNewModelItem || ((packetContainsBits & 
                    MODEL_PACKET_CONTAINS_MODEL_ROTATION) == MODEL_PACKET_CONTAINS_MODEL_ROTATION)) {
        int bytes = unpackOrientationQuatFromBytes(dataAt, newModelItem._modelRotation);
        dataAt += bytes;
        processedBytes += bytes;
    }

    // animationURL
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_ANIMATION_URL) == MODEL_PACKET_CONTAINS_ANIMATION_URL)) {
        uint16_t animationURLLength;
        memcpy(&animationURLLength, dataAt, sizeof(animationURLLength));
        dataAt += sizeof(animationURLLength);
        processedBytes += sizeof(animationURLLength);
        QString tempString((const char*)dataAt);
        newModelItem._animationURL = tempString;
        dataAt += animationURLLength;
        processedBytes += animationURLLength;
    }

    // animationIsPlaying
    if (isNewModelItem || ((packetContainsBits & 
                    MODEL_PACKET_CONTAINS_ANIMATION_PLAYING) == MODEL_PACKET_CONTAINS_ANIMATION_PLAYING)) {
                    
        memcpy(&newModelItem._animationIsPlaying, dataAt, sizeof(newModelItem._animationIsPlaying));
        dataAt += sizeof(newModelItem._animationIsPlaying);
        processedBytes += sizeof(newModelItem._animationIsPlaying);
    }

    // animationFrameIndex
    if (isNewModelItem || ((packetContainsBits & 
                    MODEL_PACKET_CONTAINS_ANIMATION_FRAME) == MODEL_PACKET_CONTAINS_ANIMATION_FRAME)) {
                    
        memcpy(&newModelItem._animationFrameIndex, dataAt, sizeof(newModelItem._animationFrameIndex));
        dataAt += sizeof(newModelItem._animationFrameIndex);
        processedBytes += sizeof(newModelItem._animationFrameIndex);
    }

    // animationFPS
    if (isNewModelItem || ((packetContainsBits & 
                    MODEL_PACKET_CONTAINS_ANIMATION_FPS) == MODEL_PACKET_CONTAINS_ANIMATION_FPS)) {
                    
        memcpy(&newModelItem._animationFPS, dataAt, sizeof(newModelItem._animationFPS));
        dataAt += sizeof(newModelItem._animationFPS);
        processedBytes += sizeof(newModelItem._animationFPS);
    }

    const bool wantDebugging = false;
    if (wantDebugging) {
        qDebug("ModelItem::fromEditPacket()...");
        qDebug() << "   ModelItem id in packet:" << editID;
        newModelItem.debugDump();
    }

    return newModelItem;
}
コード例 #15
0
ファイル: OctreeSceneStats.cpp プロジェクト: brotchie/hifi
void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) {
    _totalEncodeTime = other._totalEncodeTime;
    _elapsed = other._elapsed;
    _lastFullElapsed = other._lastFullElapsed;
    _lastFullTotalEncodeTime = other._lastFullTotalEncodeTime;
    _lastFullTotalPackets = other._lastFullTotalPackets;
    _lastFullTotalBytes = other._lastFullTotalBytes;
    _encodeStart = other._encodeStart;

    _packets = other._packets;
    _bytes = other._bytes;
    _passes = other._passes;

    _totalElements = other._totalElements;
    _totalInternal = other._totalInternal;
    _totalLeaves = other._totalLeaves;

    _traversed = other._traversed;
    _internal = other._internal;
    _leaves = other._leaves;

    _skippedDistance = other._skippedDistance;
    _internalSkippedDistance = other._internalSkippedDistance;
    _leavesSkippedDistance = other._leavesSkippedDistance;

    _skippedOutOfView = other._skippedOutOfView;
    _internalSkippedOutOfView = other._internalSkippedOutOfView;
    _leavesSkippedOutOfView = other._leavesSkippedOutOfView;

    _skippedWasInView = other._skippedWasInView;
    _internalSkippedWasInView = other._internalSkippedWasInView;
    _leavesSkippedWasInView = other._leavesSkippedWasInView;

    _skippedNoChange = other._skippedNoChange;
    _internalSkippedNoChange = other._internalSkippedNoChange;
    _leavesSkippedNoChange = other._leavesSkippedNoChange;

    _skippedOccluded = other._skippedOccluded;
    _internalSkippedOccluded = other._internalSkippedOccluded;
    _leavesSkippedOccluded = other._leavesSkippedOccluded;

    _colorSent = other._colorSent;
    _internalColorSent = other._internalColorSent;
    _leavesColorSent = other._leavesColorSent;

    _didntFit = other._didntFit;
    _internalDidntFit = other._internalDidntFit;
    _leavesDidntFit = other._leavesDidntFit;

    _colorBitsWritten = other._colorBitsWritten;
    _existsBitsWritten = other._existsBitsWritten;
    _existsInPacketBitsWritten = other._existsInPacketBitsWritten;
    _treesRemoved = other._treesRemoved;

    // before copying the jurisdictions, delete any current values...
    if (_jurisdictionRoot) {
        delete[] _jurisdictionRoot;
        _jurisdictionRoot = NULL;
    }
    for (size_t i = 0; i < _jurisdictionEndNodes.size(); i++) {
        if (_jurisdictionEndNodes[i]) {
            delete[] _jurisdictionEndNodes[i];
        }
    }
    _jurisdictionEndNodes.clear();
    
    // Now copy the values from the other    
    if (other._jurisdictionRoot) {
        int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(other._jurisdictionRoot));
        _jurisdictionRoot = new unsigned char[bytes];
        memcpy(_jurisdictionRoot, other._jurisdictionRoot, bytes);
    }
    for (size_t i = 0; i < other._jurisdictionEndNodes.size(); i++) {
        unsigned char* endNodeCode = other._jurisdictionEndNodes[i];
        if (endNodeCode) {
            int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode));
            unsigned char* endNodeCodeCopy = new unsigned char[bytes];
            memcpy(endNodeCodeCopy, endNodeCode, bytes);
            _jurisdictionEndNodes.push_back(endNodeCodeCopy);
        }
    }

    _incomingPacket = other._incomingPacket;
    _incomingBytes = other._incomingBytes;
    _incomingWastedBytes = other._incomingWastedBytes;
    _incomingLastSequence = other._incomingLastSequence;
    _incomingLikelyLost = other._incomingLikelyLost;
    _incomingRecovered = other._incomingRecovered;
    _incomingEarly = other._incomingEarly;
    _incomingLate = other._incomingLate;
    _incomingReallyLate = other._incomingReallyLate;
    _incomingPossibleDuplicate = other._incomingPossibleDuplicate;
    
    _missingSequenceNumbers = other._missingSequenceNumbers;
}
コード例 #16
0
ファイル: OctreeSceneStats.cpp プロジェクト: brotchie/hifi
int OctreeSceneStats::packIntoMessage(unsigned char* destinationBuffer, int availableBytes) {
    unsigned char* bufferStart = destinationBuffer;
    
    int headerLength = populatePacketHeader(reinterpret_cast<char*>(destinationBuffer), PacketTypeOctreeStats);
    destinationBuffer += headerLength;
    
    memcpy(destinationBuffer, &_start, sizeof(_start));
    destinationBuffer += sizeof(_start);
    memcpy(destinationBuffer, &_end, sizeof(_end));
    destinationBuffer += sizeof(_end);
    memcpy(destinationBuffer, &_elapsed, sizeof(_elapsed));
    destinationBuffer += sizeof(_elapsed);
    memcpy(destinationBuffer, &_totalEncodeTime, sizeof(_totalEncodeTime));
    destinationBuffer += sizeof(_totalEncodeTime);
    memcpy(destinationBuffer, &_isFullScene, sizeof(_isFullScene));
    destinationBuffer += sizeof(_isFullScene);
    memcpy(destinationBuffer, &_isMoving, sizeof(_isMoving));
    destinationBuffer += sizeof(_isMoving);
    memcpy(destinationBuffer, &_packets, sizeof(_packets));
    destinationBuffer += sizeof(_packets);
    memcpy(destinationBuffer, &_bytes, sizeof(_bytes));
    destinationBuffer += sizeof(_bytes);

    memcpy(destinationBuffer, &_totalInternal, sizeof(_totalInternal));
    destinationBuffer += sizeof(_totalInternal);
    memcpy(destinationBuffer, &_totalLeaves, sizeof(_totalLeaves));
    destinationBuffer += sizeof(_totalLeaves);
    memcpy(destinationBuffer, &_internal, sizeof(_internal));
    destinationBuffer += sizeof(_internal);
    memcpy(destinationBuffer, &_leaves, sizeof(_leaves));
    destinationBuffer += sizeof(_leaves);
    memcpy(destinationBuffer, &_internalSkippedDistance, sizeof(_internalSkippedDistance));
    destinationBuffer += sizeof(_internalSkippedDistance);
    memcpy(destinationBuffer, &_leavesSkippedDistance, sizeof(_leavesSkippedDistance));
    destinationBuffer += sizeof(_leavesSkippedDistance);
    memcpy(destinationBuffer, &_internalSkippedOutOfView, sizeof(_internalSkippedOutOfView));
    destinationBuffer += sizeof(_internalSkippedOutOfView);
    memcpy(destinationBuffer, &_leavesSkippedOutOfView, sizeof(_leavesSkippedOutOfView));
    destinationBuffer += sizeof(_leavesSkippedOutOfView);
    memcpy(destinationBuffer, &_internalSkippedWasInView, sizeof(_internalSkippedWasInView));
    destinationBuffer += sizeof(_internalSkippedWasInView);
    memcpy(destinationBuffer, &_leavesSkippedWasInView, sizeof(_leavesSkippedWasInView));
    destinationBuffer += sizeof(_leavesSkippedWasInView);
    memcpy(destinationBuffer, &_internalSkippedNoChange, sizeof(_internalSkippedNoChange));
    destinationBuffer += sizeof(_internalSkippedNoChange);
    memcpy(destinationBuffer, &_leavesSkippedNoChange, sizeof(_leavesSkippedNoChange));
    destinationBuffer += sizeof(_leavesSkippedNoChange);
    memcpy(destinationBuffer, &_internalSkippedOccluded, sizeof(_internalSkippedOccluded));
    destinationBuffer += sizeof(_internalSkippedOccluded);
    memcpy(destinationBuffer, &_leavesSkippedOccluded, sizeof(_leavesSkippedOccluded));
    destinationBuffer += sizeof(_leavesSkippedOccluded);
    memcpy(destinationBuffer, &_internalColorSent, sizeof(_internalColorSent));
    destinationBuffer += sizeof(_internalColorSent);
    memcpy(destinationBuffer, &_leavesColorSent, sizeof(_leavesColorSent));
    destinationBuffer += sizeof(_leavesColorSent);
    memcpy(destinationBuffer, &_internalDidntFit, sizeof(_internalDidntFit));
    destinationBuffer += sizeof(_internalDidntFit);
    memcpy(destinationBuffer, &_leavesDidntFit, sizeof(_leavesDidntFit));
    destinationBuffer += sizeof(_leavesDidntFit);
    memcpy(destinationBuffer, &_colorBitsWritten, sizeof(_colorBitsWritten));
    destinationBuffer += sizeof(_colorBitsWritten);
    memcpy(destinationBuffer, &_existsBitsWritten, sizeof(_existsBitsWritten));
    destinationBuffer += sizeof(_existsBitsWritten);
    memcpy(destinationBuffer, &_existsInPacketBitsWritten, sizeof(_existsInPacketBitsWritten));
    destinationBuffer += sizeof(_existsInPacketBitsWritten);
    memcpy(destinationBuffer, &_treesRemoved, sizeof(_treesRemoved));
    destinationBuffer += sizeof(_treesRemoved);

    // add the root jurisdiction
    if (_jurisdictionRoot) {
        // copy the 
        int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_jurisdictionRoot));
        memcpy(destinationBuffer, &bytes, sizeof(bytes));
        destinationBuffer += sizeof(bytes);
        memcpy(destinationBuffer, _jurisdictionRoot, bytes);
        destinationBuffer += bytes;
        
        // if and only if there's a root jurisdiction, also include the end elements
        int endNodeCount = _jurisdictionEndNodes.size(); 

        memcpy(destinationBuffer, &endNodeCount, sizeof(endNodeCount));
        destinationBuffer += sizeof(endNodeCount);

        for (int i=0; i < endNodeCount; i++) {
            unsigned char* endNodeCode = _jurisdictionEndNodes[i];
            int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode));
            memcpy(destinationBuffer, &bytes, sizeof(bytes));
            destinationBuffer += sizeof(bytes);
            memcpy(destinationBuffer, endNodeCode, bytes);
            destinationBuffer += bytes;
        }
    } else {
        int bytes = 0;
        memcpy(destinationBuffer, &bytes, sizeof(bytes));
        destinationBuffer += sizeof(bytes);
    }
    
    return destinationBuffer - bufferStart; // includes header!
}
コード例 #17
0
ファイル: ModelItem.cpp プロジェクト: Adrianl3d/hifi
bool ModelItem::encodeModelEditMessageDetails(PacketType command, ModelItemID id, const ModelItemProperties& properties,
        unsigned char* bufferOut, int sizeIn, int& sizeOut) {

    bool success = true; // assume the best
    unsigned char* copyAt = bufferOut;
    sizeOut = 0;

    // get the octal code for the modelItem

    // this could be a problem if the caller doesn't include position....
    glm::vec3 rootPosition(0);
    float rootScale = 0.5f;
    unsigned char* octcode = pointToOctalCode(rootPosition.x, rootPosition.y, rootPosition.z, rootScale);

    // TODO: Consider this old code... including the correct octree for where the modelItem will go matters for 
    // modelItem servers with different jurisdictions, but for now, we'll send everything to the root, since the 
    // tree does the right thing...
    //
    //unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y,
    //                                          details[i].position.z, details[i].radius);

    int octets = numberOfThreeBitSectionsInCode(octcode);
    int lengthOfOctcode = bytesRequiredForCodeLength(octets);

    // add it to our message
    memcpy(copyAt, octcode, lengthOfOctcode);
    copyAt += lengthOfOctcode;
    sizeOut += lengthOfOctcode;

    // Now add our edit content details...
    bool isNewModelItem = (id.id == NEW_MODEL);

    // id
    memcpy(copyAt, &id.id, sizeof(id.id));
    copyAt += sizeof(id.id);
    sizeOut += sizeof(id.id);

    // special case for handling "new" modelItems
    if (isNewModelItem) {
        // If this is a NEW_MODEL, then we assume that there's an additional uint32_t creatorToken, that
        // we want to send back to the creator as an map to the actual id
        memcpy(copyAt, &id.creatorTokenID, sizeof(id.creatorTokenID));
        copyAt += sizeof(id.creatorTokenID);
        sizeOut += sizeof(id.creatorTokenID);
    }
    
    // lastEdited
    quint64 lastEdited = properties.getLastEdited();
    memcpy(copyAt, &lastEdited, sizeof(lastEdited));
    copyAt += sizeof(lastEdited);
    sizeOut += sizeof(lastEdited);
    
    // For new modelItems, all remaining items are mandatory, for an edited modelItem, All of the remaining items are
    // optional, and may or may not be included based on their included values in the properties included bits
    uint16_t packetContainsBits = properties.getChangedBits();
    if (!isNewModelItem) {
        memcpy(copyAt, &packetContainsBits, sizeof(packetContainsBits));
        copyAt += sizeof(packetContainsBits);
        sizeOut += sizeof(packetContainsBits);
    }

    // radius
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_RADIUS) == MODEL_PACKET_CONTAINS_RADIUS)) {
        float radius = properties.getRadius() / (float) TREE_SCALE;
        memcpy(copyAt, &radius, sizeof(radius));
        copyAt += sizeof(radius);
        sizeOut += sizeof(radius);
    }

    // position
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_POSITION) == MODEL_PACKET_CONTAINS_POSITION)) {
        glm::vec3 position = properties.getPosition() / (float)TREE_SCALE;
        memcpy(copyAt, &position, sizeof(position));
        copyAt += sizeof(position);
        sizeOut += sizeof(position);
    }

    // color
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_COLOR) == MODEL_PACKET_CONTAINS_COLOR)) {
        rgbColor color = { properties.getColor().red, properties.getColor().green, properties.getColor().blue };
        memcpy(copyAt, color, sizeof(color));
        copyAt += sizeof(color);
        sizeOut += sizeof(color);
    }

    // shoulDie
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_SHOULDDIE) == MODEL_PACKET_CONTAINS_SHOULDDIE)) {
        bool shouldDie = properties.getShouldDie();
        memcpy(copyAt, &shouldDie, sizeof(shouldDie));
        copyAt += sizeof(shouldDie);
        sizeOut += sizeof(shouldDie);
    }

    // modelURL
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_MODEL_URL) == MODEL_PACKET_CONTAINS_MODEL_URL)) {
        uint16_t urlLength = properties.getModelURL().size() + 1;
        memcpy(copyAt, &urlLength, sizeof(urlLength));
        copyAt += sizeof(urlLength);
        sizeOut += sizeof(urlLength);
        memcpy(copyAt, qPrintable(properties.getModelURL()), urlLength);
        copyAt += urlLength;
        sizeOut += urlLength;
    }

    // modelRotation
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_MODEL_ROTATION) == MODEL_PACKET_CONTAINS_MODEL_ROTATION)) {
        int bytes = packOrientationQuatToBytes(copyAt, properties.getModelRotation());
        copyAt += bytes;
        sizeOut += bytes;
    }

    // animationURL
    if (isNewModelItem || ((packetContainsBits & MODEL_PACKET_CONTAINS_ANIMATION_URL) == MODEL_PACKET_CONTAINS_ANIMATION_URL)) {
        uint16_t urlLength = properties.getAnimationURL().size() + 1;
        memcpy(copyAt, &urlLength, sizeof(urlLength));
        copyAt += sizeof(urlLength);
        sizeOut += sizeof(urlLength);
        memcpy(copyAt, qPrintable(properties.getAnimationURL()), urlLength);
        copyAt += urlLength;
        sizeOut += urlLength;
    }

    // animationIsPlaying
    if (isNewModelItem || ((packetContainsBits & 
                    MODEL_PACKET_CONTAINS_ANIMATION_PLAYING) == MODEL_PACKET_CONTAINS_ANIMATION_PLAYING)) {
                    
        bool animationIsPlaying = properties.getAnimationIsPlaying();
        memcpy(copyAt, &animationIsPlaying, sizeof(animationIsPlaying));
        copyAt += sizeof(animationIsPlaying);
        sizeOut += sizeof(animationIsPlaying);
    }

    // animationFrameIndex
    if (isNewModelItem || ((packetContainsBits & 
                    MODEL_PACKET_CONTAINS_ANIMATION_FRAME) == MODEL_PACKET_CONTAINS_ANIMATION_FRAME)) {
                    
        float animationFrameIndex = properties.getAnimationFrameIndex();
        memcpy(copyAt, &animationFrameIndex, sizeof(animationFrameIndex));
        copyAt += sizeof(animationFrameIndex);
        sizeOut += sizeof(animationFrameIndex);
    }

    // animationFPS
    if (isNewModelItem || ((packetContainsBits & 
                    MODEL_PACKET_CONTAINS_ANIMATION_FPS) == MODEL_PACKET_CONTAINS_ANIMATION_FPS)) {
                    
        float animationFPS = properties.getAnimationFPS();
        memcpy(copyAt, &animationFPS, sizeof(animationFPS));
        copyAt += sizeof(animationFPS);
        sizeOut += sizeof(animationFPS);
    }

    bool wantDebugging = false;
    if (wantDebugging) {
        qDebug("encodeModelItemEditMessageDetails()....");
        qDebug("ModelItem id  :%u", id.id);
        qDebug(" nextID:%u", _nextID);
    }

    // cleanup
    delete[] octcode;
    
    return success;
}
コード例 #18
0
ファイル: VoxelTree.cpp プロジェクト: harrisonpartch/hifi
void VoxelTree::readCodeColorBufferToTreeRecursion(VoxelTreeElement* node, ReadCodeColorBufferToTreeArgs& args) {
    int lengthOfNodeCode = numberOfThreeBitSectionsInCode(node->getOctalCode());

    // Since we traverse the tree in code order, we know that if our code
    // matches, then we've reached  our target node.
    if (lengthOfNodeCode == args.lengthOfCode) {
        // we've reached our target -- we might have found our node, but that node might have children.
        // in this case, we only allow you to set the color if you explicitly asked for a destructive
        // write.
        if (!node->isLeaf() && args.destructive) {
            // if it does exist, make sure it has no children
            for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
                node->deleteChildAtIndex(i);
            }
        } else {
            if (!node->isLeaf()) {
                qDebug("WARNING! operation would require deleting children, add Voxel ignored!\n ");
            }
        }

        // If we get here, then it means, we either had a true leaf to begin with, or we were in
        // destructive mode and we deleted all the child trees. So we can color.
        if (node->isLeaf()) {
            // give this node its color
            int octalCodeBytes = bytesRequiredForCodeLength(args.lengthOfCode);

            nodeColor newColor;
            memcpy(newColor, args.codeColorBuffer + octalCodeBytes, SIZE_OF_COLOR_DATA);
            newColor[SIZE_OF_COLOR_DATA] = 1;
            node->setColor(newColor);

            // It's possible we just reset the node to it's exact same color, in
            // which case we don't consider this to be dirty...
            if (node->isDirty()) {
                // track our tree dirtiness
                _isDirty = true;
                // track that path has changed
                args.pathChanged = true;
            }
        }
        return;
    }

    // Ok, we know we haven't reached our target node yet, so keep looking
    //printOctalCode(args.codeColorBuffer);
    int childIndex = branchIndexWithDescendant(node->getOctalCode(), args.codeColorBuffer);
    VoxelTreeElement* childNode = node->getChildAtIndex(childIndex);

    // If the branch we need to traverse does not exist, then create it on the way down...
    if (!childNode) {
        childNode = node->addChildAtIndex(childIndex);
    }

    // recurse...
    readCodeColorBufferToTreeRecursion(childNode, args);

    // Unwinding...

    // If the lower level did some work, then we need to let this node know, so it can
    // do any bookkeeping it wants to, like color re-averaging, time stamp marking, etc
    if (args.pathChanged) {
        node->handleSubtreeChanged(this);
    }
}
コード例 #19
0
// TODO: 
//   how to handle lastEdited?
//   how to handle lastUpdated?
//   consider handling case where no properties are included... we should just ignore this packet...
//
// TODO: Right now, all possible properties for all subclasses are handled here. Ideally we'd prefer
//       to handle this in a more generic way. Allowing subclasses of EntityItem to register their properties
//
// TODO: There's a lot of repeated patterns in the code below to handle each property. It would be nice if the property
//       registration mechanism allowed us to collapse these repeated sections of code into a single implementation that
//       utilized the registration table to shorten up and simplify this code.
//
// TODO: Implement support for paged properties, spanning MTU, and custom properties
//
// TODO: Implement support for script and visible properties.
//
bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
                        EntityItemID& entityID, EntityItemProperties& properties) {
    bool valid = false;

    const unsigned char* dataAt = data;
    processedBytes = 0;

    // the first part of the data is an octcode, this is a required element of the edit packet format, but we don't
    // actually use it, we do need to skip it and read to the actual data we care about.
    int octets = numberOfThreeBitSectionsInCode(data);
    int bytesToReadOfOctcode = bytesRequiredForCodeLength(octets);

    // we don't actually do anything with this octcode...
    dataAt += bytesToReadOfOctcode;
    processedBytes += bytesToReadOfOctcode;
    
    // Edit packets have a last edited time stamp immediately following the octcode.
    // NOTE: the edit times have been set by the editor to match out clock, so we don't need to adjust
    // these times for clock skew at this point.
    quint64 lastEdited;
    memcpy(&lastEdited, dataAt, sizeof(lastEdited));
    dataAt += sizeof(lastEdited);
    processedBytes += sizeof(lastEdited);
    properties.setLastEdited(lastEdited);

    // NOTE: We intentionally do not send "created" times in edit messages. This is because:
    //   1) if the edit is to an existing entity, the created time can not be changed
    //   2) if the edit is to a new entity, the created time is the last edited time

    // encoded id
    QByteArray encodedID((const char*)dataAt, NUM_BYTES_RFC4122_UUID); // maximum possible size
    QUuid editID = QUuid::fromRfc4122(encodedID);
    dataAt += encodedID.size();
    processedBytes += encodedID.size();

    bool isNewEntityItem = (editID == NEW_ENTITY);

    if (isNewEntityItem) {
        // If this is a NEW_ENTITY, then we assume that there's an additional uint32_t creatorToken, that
        // we want to send back to the creator as an map to the actual id

        QByteArray encodedToken((const char*)dataAt, (bytesToRead - processedBytes));
        ByteCountCoded<quint32> tokenCoder = encodedToken;
        quint32 creatorTokenID = tokenCoder;
        encodedToken = tokenCoder; // determine true bytesToRead
        dataAt += encodedToken.size();
        processedBytes += encodedToken.size();

        //newEntityItem.setCreatorTokenID(creatorTokenID);
        //newEntityItem._newlyCreated = true;
        
        entityID.id = NEW_ENTITY;
        entityID.creatorTokenID = creatorTokenID;
        entityID.isKnownID = false;

        valid = true;

        // created time is lastEdited time
        properties.setCreated(lastEdited);
    } else {
        entityID.id = editID;
        entityID.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
        entityID.isKnownID = true;
        valid = true;

        // created time is lastEdited time
        properties.setCreated(USE_EXISTING_CREATED_TIME);
    }

    // Entity Type...
    QByteArray encodedType((const char*)dataAt, (bytesToRead - processedBytes));
    ByteCountCoded<quint32> typeCoder = encodedType;
    quint32 entityTypeCode = typeCoder;
    properties.setType((EntityTypes::EntityType)entityTypeCode);
    encodedType = typeCoder; // determine true bytesToRead
    dataAt += encodedType.size();
    processedBytes += encodedType.size();

    // Update Delta - when was this item updated relative to last edit... this really should be 0
    // TODO: Should we get rid of this in this in edit packets, since this has to always be 0?
    // TODO: do properties need to handle lastupdated???

    // last updated is stored as ByteCountCoded delta from lastEdited
    QByteArray encodedUpdateDelta((const char*)dataAt, (bytesToRead - processedBytes));
    ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
    encodedUpdateDelta = updateDeltaCoder; // determine true bytesToRead
    dataAt += encodedUpdateDelta.size();
    processedBytes += encodedUpdateDelta.size();

    // TODO: Do we need this lastUpdated?? We don't seem to use it.
    //quint64 updateDelta = updateDeltaCoder;
    //quint64 lastUpdated = lastEdited + updateDelta; // don't adjust for clock skew since we already did that for lastEdited
    
    // Property Flags...
    QByteArray encodedPropertyFlags((const char*)dataAt, (bytesToRead - processedBytes));
    EntityPropertyFlags propertyFlags = encodedPropertyFlags;
    dataAt += propertyFlags.getEncodedLength();
    processedBytes += propertyFlags.getEncodedLength();

    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions);  // NOTE: PROP_RADIUS obsolete
    READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(PROP_ROTATION, setRotation);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MASS, float, setMass);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VELOCITY, glm::vec3, setVelocity);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GRAVITY, glm::vec3, setGravity);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DAMPING, float, setDamping);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFETIME, float, setLifetime);
    READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_SCRIPT,setScript);
    READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_COLOR, setColor);
    READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL);
    READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, glm::vec3, setAngularVelocity);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping);
    READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible);

    return valid;
}