mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 18:13:47 +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...
|
||||
// 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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
**/
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue