more work on allowing for local particle trees

This commit is contained in:
ZappoMan 2014-01-27 13:50:05 -08:00
parent 13a92bc3c9
commit 5e4813ab11
12 changed files with 201 additions and 28 deletions

View file

@ -46,6 +46,9 @@ void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr&
} else if (dataByteArray[0] == PACKET_TYPE_PARTICLE_ADD_RESPONSE) {
// this will keep creatorTokenIDs to IDs mapped correctly
Particle::handleAddParticleResponse((unsigned char*) dataByteArray.data(), dataByteArray.size());
// also give our local particle tree a chance to remap any internal locally created particles
_particleTree.handleAddParticleResponse((unsigned char*) dataByteArray.data(), dataByteArray.size());
} else {
NodeList::getInstance()->processNodeData(senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size());
}

View file

@ -57,6 +57,7 @@ void DatagramProcessor::processDatagrams() {
case PACKET_TYPE_PARTICLE_ADD_RESPONSE:
// this will keep creatorTokenIDs to IDs mapped correctly
Particle::handleAddParticleResponse(incomingPacket, bytesReceived);
application->getParticles()->getTree()->handleAddParticleResponse(incomingPacket, bytesReceived);
break;
case PACKET_TYPE_PARTICLE_DATA:

View file

@ -43,6 +43,7 @@ Octree::Octree(bool shouldReaverage) :
_shouldReaverage(shouldReaverage),
_stopImport(false) {
_rootNode = NULL;
_isViewing = false;
}
Octree::~Octree() {

View file

@ -258,6 +258,9 @@ public:
void recurseNodeWithOperationDistanceSorted(OctreeElement* node, RecurseOctreeOperation operation,
const glm::vec3& point, void* extraData, int recursionCount = 0);
bool getIsViewing() const { return _isViewing; }
void setIsViewing(bool isViewing) { _isViewing = isViewing; }
signals:
void importSize(float x, float y, float z);
void importProgress(int progress);
@ -321,6 +324,9 @@ protected:
void emptyDeleteQueue();
QReadWriteLock lock;
/// This tree is receiving inbound viewer datagrams.
bool _isViewing;
};
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale);

View file

@ -42,6 +42,10 @@ void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const Hifi
if(command == expectedType) {
PerformanceWarning warn(showTimingDetails, "OctreeRenderer::processDatagram expected PACKET_TYPE",showTimingDetails);
// if we are getting inbound packets, then our tree is also viewing, and we should remember that fact.
_tree->setIsViewing(true);
const unsigned char* dataAt = packetData + numBytesPacketHeader;

View file

@ -78,6 +78,33 @@ Particle::Particle() {
DEFAULT_GRAVITY, DEFAULT_DAMPING, DEFAULT_LIFETIME, NOT_IN_HAND, DEFAULT_SCRIPT, NEW_PARTICLE);
}
Particle::Particle(const ParticleID& particleID, const ParticleProperties& properties) {
_id = particleID.id;
_creatorTokenID = particleID.creatorTokenID;
// init values with defaults before calling setProperties
uint64_t now = usecTimestampNow();
_lastEdited = now;
_lastUpdated = now;
_created = now; // will get updated as appropriate in setAge()
_position = glm::vec3(0,0,0);
_radius = 0;
_mass = 1.0f;
rgbColor noColor = { 0, 0, 0 };
memcpy(_color, noColor, sizeof(_color));
_velocity = glm::vec3(0,0,0);
_damping = DEFAULT_DAMPING;
_lifetime = DEFAULT_LIFETIME;
_gravity = DEFAULT_GRAVITY;
_script = DEFAULT_SCRIPT;
_inHand = NOT_IN_HAND;
_shouldDie = false;
setProperties(properties);
}
Particle::~Particle() {
}
@ -86,10 +113,8 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3
if (id == NEW_PARTICLE) {
_id = _nextID;
_nextID++;
//qDebug() << "Particle::init()... assigning new id... _id=" << _id;
} else {
_id = id;
//qDebug() << "Particle::init()... assigning id from init... _id=" << _id;
}
uint64_t now = usecTimestampNow();
_lastEdited = now;

View file

@ -161,6 +161,8 @@ class Particle {
public:
Particle();
Particle(const ParticleID& particleID, const ParticleProperties& properties);
/// all position, velocity, gravity, radius units are in domain units (0.0 to 1.0)
Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity,
@ -207,6 +209,7 @@ public:
float getAge() const { return static_cast<float>(usecTimestampNow() - _created) / static_cast<float>(USECS_PER_SECOND); }
float getEditedAgo() const { return static_cast<float>(usecTimestampNow() - _lastEdited) / static_cast<float>(USECS_PER_SECOND); }
uint32_t getID() const { return _id; }
void setID(uint32_t id) { _id = id; }
bool getShouldDie() const { return _shouldDie; }
QString getScript() const { return _script; }
uint32_t getCreatorTokenID() const { return _creatorTokenID; }

View file

@ -121,6 +121,12 @@ bool ParticleTree::findAndUpdateWithIDandPropertiesOperation(OctreeElement* elem
args->found = true;
return false; // stop searching
}
// if we've found our particle stop searching
if (args->found) {
return false;
}
return true;
}
@ -134,6 +140,21 @@ void ParticleTree::updateParticle(const ParticleID& particleID, const ParticlePr
}
}
void ParticleTree::addParticle(const ParticleID& particleID, const ParticleProperties& properties) {
// This only operates on locally created particles
if (particleID.isKnownID) {
return; // not allowed
}
Particle particle(particleID, properties);
glm::vec3 position = particle.getPosition();
float size = std::max(MINIMUM_PARTICLE_ELEMENT_SIZE, particle.getRadius());
ParticleTreeElement* element = (ParticleTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size);
element->storeParticle(particle);
_isDirty = true;
}
void ParticleTree::deleteParticle(const ParticleID& particleID) {
if (particleID.isKnownID) {
FindAndDeleteParticlesArgs args;
@ -142,6 +163,61 @@ void ParticleTree::deleteParticle(const ParticleID& particleID) {
}
}
// scans the tree and handles mapping locally created particles to know IDs.
// in the event that this tree is also viewing the scene, then we need to also
// search the tree to make sure we don't have a duplicate particle from the viewing
// operation.
bool ParticleTree::findAndUpdateParticleIDOperation(OctreeElement* element, void* extraData) {
bool keepSearching = true;
FindAndUpdateParticleIDArgs* args = static_cast<FindAndUpdateParticleIDArgs*>(extraData);
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
// Note: updateParticleID() will only operate on correctly found particles
particleTreeElement->updateParticleID(args);
// if we've found and replaced both the creatorTokenID and the viewedParticle, then we
// can stop looking, otherwise we will keep looking
if (args->creatorTokenFound && args->viewedParticleFound) {
keepSearching = false;
}
return keepSearching;
}
void ParticleTree::handleAddParticleResponse(unsigned char* packetData , int packetLength) {
unsigned char* dataAt = packetData;
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
dataAt += numBytesPacketHeader;
uint32_t creatorTokenID;
memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID));
dataAt += sizeof(creatorTokenID);
uint32_t particleID;
memcpy(&particleID, dataAt, sizeof(particleID));
dataAt += sizeof(particleID);
// update particles in our tree
bool assumeParticleFound = !getIsViewing(); // if we're not a viewing tree, then we don't have to find the actual particle
FindAndUpdateParticleIDArgs args = {
particleID,
creatorTokenID,
false,
assumeParticleFound,
getIsViewing()
};
const bool wantDebug = false;
if (wantDebug) {
qDebug() << "looking for creatorTokenID=" << creatorTokenID << " particleID=" << particleID
<< " getIsViewing()=" << getIsViewing();
}
lockForWrite();
recurseTreeWithOperation(findAndUpdateParticleIDOperation, &args);
unlock();
}
class FindNearPointArgs {
public:

View file

@ -41,6 +41,7 @@ public:
void storeParticle(const Particle& particle, Node* senderNode = NULL);
void updateParticle(const ParticleID& particleID, const ParticleProperties& properties);
void addParticle(const ParticleID& particleID, const ParticleProperties& properties);
void deleteParticle(const ParticleID& particleID);
const Particle* findClosestParticle(glm::vec3 position, float targetRadius);
const Particle* findParticleByID(uint32_t id, bool alreadyLocked = false);
@ -55,6 +56,7 @@ public:
void forgetParticlesDeletedBefore(uint64_t sinceTime);
void processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, Node* sourceNode);
void handleAddParticleResponse(unsigned char* packetData , int packetLength);
private:
@ -66,6 +68,7 @@ private:
static bool pruneOperation(OctreeElement* element, void* extraData);
static bool findByIDOperation(OctreeElement* element, void* extraData);
static bool findAndDeleteOperation(OctreeElement* element, void* extraData);
static bool findAndUpdateParticleIDOperation(OctreeElement* element, void* extraData);
void notifyNewlyCreatedParticle(const Particle& newParticle, Node* senderNode);

View file

@ -161,32 +161,61 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) {
}
bool ParticleTreeElement::updateParticle(const ParticleID& particleID, const ParticleProperties& properties) {
// currently only known IDs are in the tree... in the future we might support local storage of creatorTokenID particles
if (particleID.isKnownID) {
uint16_t numberOfParticles = _particles->size();
uint32_t searchID = particleID.id;
for (uint16_t i = 0; i < numberOfParticles; i++) {
// note: unlike storeParticle() which is called from inbound packets, this is only called by local editors
// and therefore we can be confident that this change is higher priority and should be honored
Particle& thisParticle = (*_particles)[i];
if (thisParticle.getID() == searchID) {
thisParticle.setProperties(properties);
uint16_t numberOfParticles = _particles->size();
for (uint16_t i = 0; i < numberOfParticles; i++) {
// note: unlike storeParticle() which is called from inbound packets, this is only called by local editors
// and therefore we can be confident that this change is higher priority and should be honored
Particle& thisParticle = (*_particles)[i];
bool found = false;
if (particleID.isKnownID) {
found = thisParticle.getID() == particleID.id;
} else {
found = thisParticle.getCreatorTokenID() == particleID.creatorTokenID;
}
if (found) {
thisParticle.setProperties(properties);
const bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();
int elapsed = now - thisParticle.getLastEdited();
const bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();
int elapsed = now - thisParticle.getLastEdited();
qDebug() << "ParticleTreeElement::updateParticle() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " thisParticle.getLastEdited()=" << thisParticle.getLastEdited();
}
return true;
}
qDebug() << "ParticleTreeElement::updateParticle() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " thisParticle.getLastEdited()=" << thisParticle.getLastEdited();
}
return true;
}
}
return false;
}
void ParticleTreeElement::updateParticleID(FindAndUpdateParticleIDArgs* args) {
uint16_t numberOfParticles = _particles->size();
for (uint16_t i = 0; i < numberOfParticles; i++) {
Particle& thisParticle = (*_particles)[i];
if (!args->creatorTokenFound) {
// first, we're looking for matching creatorTokenIDs, if we find that, then we fix it to know the actual ID
if (thisParticle.getCreatorTokenID() == args->creatorTokenID) {
thisParticle.setID(args->particleID);
args->creatorTokenFound = true;
}
}
// if we're in an isViewing tree, we also need to look for an kill any viewed particles
if (!args->viewedParticleFound && args->isViewing) {
if (thisParticle.getCreatorTokenID() == UNKNOWN_TOKEN && thisParticle.getID() == args->particleID) {
_particles->removeAt(i); // remove the particle at this index
numberOfParticles--; // this means we have 1 fewer particle in this list
i--; // and we actually want to back up i as well.
args->viewedParticleFound = true;
}
}
}
}
const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) const {
const Particle* closestParticle = NULL;

View file

@ -26,6 +26,17 @@ public:
QList<Particle> _movingParticles;
};
class FindAndUpdateParticleIDArgs {
public:
uint32_t particleID;
uint32_t creatorTokenID;
bool creatorTokenFound;
bool viewedParticleFound;
bool isViewing;
};
class ParticleTreeElement : public OctreeElement {
friend class ParticleTree; // to allow createElement to new us...
@ -88,6 +99,7 @@ public:
bool updateParticle(const Particle& particle);
bool updateParticle(const ParticleID& particleID, const ParticleProperties& properties);
void updateParticleID(FindAndUpdateParticleIDArgs* args);
const Particle* getClosestParticle(glm::vec3 position) const;
QVector<const Particle*> getParticles(glm::vec3 position, float radius) const;

View file

@ -31,6 +31,13 @@ ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& pr
// queue the packet
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, id, properties);
// If we have a local particle tree set, then also update it.
if (_particleTree) {
_particleTree->lockForWrite();
_particleTree->addParticle(id, properties);
_particleTree->unlock();
}
return id;
}
@ -70,18 +77,21 @@ ParticleProperties ParticlesScriptingInterface::getParticleProperties(ParticleID
ParticleID ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) {
uint32_t actualID = particleID.id;
// if the particle is unknown, attempt to look it up
if (!particleID.isKnownID) {
actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID);
if (actualID == UNKNOWN_PARTICLE_ID) {
return particleID; // bailing early
}
}
particleID.id = actualID;
particleID.isKnownID = true;
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, particleID, properties);
// if at this point, we know the id, send the update to the particle server
if (actualID != UNKNOWN_PARTICLE_ID) {
particleID.id = actualID;
particleID.isKnownID = true;
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, particleID, properties);
}
// If we have a local particle tree set, then also update it.
// If we have a local particle tree set, then also update it. We can do this even if we don't know
// the actual id, because we can edit out local particles just with creatorTokenID
if (_particleTree) {
_particleTree->lockForWrite();
_particleTree->updateParticle(particleID, properties);