mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 15:30:38 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into temp0
This commit is contained in:
commit
1a044b4ea6
18 changed files with 241 additions and 400 deletions
|
@ -274,7 +274,7 @@ function controller(wichSide) {
|
||||||
this.glowedIntersectingModel.isKnownID = false;
|
this.glowedIntersectingModel.isKnownID = false;
|
||||||
}
|
}
|
||||||
if (!this.grabbing) {
|
if (!this.grabbing) {
|
||||||
var intersection = Entities.findRayIntersection({
|
var intersection = Entities.findRayIntersectionBlocking({
|
||||||
origin: this.palmPosition,
|
origin: this.palmPosition,
|
||||||
direction: this.front
|
direction: this.front
|
||||||
});
|
});
|
||||||
|
@ -304,7 +304,7 @@ function controller(wichSide) {
|
||||||
if (this.grabbing) {
|
if (this.grabbing) {
|
||||||
if (!this.entityID.isKnownID) {
|
if (!this.entityID.isKnownID) {
|
||||||
print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
|
print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
|
||||||
this.entityID = Entities.findRayIntersection({
|
this.entityID = Entities.findRayIntersectionBlocking({
|
||||||
origin: this.palmPosition,
|
origin: this.palmPosition,
|
||||||
direction: this.front
|
direction: this.front
|
||||||
}).entityID;
|
}).entityID;
|
||||||
|
@ -475,7 +475,7 @@ function controller(wichSide) {
|
||||||
Vec3.print("Looking at: ", this.palmPosition);
|
Vec3.print("Looking at: ", this.palmPosition);
|
||||||
var pickRay = { origin: this.palmPosition,
|
var pickRay = { origin: this.palmPosition,
|
||||||
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) };
|
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) };
|
||||||
var foundIntersection = Entities.findRayIntersection(pickRay);
|
var foundIntersection = Entities.findRayIntersectionBlocking(pickRay);
|
||||||
|
|
||||||
if(!foundIntersection.accurate) {
|
if(!foundIntersection.accurate) {
|
||||||
print("No accurate intersection");
|
print("No accurate intersection");
|
||||||
|
|
|
@ -140,9 +140,17 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
||||||
ByteCountCoded<quint32> typeCoder = getType();
|
ByteCountCoded<quint32> typeCoder = getType();
|
||||||
QByteArray encodedType = typeCoder;
|
QByteArray encodedType = typeCoder;
|
||||||
|
|
||||||
quint64 updateDelta = getLastSimulated() <= getLastEdited() ? 0 : getLastSimulated() - getLastEdited();
|
// last updated (animations, non-physics changes)
|
||||||
|
quint64 updateDelta = getLastUpdated() <= getLastEdited() ? 0 : getLastUpdated() - getLastEdited();
|
||||||
ByteCountCoded<quint64> updateDeltaCoder = updateDelta;
|
ByteCountCoded<quint64> updateDeltaCoder = updateDelta;
|
||||||
QByteArray encodedUpdateDelta = updateDeltaCoder;
|
QByteArray encodedUpdateDelta = updateDeltaCoder;
|
||||||
|
|
||||||
|
// last simulated (velocity, angular velocity, physics changes)
|
||||||
|
quint64 simulatedDelta = getLastSimulated() <= getLastEdited() ? 0 : getLastSimulated() - getLastEdited();
|
||||||
|
ByteCountCoded<quint64> simulatedDeltaCoder = simulatedDelta;
|
||||||
|
QByteArray encodedSimulatedDelta = simulatedDeltaCoder;
|
||||||
|
|
||||||
|
|
||||||
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
|
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
|
||||||
EntityPropertyFlags requestedProperties = getEntityProperties(params);
|
EntityPropertyFlags requestedProperties = getEntityProperties(params);
|
||||||
EntityPropertyFlags propertiesDidntFit = requestedProperties;
|
EntityPropertyFlags propertiesDidntFit = requestedProperties;
|
||||||
|
@ -170,6 +178,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
||||||
bool successCreatedFits = false;
|
bool successCreatedFits = false;
|
||||||
bool successLastEditedFits = false;
|
bool successLastEditedFits = false;
|
||||||
bool successLastUpdatedFits = false;
|
bool successLastUpdatedFits = false;
|
||||||
|
bool successLastSimulatedFits = false;
|
||||||
bool successPropertyFlagsFits = false;
|
bool successPropertyFlagsFits = false;
|
||||||
int propertyFlagsOffset = 0;
|
int propertyFlagsOffset = 0;
|
||||||
int oldPropertyFlagsLength = 0;
|
int oldPropertyFlagsLength = 0;
|
||||||
|
@ -189,8 +198,11 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
||||||
if (successLastEditedFits) {
|
if (successLastEditedFits) {
|
||||||
successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
|
successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (successLastUpdatedFits) {
|
if (successLastUpdatedFits) {
|
||||||
|
successLastSimulatedFits = packetData->appendValue(encodedSimulatedDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (successLastSimulatedFits) {
|
||||||
propertyFlagsOffset = packetData->getUncompressedByteOffset();
|
propertyFlagsOffset = packetData->getUncompressedByteOffset();
|
||||||
encodedPropertyFlags = propertyFlags;
|
encodedPropertyFlags = propertyFlags;
|
||||||
oldPropertyFlagsLength = encodedPropertyFlags.length();
|
oldPropertyFlagsLength = encodedPropertyFlags.length();
|
||||||
|
@ -459,6 +471,25 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
dataAt += encodedUpdateDelta.size();
|
dataAt += encodedUpdateDelta.size();
|
||||||
bytesRead += encodedUpdateDelta.size();
|
bytesRead += encodedUpdateDelta.size();
|
||||||
|
|
||||||
|
// Newer bitstreams will have a last simulated and a last updated value
|
||||||
|
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) {
|
||||||
|
// last simulated is stored as ByteCountCoded delta from lastEdited
|
||||||
|
QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||||
|
ByteCountCoded<quint64> simulatedDeltaCoder = encodedSimulatedDelta;
|
||||||
|
quint64 simulatedDelta = simulatedDeltaCoder;
|
||||||
|
if (overwriteLocalData) {
|
||||||
|
_lastSimulated = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that
|
||||||
|
if (wantDebug) {
|
||||||
|
qDebug() << "_lastSimulated =" << _lastSimulated;
|
||||||
|
qDebug() << "_lastEdited=" << _lastEdited;
|
||||||
|
qDebug() << "lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
encodedSimulatedDelta = simulatedDeltaCoder; // determine true length
|
||||||
|
dataAt += encodedSimulatedDelta.size();
|
||||||
|
bytesRead += encodedSimulatedDelta.size();
|
||||||
|
}
|
||||||
|
|
||||||
// Property Flags
|
// Property Flags
|
||||||
QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size
|
QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||||
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
|
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
|
||||||
|
@ -520,7 +551,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
|
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
|
||||||
|
|
||||||
recalculateCollisionShape();
|
recalculateCollisionShape();
|
||||||
if (overwriteLocalData && (getDirtyFlags() & EntityItem::DIRTY_POSITION)) {
|
if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) {
|
||||||
|
// TODO: Andrew & Brad to discuss -- this probably should not be "now" but instead should be the last
|
||||||
|
// simulated time from server. The logic should maybe be: the position changed from the server, so the
|
||||||
|
// position we just set can be thought of as the position at the time it was last simulated by the
|
||||||
|
// server (clock skew adjusted). By setting it to "now" we are saying that the last position is to be
|
||||||
|
// considered to be the correct position for "now" which is likely in the future from when it actually
|
||||||
|
// was at that last known positition.
|
||||||
_lastSimulated = now;
|
_lastSimulated = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -607,11 +644,6 @@ bool EntityItem::isRestingOnSurface() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::simulate(const quint64& now) {
|
void EntityItem::simulate(const quint64& now) {
|
||||||
if (_physicsInfo) {
|
|
||||||
// we rely on bullet for simulation, so bail
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wantDebug = false;
|
bool wantDebug = false;
|
||||||
|
|
||||||
if (_lastSimulated == 0) {
|
if (_lastSimulated == 0) {
|
||||||
|
@ -661,9 +693,13 @@ void EntityItem::simulate(const quint64& now) {
|
||||||
qDebug() << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated;
|
qDebug() << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasAngularVelocity()) {
|
simulateKinematicMotion(timeElapsed);
|
||||||
glm::quat rotation = getRotation();
|
_lastSimulated = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityItem::simulateKinematicMotion(float timeElapsed) {
|
||||||
|
bool wantDebug = false;
|
||||||
|
if (hasAngularVelocity()) {
|
||||||
// angular damping
|
// angular damping
|
||||||
glm::vec3 angularVelocity = getAngularVelocity();
|
glm::vec3 angularVelocity = getAngularVelocity();
|
||||||
if (_angularDamping > 0.0f) {
|
if (_angularDamping > 0.0f) {
|
||||||
|
@ -679,6 +715,9 @@ void EntityItem::simulate(const quint64& now) {
|
||||||
|
|
||||||
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.1f; //
|
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.1f; //
|
||||||
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
|
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
|
||||||
|
if (angularSpeed > 0.0f) {
|
||||||
|
_dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE;
|
||||||
|
}
|
||||||
setAngularVelocity(ENTITY_ITEM_ZERO_VEC3);
|
setAngularVelocity(ENTITY_ITEM_ZERO_VEC3);
|
||||||
} else {
|
} else {
|
||||||
// NOTE: angularSpeed is currently in degrees/sec!!!
|
// NOTE: angularSpeed is currently in degrees/sec!!!
|
||||||
|
@ -686,7 +725,7 @@ void EntityItem::simulate(const quint64& now) {
|
||||||
float angle = timeElapsed * glm::radians(angularSpeed);
|
float angle = timeElapsed * glm::radians(angularSpeed);
|
||||||
glm::vec3 axis = _angularVelocity / angularSpeed;
|
glm::vec3 axis = _angularVelocity / angularSpeed;
|
||||||
glm::quat dQ = glm::angleAxis(angle, axis);
|
glm::quat dQ = glm::angleAxis(angle, axis);
|
||||||
rotation = glm::normalize(dQ * rotation);
|
glm::quat rotation = glm::normalize(dQ * getRotation());
|
||||||
setRotation(rotation);
|
setRotation(rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -722,77 +761,6 @@ void EntityItem::simulate(const quint64& now) {
|
||||||
|
|
||||||
position = newPosition;
|
position = newPosition;
|
||||||
|
|
||||||
// handle bounces off the ground... We bounce at the distance to the bottom of our entity
|
|
||||||
if (position.y <= getDistanceToBottomOfEntity()) {
|
|
||||||
velocity = velocity * glm::vec3(1,-1,1);
|
|
||||||
position.y = getDistanceToBottomOfEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply gravity
|
|
||||||
if (hasGravity()) {
|
|
||||||
// handle resting on surface case, this is definitely a bit of a hack, and it only works on the
|
|
||||||
// "ground" plane of the domain, but for now it's what we've got
|
|
||||||
if (isRestingOnSurface()) {
|
|
||||||
velocity.y = 0.0f;
|
|
||||||
position.y = getDistanceToBottomOfEntity();
|
|
||||||
} else {
|
|
||||||
velocity += getGravity() * timeElapsed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: we don't zero out very small velocities --> we rely on a remote Bullet simulation
|
|
||||||
// to tell us when the entity has stopped.
|
|
||||||
|
|
||||||
// NOTE: the simulation should NOT set any DirtyFlags on this entity
|
|
||||||
setPosition(position); // this will automatically recalculate our collision shape
|
|
||||||
setVelocity(velocity);
|
|
||||||
|
|
||||||
if (wantDebug) {
|
|
||||||
qDebug() << " new position:" << position;
|
|
||||||
qDebug() << " new velocity:" << velocity;
|
|
||||||
qDebug() << " new AACube:" << getMaximumAACube();
|
|
||||||
qDebug() << " old getAABox:" << getAABox();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastSimulated = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityItem::simulateSimpleKinematicMotion(float timeElapsed) {
|
|
||||||
if (hasAngularVelocity()) {
|
|
||||||
// angular damping
|
|
||||||
glm::vec3 angularVelocity = getAngularVelocity();
|
|
||||||
if (_angularDamping > 0.0f) {
|
|
||||||
angularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
|
|
||||||
setAngularVelocity(angularVelocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
float angularSpeed = glm::length(_angularVelocity);
|
|
||||||
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.1f; //
|
|
||||||
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
|
|
||||||
setAngularVelocity(ENTITY_ITEM_ZERO_VEC3);
|
|
||||||
} else {
|
|
||||||
// NOTE: angularSpeed is currently in degrees/sec!!!
|
|
||||||
// TODO: Andrew to convert to radians/sec
|
|
||||||
float angle = timeElapsed * glm::radians(angularSpeed);
|
|
||||||
glm::vec3 axis = _angularVelocity / angularSpeed;
|
|
||||||
glm::quat dQ = glm::angleAxis(angle, axis);
|
|
||||||
glm::quat rotation = getRotation();
|
|
||||||
rotation = glm::normalize(dQ * rotation);
|
|
||||||
setRotation(rotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasVelocity()) {
|
|
||||||
// linear damping
|
|
||||||
glm::vec3 velocity = getVelocity();
|
|
||||||
if (_damping > 0.0f) {
|
|
||||||
velocity *= powf(1.0f - _damping, timeElapsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
// integrate position forward
|
|
||||||
glm::vec3 position = getPosition() + (velocity * timeElapsed);
|
|
||||||
|
|
||||||
// apply gravity
|
// apply gravity
|
||||||
if (hasGravity()) {
|
if (hasGravity()) {
|
||||||
// handle resting on surface case, this is definitely a bit of a hack, and it only works on the
|
// handle resting on surface case, this is definitely a bit of a hack, and it only works on the
|
||||||
|
@ -800,9 +768,24 @@ void EntityItem::simulateSimpleKinematicMotion(float timeElapsed) {
|
||||||
velocity += getGravity() * timeElapsed;
|
velocity += getGravity() * timeElapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: the simulation should NOT set any DirtyFlags on this entity
|
float speed = glm::length(velocity);
|
||||||
setPosition(position); // this will automatically recalculate our collision shape
|
const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f / (float)TREE_SCALE; // 1mm/sec
|
||||||
setVelocity(velocity);
|
if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) {
|
||||||
|
setVelocity(ENTITY_ITEM_ZERO_VEC3);
|
||||||
|
if (speed > 0.0f) {
|
||||||
|
_dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setPosition(position);
|
||||||
|
setVelocity(velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wantDebug) {
|
||||||
|
qDebug() << " new position:" << position;
|
||||||
|
qDebug() << " new velocity:" << velocity;
|
||||||
|
qDebug() << " new AACube:" << getMaximumAACube();
|
||||||
|
qDebug() << " old getAABox:" << getAABox();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,7 +869,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
if (_created != UNKNOWN_CREATED_TIME) {
|
if (_created != UNKNOWN_CREATED_TIME) {
|
||||||
setLastEdited(now);
|
setLastEdited(now);
|
||||||
}
|
}
|
||||||
if (getDirtyFlags() & EntityItem::DIRTY_POSITION) {
|
if (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) {
|
||||||
|
// TODO: Andrew & Brad to discuss. Is this correct? Maybe it is. Need to think through all cases.
|
||||||
_lastSimulated = now;
|
_lastSimulated = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ public:
|
||||||
|
|
||||||
void recordCreationTime(); // set _created to 'now'
|
void recordCreationTime(); // set _created to 'now'
|
||||||
quint64 getLastSimulated() const { return _lastSimulated; } /// Last simulated time of this entity universal usecs
|
quint64 getLastSimulated() const { return _lastSimulated; } /// Last simulated time of this entity universal usecs
|
||||||
|
void setLastSimulated(quint64 now) { _lastSimulated = now; }
|
||||||
|
|
||||||
/// Last edited time of this entity universal usecs
|
/// Last edited time of this entity universal usecs
|
||||||
quint64 getLastEdited() const { return _lastEdited; }
|
quint64 getLastEdited() const { return _lastEdited; }
|
||||||
|
@ -125,11 +126,11 @@ public:
|
||||||
|
|
||||||
// perform update
|
// perform update
|
||||||
virtual void update(const quint64& now) { _lastUpdated = now; }
|
virtual void update(const quint64& now) { _lastUpdated = now; }
|
||||||
|
quint64 getLastUpdated() const { return _lastUpdated; }
|
||||||
|
|
||||||
// perform linear extrapolation for SimpleEntitySimulation
|
// perform linear extrapolation for SimpleEntitySimulation
|
||||||
void simulate(const quint64& now);
|
void simulate(const quint64& now);
|
||||||
|
void simulateKinematicMotion(float timeElapsed);
|
||||||
void simulateSimpleKinematicMotion(float timeElapsed);
|
|
||||||
|
|
||||||
virtual bool needsToCallUpdate() const { return false; }
|
virtual bool needsToCallUpdate() const { return false; }
|
||||||
|
|
||||||
|
@ -296,9 +297,10 @@ protected:
|
||||||
QUuid _id;
|
QUuid _id;
|
||||||
uint32_t _creatorTokenID;
|
uint32_t _creatorTokenID;
|
||||||
bool _newlyCreated;
|
bool _newlyCreated;
|
||||||
quint64 _lastSimulated; // last time this entity called simulate()
|
quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, and physics changes
|
||||||
quint64 _lastUpdated; // last time this entity called update()
|
quint64 _lastUpdated; // last time this entity called update(), this includes animations and non-physics changes
|
||||||
quint64 _lastEdited; // last official local or remote edit time
|
quint64 _lastEdited; // last official local or remote edit time
|
||||||
|
|
||||||
quint64 _lastEditedFromRemote; // last time we received and edit from the server
|
quint64 _lastEditedFromRemote; // last time we received and edit from the server
|
||||||
quint64 _lastEditedFromRemoteInRemoteTime; // last time we received and edit from the server (in server-time-frame)
|
quint64 _lastEditedFromRemoteInRemoteTime; // last time we received and edit from the server (in server-time-frame)
|
||||||
quint64 _created;
|
quint64 _created;
|
||||||
|
|
|
@ -60,7 +60,8 @@ public:
|
||||||
// own definition. Implement these to allow your octree based server to support editing
|
// own definition. Implement these to allow your octree based server to support editing
|
||||||
virtual bool getWantSVOfileVersions() const { return true; }
|
virtual bool getWantSVOfileVersions() const { return true; }
|
||||||
virtual PacketType expectedDataPacketType() const { return PacketTypeEntityData; }
|
virtual PacketType expectedDataPacketType() const { return PacketTypeEntityData; }
|
||||||
virtual bool canProcessVersion(PacketVersion thisVersion) const { return true; } // we support all versions
|
virtual bool canProcessVersion(PacketVersion thisVersion) const
|
||||||
|
{ return thisVersion >= VERSION_ENTITIES_SUPPORT_SPLIT_MTU; } // we support all versions with split mtu
|
||||||
virtual bool handlesEditPacketType(PacketType packetType) const;
|
virtual bool handlesEditPacketType(PacketType packetType) const;
|
||||||
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||||
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode);
|
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode);
|
||||||
|
|
|
@ -81,17 +81,6 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
return somethingChanged;
|
return somethingChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int ModelEntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
|
|
||||||
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {
|
|
||||||
return oldVersionReadEntityDataFromBuffer(data, bytesLeftToRead, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// let our base class do most of the work... it will call us back for our porition...
|
|
||||||
return EntityItem::readEntityDataFromBuffer(data, bytesLeftToRead, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
ReadBitstreamToTreeParams& args,
|
ReadBitstreamToTreeParams& args,
|
||||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
|
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
|
||||||
|
@ -131,122 +120,6 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
|
|
||||||
|
|
||||||
int bytesRead = 0;
|
|
||||||
if (bytesLeftToRead >= expectedBytes()) {
|
|
||||||
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
|
|
||||||
|
|
||||||
const unsigned char* dataAt = data;
|
|
||||||
|
|
||||||
// id
|
|
||||||
// this old bitstream format had 32bit IDs. They are obsolete and need to be replaced with our new UUID
|
|
||||||
// format. We can simply read and ignore the old ID since they should not be repeated. This code should only
|
|
||||||
// run on loading from an old file.
|
|
||||||
quint32 oldID;
|
|
||||||
memcpy(&oldID, dataAt, sizeof(oldID));
|
|
||||||
dataAt += sizeof(oldID);
|
|
||||||
bytesRead += sizeof(oldID);
|
|
||||||
_id = QUuid::createUuid();
|
|
||||||
|
|
||||||
// _lastUpdated
|
|
||||||
memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated));
|
|
||||||
dataAt += sizeof(_lastUpdated);
|
|
||||||
bytesRead += sizeof(_lastUpdated);
|
|
||||||
_lastUpdated -= clockSkew;
|
|
||||||
|
|
||||||
// _lastEdited
|
|
||||||
memcpy(&_lastEdited, dataAt, sizeof(_lastEdited));
|
|
||||||
dataAt += sizeof(_lastEdited);
|
|
||||||
bytesRead += sizeof(_lastEdited);
|
|
||||||
_lastEdited -= clockSkew;
|
|
||||||
_created = _lastEdited; // NOTE: old models didn't have age or created time, assume their last edit was a create
|
|
||||||
|
|
||||||
QString ageAsString = formatSecondsElapsed(getAge());
|
|
||||||
qDebug() << "Loading old model file, _created = _lastEdited =" << _created
|
|
||||||
<< " age=" << getAge() << "seconds - " << ageAsString
|
|
||||||
<< "old ID=" << oldID << "new ID=" << _id;
|
|
||||||
|
|
||||||
// radius
|
|
||||||
float radius;
|
|
||||||
memcpy(&radius, dataAt, sizeof(radius));
|
|
||||||
dataAt += sizeof(radius);
|
|
||||||
bytesRead += sizeof(radius);
|
|
||||||
setRadius(radius);
|
|
||||||
|
|
||||||
// position
|
|
||||||
memcpy(&_position, dataAt, sizeof(_position));
|
|
||||||
dataAt += sizeof(_position);
|
|
||||||
bytesRead += sizeof(_position);
|
|
||||||
|
|
||||||
// color
|
|
||||||
memcpy(&_color, dataAt, sizeof(_color));
|
|
||||||
dataAt += sizeof(_color);
|
|
||||||
bytesRead += sizeof(_color);
|
|
||||||
|
|
||||||
// TODO: how to handle this? Presumable, this would only ever be true if the model file was saved with
|
|
||||||
// a model being in a shouldBeDeleted state. Which seems unlikely. But if it happens, maybe we should delete the entity after loading?
|
|
||||||
// shouldBeDeleted
|
|
||||||
bool shouldBeDeleted = false;
|
|
||||||
memcpy(&shouldBeDeleted, dataAt, sizeof(shouldBeDeleted));
|
|
||||||
dataAt += sizeof(shouldBeDeleted);
|
|
||||||
bytesRead += sizeof(shouldBeDeleted);
|
|
||||||
if (shouldBeDeleted) {
|
|
||||||
qDebug() << "UNEXPECTED - read shouldBeDeleted=TRUE from an old format file";
|
|
||||||
}
|
|
||||||
|
|
||||||
// modelURL
|
|
||||||
uint16_t modelURLLength;
|
|
||||||
memcpy(&modelURLLength, dataAt, sizeof(modelURLLength));
|
|
||||||
dataAt += sizeof(modelURLLength);
|
|
||||||
bytesRead += sizeof(modelURLLength);
|
|
||||||
QString modelURLString((const char*)dataAt);
|
|
||||||
setModelURL(modelURLString);
|
|
||||||
dataAt += modelURLLength;
|
|
||||||
bytesRead += modelURLLength;
|
|
||||||
|
|
||||||
// rotation
|
|
||||||
int bytes = unpackOrientationQuatFromBytes(dataAt, _rotation);
|
|
||||||
dataAt += bytes;
|
|
||||||
bytesRead += bytes;
|
|
||||||
|
|
||||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ANIMATION) {
|
|
||||||
// animationURL
|
|
||||||
uint16_t animationURLLength;
|
|
||||||
memcpy(&animationURLLength, dataAt, sizeof(animationURLLength));
|
|
||||||
dataAt += sizeof(animationURLLength);
|
|
||||||
bytesRead += sizeof(animationURLLength);
|
|
||||||
QString animationURLString((const char*)dataAt);
|
|
||||||
setAnimationURL(animationURLString);
|
|
||||||
dataAt += animationURLLength;
|
|
||||||
bytesRead += animationURLLength;
|
|
||||||
|
|
||||||
// animationIsPlaying
|
|
||||||
bool animationIsPlaying;
|
|
||||||
memcpy(&animationIsPlaying, dataAt, sizeof(animationIsPlaying));
|
|
||||||
dataAt += sizeof(animationIsPlaying);
|
|
||||||
bytesRead += sizeof(animationIsPlaying);
|
|
||||||
setAnimationIsPlaying(animationIsPlaying);
|
|
||||||
|
|
||||||
// animationFrameIndex
|
|
||||||
float animationFrameIndex;
|
|
||||||
memcpy(&animationFrameIndex, dataAt, sizeof(animationFrameIndex));
|
|
||||||
dataAt += sizeof(animationFrameIndex);
|
|
||||||
bytesRead += sizeof(animationFrameIndex);
|
|
||||||
setAnimationFrameIndex(animationFrameIndex);
|
|
||||||
|
|
||||||
// animationFPS
|
|
||||||
float animationFPS;
|
|
||||||
memcpy(&animationFPS, dataAt, sizeof(animationFPS));
|
|
||||||
dataAt += sizeof(animationFPS);
|
|
||||||
bytesRead += sizeof(animationFPS);
|
|
||||||
setAnimationFPS(animationFPS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||||
EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
|
EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
|
||||||
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||||
|
|
|
@ -40,7 +40,6 @@ public:
|
||||||
OctreeElement::AppendState& appendState) const;
|
OctreeElement::AppendState& appendState) const;
|
||||||
|
|
||||||
|
|
||||||
virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
|
||||||
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
ReadBitstreamToTreeParams& args,
|
ReadBitstreamToTreeParams& args,
|
||||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||||
|
@ -116,8 +115,6 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/// For reading models from pre V3 bitstreams
|
|
||||||
int oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
|
||||||
bool isAnimatingSomething() const;
|
bool isAnimatingSomething() const;
|
||||||
|
|
||||||
rgbColor _color;
|
rgbColor _color;
|
||||||
|
|
|
@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
||||||
return 1;
|
return 1;
|
||||||
case PacketTypeEntityAddOrEdit:
|
case PacketTypeEntityAddOrEdit:
|
||||||
case PacketTypeEntityData:
|
case PacketTypeEntityData:
|
||||||
return VERSION_ENTITIES_HAVE_USER_DATA;
|
return VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME;
|
||||||
case PacketTypeEntityErase:
|
case PacketTypeEntityErase:
|
||||||
return 2;
|
return 2;
|
||||||
case PacketTypeAudioStreamStats:
|
case PacketTypeAudioStreamStats:
|
||||||
|
|
|
@ -126,6 +126,7 @@ const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_
|
||||||
const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4;
|
const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4;
|
||||||
const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5;
|
const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5;
|
||||||
const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6;
|
const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6;
|
||||||
|
const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7;
|
||||||
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
|
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
|
||||||
|
|
||||||
#endif // hifi_PacketHeaders_h
|
#endif // hifi_PacketHeaders_h
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include "BulletUtil.h"
|
#include "BulletUtil.h"
|
||||||
#include "EntityMotionState.h"
|
#include "EntityMotionState.h"
|
||||||
#include "SimpleEntityKinematicController.h"
|
#include "PhysicsEngine.h"
|
||||||
|
|
||||||
|
|
||||||
QSet<EntityItem*>* _outgoingEntityList;
|
QSet<EntityItem*>* _outgoingEntityList;
|
||||||
|
@ -41,8 +41,6 @@ EntityMotionState::~EntityMotionState() {
|
||||||
assert(_entity);
|
assert(_entity);
|
||||||
_entity->setPhysicsInfo(NULL);
|
_entity->setPhysicsInfo(NULL);
|
||||||
_entity = NULL;
|
_entity = NULL;
|
||||||
delete _kinematicController;
|
|
||||||
_kinematicController = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionType EntityMotionState::computeMotionType() const {
|
MotionType EntityMotionState::computeMotionType() const {
|
||||||
|
@ -52,13 +50,16 @@ MotionType EntityMotionState::computeMotionType() const {
|
||||||
return _entity->isMoving() ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC;
|
return _entity->isMoving() ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::addKinematicController() {
|
void EntityMotionState::updateKinematicState(uint32_t substep) {
|
||||||
if (!_kinematicController) {
|
setKinematic(_entity->isMoving(), substep);
|
||||||
_kinematicController = new SimpleEntityKinematicController(_entity);
|
}
|
||||||
_kinematicController->start();
|
|
||||||
} else {
|
void EntityMotionState::stepKinematicSimulation(quint64 now) {
|
||||||
_kinematicController->start();
|
assert(_isKinematic);
|
||||||
}
|
// NOTE: this is non-physical kinematic motion which steps to real run-time (now)
|
||||||
|
// which is different from physical kinematic motion (inside getWorldTransform())
|
||||||
|
// which steps in physics simulation time.
|
||||||
|
_entity->simulate(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This callback is invoked by the physics simulation in two cases:
|
// This callback is invoked by the physics simulation in two cases:
|
||||||
|
@ -67,8 +68,16 @@ void EntityMotionState::addKinematicController() {
|
||||||
// (2) at the beginning of each simulation frame for KINEMATIC RigidBody's --
|
// (2) at the beginning of each simulation frame for KINEMATIC RigidBody's --
|
||||||
// it is an opportunity for outside code to update the object's simulation position
|
// it is an opportunity for outside code to update the object's simulation position
|
||||||
void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
|
void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
|
||||||
if (_kinematicController && _kinematicController->isRunning()) {
|
if (_isKinematic) {
|
||||||
_kinematicController->stepForward();
|
// This is physical kinematic motion which steps strictly by the subframe count
|
||||||
|
// of the physics simulation.
|
||||||
|
uint32_t substep = PhysicsEngine::getNumSubsteps();
|
||||||
|
float dt = (substep - _lastKinematicSubstep) * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
||||||
|
_entity->simulateKinematicMotion(dt);
|
||||||
|
_entity->setLastSimulated(usecTimestampNow());
|
||||||
|
|
||||||
|
// bypass const-ness so we can remember the substep
|
||||||
|
const_cast<EntityMotionState*>(this)->_lastKinematicSubstep = substep;
|
||||||
}
|
}
|
||||||
worldTrans.setOrigin(glmToBullet(_entity->getPositionInMeters() - ObjectMotionState::getWorldOffset()));
|
worldTrans.setOrigin(glmToBullet(_entity->getPositionInMeters() - ObjectMotionState::getWorldOffset()));
|
||||||
worldTrans.setRotation(glmToBullet(_entity->getRotation()));
|
worldTrans.setRotation(glmToBullet(_entity->getRotation()));
|
||||||
|
@ -208,6 +217,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
||||||
if (_numNonMovingUpdates <= 1) {
|
if (_numNonMovingUpdates <= 1) {
|
||||||
// we only update lastEdited when we're sending new physics data
|
// we only update lastEdited when we're sending new physics data
|
||||||
// (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data)
|
// (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data)
|
||||||
|
// NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly
|
||||||
quint64 lastSimulated = _entity->getLastSimulated();
|
quint64 lastSimulated = _entity->getLastSimulated();
|
||||||
_entity->setLastEdited(lastSimulated);
|
_entity->setLastEdited(lastSimulated);
|
||||||
properties.setLastEdited(lastSimulated);
|
properties.setLastEdited(lastSimulated);
|
||||||
|
@ -229,12 +239,14 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
||||||
uint32_t EntityMotionState::getIncomingDirtyFlags() const {
|
uint32_t EntityMotionState::getIncomingDirtyFlags() const {
|
||||||
uint32_t dirtyFlags = _entity->getDirtyFlags();
|
uint32_t dirtyFlags = _entity->getDirtyFlags();
|
||||||
|
|
||||||
// we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings
|
if (_body) {
|
||||||
int bodyFlags = _body->getCollisionFlags();
|
// we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings
|
||||||
bool isMoving = _entity->isMoving();
|
int bodyFlags = _body->getCollisionFlags();
|
||||||
if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) ||
|
bool isMoving = _entity->isMoving();
|
||||||
(bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) {
|
if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) ||
|
||||||
dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE;
|
(bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) {
|
||||||
|
dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return dirtyFlags;
|
return dirtyFlags;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
#include <AACube.h>
|
#include <AACube.h>
|
||||||
|
|
||||||
#include "KinematicController.h"
|
|
||||||
#include "ObjectMotionState.h"
|
#include "ObjectMotionState.h"
|
||||||
|
|
||||||
class EntityItem;
|
class EntityItem;
|
||||||
|
@ -39,8 +38,8 @@ public:
|
||||||
/// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem
|
/// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem
|
||||||
MotionType computeMotionType() const;
|
MotionType computeMotionType() const;
|
||||||
|
|
||||||
// virtual override for ObjectMotionState
|
void updateKinematicState(uint32_t substep);
|
||||||
void addKinematicController();
|
void stepKinematicSimulation(quint64 now);
|
||||||
|
|
||||||
// this relays incoming position/rotation to the RigidBody
|
// this relays incoming position/rotation to the RigidBody
|
||||||
void getWorldTransform(btTransform& worldTrans) const;
|
void getWorldTransform(btTransform& worldTrans) const;
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
//
|
|
||||||
// KinematicController.cpp
|
|
||||||
// libraries/physcis/src
|
|
||||||
//
|
|
||||||
// Created by Andrew Meadows 2015.01.13
|
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "KinematicController.h"
|
|
||||||
#include "PhysicsEngine.h"
|
|
||||||
|
|
||||||
KinematicController::KinematicController() {
|
|
||||||
_lastSubstep = PhysicsEngine::getNumSubsteps();
|
|
||||||
}
|
|
||||||
|
|
||||||
void KinematicController::start() {
|
|
||||||
_enabled = true;
|
|
||||||
_lastSubstep = PhysicsEngine::getNumSubsteps();
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
//
|
|
||||||
// KinematicController.h
|
|
||||||
// libraries/physcis/src
|
|
||||||
//
|
|
||||||
// Created by Andrew Meadows 2015.01.13
|
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef hifi_KinematicController_h
|
|
||||||
#define hifi_KinematicController_h
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/// KinematicController defines an API for derived classes.
|
|
||||||
|
|
||||||
class KinematicController {
|
|
||||||
public:
|
|
||||||
KinematicController();
|
|
||||||
|
|
||||||
virtual ~KinematicController() {}
|
|
||||||
|
|
||||||
virtual void stepForward() = 0;
|
|
||||||
|
|
||||||
void start();
|
|
||||||
void stop() { _enabled = false; }
|
|
||||||
bool isRunning() const { return _enabled; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool _enabled = false;
|
|
||||||
uint32_t _lastSubstep;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_KinematicController_h
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "BulletUtil.h"
|
#include "BulletUtil.h"
|
||||||
#include "KinematicController.h"
|
|
||||||
#include "ObjectMotionState.h"
|
#include "ObjectMotionState.h"
|
||||||
#include "PhysicsEngine.h"
|
#include "PhysicsEngine.h"
|
||||||
|
|
||||||
|
@ -56,10 +55,6 @@ ObjectMotionState::ObjectMotionState() :
|
||||||
ObjectMotionState::~ObjectMotionState() {
|
ObjectMotionState::~ObjectMotionState() {
|
||||||
// NOTE: you MUST remove this MotionState from the world before you call the dtor.
|
// NOTE: you MUST remove this MotionState from the world before you call the dtor.
|
||||||
assert(_body == NULL);
|
assert(_body == NULL);
|
||||||
if (_kinematicController) {
|
|
||||||
delete _kinematicController;
|
|
||||||
_kinematicController = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectMotionState::setFriction(float friction) {
|
void ObjectMotionState::setFriction(float friction) {
|
||||||
|
@ -108,7 +103,6 @@ bool ObjectMotionState::doesNotNeedToSendUpdate() const {
|
||||||
|
|
||||||
bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) {
|
bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) {
|
||||||
assert(_body);
|
assert(_body);
|
||||||
|
|
||||||
// if we've never checked before, our _sentFrame will be 0, and we need to initialize our state
|
// if we've never checked before, our _sentFrame will be 0, and we need to initialize our state
|
||||||
if (_sentFrame == 0) {
|
if (_sentFrame == 0) {
|
||||||
_sentPosition = bulletToGLM(_body->getWorldTransform().getOrigin());
|
_sentPosition = bulletToGLM(_body->getWorldTransform().getOrigin());
|
||||||
|
@ -174,13 +168,6 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) {
|
||||||
return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT);
|
return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectMotionState::removeKinematicController() {
|
|
||||||
if (_kinematicController) {
|
|
||||||
delete _kinematicController;
|
|
||||||
_kinematicController = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectMotionState::setRigidBody(btRigidBody* body) {
|
void ObjectMotionState::setRigidBody(btRigidBody* body) {
|
||||||
// give the body a (void*) back-pointer to this ObjectMotionState
|
// give the body a (void*) back-pointer to this ObjectMotionState
|
||||||
if (_body != body) {
|
if (_body != body) {
|
||||||
|
@ -193,3 +180,8 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectMotionState::setKinematic(bool kinematic, uint32_t substep) {
|
||||||
|
_isKinematic = kinematic;
|
||||||
|
_lastKinematicSubstep = substep;
|
||||||
|
}
|
||||||
|
|
|
@ -46,7 +46,6 @@ const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_POSITION | Entit
|
||||||
|
|
||||||
|
|
||||||
class OctreeEditPacketSender;
|
class OctreeEditPacketSender;
|
||||||
class KinematicController;
|
|
||||||
|
|
||||||
class ObjectMotionState : public btMotionState {
|
class ObjectMotionState : public btMotionState {
|
||||||
public:
|
public:
|
||||||
|
@ -93,11 +92,15 @@ public:
|
||||||
|
|
||||||
virtual MotionType computeMotionType() const = 0;
|
virtual MotionType computeMotionType() const = 0;
|
||||||
|
|
||||||
virtual void addKinematicController() = 0;
|
virtual void updateKinematicState(uint32_t substep) = 0;
|
||||||
virtual void removeKinematicController();
|
|
||||||
|
|
||||||
btRigidBody* getRigidBody() const { return _body; }
|
btRigidBody* getRigidBody() const { return _body; }
|
||||||
|
|
||||||
|
bool isKinematic() const { return _isKinematic; }
|
||||||
|
|
||||||
|
void setKinematic(bool kinematic, uint32_t substep);
|
||||||
|
virtual void stepKinematicSimulation(quint64 now) = 0;
|
||||||
|
|
||||||
friend class PhysicsEngine;
|
friend class PhysicsEngine;
|
||||||
protected:
|
protected:
|
||||||
void setRigidBody(btRigidBody* body);
|
void setRigidBody(btRigidBody* body);
|
||||||
|
@ -114,6 +117,9 @@ protected:
|
||||||
|
|
||||||
btRigidBody* _body;
|
btRigidBody* _body;
|
||||||
|
|
||||||
|
bool _isKinematic = false;
|
||||||
|
uint32_t _lastKinematicSubstep = 0;
|
||||||
|
|
||||||
bool _sentMoving; // true if last update was moving
|
bool _sentMoving; // true if last update was moving
|
||||||
int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects
|
int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects
|
||||||
|
|
||||||
|
@ -124,8 +130,6 @@ protected:
|
||||||
glm::vec3 _sentVelocity;
|
glm::vec3 _sentVelocity;
|
||||||
glm::vec3 _sentAngularVelocity; // radians per second
|
glm::vec3 _sentAngularVelocity; // radians per second
|
||||||
glm::vec3 _sentAcceleration;
|
glm::vec3 _sentAcceleration;
|
||||||
|
|
||||||
KinematicController* _kinematicController = NULL;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ObjectMotionState_h
|
#endif // hifi_ObjectMotionState_h
|
||||||
|
|
|
@ -62,7 +62,13 @@ void PhysicsEngine::addEntityInternal(EntityItem* entity) {
|
||||||
entity->setPhysicsInfo(static_cast<void*>(motionState));
|
entity->setPhysicsInfo(static_cast<void*>(motionState));
|
||||||
_entityMotionStates.insert(motionState);
|
_entityMotionStates.insert(motionState);
|
||||||
addObject(shapeInfo, shape, motionState);
|
addObject(shapeInfo, shape, motionState);
|
||||||
} else {
|
} else if (entity->isMoving()) {
|
||||||
|
EntityMotionState* motionState = new EntityMotionState(entity);
|
||||||
|
entity->setPhysicsInfo(static_cast<void*>(motionState));
|
||||||
|
_entityMotionStates.insert(motionState);
|
||||||
|
|
||||||
|
motionState->setKinematic(true, _numSubsteps);
|
||||||
|
_nonPhysicalKinematicObjects.insert(motionState);
|
||||||
// We failed to add the entity to the simulation. Probably because we couldn't create a shape for it.
|
// We failed to add the entity to the simulation. Probably because we couldn't create a shape for it.
|
||||||
//qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine";
|
//qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine";
|
||||||
}
|
}
|
||||||
|
@ -74,10 +80,16 @@ void PhysicsEngine::removeEntityInternal(EntityItem* entity) {
|
||||||
void* physicsInfo = entity->getPhysicsInfo();
|
void* physicsInfo = entity->getPhysicsInfo();
|
||||||
if (physicsInfo) {
|
if (physicsInfo) {
|
||||||
EntityMotionState* motionState = static_cast<EntityMotionState*>(physicsInfo);
|
EntityMotionState* motionState = static_cast<EntityMotionState*>(physicsInfo);
|
||||||
removeObject(motionState);
|
if (motionState->getRigidBody()) {
|
||||||
|
removeObject(motionState);
|
||||||
|
} else {
|
||||||
|
// only need to hunt in this list when there is no RigidBody
|
||||||
|
_nonPhysicalKinematicObjects.remove(motionState);
|
||||||
|
}
|
||||||
_entityMotionStates.remove(motionState);
|
_entityMotionStates.remove(motionState);
|
||||||
_incomingChanges.remove(motionState);
|
_incomingChanges.remove(motionState);
|
||||||
_outgoingPackets.remove(motionState);
|
_outgoingPackets.remove(motionState);
|
||||||
|
// NOTE: EntityMotionState dtor will remove its backpointer from EntityItem
|
||||||
delete motionState;
|
delete motionState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +129,7 @@ void PhysicsEngine::clearEntitiesInternal() {
|
||||||
delete (*stateItr);
|
delete (*stateItr);
|
||||||
}
|
}
|
||||||
_entityMotionStates.clear();
|
_entityMotionStates.clear();
|
||||||
|
_nonPhysicalKinematicObjects.clear();
|
||||||
_incomingChanges.clear();
|
_incomingChanges.clear();
|
||||||
_outgoingPackets.clear();
|
_outgoingPackets.clear();
|
||||||
}
|
}
|
||||||
|
@ -127,19 +140,75 @@ void PhysicsEngine::relayIncomingChangesToSimulation() {
|
||||||
QSet<ObjectMotionState*>::iterator stateItr = _incomingChanges.begin();
|
QSet<ObjectMotionState*>::iterator stateItr = _incomingChanges.begin();
|
||||||
while (stateItr != _incomingChanges.end()) {
|
while (stateItr != _incomingChanges.end()) {
|
||||||
ObjectMotionState* motionState = *stateItr;
|
ObjectMotionState* motionState = *stateItr;
|
||||||
|
++stateItr;
|
||||||
uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS;
|
uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS;
|
||||||
|
|
||||||
|
bool removeMotionState = false;
|
||||||
btRigidBody* body = motionState->getRigidBody();
|
btRigidBody* body = motionState->getRigidBody();
|
||||||
if (body) {
|
if (body) {
|
||||||
if (flags & HARD_DIRTY_PHYSICS_FLAGS) {
|
if (flags & HARD_DIRTY_PHYSICS_FLAGS) {
|
||||||
// a HARD update requires the body be pulled out of physics engine, changed, then reinserted
|
// a HARD update requires the body be pulled out of physics engine, changed, then reinserted
|
||||||
// but it also handles all EASY changes
|
// but it also handles all EASY changes
|
||||||
updateObjectHard(body, motionState, flags);
|
bool success = updateObjectHard(body, motionState, flags);
|
||||||
|
if (!success) {
|
||||||
|
// NOTE: since updateObjectHard() failed we know that motionState has been removed
|
||||||
|
// from simulation and body has been deleted. Depending on what else has changed
|
||||||
|
// we might need to remove motionState altogether...
|
||||||
|
if (flags & EntityItem::DIRTY_VELOCITY) {
|
||||||
|
motionState->updateKinematicState(_numSubsteps);
|
||||||
|
if (motionState->isKinematic()) {
|
||||||
|
// all is NOT lost, we still need to move this object around kinematically
|
||||||
|
_nonPhysicalKinematicObjects.insert(motionState);
|
||||||
|
} else {
|
||||||
|
// no need to keep motionState around
|
||||||
|
removeMotionState = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no need to keep motionState around
|
||||||
|
removeMotionState = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (flags) {
|
} else if (flags) {
|
||||||
// an EASY update does NOT require that the body be pulled out of physics engine
|
// an EASY update does NOT require that the body be pulled out of physics engine
|
||||||
// hence the MotionState has all the knowledge and authority to perform the update.
|
// hence the MotionState has all the knowledge and authority to perform the update.
|
||||||
motionState->updateObjectEasy(flags, _numSubsteps);
|
motionState->updateObjectEasy(flags, _numSubsteps);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// the only way we should ever get here (motionState exists but no body) is when the object
|
||||||
|
// is undergoing non-physical kinematic motion.
|
||||||
|
assert(_nonPhysicalKinematicObjects.contains(motionState));
|
||||||
|
|
||||||
|
// it is possible that the changes are such that the object can now be added to the physical simulation
|
||||||
|
if (flags & EntityItem::DIRTY_SHAPE) {
|
||||||
|
ShapeInfo shapeInfo;
|
||||||
|
motionState->computeShapeInfo(shapeInfo);
|
||||||
|
btCollisionShape* shape = _shapeManager.getShape(shapeInfo);
|
||||||
|
if (shape) {
|
||||||
|
addObject(shapeInfo, shape, motionState);
|
||||||
|
_nonPhysicalKinematicObjects.remove(motionState);
|
||||||
|
} else if (flags & EntityItem::DIRTY_VELOCITY) {
|
||||||
|
// although we couldn't add the object to the simulation, might need to update kinematic motion...
|
||||||
|
motionState->updateKinematicState(_numSubsteps);
|
||||||
|
if (!motionState->isKinematic()) {
|
||||||
|
_nonPhysicalKinematicObjects.remove(motionState);
|
||||||
|
removeMotionState = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (flags & EntityItem::DIRTY_VELOCITY) {
|
||||||
|
// although we still can't add to physics simulation, might need to update kinematic motion...
|
||||||
|
motionState->updateKinematicState(_numSubsteps);
|
||||||
|
if (!motionState->isKinematic()) {
|
||||||
|
_nonPhysicalKinematicObjects.remove(motionState);
|
||||||
|
removeMotionState = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (removeMotionState) {
|
||||||
|
// if we get here then there is no need to keep this motionState around (no physics or kinematics)
|
||||||
|
_outgoingPackets.remove(motionState);
|
||||||
|
// NOTE: motionState will clean up its own backpointers in the Object
|
||||||
|
delete motionState;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: the grand order of operations is:
|
// NOTE: the grand order of operations is:
|
||||||
|
@ -152,7 +221,6 @@ void PhysicsEngine::relayIncomingChangesToSimulation() {
|
||||||
// outgoing changes at this point.
|
// outgoing changes at this point.
|
||||||
motionState->clearOutgoingPacketFlags(flags); // clear outgoing flags that were trumped
|
motionState->clearOutgoingPacketFlags(flags); // clear outgoing flags that were trumped
|
||||||
motionState->clearIncomingDirtyFlags(flags); // clear incoming flags that were processed
|
motionState->clearIncomingDirtyFlags(flags); // clear incoming flags that were processed
|
||||||
++stateItr;
|
|
||||||
}
|
}
|
||||||
_incomingChanges.clear();
|
_incomingChanges.clear();
|
||||||
}
|
}
|
||||||
|
@ -213,6 +281,7 @@ void PhysicsEngine::stepSimulation() {
|
||||||
// This is step (2).
|
// This is step (2).
|
||||||
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||||
_numSubsteps += (uint32_t)numSubsteps;
|
_numSubsteps += (uint32_t)numSubsteps;
|
||||||
|
stepNonPhysicalKinematics(usecTimestampNow());
|
||||||
unlock();
|
unlock();
|
||||||
|
|
||||||
if (numSubsteps > 0) {
|
if (numSubsteps > 0) {
|
||||||
|
@ -234,6 +303,17 @@ void PhysicsEngine::stepSimulation() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) {
|
||||||
|
QSet<ObjectMotionState*>::iterator stateItr = _nonPhysicalKinematicObjects.begin();
|
||||||
|
while (stateItr != _nonPhysicalKinematicObjects.end()) {
|
||||||
|
ObjectMotionState* motionState = *stateItr;
|
||||||
|
motionState->stepKinematicSimulation(now);
|
||||||
|
++stateItr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO?: need to occasionally scan for stopped non-physical kinematics objects
|
||||||
|
|
||||||
void PhysicsEngine::computeCollisionEvents() {
|
void PhysicsEngine::computeCollisionEvents() {
|
||||||
// update all contacts every frame
|
// update all contacts every frame
|
||||||
int numManifolds = _collisionDispatcher->getNumManifolds();
|
int numManifolds = _collisionDispatcher->getNumManifolds();
|
||||||
|
@ -332,7 +412,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
|
||||||
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||||
body->updateInertiaTensor();
|
body->updateInertiaTensor();
|
||||||
motionState->setRigidBody(body);
|
motionState->setRigidBody(body);
|
||||||
motionState->addKinematicController();
|
motionState->setKinematic(true, _numSubsteps);
|
||||||
const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec
|
const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec
|
||||||
const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec
|
const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec
|
||||||
body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD);
|
body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD);
|
||||||
|
@ -344,6 +424,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
|
||||||
body = new btRigidBody(mass, motionState, shape, inertia);
|
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||||
body->updateInertiaTensor();
|
body->updateInertiaTensor();
|
||||||
motionState->setRigidBody(body);
|
motionState->setRigidBody(body);
|
||||||
|
motionState->setKinematic(false, _numSubsteps);
|
||||||
motionState->updateObjectVelocities();
|
motionState->updateObjectVelocities();
|
||||||
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
|
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
|
||||||
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
|
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
|
||||||
|
@ -358,6 +439,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
|
||||||
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
||||||
body->updateInertiaTensor();
|
body->updateInertiaTensor();
|
||||||
motionState->setRigidBody(body);
|
motionState->setRigidBody(body);
|
||||||
|
motionState->setKinematic(false, _numSubsteps);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,7 +450,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
|
||||||
_dynamicsWorld->addRigidBody(body);
|
_dynamicsWorld->addRigidBody(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsEngine::removeObject(ObjectMotionState* motionState) {
|
void PhysicsEngine::removeObject(ObjectMotionState* motionState) {
|
||||||
assert(motionState);
|
assert(motionState);
|
||||||
btRigidBody* body = motionState->getRigidBody();
|
btRigidBody* body = motionState->getRigidBody();
|
||||||
if (body) {
|
if (body) {
|
||||||
|
@ -379,16 +461,14 @@ bool PhysicsEngine::removeObject(ObjectMotionState* motionState) {
|
||||||
_shapeManager.releaseShape(shapeInfo);
|
_shapeManager.releaseShape(shapeInfo);
|
||||||
delete body;
|
delete body;
|
||||||
motionState->setRigidBody(NULL);
|
motionState->setRigidBody(NULL);
|
||||||
motionState->removeKinematicController();
|
motionState->setKinematic(false, _numSubsteps);
|
||||||
|
|
||||||
removeContacts(motionState);
|
removeContacts(motionState);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) {
|
bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) {
|
||||||
MotionType newType = motionState->computeMotionType();
|
MotionType newType = motionState->computeMotionType();
|
||||||
|
|
||||||
// pull body out of physics engine
|
// pull body out of physics engine
|
||||||
|
@ -403,7 +483,16 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
||||||
ShapeInfo shapeInfo;
|
ShapeInfo shapeInfo;
|
||||||
motionState->computeShapeInfo(shapeInfo);
|
motionState->computeShapeInfo(shapeInfo);
|
||||||
btCollisionShape* newShape = _shapeManager.getShape(shapeInfo);
|
btCollisionShape* newShape = _shapeManager.getShape(shapeInfo);
|
||||||
if (newShape != oldShape) {
|
if (!newShape) {
|
||||||
|
// FAIL! we are unable to support these changes!
|
||||||
|
_shapeManager.releaseShape(oldShape);
|
||||||
|
|
||||||
|
delete body;
|
||||||
|
motionState->setRigidBody(NULL);
|
||||||
|
motionState->setKinematic(false, _numSubsteps);
|
||||||
|
removeContacts(motionState);
|
||||||
|
return false;
|
||||||
|
} else if (newShape != oldShape) {
|
||||||
// BUG: if shape doesn't change but density does then we won't compute new mass properties
|
// BUG: if shape doesn't change but density does then we won't compute new mass properties
|
||||||
// TODO: fix this BUG by replacing DIRTY_MASS with DIRTY_DENSITY and then fix logic accordingly.
|
// TODO: fix this BUG by replacing DIRTY_MASS with DIRTY_DENSITY and then fix logic accordingly.
|
||||||
body->setCollisionShape(newShape);
|
body->setCollisionShape(newShape);
|
||||||
|
@ -436,7 +525,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
||||||
|
|
||||||
body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f));
|
body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f));
|
||||||
body->updateInertiaTensor();
|
body->updateInertiaTensor();
|
||||||
motionState->addKinematicController();
|
motionState->setKinematic(true, _numSubsteps);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MOTION_TYPE_DYNAMIC: {
|
case MOTION_TYPE_DYNAMIC: {
|
||||||
|
@ -453,7 +542,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
||||||
body->updateInertiaTensor();
|
body->updateInertiaTensor();
|
||||||
}
|
}
|
||||||
body->forceActivationState(ACTIVE_TAG);
|
body->forceActivationState(ACTIVE_TAG);
|
||||||
motionState->removeKinematicController();
|
motionState->setKinematic(false, _numSubsteps);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -468,7 +557,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
||||||
|
|
||||||
body->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
|
body->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
|
||||||
body->setAngularVelocity(btVector3(0.0f, 0.0f, 0.0f));
|
body->setAngularVelocity(btVector3(0.0f, 0.0f, 0.0f));
|
||||||
motionState->removeKinematicController();
|
motionState->setKinematic(false, _numSubsteps);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -477,4 +566,5 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
||||||
_dynamicsWorld->addRigidBody(body);
|
_dynamicsWorld->addRigidBody(body);
|
||||||
|
|
||||||
body->activate();
|
body->activate();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
virtual void init(EntityEditPacketSender* packetSender);
|
virtual void init(EntityEditPacketSender* packetSender);
|
||||||
|
|
||||||
void stepSimulation();
|
void stepSimulation();
|
||||||
|
void stepNonPhysicalKinematics(const quint64& now);
|
||||||
|
|
||||||
void computeCollisionEvents();
|
void computeCollisionEvents();
|
||||||
|
|
||||||
|
@ -81,15 +82,16 @@ public:
|
||||||
void addObject(const ShapeInfo& shapeInfo, btCollisionShape* shape, ObjectMotionState* motionState);
|
void addObject(const ShapeInfo& shapeInfo, btCollisionShape* shape, ObjectMotionState* motionState);
|
||||||
|
|
||||||
/// \param motionState pointer to Object's MotionState
|
/// \param motionState pointer to Object's MotionState
|
||||||
/// \return true if Object removed
|
void removeObject(ObjectMotionState* motionState);
|
||||||
bool removeObject(ObjectMotionState* motionState);
|
|
||||||
|
|
||||||
/// process queue of changed from external sources
|
/// process queue of changed from external sources
|
||||||
void relayIncomingChangesToSimulation();
|
void relayIncomingChangesToSimulation();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void removeContacts(ObjectMotionState* motionState);
|
void removeContacts(ObjectMotionState* motionState);
|
||||||
void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
|
||||||
|
// return 'true' of update was successful
|
||||||
|
bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
||||||
void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
||||||
|
|
||||||
btClock _clock;
|
btClock _clock;
|
||||||
|
@ -104,6 +106,7 @@ private:
|
||||||
|
|
||||||
// EntitySimulation stuff
|
// EntitySimulation stuff
|
||||||
QSet<EntityMotionState*> _entityMotionStates; // all entities that we track
|
QSet<EntityMotionState*> _entityMotionStates; // all entities that we track
|
||||||
|
QSet<ObjectMotionState*> _nonPhysicalKinematicObjects; // not in physics simulation, but still need kinematic simulation
|
||||||
QSet<ObjectMotionState*> _incomingChanges; // entities with pending physics changes by script or packet
|
QSet<ObjectMotionState*> _incomingChanges; // entities with pending physics changes by script or packet
|
||||||
QSet<ObjectMotionState*> _outgoingPackets; // MotionStates with pending changes that need to be sent over wire
|
QSet<ObjectMotionState*> _outgoingPackets; // MotionStates with pending changes that need to be sent over wire
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
//
|
|
||||||
// SimpleEntityKinematicController.cpp
|
|
||||||
// libraries/physcis/src
|
|
||||||
//
|
|
||||||
// Created by Andrew Meadows 2015.01.13
|
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "PhysicsEngine.h"
|
|
||||||
#include "SimpleEntityKinematicController.h"
|
|
||||||
|
|
||||||
void SimpleEntityKinematicController:: stepForward() {
|
|
||||||
uint32_t substep = PhysicsEngine::getNumSubsteps();
|
|
||||||
float dt = (substep - _lastSubstep) * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
|
||||||
_entity->simulateSimpleKinematicMotion(dt);
|
|
||||||
_lastSubstep = substep;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
//
|
|
||||||
// SimpleEntityKinematicController.h
|
|
||||||
// libraries/physcis/src
|
|
||||||
//
|
|
||||||
// Created by Andrew Meadows 2015.01.13
|
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef hifi_SimpleEntityKinematicController_h
|
|
||||||
#define hifi_SimpleEntityKinematicController_h
|
|
||||||
|
|
||||||
/// SimpleKinematicConstroller performs simple exrapolation of velocities.
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
#include <EntityItem.h>
|
|
||||||
|
|
||||||
#include "KinematicController.h"
|
|
||||||
|
|
||||||
class SimpleEntityKinematicController : public KinematicController {
|
|
||||||
public:
|
|
||||||
SimpleEntityKinematicController() = delete; // prevent compiler from making a default ctor
|
|
||||||
|
|
||||||
SimpleEntityKinematicController(EntityItem* entity) : KinematicController(), _entity(entity) { assert(entity); }
|
|
||||||
|
|
||||||
~SimpleEntityKinematicController() { _entity = NULL; }
|
|
||||||
|
|
||||||
void stepForward();
|
|
||||||
|
|
||||||
private:
|
|
||||||
EntityItem* _entity;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_SimpleEntityKinematicController_h
|
|
Loading…
Reference in a new issue