mirror of
https://github.com/overte-org/overte.git
synced 2025-08-11 23:51:49 +02:00
ParticleTreeElement::_particles is now a QList<> instead of std::vector<> for faster erase()
This commit is contained in:
parent
d0a53f817a
commit
61e1b25e70
4 changed files with 71 additions and 48 deletions
|
@ -32,7 +32,7 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg
|
|||
// we need to iterate the actual particles of the element
|
||||
ParticleTreeElement* particleTreeElement = (ParticleTreeElement*)element;
|
||||
|
||||
const std::vector<Particle>& particles = particleTreeElement->getParticles();
|
||||
const QList<Particle>& particles = particleTreeElement->getParticles();
|
||||
|
||||
uint16_t numberOfParticles = particles.size();
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ bool ParticleCollisionSystem::updateOperation(OctreeElement* element, void* extr
|
|||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
|
||||
// iterate the particles...
|
||||
std::vector<Particle>& particles = particleTreeElement->getParticles();
|
||||
QList<Particle>& particles = particleTreeElement->getParticles();
|
||||
uint16_t numberOfParticles = particles.size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
Particle* particle = &particles[i];
|
||||
|
@ -227,13 +227,14 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, float elast
|
|||
float velocityDotPenetration = glm::dot(velocity, collisionInfo._penetration);
|
||||
if (velocityDotPenetration > EPSILON) {
|
||||
position -= collisionInfo._penetration;
|
||||
static float HALTING_VELOCITY = 0.2f / (float)(TREE_SCALE);
|
||||
// cancel out the velocity component in the direction of penetration
|
||||
|
||||
glm::vec3 direction = glm::normalize(collisionInfo._penetration);
|
||||
velocity += collisionInfo._addedVelocity - (glm::dot(velocity, direction) * (1.0f + elasticity)) * direction;
|
||||
velocity *= glm::clamp(1.f - damping, 0.0f, 1.0f);
|
||||
if (glm::length(velocity) < HALTING_VELOCITY) {
|
||||
|
||||
// TODO: move this halt logic into Particle::update() method
|
||||
static float HALTING_SPEED = 0.2f / (float)(TREE_SCALE);
|
||||
if (glm::length(velocity) < HALTING_SPEED) {
|
||||
// If moving really slowly after a collision, and not applying forces, stop altogether
|
||||
velocity *= 0.f;
|
||||
}
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
#include "ParticleTree.h"
|
||||
#include "ParticleTreeElement.h"
|
||||
|
||||
ParticleTreeElement::ParticleTreeElement(unsigned char* octalCode) : OctreeElement() {
|
||||
ParticleTreeElement::ParticleTreeElement(unsigned char* octalCode) : OctreeElement(), _particles(NULL) {
|
||||
init(octalCode);
|
||||
};
|
||||
|
||||
ParticleTreeElement::~ParticleTreeElement() {
|
||||
_voxelMemoryUsage -= sizeof(ParticleTreeElement);
|
||||
delete _particles;
|
||||
_particles = NULL;
|
||||
}
|
||||
|
||||
// This will be called primarily on addChildAt(), which means we're adding a child of our
|
||||
|
@ -31,6 +33,7 @@ OctreeElement* ParticleTreeElement::createNewElement(unsigned char* octalCode) c
|
|||
|
||||
void ParticleTreeElement::init(unsigned char* octalCode) {
|
||||
OctreeElement::init(octalCode);
|
||||
_particles = new QList<Particle>;
|
||||
_voxelMemoryUsage += sizeof(ParticleTreeElement);
|
||||
}
|
||||
|
||||
|
@ -45,12 +48,12 @@ bool ParticleTreeElement::appendElementData(OctreePacketData* packetData) const
|
|||
bool success = true; // assume the best...
|
||||
|
||||
// write our particles out...
|
||||
uint16_t numberOfParticles = _particles.size();
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
success = packetData->appendValue(numberOfParticles);
|
||||
|
||||
if (success) {
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
const Particle& particle = _particles[i];
|
||||
const Particle& particle = (*_particles)[i];
|
||||
success = particle.appendParticleData(packetData);
|
||||
if (!success) {
|
||||
break;
|
||||
|
@ -62,35 +65,42 @@ bool ParticleTreeElement::appendElementData(OctreePacketData* packetData) const
|
|||
|
||||
void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) {
|
||||
markWithChangedTime();
|
||||
// TODO: early exit when _particles is empty
|
||||
|
||||
// update our contained particles
|
||||
uint16_t numberOfParticles = _particles.size();
|
||||
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
_particles[i].update();
|
||||
QList<Particle>::iterator particleItr = _particles->begin();
|
||||
while(particleItr != _particles->end()) {
|
||||
Particle& particle = (*particleItr);
|
||||
particle.update();
|
||||
|
||||
// If the particle wants to die, or if it's left our bounding box, then move it
|
||||
// into the arguments moving particles. These will be added back or deleted completely
|
||||
if (_particles[i].getShouldDie() || !_box.contains(_particles[i].getPosition())) {
|
||||
args._movingParticles.push_back(_particles[i]);
|
||||
if (particle.getShouldDie() || !_box.contains(particle.getPosition())) {
|
||||
args._movingParticles.push_back(particle);
|
||||
|
||||
// erase this particle
|
||||
_particles.erase(_particles.begin()+i);
|
||||
|
||||
// reduce our index since we just removed this item
|
||||
i--;
|
||||
numberOfParticles--;
|
||||
particleItr = _particles->erase(particleItr);
|
||||
}
|
||||
else
|
||||
{
|
||||
++particleItr;
|
||||
}
|
||||
}
|
||||
// TODO: if _particles is empty after while loop consider freeing memory in _particles if
|
||||
// internal array is too big (QList internal array does not decrease size except in dtor and
|
||||
// assignment operator). Otherwise _particles could become a "resource leak" for large
|
||||
// roaming piles of particles.
|
||||
}
|
||||
|
||||
bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
||||
glm::vec3& penetration, void** penetratedObject) const {
|
||||
|
||||
uint16_t numberOfParticles = _particles.size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
glm::vec3 particleCenter = _particles[i].getPosition();
|
||||
float particleRadius = _particles[i].getRadius();
|
||||
QList<Particle>::iterator particleItr = _particles->begin();
|
||||
QList<Particle>::const_iterator particleEnd = _particles->end();
|
||||
while(particleItr != particleEnd) {
|
||||
Particle& particle = (*particleItr);
|
||||
glm::vec3 particleCenter = particle.getPosition();
|
||||
float particleRadius = particle.getRadius();
|
||||
|
||||
// don't penetrate yourself
|
||||
if (particleCenter == center && particleRadius == radius) {
|
||||
|
@ -102,23 +112,28 @@ bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float r
|
|||
const bool IN_HAND_PARTICLES_DONT_COLLIDE = false;
|
||||
if (IN_HAND_PARTICLES_DONT_COLLIDE) {
|
||||
// don't penetrate if the particle is "inHand" -- they don't collide
|
||||
if (_particles[i].getInHand()) {
|
||||
return false;
|
||||
if (particle.getInHand()) {
|
||||
++particleItr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (findSphereSpherePenetration(center, radius, particleCenter, particleRadius, penetration)) {
|
||||
*penetratedObject = (void*)&_particles[i];
|
||||
// return true on first valid particle penetration
|
||||
*penetratedObject = (void*)(&particle);
|
||||
return true;
|
||||
}
|
||||
++particleItr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParticleTreeElement::containsParticle(const Particle& particle) const {
|
||||
uint16_t numberOfParticles = _particles.size();
|
||||
// TODO: remove this method and force callers to use getParticleWithID() instead
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
uint32_t particleID = particle.getID();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
if (_particles[i].getID() == particle.getID()) {
|
||||
if ((*_particles)[i].getID() == particleID) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -126,13 +141,17 @@ bool ParticleTreeElement::containsParticle(const Particle& particle) const {
|
|||
}
|
||||
|
||||
bool ParticleTreeElement::updateParticle(const Particle& particle) {
|
||||
// NOTE: this method must first lookup the particle by ID, hence it is O(N)
|
||||
// and "particle is not found" is worst-case (full N) but maybe we don't care?
|
||||
// (guaranteed that num particles per elemen is small?)
|
||||
const bool wantDebug = false;
|
||||
uint16_t numberOfParticles = _particles.size();
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
if (_particles[i].getID() == particle.getID()) {
|
||||
int difference = _particles[i].getLastUpdated() - particle.getLastUpdated();
|
||||
bool changedOnServer = _particles[i].getLastEdited() < particle.getLastEdited();
|
||||
bool localOlder = _particles[i].getLastUpdated() < particle.getLastUpdated();
|
||||
Particle& thisParticle = (*_particles)[i];
|
||||
if (thisParticle.getID() == particle.getID()) {
|
||||
int difference = thisParticle.getLastUpdated() - particle.getLastUpdated();
|
||||
bool changedOnServer = thisParticle.getLastEdited() < particle.getLastEdited();
|
||||
bool localOlder = thisParticle.getLastUpdated() < particle.getLastUpdated();
|
||||
if (changedOnServer || localOlder) {
|
||||
if (wantDebug) {
|
||||
printf("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n",
|
||||
|
@ -140,7 +159,7 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) {
|
|||
(localOlder ? "OLDER" : "NEWER"),
|
||||
difference, debug::valueOf(particle.isNewlyCreated()) );
|
||||
}
|
||||
_particles[i].copyChangedProperties(particle);
|
||||
thisParticle.copyChangedProperties(particle);
|
||||
} else {
|
||||
if (wantDebug) {
|
||||
printf(">>> IGNORING SERVER!!! Would've caused jutter! <<< "
|
||||
|
@ -159,22 +178,23 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) {
|
|||
const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) const {
|
||||
const Particle* closestParticle = NULL;
|
||||
float closestParticleDistance = FLT_MAX;
|
||||
uint16_t numberOfParticles = _particles.size();
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
float distanceToParticle = glm::distance(position, _particles[i].getPosition());
|
||||
float distanceToParticle = glm::distance(position, (*_particles)[i].getPosition());
|
||||
if (distanceToParticle < closestParticleDistance) {
|
||||
closestParticle = &_particles[i];
|
||||
closestParticle = &(*_particles)[i];
|
||||
}
|
||||
}
|
||||
return closestParticle;
|
||||
}
|
||||
|
||||
const Particle* ParticleTreeElement::getParticleWithID(uint32_t id) const {
|
||||
// NOTE: this lookup is O(N) but maybe we don't care? (guaranteed that num particles per elemen is small?)
|
||||
const Particle* foundParticle = NULL;
|
||||
uint16_t numberOfParticles = _particles.size();
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
if (_particles[i].getID() == id) {
|
||||
foundParticle = &_particles[i];
|
||||
if ((*_particles)[i].getID() == id) {
|
||||
foundParticle = &(*_particles)[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +249,7 @@ bool ParticleTreeElement::collapseChildren() {
|
|||
|
||||
|
||||
void ParticleTreeElement::storeParticle(const Particle& particle, Node* senderNode) {
|
||||
_particles.push_back(particle);
|
||||
_particles->push_back(particle);
|
||||
markWithChangedTime();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
#ifndef __hifi__ParticleTreeElement__
|
||||
#define __hifi__ParticleTreeElement__
|
||||
|
||||
#include <vector>
|
||||
//#include <vector>
|
||||
|
||||
#include <OctreeElement.h>
|
||||
#include <QList>
|
||||
|
||||
#include "Particle.h"
|
||||
#include "ParticleTree.h"
|
||||
|
@ -22,7 +23,7 @@ class ParticleTreeElement;
|
|||
|
||||
class ParticleTreeUpdateArgs {
|
||||
public:
|
||||
std::vector<Particle> _movingParticles;
|
||||
QList<Particle> _movingParticles;
|
||||
};
|
||||
|
||||
class ParticleTreeElement : public OctreeElement {
|
||||
|
@ -34,7 +35,6 @@ class ParticleTreeElement : public OctreeElement {
|
|||
|
||||
public:
|
||||
virtual ~ParticleTreeElement();
|
||||
virtual void init(unsigned char * octalCode);
|
||||
|
||||
// type safe versions of OctreeElement methods
|
||||
ParticleTreeElement* getChildAtIndex(int index) { return (ParticleTreeElement*)OctreeElement::getChildAtIndex(index); }
|
||||
|
@ -79,9 +79,9 @@ public:
|
|||
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
||||
glm::vec3& penetration, void** penetratedObject) const;
|
||||
|
||||
const std::vector<Particle>& getParticles() const { return _particles; }
|
||||
std::vector<Particle>& getParticles() { return _particles; }
|
||||
bool hasParticles() const { return _particles.size() > 0; }
|
||||
const QList<Particle>& getParticles() const { return *_particles; }
|
||||
QList<Particle>& getParticles() { return *_particles; }
|
||||
bool hasParticles() const { return _particles->size() > 0; }
|
||||
|
||||
void update(ParticleTreeUpdateArgs& args);
|
||||
void setTree(ParticleTree* tree) { _myTree = tree; }
|
||||
|
@ -93,10 +93,12 @@ public:
|
|||
|
||||
|
||||
protected:
|
||||
virtual void init(unsigned char * octalCode);
|
||||
|
||||
void storeParticle(const Particle& particle, Node* senderNode = NULL);
|
||||
|
||||
ParticleTree* _myTree;
|
||||
std::vector<Particle> _particles;
|
||||
QList<Particle>* _particles;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__ParticleTreeElement__) */
|
||||
|
|
Loading…
Reference in a new issue