Merge branch 'master' of https://github.com/worklist/hifi into metavoxels

This commit is contained in:
Andrzej Kapolka 2013-12-19 13:52:20 -08:00
commit de175e97b6
22 changed files with 305 additions and 161 deletions

View file

@ -225,12 +225,12 @@ void DomainServer::readAvailableDatagrams() {
} }
} else if (packetData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) { } else if (packetData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) {
qDebug("Received a request for assignment.\n");
if (_assignmentQueue.size() > 0) { if (_assignmentQueue.size() > 0) {
// construct the requested assignment from the packet data // construct the requested assignment from the packet data
Assignment requestAssignment(packetData, receivedBytes); Assignment requestAssignment(packetData, receivedBytes);
qDebug("Received a request for assignment type %i from %s.\n", requestAssignment.getType(), qPrintable(senderSockAddr.getAddress().toString()));
Assignment* assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); Assignment* assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
if (assignmentToDeploy) { if (assignmentToDeploy) {
@ -248,6 +248,8 @@ void DomainServer::readAvailableDatagrams() {
} }
} }
} else {
qDebug("Received an invalid assignment request from %s.\n", qPrintable(senderSockAddr.getAddress().toString()));
} }
} }
} }

View file

@ -338,8 +338,6 @@ void Avatar::render(bool forceRenderHead) {
} }
} }
// returns true if the Leap controls any of the avatar's hands. // returns true if the Leap controls any of the avatar's hands.
bool Avatar::updateLeapHandPositions() { bool Avatar::updateLeapHandPositions() {
bool returnValue = false; bool returnValue = false;
@ -443,8 +441,6 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
return glm::angleAxis(angle * proportion, axis); return glm::angleAxis(angle * proportion, axis);
} }
void Avatar::renderBody(bool forceRenderHead) { void Avatar::renderBody(bool forceRenderHead) {
if (_head.getVideoFace().isFullFrame()) { if (_head.getVideoFace().isFullFrame()) {

View file

@ -77,6 +77,8 @@ void Hand::reset() {
} }
void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, float deltaTime) { void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, float deltaTime) {
Application* app = Application::getInstance();
ParticleTree* particles = app->getParticles()->getTree();
bool ballFromHand = Menu::getInstance()->isOptionChecked(MenuOption::BallFromHand); bool ballFromHand = Menu::getInstance()->isOptionChecked(MenuOption::BallFromHand);
int handID = palm.getSixenseID(); int handID = palm.getSixenseID();
@ -85,14 +87,14 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
glm::vec3 targetPosition = (ballFromHand ? palm.getPosition() : fingerTipPosition) / (float)TREE_SCALE; glm::vec3 targetPosition = (ballFromHand ? palm.getPosition() : fingerTipPosition) / (float)TREE_SCALE;
float targetRadius = CATCH_RADIUS / (float)TREE_SCALE; float targetRadius = CATCH_RADIUS / (float)TREE_SCALE;
const Particle* closestParticle = Application::getInstance()->getParticles()
->getTree()->findClosestParticle(targetPosition, targetRadius);
// If I don't currently have a ball in my hand, then I can catch this closest particle
if (!ballAlreadyInHand && grabButtonPressed) {
if (closestParticle) { const Particle* closestParticle = particles->findClosestParticle(targetPosition, targetRadius);
// If I don't currently have a ball in my hand, then I can catch this closest particle
if (!ballAlreadyInHand && grabButtonPressed) { if (closestParticle) {
ParticleEditHandle* caughtParticle = Application::getInstance()->newParticleEditHandle(closestParticle->getID()); ParticleEditHandle* caughtParticle = app->newParticleEditHandle(closestParticle->getID());
glm::vec3 newPosition = targetPosition; glm::vec3 newPosition = targetPosition;
glm::vec3 newVelocity = NO_VELOCITY; glm::vec3 newVelocity = NO_VELOCITY;
@ -117,10 +119,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
_ballParticleEditHandles[handID] = caughtParticle; _ballParticleEditHandles[handID] = caughtParticle;
caughtParticle = NULL; caughtParticle = NULL;
// Play a catch sound! // Play a catch sound!
Application::getInstance()->getAudio()->startDrumSound(1.0, app->getAudio()->startDrumSound(1.0, 300, 0.5, 0.05);
300,
0.5,
0.05);
} }
} }
@ -155,20 +154,17 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
qDebug("Created New Ball\n"); qDebug("Created New Ball\n");
#endif #endif
glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition;
_ballParticleEditHandles[handID] = Application::getInstance()->makeParticle( _ballParticleEditHandles[handID] = app->makeParticle(
ballPosition / (float)TREE_SCALE, ballPosition / (float)TREE_SCALE,
TOY_BALL_RADIUS / (float) TREE_SCALE, TOY_BALL_RADIUS / (float) TREE_SCALE,
TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]], TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]],
NO_VELOCITY / (float)TREE_SCALE, NO_VELOCITY / (float)TREE_SCALE,
TOY_BALL_GRAVITY / (float) TREE_SCALE, TOY_BALL_GRAVITY / (float) TREE_SCALE,
TOY_BALL_DAMPING, TOY_BALL_DAMPING,
IN_HAND, IN_HAND,
TOY_BALL_UPDATE_SCRIPT); TOY_BALL_UPDATE_SCRIPT);
// Play a new ball sound // Play a new ball sound
Application::getInstance()->getAudio()->startDrumSound(1.0, app->getAudio()->startDrumSound(1.0, 2000, 0.5, 0.02);
2000,
0.5,
0.02);
} }
} else { } else {
@ -176,10 +172,16 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
#ifdef DEBUG_HAND #ifdef DEBUG_HAND
//qDebug("Ball in hand\n"); //qDebug("Ball in hand\n");
#endif #endif
uint32_t particleInHandID = _ballParticleEditHandles[handID]->getID();
const Particle* particleInHand = particles->findParticleByID(particleInHandID);
xColor colorForParticleInHand = particleInHand ? particleInHand->getXColor()
: TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]];
glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition;
_ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE, _ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE,
TOY_BALL_RADIUS / (float) TREE_SCALE, TOY_BALL_RADIUS / (float) TREE_SCALE,
TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]], colorForParticleInHand,
NO_VELOCITY / (float)TREE_SCALE, NO_VELOCITY / (float)TREE_SCALE,
TOY_BALL_GRAVITY / (float) TREE_SCALE, TOY_BALL_GRAVITY / (float) TREE_SCALE,
TOY_BALL_DAMPING, TOY_BALL_DAMPING,
@ -201,9 +203,14 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
#ifdef DEBUG_HAND #ifdef DEBUG_HAND
qDebug("Threw ball, v = %.3f\n", glm::length(ballVelocity)); qDebug("Threw ball, v = %.3f\n", glm::length(ballVelocity));
#endif #endif
uint32_t particleInHandID = _ballParticleEditHandles[handID]->getID();
const Particle* particleInHand = particles->findParticleByID(particleInHandID);
xColor colorForParticleInHand = particleInHand ? particleInHand->getXColor()
: TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]];
_ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE, _ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE,
TOY_BALL_RADIUS / (float) TREE_SCALE, TOY_BALL_RADIUS / (float) TREE_SCALE,
TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]], colorForParticleInHand,
ballVelocity / (float)TREE_SCALE, ballVelocity / (float)TREE_SCALE,
TOY_BALL_GRAVITY / (float) TREE_SCALE, TOY_BALL_GRAVITY / (float) TREE_SCALE,
TOY_BALL_DAMPING, TOY_BALL_DAMPING,
@ -216,12 +223,7 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
_ballParticleEditHandles[handID] = NULL; _ballParticleEditHandles[handID] = NULL;
// Play a throw sound // Play a throw sound
Application::getInstance()->getAudio()->startDrumSound(1.0, app->getAudio()->startDrumSound(1.0, 3000, 0.5, 0.02);
3000,
0.5,
0.02);
} }
} }
@ -474,30 +476,27 @@ void Hand::calculateGeometry() {
} }
} }
void Hand::render( bool isMine) { void Hand::render(bool isMine) {
_renderAlpha = 1.0; _renderAlpha = 1.0;
if (Menu::getInstance()->isOptionChecked(MenuOption::CollisionProxies)) {
for (int i = 0; i < getNumPalms(); i++) {
PalmData& palm = getPalms()[i];
if (Menu::getInstance()->isOptionChecked(MenuOption::CollisionProxies)) { if (!palm.isActive()) {
for (int i = 0; i < getNumPalms(); i++) { continue;
PalmData& palm = getPalms()[i];
if (!palm.isActive()) {
continue;
}
glm::vec3 position = palm.getPosition();
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glColor3f(0.0f, 1.0f, 0.0f);
glutSolidSphere(PALM_COLLISION_RADIUS * _owningAvatar->getScale(), 10, 10);
glPopMatrix();
} }
glm::vec3 position = palm.getPosition();
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glColor3f(0.0f, 1.0f, 0.0f);
glutSolidSphere(PALM_COLLISION_RADIUS * _owningAvatar->getScale(), 10, 10);
glPopMatrix();
} }
}
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayLeapHands)) { if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayLeapHands)) {
renderLeapHands(); renderLeapHands(isMine);
} }
if (isMine) { if (isMine) {
@ -520,7 +519,7 @@ void Hand::render( bool isMine) {
} }
void Hand::renderLeapHands() { void Hand::renderLeapHands(bool isMine) {
const float alpha = 1.0f; const float alpha = 1.0f;
const float TARGET_ALPHA = 0.5f; const float TARGET_ALPHA = 0.5f;
@ -532,7 +531,7 @@ void Hand::renderLeapHands() {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayHandTargets)) { if (isMine && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHandTargets)) {
for (size_t i = 0; i < getNumPalms(); ++i) { for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i]; PalmData& palm = getPalms()[i];
if (!palm.isActive()) { if (!palm.isActive()) {
@ -541,8 +540,8 @@ void Hand::renderLeapHands() {
glm::vec3 targetPosition = ballFromHand ? palm.getPosition() : palm.getTipPosition(); glm::vec3 targetPosition = ballFromHand ? palm.getPosition() : palm.getTipPosition();
glPushMatrix(); glPushMatrix();
const Particle* closestParticle = Application::getInstance()->getParticles() ParticleTree* particles = Application::getInstance()->getParticles()->getTree();
->getTree()->findClosestParticle(targetPosition / (float)TREE_SCALE, const Particle* closestParticle = particles->findClosestParticle(targetPosition / (float)TREE_SCALE,
CATCH_RADIUS / (float)TREE_SCALE); CATCH_RADIUS / (float)TREE_SCALE);
// If we are hitting a particle then draw the target green, otherwise yellow // If we are hitting a particle then draw the target green, otherwise yellow

View file

@ -89,7 +89,7 @@ private:
void setLeapHands(const std::vector<glm::vec3>& handPositions, void setLeapHands(const std::vector<glm::vec3>& handPositions,
const std::vector<glm::vec3>& handNormals); const std::vector<glm::vec3>& handNormals);
void renderLeapHands(); void renderLeapHands(bool isMine);
void renderLeapFingerTrails(); void renderLeapFingerTrails();
void updateCollisions(); void updateCollisions();

View file

@ -19,11 +19,23 @@
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <SharedUtil.h>
int main(int argc, const char * argv[]) { int main(int argc, const char * argv[]) {
timeval startup_time; timeval startup_time;
gettimeofday(&startup_time, NULL); gettimeofday(&startup_time, NULL);
// Debug option to demonstrate that the client's local time does not
// need to be in sync with any other network node. This forces clock
// skew for the individual client
const char* CLOCK_SKEW = "--clockSkew";
const char* clockSkewOption = getCmdOption(argc, argv, CLOCK_SKEW);
if (clockSkewOption) {
int clockSkew = atoi(clockSkewOption);
usecTimestampNowForceClockSkew(clockSkew);
qDebug("clockSkewOption=%s clockSkew=%d\n", clockSkewOption, clockSkew);
}
int exitCode; int exitCode;
{ {
Application app(argc, const_cast<char**>(argv), startup_time); Application app(argc, const_cast<char**>(argv), startup_time);

View file

@ -656,6 +656,17 @@ void OctreeServer::run() {
_persistThread->initialize(true); _persistThread->initialize(true);
} }
} }
// Debug option to demonstrate that the server's local time does not
// need to be in sync with any other network node. This forces clock
// skew for the individual server node
const char* CLOCK_SKEW = "--clockSkew";
const char* clockSkewOption = getCmdOption(_argc, _argv, CLOCK_SKEW);
if (clockSkewOption) {
int clockSkew = atoi(clockSkewOption);
usecTimestampNowForceClockSkew(clockSkew);
qDebug("clockSkewOption=%s clockSkew=%d\n", clockSkewOption, clockSkew);
}
// Check to see if the user passed in a command line option for setting packet send rate // Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND = "--packetsPerSecond"; const char* PACKETS_PER_SECOND = "--packetsPerSecond";

View file

@ -583,7 +583,7 @@ public:
float radius; float radius;
glm::vec3& penetration; glm::vec3& penetration;
bool found; bool found;
OctreeElement* penetratedElement; void* penetratedObject; /// the type is defined by the type of Octree, the caller is assumed to know the type
}; };
bool findSpherePenetrationOp(OctreeElement* element, void* extraData) { bool findSpherePenetrationOp(OctreeElement* element, void* extraData) {
@ -599,23 +599,22 @@ bool findSpherePenetrationOp(OctreeElement* element, void* extraData) {
} }
if (element->hasContent()) { if (element->hasContent()) {
glm::vec3 elementPenetration; glm::vec3 elementPenetration;
if (element->findSpherePenetration(args->center, args->radius, elementPenetration)) { if (element->findSpherePenetration(args->center, args->radius, elementPenetration, &args->penetratedObject)) {
args->penetration = addPenetrations(args->penetration, elementPenetration * (float)TREE_SCALE); args->penetration = addPenetrations(args->penetration, elementPenetration * (float)TREE_SCALE);
args->found = true; args->found = true;
args->penetratedElement = element;
} }
} }
return false; return false;
} }
bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration,
OctreeElement** penetratedElement) { void** penetratedObject) {
SphereArgs args = { center / (float)TREE_SCALE, radius / TREE_SCALE, penetration, false, NULL }; SphereArgs args = { center / (float)TREE_SCALE, radius / TREE_SCALE, penetration, false, NULL };
penetration = glm::vec3(0.0f, 0.0f, 0.0f); penetration = glm::vec3(0.0f, 0.0f, 0.0f);
recurseTreeWithOperation(findSpherePenetrationOp, &args); recurseTreeWithOperation(findSpherePenetrationOp, &args);
if (penetratedElement) { if (penetratedObject) {
*penetratedElement = args.penetratedElement; *penetratedObject = args.penetratedObject;
} }
return args.found; return args.found;
} }

View file

@ -221,7 +221,7 @@ public:
OctreeElement*& node, float& distance, BoxFace& face); OctreeElement*& node, float& distance, BoxFace& face);
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration,
OctreeElement** penetratedElement = NULL); void** penetratedObject = NULL);
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration); bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration);

View file

@ -1285,7 +1285,8 @@ void OctreeElement::notifyUpdateHooks() {
} }
} }
bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const {
return _box.findSpherePenetration(center, radius, penetration); return _box.findSpherePenetration(center, radius, penetration);
} }

View file

@ -93,7 +93,8 @@ public:
virtual bool deleteApproved() const { return true; } virtual bool deleteApproved() const { return true; }
virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; virtual bool findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const;
// Base class methods you don't need to implement // Base class methods you don't need to implement
const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode.pointer : &_octalCode.buffer[0]; } const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode.pointer : &_octalCode.buffer[0]; }

View file

@ -36,15 +36,16 @@ Particle::~Particle() {
void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity, void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity,
float damping, bool inHand, QString updateScript, uint32_t id) { float damping, bool inHand, QString updateScript, uint32_t id) {
if (id == NEW_PARTICLE) { if (id == NEW_PARTICLE) {
_created = usecTimestampNow();
_id = _nextID; _id = _nextID;
_nextID++; _nextID++;
} else { } else {
_id = id; _id = id;
} }
_lastUpdated = usecTimestampNow(); uint64_t now = usecTimestampNow();
_lastEdited = _lastUpdated; _lastEdited = now;
_lastUpdated = now;
_created = now; // will get updated as appropriate in setLifetime()
_position = position; _position = position;
_radius = radius; _radius = radius;
memcpy(_color, color, sizeof(_color)); memcpy(_color, color, sizeof(_color));
@ -63,7 +64,7 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
//printf("Particle::appendParticleData()... getID()=%d\n", getID()); //printf("Particle::appendParticleData()... getID()=%d\n", getID());
if (success) { if (success) {
success = packetData->appendValue(getCreated()); success = packetData->appendValue(getLifetime());
} }
if (success) { if (success) {
success = packetData->appendValue(getLastUpdated()); success = packetData->appendValue(getLastUpdated());
@ -103,9 +104,32 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
} }
int Particle::expectedBytes() { int Particle::expectedBytes() {
int expectedBytes = sizeof(uint32_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(float) + int expectedBytes = sizeof(uint32_t) // id
sizeof(glm::vec3) + sizeof(rgbColor) + sizeof(glm::vec3) + + sizeof(float) // lifetime
sizeof(glm::vec3) + sizeof(float) + sizeof(bool); + sizeof(uint64_t) // last updated
+ sizeof(uint64_t) // lasted edited
+ sizeof(float) // radius
+ sizeof(glm::vec3) // position
+ sizeof(rgbColor) // color
+ sizeof(glm::vec3) // velocity
+ sizeof(glm::vec3) // gravity
+ sizeof(float) // damping
+ sizeof(bool); // inhand
// potentially more...
return expectedBytes;
}
int Particle::expectedEditMessageBytes() {
int expectedBytes = sizeof(uint32_t) // id
+ sizeof(uint64_t) // lasted edited
+ sizeof(float) // radius
+ sizeof(glm::vec3) // position
+ sizeof(rgbColor) // color
+ sizeof(glm::vec3) // velocity
+ sizeof(glm::vec3) // gravity
+ sizeof(float) // damping
+ sizeof(bool); // inhand
// potentially more...
return expectedBytes; return expectedBytes;
} }
@ -119,12 +143,14 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += sizeof(_id); dataAt += sizeof(_id);
bytesRead += sizeof(_id); bytesRead += sizeof(_id);
// created // lifetime
memcpy(&_created, dataAt, sizeof(_created)); float lifetime;
dataAt += sizeof(_created); memcpy(&lifetime, dataAt, sizeof(lifetime));
bytesRead += sizeof(_created); dataAt += sizeof(lifetime);
bytesRead += sizeof(lifetime);
setLifetime(lifetime);
// lastupdated // _lastUpdated
memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated)); memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated));
dataAt += sizeof(_lastUpdated); dataAt += sizeof(_lastUpdated);
bytesRead += sizeof(_lastUpdated); bytesRead += sizeof(_lastUpdated);
@ -186,7 +212,7 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes) { Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes) {
Particle newParticle; // id and lastUpdated will get set here... Particle newParticle; // id and _lastUpdated will get set here...
unsigned char* dataAt = data; unsigned char* dataAt = data;
processedBytes = 0; processedBytes = 0;
@ -214,26 +240,19 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
processedBytes += sizeof(creatorTokenID); processedBytes += sizeof(creatorTokenID);
newParticle.setCreatorTokenID(creatorTokenID); newParticle.setCreatorTokenID(creatorTokenID);
newParticle._newlyCreated = true; newParticle._newlyCreated = true;
newParticle.setLifetime(0); // this guy is new!
} else { } else {
newParticle._id = editID; newParticle._id = editID;
newParticle._newlyCreated = false; newParticle._newlyCreated = false;
} }
// created
memcpy(&newParticle._created, dataAt, sizeof(newParticle._created));
dataAt += sizeof(newParticle._created);
processedBytes += sizeof(newParticle._created);
// lastUpdated
memcpy(&newParticle._lastUpdated, dataAt, sizeof(newParticle._lastUpdated));
dataAt += sizeof(newParticle._lastUpdated);
processedBytes += sizeof(newParticle._lastUpdated);
// lastEdited // lastEdited
memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited)); memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited));
dataAt += sizeof(newParticle._lastEdited); dataAt += sizeof(newParticle._lastEdited);
processedBytes += sizeof(newParticle._lastEdited); processedBytes += sizeof(newParticle._lastEdited);
// radius // radius
memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius)); memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius));
dataAt += sizeof(newParticle._radius); dataAt += sizeof(newParticle._radius);
@ -291,9 +310,8 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
void Particle::debugDump() const { void Particle::debugDump() const {
printf("Particle id :%u\n", _id); printf("Particle id :%u\n", _id);
printf(" created:%llu\n", _created); printf(" lifetime:%f\n", getLifetime());
printf(" last updated:%llu\n", _lastUpdated); printf(" edited ago:%f\n", getEditedAgo());
printf(" last edited:%llu\n", _lastEdited);
printf(" position:%f,%f,%f\n", _position.x, _position.y, _position.z); printf(" position:%f,%f,%f\n", _position.x, _position.y, _position.z);
printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z); printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z);
printf(" gravity:%f,%f,%f\n", _gravity.x, _gravity.y, _gravity.z); printf(" gravity:%f,%f,%f\n", _gravity.x, _gravity.y, _gravity.z);
@ -313,7 +331,7 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
int octets = numberOfThreeBitSectionsInCode(octcode); int octets = numberOfThreeBitSectionsInCode(octcode);
int lengthOfOctcode = bytesRequiredForCodeLength(octets); int lengthOfOctcode = bytesRequiredForCodeLength(octets);
int lenfthOfEditData = lengthOfOctcode + expectedBytes(); int lenfthOfEditData = lengthOfOctcode + expectedEditMessageBytes();
// make sure we have room to copy this particle // make sure we have room to copy this particle
if (sizeOut + lenfthOfEditData > sizeIn) { if (sizeOut + lenfthOfEditData > sizeIn) {
@ -325,7 +343,6 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
sizeOut += lengthOfOctcode; sizeOut += lengthOfOctcode;
// Now add our edit content details... // Now add our edit content details...
uint64_t created = usecTimestampNow();
// id // id
memcpy(copyAt, &details[i].id, sizeof(details[i].id)); memcpy(copyAt, &details[i].id, sizeof(details[i].id));
@ -338,25 +355,13 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
memcpy(copyAt, &details[i].creatorTokenID, sizeof(details[i].creatorTokenID)); memcpy(copyAt, &details[i].creatorTokenID, sizeof(details[i].creatorTokenID));
copyAt += sizeof(details[i].creatorTokenID); copyAt += sizeof(details[i].creatorTokenID);
sizeOut += sizeof(details[i].creatorTokenID); sizeOut += sizeof(details[i].creatorTokenID);
} else {
created = 0;
} }
// created // radius
memcpy(copyAt, &created, sizeof(created));
copyAt += sizeof(created);
sizeOut += sizeof(created);
// lastUpdated
memcpy(copyAt, &details[i].lastUpdated, sizeof(details[i].lastUpdated));
copyAt += sizeof(details[i].lastUpdated);
sizeOut += sizeof(details[i].lastUpdated);
// lastEdited
memcpy(copyAt, &details[i].lastEdited, sizeof(details[i].lastEdited)); memcpy(copyAt, &details[i].lastEdited, sizeof(details[i].lastEdited));
copyAt += sizeof(details[i].lastEdited); copyAt += sizeof(details[i].lastEdited);
sizeOut += sizeof(details[i].lastEdited); sizeOut += sizeof(details[i].lastEdited);
// radius // radius
memcpy(copyAt, &details[i].radius, sizeof(details[i].radius)); memcpy(copyAt, &details[i].radius, sizeof(details[i].radius));
copyAt += sizeof(details[i].radius); copyAt += sizeof(details[i].radius);
@ -405,7 +410,6 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
if (wantDebugging) { if (wantDebugging) {
printf("encodeParticleEditMessageDetails()....\n"); printf("encodeParticleEditMessageDetails()....\n");
printf("Particle id :%u\n", details[i].id); printf("Particle id :%u\n", details[i].id);
printf(" last updated:%llu\n", details[i].lastUpdated);
printf(" nextID:%u\n", _nextID); printf(" nextID:%u\n", _nextID);
} }
} }
@ -418,21 +422,30 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
void Particle::update() { void Particle::update() {
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
uint64_t elapsed = now - _lastUpdated; int elapsed = now - _lastUpdated; // making this signed slightly improves clock skew behavior
uint64_t USECS_PER_SECOND = 1000 * 1000;
float timeElapsed = (float)((float)elapsed/(float)USECS_PER_SECOND); float timeElapsed = (float)((float)elapsed/(float)USECS_PER_SECOND);
// calculate our default shouldDie state... then allow script to change it if it wants... // calculate our default shouldDie state... then allow script to change it if it wants...
float velocityScalar = glm::length(getVelocity()); float velocityScalar = glm::length(getVelocity());
const float STILL_MOVING = 0.05 / TREE_SCALE; const float STILL_MOVING = 0.05 / TREE_SCALE;
bool isStillMoving = (velocityScalar > STILL_MOVING); bool isStillMoving = (velocityScalar > STILL_MOVING);
const uint64_t REALLY_OLD = 30 * 1000 * 1000; const float REALLY_OLD = 30.0f; // 30 seconds
bool isReallyOld = (getLifetime() > REALLY_OLD); bool isReallyOld = (getLifetime() > REALLY_OLD);
bool isInHand = getInHand(); bool isInHand = getInHand();
bool shouldDie = !isInHand && !isStillMoving && isReallyOld; bool shouldDie = !isInHand && !isStillMoving && isReallyOld;
setShouldDie(shouldDie); setShouldDie(shouldDie);
const bool wantDebug = false;
if (wantDebug) {
printf("Particle::update()... timeElapsed: %f lifeTime:%f editedAgo:%f "
"isInHand:%s isStillMoveing:%s isReallyOld:%s shouldDie:%s\n",
timeElapsed, getLifetime(), getEditedAgo(), debug::valueOf(isInHand), debug::valueOf(isStillMoving),
debug::valueOf(isReallyOld), debug::valueOf(shouldDie));
}
runScript(); // allow the javascript to alter our state runScript(); // allow the javascript to alter our state
// If the ball is in hand, it doesn't move or have gravity effect it // If the ball is in hand, it doesn't move or have gravity effect it
@ -484,3 +497,14 @@ void Particle::runScript() {
} }
} }
} }
void Particle::setLifetime(float lifetime) {
uint64_t lifetimeInUsecs = lifetime * USECS_PER_SECOND;
_created = usecTimestampNow() - lifetimeInUsecs;
}
void Particle::copyChangedProperties(const Particle& other) {
float lifetime = getLifetime();
*this = other;
setLifetime(lifetime);
}

View file

@ -25,7 +25,6 @@ const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF;
class ParticleDetail { class ParticleDetail {
public: public:
uint32_t id; uint32_t id;
uint64_t lastUpdated;
uint64_t lastEdited; uint64_t lastEdited;
glm::vec3 position; glm::vec3 position;
float radius; float radius;
@ -68,10 +67,16 @@ public:
const glm::vec3& getGravity() const { return _gravity; } const glm::vec3& getGravity() const { return _gravity; }
bool getInHand() const { return _inHand; } bool getInHand() const { return _inHand; }
float getDamping() const { return _damping; } float getDamping() const { return _damping; }
uint64_t getCreated() const { return _created; }
uint64_t getLifetime() const { return usecTimestampNow() - _created; } /// The last updated/simulated time of this particle from the time perspective of the authoritative server/source
uint64_t getLastUpdated() const { return _lastUpdated; } uint64_t getLastUpdated() const { return _lastUpdated; }
/// The last edited time of this particle from the time perspective of the authoritative server/source
uint64_t getLastEdited() const { return _lastEdited; } uint64_t getLastEdited() const { return _lastEdited; }
/// lifetime of the particle in seconds
float getLifetime() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
float getEditedAgo() const { return (float)(usecTimestampNow() - _lastEdited) / (float)USECS_PER_SECOND; }
uint32_t getID() const { return _id; } uint32_t getID() const { return _id; }
bool getShouldDie() const { return _shouldDie; } bool getShouldDie() const { return _shouldDie; }
QString getUpdateScript() const { return _updateScript; } QString getUpdateScript() const { return _updateScript; }
@ -93,11 +98,11 @@ public:
void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; } void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; }
void setUpdateScript(QString updateScript) { _updateScript = updateScript; } void setUpdateScript(QString updateScript) { _updateScript = updateScript; }
void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; } void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; }
void setCreated(uint64_t created) { _created = created; }
bool appendParticleData(OctreePacketData* packetData) const; bool appendParticleData(OctreePacketData* packetData) const;
int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
static int expectedBytes(); static int expectedBytes();
static int expectedEditMessageBytes();
static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details, static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details,
unsigned char* bufferOut, int sizeIn, int& sizeOut); unsigned char* bufferOut, int sizeIn, int& sizeOut);
@ -105,20 +110,23 @@ public:
void update(); void update();
void debugDump() const; void debugDump() const;
// similar to assignment/copy, but it handles keeping lifetime accurate
void copyChangedProperties(const Particle& other);
protected: protected:
void runScript(); void runScript();
static QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3); static QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3);
static void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3); static void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3);
static QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color); static QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color);
static void xColorFromScriptValue(const QScriptValue &object, xColor& color); static void xColorFromScriptValue(const QScriptValue &object, xColor& color);
void setLifetime(float lifetime);
glm::vec3 _position; glm::vec3 _position;
rgbColor _color; rgbColor _color;
float _radius; float _radius;
glm::vec3 _velocity; glm::vec3 _velocity;
uint64_t _lastUpdated;
uint64_t _created;
uint64_t _lastEdited;
uint32_t _id; uint32_t _id;
static uint32_t _nextID; static uint32_t _nextID;
bool _shouldDie; bool _shouldDie;
@ -129,6 +137,12 @@ protected:
uint32_t _creatorTokenID; uint32_t _creatorTokenID;
bool _newlyCreated; bool _newlyCreated;
uint64_t _lastUpdated;
uint64_t _lastEdited;
// this doesn't go on the wire, we send it as lifetime
uint64_t _created;
}; };
class ParticleScriptObject : public QObject { class ParticleScriptObject : public QObject {
@ -144,9 +158,7 @@ public slots:
float getDamping() const { return _particle->getDamping(); } float getDamping() const { return _particle->getDamping(); }
float getRadius() const { return _particle->getRadius(); } float getRadius() const { return _particle->getRadius(); }
bool getShouldDie() { return _particle->getShouldDie(); } bool getShouldDie() { return _particle->getShouldDie(); }
float getCreated() const { return ((float)_particle->getCreated() / (float)USECS_PER_SECOND); } float getLifetime() const { return _particle->getLifetime(); }
float getLifetime() const { return ((float)_particle->getLifetime() / (float)USECS_PER_SECOND); }
void setPosition(glm::vec3 value) { _particle->setPosition(value); } void setPosition(glm::vec3 value) { _particle->setPosition(value); }
void setVelocity(glm::vec3 value) { _particle->setVelocity(value); } void setVelocity(glm::vec3 value) { _particle->setVelocity(value); }

View file

@ -73,8 +73,7 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
const float VOXEL_DAMPING = 0.0; const float VOXEL_DAMPING = 0.0;
const float VOXEL_COLLISION_FREQUENCY = 0.5f; const float VOXEL_COLLISION_FREQUENCY = 0.5f;
glm::vec3 penetration; glm::vec3 penetration;
OctreeElement* penetratedVoxel; if (_voxels->findSpherePenetration(center, radius, penetration)) {
if (_voxels->findSpherePenetration(center, radius, penetration, &penetratedVoxel)) {
penetration /= (float)TREE_SCALE; penetration /= (float)TREE_SCALE;
updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY); updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY);
applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
@ -88,11 +87,29 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) {
const float VOXEL_DAMPING = 0.0; const float VOXEL_DAMPING = 0.0;
const float VOXEL_COLLISION_FREQUENCY = 0.5f; const float VOXEL_COLLISION_FREQUENCY = 0.5f;
glm::vec3 penetration; glm::vec3 penetration;
OctreeElement* penetratedElement; Particle* penetratedParticle;
if (_particles->findSpherePenetration(center, radius, penetration, &penetratedElement)) { if (_particles->findSpherePenetration(center, radius, penetration, (void**)&penetratedParticle)) {
penetration /= (float)TREE_SCALE; penetration /= (float)TREE_SCALE;
updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY); updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY);
applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
// apply a hard collision to both particles of half the penetration each
float particleShare, penetratedParticleShare;
if (particle->getInHand() && penetratedParticle->getInHand()) {
particleShare = 0.5f;
penetratedParticleShare = -0.5f;
} else if (particle->getInHand()) {
particleShare = 0.f;
penetratedParticleShare = -1.f;
} else if (penetratedParticle->getInHand()) {
particleShare = -1.f;
penetratedParticleShare = 0.f;
} else {
particleShare = 0.5f;
penetratedParticleShare = -0.5f;
}
applyHardCollision(particle, penetration * particleShare, VOXEL_ELASTICITY, VOXEL_DAMPING);
applyHardCollision(penetratedParticle, penetration * penetratedParticleShare, VOXEL_ELASTICITY, VOXEL_DAMPING);
} }
} }
@ -172,7 +189,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::vec3& penetration, void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::vec3& penetration,
float elasticity, float damping, const glm::vec3& addedVelocity) { float elasticity, float damping, const glm::vec3& addedVelocity) {
// //
// Update the avatar in response to a hard collision. Position will be reset exactly // Update the particle in response to a hard collision. Position will be reset exactly
// to outside the colliding surface. Velocity will be modified according to elasticity. // to outside the colliding surface. Velocity will be modified according to elasticity.
// //
// if elasticity = 1.0, collision is inelastic. // if elasticity = 1.0, collision is inelastic.
@ -197,6 +214,12 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::
velocity *= 0.f; velocity *= 0.f;
} }
} }
const bool wantDebug = false;
if (wantDebug) {
printf("ParticleCollisionSystem::applyHardCollision() particle id:%d new velocity:%f,%f,%f inHand:%s\n",
particle->getID(), velocity.x, velocity.y, velocity.z, debug::valueOf(particle->getInHand()));
}
ParticleEditHandle particleEditHandle(_packetSender, _particles, particle->getID()); ParticleEditHandle particleEditHandle(_packetSender, _particles, particle->getID());
particleEditHandle.updateParticle(position, particle->getRadius(), particle->getXColor(), velocity, particleEditHandle.updateParticle(position, particle->getRadius(), particle->getXColor(), velocity,
particle->getGravity(), particle->getDamping(), particle->getInHand(), particle->getUpdateScript()); particle->getGravity(), particle->getDamping(), particle->getInHand(), particle->getUpdateScript());

View file

@ -45,7 +45,7 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor
// setup a ParticleDetail struct with the data // setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
ParticleDetail addParticleDetail = { NEW_PARTICLE, now, now, ParticleDetail addParticleDetail = { NEW_PARTICLE, now,
position, radius, {color.red, color.green, color.blue }, position, radius, {color.red, color.green, color.blue },
velocity, gravity, damping, inHand, updateScript, _creatorTokenID }; velocity, gravity, damping, inHand, updateScript, _creatorTokenID };
@ -71,7 +71,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor
// setup a ParticleDetail struct with the data // setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
ParticleDetail newParticleDetail = { _id, now, now, ParticleDetail newParticleDetail = { _id, now,
position, radius, {color.red, color.green, color.blue }, position, radius, {color.red, color.green, color.blue },
velocity, gravity, damping, inHand, updateScript, _creatorTokenID }; velocity, gravity, damping, inHand, updateScript, _creatorTokenID };

View file

@ -23,7 +23,7 @@ unsigned int ParticleScriptingInterface::queueParticleAdd(glm::vec3 position, fl
// setup a ParticleDetail struct with the data // setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
ParticleDetail addParticleDetail = { NEW_PARTICLE, now, now, ParticleDetail addParticleDetail = { NEW_PARTICLE, now,
position, radius, {color.red, color.green, color.blue }, velocity, position, radius, {color.red, color.green, color.blue }, velocity,
gravity, damping, inHand, updateScript, creatorTokenID }; gravity, damping, inHand, updateScript, creatorTokenID };

View file

@ -111,7 +111,6 @@ bool ParticleTree::findNearPointOperation(OctreeElement* element, void* extraDat
} }
const Particle* ParticleTree::findClosestParticle(glm::vec3 position, float targetRadius) { const Particle* ParticleTree::findClosestParticle(glm::vec3 position, float targetRadius) {
// First, look for the existing particle in the tree..
FindNearPointArgs args = { position, targetRadius, false, NULL, FLT_MAX }; FindNearPointArgs args = { position, targetRadius, false, NULL, FLT_MAX };
lockForRead(); lockForRead();
recurseTreeWithOperation(findNearPointOperation, &args); recurseTreeWithOperation(findNearPointOperation, &args);
@ -119,6 +118,44 @@ const Particle* ParticleTree::findClosestParticle(glm::vec3 position, float targ
return args.closestParticle; return args.closestParticle;
} }
class FindByIDArgs {
public:
uint32_t id;
bool found;
const Particle* foundParticle;
};
bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) {
FindByIDArgs* args = static_cast<FindByIDArgs*>(extraData);
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
// if already found, stop looking
if (args->found) {
return false;
}
// as the tree element if it has this particle
const Particle* foundParticle = particleTreeElement->getParticleWithID(args->id);
if (foundParticle) {
args->foundParticle = foundParticle;
args->found = true;
return false;
}
// keep looking
return true;
}
const Particle* ParticleTree::findParticleByID(uint32_t id) {
FindByIDArgs args = { id, false, NULL };
lockForRead();
recurseTreeWithOperation(findByIDOperation, &args);
unlock();
return args.foundParticle;
}
int ParticleTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* packetData, int packetLength, int ParticleTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* packetData, int packetLength,
unsigned char* editData, int maxLength, Node* senderNode) { unsigned char* editData, int maxLength, Node* senderNode) {

View file

@ -46,6 +46,7 @@ public:
void storeParticle(const Particle& particle); void storeParticle(const Particle& particle);
const Particle* findClosestParticle(glm::vec3 position, float targetRadius); const Particle* findClosestParticle(glm::vec3 position, float targetRadius);
const Particle* findParticleByID(uint32_t id);
void addNewlyCreatedHook(NewlyCreatedParticleHook* hook); void addNewlyCreatedHook(NewlyCreatedParticleHook* hook);
void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook); void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook);
@ -56,6 +57,7 @@ private:
static bool findAndUpdateOperation(OctreeElement* element, void* extraData); static bool findAndUpdateOperation(OctreeElement* element, void* extraData);
static bool findNearPointOperation(OctreeElement* element, void* extraData); static bool findNearPointOperation(OctreeElement* element, void* extraData);
static bool pruneOperation(OctreeElement* element, void* extraData); static bool pruneOperation(OctreeElement* element, void* extraData);
static bool findByIDOperation(OctreeElement* element, void* extraData);
void notifyNewlyCreatedParticle(const Particle& newParticle, Node* senderNode); void notifyNewlyCreatedParticle(const Particle& newParticle, Node* senderNode);

View file

@ -86,7 +86,9 @@ void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) {
} }
} }
bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const {
uint16_t numberOfParticles = _particles.size(); uint16_t numberOfParticles = _particles.size();
for (uint16_t i = 0; i < numberOfParticles; i++) { for (uint16_t i = 0; i < numberOfParticles; i++) {
glm::vec3 particleCenter = _particles[i].getPosition(); glm::vec3 particleCenter = _particles[i].getPosition();
@ -96,8 +98,19 @@ bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float r
if (particleCenter == center && particleRadius == radius) { if (particleCenter == center && particleRadius == radius) {
return false; return false;
} }
// We've considered making "inHand" particles not collide, if we want to do that,
// we should change this setting... but now, we do allow inHand particles to collide
const bool IN_HAND_PARTICLES_DONT_COLLIDE = false;
if (IN_HAND_PARTICLES_DONT_COLLIDE) {
// don't penetrate if the particle is "inHand" -- they don't collide
if (_particles[i].getInHand()) {
return false;
}
}
if (findSphereSpherePenetration(center, radius, particleCenter, particleRadius, penetration)) { if (findSphereSpherePenetration(center, radius, particleCenter, particleRadius, penetration)) {
*penetratedObject = (void*)&_particles[i];
return true; return true;
} }
} }
@ -115,37 +128,28 @@ bool ParticleTreeElement::containsParticle(const Particle& particle) const {
} }
bool ParticleTreeElement::updateParticle(const Particle& particle) { bool ParticleTreeElement::updateParticle(const Particle& particle) {
bool wantDebug = false; const bool wantDebug = false;
uint16_t numberOfParticles = _particles.size(); uint16_t numberOfParticles = _particles.size();
for (uint16_t i = 0; i < numberOfParticles; i++) { for (uint16_t i = 0; i < numberOfParticles; i++) {
if (_particles[i].getID() == particle.getID()) { if (_particles[i].getID() == particle.getID()) {
int difference = _particles[i].getLastUpdated() - particle.getLastUpdated(); int difference = _particles[i].getLastUpdated() - particle.getLastUpdated();
bool changedOnServer = _particles[i].getLastEdited() < particle.getLastEdited(); bool changedOnServer = _particles[i].getLastEdited() < particle.getLastEdited();
bool localOlder = _particles[i].getLastUpdated() < particle.getLastUpdated(); bool localOlder = _particles[i].getLastUpdated() < particle.getLastUpdated();
if (changedOnServer || localOlder) {
if (changedOnServer || localOlder) {
if (wantDebug) { if (wantDebug) {
printf("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n", printf("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n",
particle.getID(), (changedOnServer ? "CHANGED" : "same"), particle.getID(), (changedOnServer ? "CHANGED" : "same"),
(localOlder ? "OLDER" : "NEWER"), (localOlder ? "OLDER" : "NEWER"),
difference, debug::valueOf(particle.isNewlyCreated()) ); difference, debug::valueOf(particle.isNewlyCreated()) );
} }
_particles[i].copyChangedProperties(particle);
uint64_t actuallyCreated = particle.getCreated();
if (!particle.isNewlyCreated()) {
actuallyCreated = _particles[i].getCreated();
}
_particles[i] = particle;
_particles[i].setCreated(actuallyCreated);
} else { } else {
if (wantDebug) { if (wantDebug) {
printf(">>> NO CHANGE <<< -- local particle [id:%d] %s and %s than server particle by %d, " printf(">>> IGNORING SERVER!!! Would've caused jutter! <<< "
"particle.isNewlyCreated()=%s\n", "local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n",
particle.getID(), (changedOnServer ? "CHANGED" : "same"), particle.getID(), (changedOnServer ? "CHANGED" : "same"),
(localOlder ? "OLDER" : "NEWER"), (localOlder ? "OLDER" : "NEWER"),
difference, debug::valueOf(particle.isNewlyCreated()) ); difference, debug::valueOf(particle.isNewlyCreated()) );
} }
} }
return true; return true;
@ -167,6 +171,18 @@ const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) cons
return closestParticle; return closestParticle;
} }
const Particle* ParticleTreeElement::getParticleWithID(uint32_t id) const {
const Particle* foundParticle = NULL;
uint16_t numberOfParticles = _particles.size();
for (uint16_t i = 0; i < numberOfParticles; i++) {
if (_particles[i].getID() == id) {
foundParticle = &_particles[i];
break;
}
}
return foundParticle;
}
int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args) { ReadBitstreamToTreeParams& args) {

View file

@ -72,7 +72,8 @@ public:
virtual bool isRendered() const { return getShouldRender(); } virtual bool isRendered() const { return getShouldRender(); }
virtual bool deleteApproved() const { return !hasParticles(); } virtual bool deleteApproved() const { return !hasParticles(); }
virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; virtual bool findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const;
const std::vector<Particle>& getParticles() const { return _particles; } const std::vector<Particle>& getParticles() const { return _particles; }
std::vector<Particle>& getParticles() { return _particles; } std::vector<Particle>& getParticles() { return _particles; }
@ -84,6 +85,8 @@ public:
bool containsParticle(const Particle& particle) const; bool containsParticle(const Particle& particle) const;
bool updateParticle(const Particle& particle); bool updateParticle(const Particle& particle);
const Particle* getClosestParticle(glm::vec3 position) const; const Particle* getClosestParticle(glm::vec3 position) const;
const Particle* getParticleWithID(uint32_t id) const;
protected: protected:
void storeParticle(const Particle& particle); void storeParticle(const Particle& particle);

View file

@ -54,7 +54,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
return 2; return 2;
case PACKET_TYPE_PARTICLE_DATA: case PACKET_TYPE_PARTICLE_DATA:
return 3; return 5;
default: default:
return 0; return 0;

View file

@ -30,10 +30,15 @@ uint64_t usecTimestamp(const timeval *time) {
return (time->tv_sec * 1000000 + time->tv_usec); return (time->tv_sec * 1000000 + time->tv_usec);
} }
int usecTimestampNowAdjust = 0;
void usecTimestampNowForceClockSkew(int clockSkew) {
::usecTimestampNowAdjust = clockSkew;
}
uint64_t usecTimestampNow() { uint64_t usecTimestampNow() {
timeval now; timeval now;
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
return (now.tv_sec * 1000000 + now.tv_usec); return (now.tv_sec * 1000000 + now.tv_usec) + ::usecTimestampNowAdjust;
} }
float randFloat () { float randFloat () {

View file

@ -56,6 +56,7 @@ static const uint64_t USECS_PER_SECOND = 1000 * 1000;
uint64_t usecTimestamp(const timeval *time); uint64_t usecTimestamp(const timeval *time);
uint64_t usecTimestampNow(); uint64_t usecTimestampNow();
void usecTimestampNowForceClockSkew(int clockSkew);
float randFloat(); float randFloat();
int randIntInRange (int min, int max); int randIntInRange (int min, int max);