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...
// we need to iterate the actual particles of the element
ParticleTreeElement* particleTreeElement = (ParticleTreeElement*)element;
@ -42,11 +42,10 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element) {
const Particle& particle = particles[i];
// render particle aspoints
glm::vec3 position = particle.getPosition() * (float)TREE_SCALE;
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;
args->_renderedItems++;
if (drawAsSphere) {
glPushMatrix();

View file

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

View file

@ -196,6 +196,7 @@ void OctreeElement::calculateAABox() {
void OctreeElement::deleteChildAtIndex(int childIndex) {
OctreeElement* childAt = getChildAtIndex(childIndex);
if (childAt) {
printf("deleteChildAtIndex()... about to call delete childAt=%p\n",childAt);
delete childAt;
setChildAtIndex(childIndex, NULL);
_isDirty = true;
@ -1119,24 +1120,33 @@ OctreeElement* OctreeElement::addChildAtIndex(int childIndex) {
}
// 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) {
qDebug() << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n";
return;
return deleteApproved;
}
OctreeElement* childToDelete = getChildAtIndex(childIndex);
if (childToDelete) {
// If the child is not a leaf, then call ourselves recursively on all the children
if (!childToDelete->isLeaf()) {
// delete all it's children
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
childToDelete->safeDeepDeleteChildAtIndex(i,recursionCount+1);
if (childToDelete->deleteApproved()) {
// If the child is not a leaf, then call ourselves recursively on all the children
if (!childToDelete->isLeaf()) {
// delete all it's children
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
/// 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 deleteApproved() const { return true; }
// Base class methods you don't need to implement
@ -96,7 +98,9 @@ public:
OctreeElement* getChildAtIndex(int childIndex) const;
void deleteChildAtIndex(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; }

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) {
RenderArgs* args = static_cast<RenderArgs*>(extraData);
//if (true || element->isInView(*args->_viewFrustum)) {
if (element->isInView(*args->_viewFrustum)) {
if (element->hasContent()) {
args->_renderer->renderElement(element);
args->_renderer->renderElement(element, args);
}
return true;
}
@ -132,7 +126,7 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) {
}
void OctreeRenderer::render() {
RenderArgs args = { this, _viewFrustum };
RenderArgs args = { 0, this, _viewFrustum };
if (_tree) {
_tree->lockForRead();
_tree->recurseTreeWithOperation(renderOperation, &args);

View file

@ -20,6 +20,16 @@
#include "OctreePacketData.h"
#include "ViewFrustum.h"
class OctreeRenderer;
class RenderArgs {
public:
int _renderedItems;
OctreeRenderer* _renderer;
ViewFrustum* _viewFrustum;
};
// Generic client side Octree renderer class.
class OctreeRenderer {
public:
@ -30,7 +40,7 @@ public:
virtual NODE_TYPE getMyNodeType() const = 0;
virtual PACKET_TYPE getMyQueryMessageType() 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
void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);

View file

@ -9,7 +9,9 @@
#include "ParticleTree.h"
ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) {
_rootNode = createNewElement();
ParticleTreeElement* rootNode = createNewElement();
rootNode->setTree(this);
_rootNode = rootNode;
}
ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) const {
@ -27,13 +29,37 @@ bool ParticleTree::handlesEditPacketType(PACKET_TYPE packetType) const {
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
_isDirty = true;
}

View file

@ -38,10 +38,12 @@ public:
unsigned char* editData, int maxLength);
virtual void update();
private:
void storeParticle(const Particle& particle);
private:
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.
OctreeElement* ParticleTreeElement::createNewElement(unsigned char* octalCode) const {
ParticleTreeElement* newChild = new ParticleTreeElement(octalCode);
newChild->setTree(_myTree);
return newChild;
}
@ -34,7 +35,9 @@ void ParticleTreeElement::init(unsigned char* octalCode) {
}
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();
success = packetData->appendValue(numberOfParticles);
//printf("ParticleTreeElement::appendElementData()... numberOfParticles=%d\n",numberOfParticles);
if (success) {
for (uint16_t i = 0; i < numberOfParticles; 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,
ReadBitstreamToTreeParams& args) {
@ -89,9 +112,7 @@ int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, in
int bytesRead = 0;
uint16_t numberOfParticles = 0;
int expectedBytesPerParticle = Particle::expectedBytes();
_particles.clear();
if (bytesLeftToRead >= sizeof(numberOfParticles)) {
// read our particles in....
@ -104,13 +125,14 @@ int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, in
for (uint16_t i = 0; i < numberOfParticles; i++) {
Particle tempParticle;
int bytesForThisParticle = tempParticle.readParticleDataFromBuffer(dataAt, bytesLeftToRead, args);
_particles.push_back(tempParticle);
_myTree->storeParticle(tempParticle);
dataAt += bytesForThisParticle;
bytesLeftToRead -= bytesForThisParticle;
bytesRead += bytesForThisParticle;
}
}
}
return bytesRead;
}
@ -131,13 +153,6 @@ bool ParticleTreeElement::collapseChildren() {
void ParticleTreeElement::storeParticle(const Particle& particle) {
_particles.push_back(particle);
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.
virtual bool isRendered() const { return getShouldRender(); }
virtual bool deleteApproved() const { return (_particles.size() == 0); }
const std::vector<Particle>& getParticles() const { return _particles; }
void update(ParticleTreeUpdateArgs& args);
void setTree(ParticleTree* tree) { _myTree = tree; }
bool containsParticle(const Particle& particle) const;
bool updateParticle(const Particle& particle);
protected:
void storeParticle(const Particle& particle);
ParticleTree* _myTree;
std::vector<Particle> _particles;
};