fix flashy particles caused by server deleting octree elements while particles still exist

This commit is contained in:
ZappoMan 2013-12-11 09:54:30 -08:00
parent 03e892d4fd
commit 1225e20fad
10 changed files with 113 additions and 47 deletions

View file

@ -27,7 +27,7 @@ void ParticleTreeRenderer::update() {
} }
} }
void ParticleTreeRenderer::renderElement(OctreeElement* element) { void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
// actually render it here... // actually render it here...
// we need to iterate the actual particles of the element // we need to iterate the actual particles of the element
ParticleTreeElement* particleTreeElement = (ParticleTreeElement*)element; ParticleTreeElement* particleTreeElement = (ParticleTreeElement*)element;
@ -42,11 +42,10 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element) {
const Particle& particle = particles[i]; const Particle& particle = particles[i];
// render particle aspoints // render particle aspoints
glm::vec3 position = particle.getPosition() * (float)TREE_SCALE; glm::vec3 position = particle.getPosition() * (float)TREE_SCALE;
glColor3ub(particle.getColor()[RED_INDEX],particle.getColor()[GREEN_INDEX],particle.getColor()[BLUE_INDEX]); glColor3ub(particle.getColor()[RED_INDEX],particle.getColor()[GREEN_INDEX],particle.getColor()[BLUE_INDEX]);
//printf("particle at... (%f, %f, %f)\n", position.x, position.y, position.z);
float sphereRadius = particle.getRadius() * (float)TREE_SCALE; float sphereRadius = particle.getRadius() * (float)TREE_SCALE;
args->_renderedItems++;
if (drawAsSphere) { if (drawAsSphere) {
glPushMatrix(); glPushMatrix();

View file

@ -31,7 +31,7 @@ public:
virtual NODE_TYPE getMyNodeType() const { return NODE_TYPE_PARTICLE_SERVER; } virtual NODE_TYPE getMyNodeType() const { return NODE_TYPE_PARTICLE_SERVER; }
virtual PACKET_TYPE getMyQueryMessageType() const { return PACKET_TYPE_PARTICLE_QUERY; } virtual PACKET_TYPE getMyQueryMessageType() const { return PACKET_TYPE_PARTICLE_QUERY; }
virtual PACKET_TYPE getExpectedPacketType() const { return PACKET_TYPE_PARTICLE_DATA; } virtual PACKET_TYPE getExpectedPacketType() const { return PACKET_TYPE_PARTICLE_DATA; }
virtual void renderElement(OctreeElement* element); virtual void renderElement(OctreeElement* element, RenderArgs* args);
void update(); void update();
protected: protected:

View file

@ -196,6 +196,7 @@ void OctreeElement::calculateAABox() {
void OctreeElement::deleteChildAtIndex(int childIndex) { void OctreeElement::deleteChildAtIndex(int childIndex) {
OctreeElement* childAt = getChildAtIndex(childIndex); OctreeElement* childAt = getChildAtIndex(childIndex);
if (childAt) { if (childAt) {
printf("deleteChildAtIndex()... about to call delete childAt=%p\n",childAt);
delete childAt; delete childAt;
setChildAtIndex(childIndex, NULL); setChildAtIndex(childIndex, NULL);
_isDirty = true; _isDirty = true;
@ -1119,24 +1120,33 @@ OctreeElement* OctreeElement::addChildAtIndex(int childIndex) {
} }
// handles staging or deletion of all deep children // handles staging or deletion of all deep children
void OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCount) { bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCount) {
bool deleteApproved = false;
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
qDebug() << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n"; qDebug() << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n";
return; return deleteApproved;
} }
OctreeElement* childToDelete = getChildAtIndex(childIndex); OctreeElement* childToDelete = getChildAtIndex(childIndex);
if (childToDelete) { if (childToDelete) {
// If the child is not a leaf, then call ourselves recursively on all the children if (childToDelete->deleteApproved()) {
if (!childToDelete->isLeaf()) { // If the child is not a leaf, then call ourselves recursively on all the children
// delete all it's children if (!childToDelete->isLeaf()) {
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { // delete all it's children
childToDelete->safeDeepDeleteChildAtIndex(i,recursionCount+1); for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
deleteApproved = childToDelete->safeDeepDeleteChildAtIndex(i,recursionCount+1);
if (!deleteApproved) {
break; // no point in continuing...
}
}
}
if (deleteApproved) {
deleteChildAtIndex(childIndex);
_isDirty = true;
markWithChangedTime();
} }
} }
deleteChildAtIndex(childIndex);
_isDirty = true;
markWithChangedTime();
} }
return deleteApproved;
} }

View file

@ -89,6 +89,8 @@ public:
/// where an element is not actually rendering all should render elements. If the isRendered() state doesn't match the /// where an element is not actually rendering all should render elements. If the isRendered() state doesn't match the
/// shouldRender() state, the tree will remark elements as changed even in cases there the elements have not changed. /// shouldRender() state, the tree will remark elements as changed even in cases there the elements have not changed.
virtual bool isRendered() const { return getShouldRender(); } virtual bool isRendered() const { return getShouldRender(); }
virtual bool deleteApproved() const { return true; }
// Base class methods you don't need to implement // Base class methods you don't need to implement
@ -96,7 +98,9 @@ public:
OctreeElement* getChildAtIndex(int childIndex) const; OctreeElement* getChildAtIndex(int childIndex) const;
void deleteChildAtIndex(int childIndex); void deleteChildAtIndex(int childIndex);
OctreeElement* removeChildAtIndex(int childIndex); OctreeElement* removeChildAtIndex(int childIndex);
void safeDeepDeleteChildAtIndex(int childIndex, int recursionCount = 0); // handles deletion of all descendents
/// handles deletion of all descendants, returns false if delete not approved
bool safeDeepDeleteChildAtIndex(int childIndex, int recursionCount = 0);
const AABox& getAABox() const { return _box; } const AABox& getAABox() const { return _box; }

View file

@ -112,18 +112,12 @@ void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const Hifi
} }
} }
class RenderArgs {
public:
OctreeRenderer* _renderer;
ViewFrustum* _viewFrustum;
};
bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) { bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) {
RenderArgs* args = static_cast<RenderArgs*>(extraData); RenderArgs* args = static_cast<RenderArgs*>(extraData);
//if (true || element->isInView(*args->_viewFrustum)) { //if (true || element->isInView(*args->_viewFrustum)) {
if (element->isInView(*args->_viewFrustum)) { if (element->isInView(*args->_viewFrustum)) {
if (element->hasContent()) { if (element->hasContent()) {
args->_renderer->renderElement(element); args->_renderer->renderElement(element, args);
} }
return true; return true;
} }
@ -132,7 +126,7 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) {
} }
void OctreeRenderer::render() { void OctreeRenderer::render() {
RenderArgs args = { this, _viewFrustum }; RenderArgs args = { 0, this, _viewFrustum };
if (_tree) { if (_tree) {
_tree->lockForRead(); _tree->lockForRead();
_tree->recurseTreeWithOperation(renderOperation, &args); _tree->recurseTreeWithOperation(renderOperation, &args);

View file

@ -20,6 +20,16 @@
#include "OctreePacketData.h" #include "OctreePacketData.h"
#include "ViewFrustum.h" #include "ViewFrustum.h"
class OctreeRenderer;
class RenderArgs {
public:
int _renderedItems;
OctreeRenderer* _renderer;
ViewFrustum* _viewFrustum;
};
// Generic client side Octree renderer class. // Generic client side Octree renderer class.
class OctreeRenderer { class OctreeRenderer {
public: public:
@ -30,7 +40,7 @@ public:
virtual NODE_TYPE getMyNodeType() const = 0; virtual NODE_TYPE getMyNodeType() const = 0;
virtual PACKET_TYPE getMyQueryMessageType() const = 0; virtual PACKET_TYPE getMyQueryMessageType() const = 0;
virtual PACKET_TYPE getExpectedPacketType() const = 0; virtual PACKET_TYPE getExpectedPacketType() const = 0;
virtual void renderElement(OctreeElement* element) = 0; virtual void renderElement(OctreeElement* element, RenderArgs* args) = 0;
/// process incoming data /// process incoming data
void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);

View file

@ -9,7 +9,9 @@
#include "ParticleTree.h" #include "ParticleTree.h"
ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) { ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) {
_rootNode = createNewElement(); ParticleTreeElement* rootNode = createNewElement();
rootNode->setTree(this);
_rootNode = rootNode;
} }
ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) const { ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) const {
@ -27,13 +29,37 @@ bool ParticleTree::handlesEditPacketType(PACKET_TYPE packetType) const {
return false; return false;
} }
void ParticleTree::storeParticle(const Particle& particle) {
glm::vec3 position = particle.getPosition();
float size = particle.getRadius();
ParticleTreeElement* element = (ParticleTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size);
element->storeParticle(particle); class FindAndUpdateParticleArgs {
public:
const Particle& searchParticle;
bool found;
};
bool ParticleTree::findAndUpdateOperation(OctreeElement* element, void* extraData) {
FindAndUpdateParticleArgs* args = static_cast<FindAndUpdateParticleArgs*>(extraData);
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
if (particleTreeElement->containsParticle(args->searchParticle)) {
particleTreeElement->updateParticle(args->searchParticle);
args->found = true;
return false; // stop searching
}
return true;
}
void ParticleTree::storeParticle(const Particle& particle) {
// First, look for the existing particle in the tree..
FindAndUpdateParticleArgs args = { particle, false };
recurseTreeWithOperation(findAndUpdateOperation, &args);
// if we didn't find it in the tree, then store it...
if (!args.found) {
glm::vec3 position = particle.getPosition();
float size = particle.getRadius();
ParticleTreeElement* element = (ParticleTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size);
element->storeParticle(particle);
}
// what else do we need to do here to get reaveraging to work // what else do we need to do here to get reaveraging to work
_isDirty = true; _isDirty = true;
} }

View file

@ -38,10 +38,12 @@ public:
unsigned char* editData, int maxLength); unsigned char* editData, int maxLength);
virtual void update(); virtual void update();
private:
void storeParticle(const Particle& particle); void storeParticle(const Particle& particle);
private:
static bool updateOperation(OctreeElement* element, void* extraData); static bool updateOperation(OctreeElement* element, void* extraData);
static bool findAndUpdateOperation(OctreeElement* element, void* extraData);

View file

@ -25,6 +25,7 @@ ParticleTreeElement::~ParticleTreeElement() {
// we know must match ours. // we know must match ours.
OctreeElement* ParticleTreeElement::createNewElement(unsigned char* octalCode) const { OctreeElement* ParticleTreeElement::createNewElement(unsigned char* octalCode) const {
ParticleTreeElement* newChild = new ParticleTreeElement(octalCode); ParticleTreeElement* newChild = new ParticleTreeElement(octalCode);
newChild->setTree(_myTree);
return newChild; return newChild;
} }
@ -34,7 +35,9 @@ void ParticleTreeElement::init(unsigned char* octalCode) {
} }
ParticleTreeElement* ParticleTreeElement::addChildAtIndex(int index) { ParticleTreeElement* ParticleTreeElement::addChildAtIndex(int index) {
return (ParticleTreeElement*)OctreeElement::addChildAtIndex(index); ParticleTreeElement* newElement = (ParticleTreeElement*)OctreeElement::addChildAtIndex(index);
newElement->setTree(_myTree);
return newElement;
} }
@ -45,8 +48,6 @@ bool ParticleTreeElement::appendElementData(OctreePacketData* packetData) const
uint16_t numberOfParticles = _particles.size(); uint16_t numberOfParticles = _particles.size();
success = packetData->appendValue(numberOfParticles); success = packetData->appendValue(numberOfParticles);
//printf("ParticleTreeElement::appendElementData()... numberOfParticles=%d\n",numberOfParticles);
if (success) { if (success) {
for (uint16_t i = 0; i < numberOfParticles; i++) { for (uint16_t i = 0; i < numberOfParticles; i++) {
const Particle& particle = _particles[i]; const Particle& particle = _particles[i];
@ -82,6 +83,28 @@ void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) {
} }
} }
bool ParticleTreeElement::containsParticle(const Particle& particle) const {
uint16_t numberOfParticles = _particles.size();
for (uint16_t i = 0; i < numberOfParticles; i++) {
if (_particles[i].getID() == particle.getID()) {
return true;
}
}
return false;
}
bool ParticleTreeElement::updateParticle(const Particle& particle) {
uint16_t numberOfParticles = _particles.size();
for (uint16_t i = 0; i < numberOfParticles; i++) {
if (_particles[i].getID() == particle.getID()) {
_particles[i] = particle;
return true;
}
}
return false;
}
int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args) { ReadBitstreamToTreeParams& args) {
@ -89,9 +112,7 @@ int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, in
int bytesRead = 0; int bytesRead = 0;
uint16_t numberOfParticles = 0; uint16_t numberOfParticles = 0;
int expectedBytesPerParticle = Particle::expectedBytes(); int expectedBytesPerParticle = Particle::expectedBytes();
_particles.clear();
if (bytesLeftToRead >= sizeof(numberOfParticles)) { if (bytesLeftToRead >= sizeof(numberOfParticles)) {
// read our particles in.... // read our particles in....
@ -104,13 +125,14 @@ int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, in
for (uint16_t i = 0; i < numberOfParticles; i++) { for (uint16_t i = 0; i < numberOfParticles; i++) {
Particle tempParticle; Particle tempParticle;
int bytesForThisParticle = tempParticle.readParticleDataFromBuffer(dataAt, bytesLeftToRead, args); int bytesForThisParticle = tempParticle.readParticleDataFromBuffer(dataAt, bytesLeftToRead, args);
_particles.push_back(tempParticle); _myTree->storeParticle(tempParticle);
dataAt += bytesForThisParticle; dataAt += bytesForThisParticle;
bytesLeftToRead -= bytesForThisParticle; bytesLeftToRead -= bytesForThisParticle;
bytesRead += bytesForThisParticle; bytesRead += bytesForThisParticle;
} }
} }
} }
return bytesRead; return bytesRead;
} }
@ -131,13 +153,6 @@ bool ParticleTreeElement::collapseChildren() {
void ParticleTreeElement::storeParticle(const Particle& particle) { void ParticleTreeElement::storeParticle(const Particle& particle) {
_particles.push_back(particle); _particles.push_back(particle);
markWithChangedTime(); markWithChangedTime();
/***
printf("ParticleTreeElement::storeParticle() element=%p _particles.size()=%ld particle.getPosition()=%f,%f,%f\n",
this, _particles.size(),
particle.getPosition().x, particle.getPosition().y, particle.getPosition().z);
**/
} }

View file

@ -71,14 +71,20 @@ public:
/// shouldRender() state, the tree will remark elements as changed even in cases there the elements have not changed. /// shouldRender() state, the tree will remark elements as changed even in cases there the elements have not changed.
virtual bool isRendered() const { return getShouldRender(); } virtual bool isRendered() const { return getShouldRender(); }
virtual bool deleteApproved() const { return (_particles.size() == 0); }
const std::vector<Particle>& getParticles() const { return _particles; } const std::vector<Particle>& getParticles() const { return _particles; }
void update(ParticleTreeUpdateArgs& args); void update(ParticleTreeUpdateArgs& args);
void setTree(ParticleTree* tree) { _myTree = tree; }
bool containsParticle(const Particle& particle) const;
bool updateParticle(const Particle& particle);
protected: protected:
void storeParticle(const Particle& particle); void storeParticle(const Particle& particle);
ParticleTree* _myTree;
std::vector<Particle> _particles; std::vector<Particle> _particles;
}; };