Example #1
0
void SphereEntityItem::recalculateCollisionShape() {
    _sphereShape.setTranslation(getCenterInMeters());
    glm::vec3 dimensionsInMeters = getDimensionsInMeters();
    float largestDiameter = glm::max(dimensionsInMeters.x, dimensionsInMeters.y, dimensionsInMeters.z);
    _sphereShape.setRadius(largestDiameter / 2.0f);
}
Example #2
0
void BoxEntityItem::computeShapeInfo(ShapeInfo& info) const {
    glm::vec3 halfExtents = 0.5f * getDimensionsInMeters();
    info.setBox(halfExtents);
}
Example #3
0
void SphereEntityItem::computeShapeInfo(ShapeInfo& info) const {
    glm::vec3 halfExtents = 0.5f * getDimensionsInMeters();
    // TODO: support ellipsoid shapes
    info.setSphere(halfExtents.x);
}
Example #4
0
int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
    bool wantDebug = false;

    if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {
    
        // NOTE: This shouldn't happen. The only versions of the bit stream that didn't support split mtu buffers should
        // be handled by the model subclass and shouldn't call this routine.
        qDebug() << "EntityItem::readEntityDataFromBuffer()... "
                        "ERROR CASE...args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU";
        return 0;
    }

    // Header bytes
    //    object ID [16 bytes]
    //    ByteCountCoded(type code) [~1 byte]
    //    last edited [8 bytes]
    //    ByteCountCoded(last_edited to last_updated delta) [~1-8 bytes]
    //    PropertyFlags<>( everything ) [1-2 bytes]
    // ~27-35 bytes...
    const int MINIMUM_HEADER_BYTES = 27;

    int bytesRead = 0;
    if (bytesLeftToRead >= MINIMUM_HEADER_BYTES) {

        int originalLength = bytesLeftToRead;
        QByteArray originalDataBuffer((const char*)data, originalLength);

        int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;

        const unsigned char* dataAt = data;

        // id
        QByteArray encodedID = originalDataBuffer.mid(bytesRead, NUM_BYTES_RFC4122_UUID); // maximum possible size
        _id = QUuid::fromRfc4122(encodedID);
        _creatorTokenID = UNKNOWN_ENTITY_TOKEN; // if we know the id, then we don't care about the creator token
        _newlyCreated = false;
        dataAt += encodedID.size();
        bytesRead += encodedID.size();
        
        // type
        QByteArray encodedType = originalDataBuffer.mid(bytesRead); // maximum possible size
        ByteCountCoded<quint32> typeCoder = encodedType;
        encodedType = typeCoder; // determine true length
        dataAt += encodedType.size();
        bytesRead += encodedType.size();
        quint32 type = typeCoder;
        _type = (EntityTypes::EntityType)type;

        bool overwriteLocalData = true; // assume the new content overwrites our local data

        // _created
        quint64 createdFromBuffer = 0;
        memcpy(&createdFromBuffer, dataAt, sizeof(createdFromBuffer));
        dataAt += sizeof(createdFromBuffer);
        bytesRead += sizeof(createdFromBuffer);
        createdFromBuffer -= clockSkew;
        
        _created = createdFromBuffer; // TODO: do we ever want to discard this???

        if (wantDebug) {
            quint64 lastEdited = getLastEdited();
            float editedAgo = getEditedAgo();
            QString agoAsString = formatSecondsElapsed(editedAgo);
            QString ageAsString = formatSecondsElapsed(getAge());
            qDebug() << "Loading entity " << getEntityItemID() << " from buffer...";
            qDebug() << "    _created =" << _created;
            qDebug() << "    age=" << getAge() << "seconds - " << ageAsString;
            qDebug() << "    lastEdited =" << lastEdited;
            qDebug() << "    ago=" << editedAgo << "seconds - " << agoAsString;
        }
        
        quint64 now = usecTimestampNow();
        quint64 lastEditedFromBuffer = 0;
        quint64 lastEditedFromBufferAdjusted = 0;

        // TODO: we could make this encoded as a delta from _created
        // _lastEdited
        memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer));
        dataAt += sizeof(lastEditedFromBuffer);
        bytesRead += sizeof(lastEditedFromBuffer);
        lastEditedFromBufferAdjusted = lastEditedFromBuffer - clockSkew;
        
        bool fromSameServerEdit = (lastEditedFromBuffer == _lastEditedFromRemoteInRemoteTime);

        if (wantDebug) {
            qDebug() << "data from server **************** ";
            qDebug() << "      entityItemID=" << getEntityItemID();
            qDebug() << "      now=" << now;
            qDebug() << "      getLastEdited()=" << getLastEdited();
            qDebug() << "      lastEditedFromBuffer=" << lastEditedFromBuffer << " (BEFORE clockskew adjust)";
            qDebug() << "      clockSkew=" << clockSkew;
            qDebug() << "      lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted << " (AFTER clockskew adjust)";
            qDebug() << "      _lastEditedFromRemote=" << _lastEditedFromRemote 
                                        << " (our local time the last server edit we accepted)";
            qDebug() << "      _lastEditedFromRemoteInRemoteTime=" << _lastEditedFromRemoteInRemoteTime 
                                        << " (remote time the last server edit we accepted)";
            qDebug() << "      fromSameServerEdit=" << fromSameServerEdit;
        }

        bool ignoreServerPacket = false; // assume we're use this server packet
        
        // If this packet is from the same server edit as the last packet we accepted from the server
        // we probably want to use it.
        if (fromSameServerEdit) {
            // If this is from the same sever packet, then check against any local changes since we got
            // the most recent packet from this server time
            if (_lastEdited > _lastEditedFromRemote) {
                ignoreServerPacket = true;
            }
        } else {
            // If this isn't from the same sever packet, then honor our skew adjusted times...
            // If we've changed our local tree more recently than the new data from this packet
            // then we will not be changing our values, instead we just read and skip the data
            if (_lastEdited > lastEditedFromBufferAdjusted) {
                ignoreServerPacket = true;
            }
        }
        
        if (ignoreServerPacket) {
            overwriteLocalData = false;
            if (wantDebug) {
                qDebug() << "IGNORING old data from server!!! ****************";
            }
        } else {

            if (wantDebug) {
                qDebug() << "USING NEW data from server!!! ****************";
            }

            _lastEdited = lastEditedFromBufferAdjusted;
            _lastEditedFromRemote = now;
            _lastEditedFromRemoteInRemoteTime = lastEditedFromBuffer;
            
            somethingChangedNotification(); // notify derived classes that something has changed
        }

        // last updated is stored as ByteCountCoded delta from lastEdited
        QByteArray encodedUpdateDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
        ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
        quint64 updateDelta = updateDeltaCoder;
        if (overwriteLocalData) {
            _lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited
            if (wantDebug) {
                qDebug() << "_lastUpdated=" << _lastUpdated;
                qDebug() << "_lastEdited=" << _lastEdited;
                qDebug() << "lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted;
            }
        }
        encodedUpdateDelta = updateDeltaCoder; // determine true length
        dataAt += encodedUpdateDelta.size();
        bytesRead += encodedUpdateDelta.size();

        // Property Flags
        QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size
        EntityPropertyFlags propertyFlags = encodedPropertyFlags;
        dataAt += propertyFlags.getEncodedLength();
        bytesRead += propertyFlags.getEncodedLength();
        
        READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, _position);

        // Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS
        if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) {
            if (propertyFlags.getHasProperty(PROP_RADIUS)) {
                float fromBuffer;
                memcpy(&fromBuffer, dataAt, sizeof(fromBuffer));
                dataAt += sizeof(fromBuffer);
                bytesRead += sizeof(fromBuffer);
                if (overwriteLocalData) {
                    setRadius(fromBuffer);
                }

                if (wantDebug) {
                    qDebug() << "    readEntityDataFromBuffer() OLD FORMAT... found PROP_RADIUS";
                }

            }
        } else {
            READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, _dimensions);
            if (wantDebug) {
                qDebug() << "    readEntityDataFromBuffer() NEW FORMAT... look for PROP_DIMENSIONS";
            }
        }
        
        if (wantDebug) {
            qDebug() << "    readEntityDataFromBuffer() _dimensions:" << getDimensionsInMeters() << " in meters";
        }
                
        READ_ENTITY_PROPERTY_QUAT(PROP_ROTATION, _rotation);
        READ_ENTITY_PROPERTY(PROP_MASS, float, _mass);
        READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, _velocity);
        READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, _gravity);
        READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping);
        READ_ENTITY_PROPERTY(PROP_LIFETIME, float, _lifetime);
        READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript);
        READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint);
        READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, _angularVelocity);
        READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping);
        READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible);
        READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, _ignoreForCollisions);
        READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, _collisionsWillMove);

        if (wantDebug) {
            qDebug() << "    readEntityDataFromBuffer() _registrationPoint:" << _registrationPoint;
            qDebug() << "    readEntityDataFromBuffer() _visible:" << _visible;
            qDebug() << "    readEntityDataFromBuffer() _ignoreForCollisions:" << _ignoreForCollisions;
            qDebug() << "    readEntityDataFromBuffer() _collisionsWillMove:" << _collisionsWillMove;
        }

        bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);

        recalculateCollisionShape();
    }
    return bytesRead;
}