mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 19:21:16 +02:00
fix flashy particles caused by server deleting octree elements while particles still exist
This commit is contained in:
parent
03e892d4fd
commit
1225e20fad
10 changed files with 113 additions and 47 deletions
|
@ -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();
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
**/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue