mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-17 01:10:11 +02:00
more work on allowing for local particle trees
This commit is contained in:
parent
13a92bc3c9
commit
5e4813ab11
12 changed files with 201 additions and 28 deletions
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -43,6 +43,7 @@ Octree::Octree(bool shouldReaverage) :
|
|||
_shouldReaverage(shouldReaverage),
|
||||
_stopImport(false) {
|
||||
_rootNode = NULL;
|
||||
_isViewing = false;
|
||||
}
|
||||
|
||||
Octree::~Octree() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue