mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 18:23:22 +02:00
Merge branch 'master' of git://github.com/worklist/hifi into 19487
This commit is contained in:
commit
28d6171be5
20 changed files with 490 additions and 41 deletions
128
examples/findParticleExample.js
Normal file
128
examples/findParticleExample.js
Normal file
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// editParticleExample.js
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 1/24/14.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// This is an example script that demonstrates "finding" particles
|
||||
//
|
||||
|
||||
var iteration = 0;
|
||||
|
||||
var particleA = Particles.addParticle(
|
||||
{
|
||||
position: { x: 2, y: 0, z: 2 },
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
radius : 0.1,
|
||||
color: { red: 0, green: 255, blue: 0 }
|
||||
});
|
||||
|
||||
var particleB = Particles.addParticle(
|
||||
{
|
||||
position: { x: 5, y: 0, z: 5 },
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
radius : 0.1,
|
||||
color: { red: 0, green: 255, blue: 255 }
|
||||
});
|
||||
|
||||
var searchAt = { x: 0, y: 0, z: 0};
|
||||
var moveSearch = { x: 0.1, y: 0, z: 0.1};
|
||||
var searchRadius = 1;
|
||||
var searchRadiusChange = 0;
|
||||
|
||||
print("particleA.creatorTokenID = " + particleA.creatorTokenID);
|
||||
print("particleB.creatorTokenID = " + particleB.creatorTokenID);
|
||||
|
||||
|
||||
function scriptEnding() {
|
||||
print("calling Particles.deleteParticle()");
|
||||
Particles.deleteParticle(particleA);
|
||||
Particles.deleteParticle(particleB);
|
||||
}
|
||||
|
||||
function printProperties(properties) {
|
||||
for (var property in properties) {
|
||||
if (properties.hasOwnProperty(property)) {
|
||||
if (property == "position" ||
|
||||
property == "gravity" ||
|
||||
property == "velocity") {
|
||||
print(property +": " + properties[property].x + ", " + properties[property].y + ", " + properties[property].z);
|
||||
} else if (property == "color") {
|
||||
print(property +": " + properties[property].red + ", "
|
||||
+ properties[property].green + ", " + properties[property].blue);
|
||||
} else {
|
||||
print(property +": " + properties[property])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findParticles() {
|
||||
|
||||
// run for a while, then clean up
|
||||
// stop it...
|
||||
if (iteration >= 100) {
|
||||
print("calling Agent.stop()");
|
||||
Agent.stop();
|
||||
}
|
||||
|
||||
print("--------------------------");
|
||||
print("iteration =" + iteration);
|
||||
iteration++;
|
||||
|
||||
// Check to see if we've been notified of the actual identity of the particles we created
|
||||
if (!particleA.isKnownID) {
|
||||
var identifyA = Particles.identifyParticle(particleA);
|
||||
if (identifyA.isKnownID) {
|
||||
particleA = identifyA;
|
||||
print(">>>> identified particleA.id = " + particleA.id);
|
||||
}
|
||||
}
|
||||
if (!particleB.isKnownID) {
|
||||
var identifyB = Particles.identifyParticle(particleB);
|
||||
if (identifyB.isKnownID) {
|
||||
particleB = identifyB;
|
||||
print(">>>> identified particleB.id = " + particleB.id);
|
||||
}
|
||||
}
|
||||
|
||||
// also check to see if we can "find" particles...
|
||||
print("searching for particles at:" + searchAt.x + ", " + searchAt.y + ", " + searchAt.z + " radius:" + searchRadius);
|
||||
var foundParticles = Particles.findParticles(searchAt, searchRadius);
|
||||
print("found this many particles: "+ foundParticles.length);
|
||||
for (var i = 0; i < foundParticles.length; i++) {
|
||||
print(" particle[" + i + "].id:" + foundParticles[i].id);
|
||||
if (foundParticles[i].id == particleA.id) {
|
||||
print(">>>> found particleA!!");
|
||||
var propertiesA = Particles.getParticleProperties(particleA);
|
||||
printProperties(propertiesA);
|
||||
}
|
||||
if (foundParticles[i].id == particleB.id) {
|
||||
print(">>>> found particleB!!");
|
||||
}
|
||||
}
|
||||
// move search
|
||||
searchAt.x += moveSearch.x;
|
||||
searchAt.y += moveSearch.y;
|
||||
searchAt.z += moveSearch.z;
|
||||
searchRadius += searchRadiusChange;
|
||||
|
||||
// after we've searched for 80 iterations, change our search mechanism to be from the center with expanding radius
|
||||
if (iteration == 80) {
|
||||
searchAt = { x: 3.5, y: 0, z: 3.5};
|
||||
moveSearch = { x: 0, y: 0, z: 0};
|
||||
searchRadius = 0.5;
|
||||
searchRadiusChange = 0.5;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Agent.willSendVisualDataCallback.connect(findParticles);
|
||||
|
||||
// register our scriptEnding callback
|
||||
Agent.scriptEnding.connect(scriptEnding);
|
174
examples/particleBird.js
Normal file
174
examples/particleBird.js
Normal file
|
@ -0,0 +1,174 @@
|
|||
//
|
||||
// particleBird.js
|
||||
// hifi
|
||||
//
|
||||
// This sample script moves a voxel around like a bird and sometimes makes tweeting noises
|
||||
//
|
||||
function vLength(v) {
|
||||
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
|
||||
}
|
||||
function printVector(v) {
|
||||
print(v.x + ", " + v.y + ", " + v.z + "\n");
|
||||
}
|
||||
// Create a random vector with individual lengths between a,b
|
||||
function randVector(a, b) {
|
||||
var rval = { x: a + Math.random() * (b - a), y: a + Math.random() * (b - a), z: a + Math.random() * (b - a) };
|
||||
return rval;
|
||||
}
|
||||
function vMinus(a, b) {
|
||||
var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
|
||||
return rval;
|
||||
}
|
||||
function vPlus(a, b) {
|
||||
var rval = { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
|
||||
return rval;
|
||||
}
|
||||
function vCopy(a, b) {
|
||||
a.x = b.x;
|
||||
a.y = b.y;
|
||||
a.z = b.z;
|
||||
return;
|
||||
}
|
||||
// Returns a vector which is fraction of the way between a and b
|
||||
function vInterpolate(a, b, fraction) {
|
||||
var rval = { x: a.x + (b.x - a.x) * fraction, y: a.y + (b.y - a.y) * fraction, z: a.z + (b.z - a.z) * fraction };
|
||||
return rval;
|
||||
}
|
||||
|
||||
// Decide what kind of bird we are
|
||||
var tweet;
|
||||
var color;
|
||||
var size;
|
||||
var which = Math.random();
|
||||
if (which < 0.2) {
|
||||
tweet = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/bushtit_1.raw");
|
||||
color = { r: 100, g: 50, b: 120 };
|
||||
size = 0.08;
|
||||
} else if (which < 0.4) {
|
||||
tweet = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/rosyfacedlovebird.raw");
|
||||
color = { r: 100, g: 150, b: 75 };
|
||||
size = 0.09;
|
||||
} else if (which < 0.6) {
|
||||
tweet = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/saysphoebe.raw");
|
||||
color = { r: 84, g: 121, b: 36 };
|
||||
size = 0.05;
|
||||
} else if (which < 0.8) {
|
||||
tweet = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/mexicanWhipoorwill.raw");
|
||||
color = { r: 23, g: 197, b: 230 };
|
||||
size = 0.12;
|
||||
} else {
|
||||
tweet = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/westernscreechowl.raw");
|
||||
color = { r: 50, g: 67, b: 144 };
|
||||
size = 0.15;
|
||||
}
|
||||
|
||||
var startTimeInSeconds = new Date().getTime() / 1000;
|
||||
|
||||
var birdLifetime = 20; // lifetime of the bird in seconds!
|
||||
var position = { x: 0, y: 0, z: 0 };
|
||||
var targetPosition = { x: 0, y: 0, z: 0 };
|
||||
var range = 1.0; // Over what distance in meters do you want your bird to fly around
|
||||
var frame = 0;
|
||||
var moving = false;
|
||||
var tweeting = 0;
|
||||
var moved = false;
|
||||
var CHANCE_OF_MOVING = 0.05;
|
||||
var CHANCE_OF_TWEETING = 0.05;
|
||||
var START_HEIGHT_ABOVE_ME = 1.5;
|
||||
var myPosition = MyAvatar.position;
|
||||
var properties = {
|
||||
lifetime: birdLifetime,
|
||||
position: { x: myPosition.x, y: myPosition.y + START_HEIGHT_ABOVE_ME, z: myPosition.z },
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
radius : 0.1,
|
||||
color: { red: 0,
|
||||
green: 255,
|
||||
blue: 0 }
|
||||
};
|
||||
var range = 1.0; // Distance around avatar where I can move
|
||||
// Create the actual bird
|
||||
var particleID = Particles.addParticle(properties);
|
||||
function moveBird() {
|
||||
|
||||
// check to see if we've been running long enough that our bird is dead
|
||||
var nowTimeInSeconds = new Date().getTime() / 1000;
|
||||
if ((nowTimeInSeconds - startTimeInSeconds) >= birdLifetime) {
|
||||
print("our bird is dying, stop our script");
|
||||
Agent.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
myPosition = MyAvatar.position;
|
||||
frame++;
|
||||
if (frame % 3 == 0) {
|
||||
// Tweeting behavior
|
||||
if (tweeting == 0) {
|
||||
if (Math.random() < CHANCE_OF_TWEETING) {
|
||||
//print("tweet!" + "\n");
|
||||
var options = new AudioInjectionOptions();
|
||||
options.position = position;
|
||||
options.volume = 0.75;
|
||||
Audio.playSound(tweet, options);
|
||||
tweeting = 10;
|
||||
}
|
||||
} else {
|
||||
tweeting -= 1;
|
||||
}
|
||||
// Moving behavior
|
||||
if (moving == false) {
|
||||
if (Math.random() < CHANCE_OF_MOVING) {
|
||||
targetPosition = randVector(- range, range);
|
||||
targetPosition = vPlus(targetPosition, myPosition);
|
||||
if (targetPosition.x < 0) {
|
||||
targetPosition.x = 0;
|
||||
}
|
||||
if (targetPosition.y < 0) {
|
||||
targetPosition.y = 0;
|
||||
}
|
||||
if (targetPosition.z < 0) {
|
||||
targetPosition.z = 0;
|
||||
}
|
||||
if (targetPosition.x > TREE_SCALE) {
|
||||
targetPosition.x = TREE_SCALE;
|
||||
}
|
||||
if (targetPosition.y > TREE_SCALE) {
|
||||
targetPosition.y = TREE_SCALE;
|
||||
}
|
||||
if (targetPosition.z > TREE_SCALE) {
|
||||
targetPosition.z = TREE_SCALE;
|
||||
}
|
||||
//printVector(position);
|
||||
moving = true;
|
||||
}
|
||||
}
|
||||
if (moving) {
|
||||
position = vInterpolate(position, targetPosition, 0.5);
|
||||
if (vLength(vMinus(position, targetPosition)) < (size / 5.0)) {
|
||||
moved = false;
|
||||
moving = false;
|
||||
} else {
|
||||
moved = true;
|
||||
}
|
||||
}
|
||||
if (moved || (tweeting > 0)) {
|
||||
if (tweeting > 0) {
|
||||
var newProperties = {
|
||||
position: position,
|
||||
radius : size * 1.5,
|
||||
color: { red: Math.random() * 255, green: 0, blue: 0 }
|
||||
};
|
||||
} else {
|
||||
var newProperties = {
|
||||
position: position,
|
||||
radius : size,
|
||||
color: { red: color.r, green: color.g, blue: color.b }
|
||||
};
|
||||
}
|
||||
Particles.editParticle(particleID, newProperties);
|
||||
moved = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// register the call back so it fires before each data send
|
||||
Agent.willSendVisualDataCallback.connect(moveBird);
|
|
@ -3955,6 +3955,9 @@ void Application::domainChanged(const QString& domainHostname) {
|
|||
_voxelServerJurisdictions.clear();
|
||||
_octreeServerSceneStats.clear();
|
||||
_particleServerJurisdictions.clear();
|
||||
|
||||
// reset the particle renderer
|
||||
_particles.clear();
|
||||
|
||||
// reset our persist thread
|
||||
qDebug() << "Domain changed to" << domainHostname << ". Swapping persist cache.";
|
||||
|
|
|
@ -182,7 +182,7 @@ public:
|
|||
~Octree();
|
||||
|
||||
/// Your tree class must implement this to create the correct element type
|
||||
virtual OctreeElement* createNewElement(unsigned char * octalCode = NULL) const = 0;
|
||||
virtual OctreeElement* createNewElement(unsigned char * octalCode = NULL) = 0;
|
||||
|
||||
// These methods will allow the OctreeServer to send your tree inbound edit packets of your
|
||||
// own definition. Implement these to allow your octree based server to support editing
|
||||
|
|
|
@ -47,7 +47,7 @@ protected:
|
|||
// can only be constructed by derived implementation
|
||||
OctreeElement();
|
||||
|
||||
virtual OctreeElement* createNewElement(unsigned char * octalCode = NULL) const = 0;
|
||||
virtual OctreeElement* createNewElement(unsigned char * octalCode = NULL) = 0;
|
||||
|
||||
public:
|
||||
virtual void init(unsigned char * octalCode); /// Your subclass must call init on construction.
|
||||
|
|
|
@ -132,3 +132,12 @@ void OctreeRenderer::render() {
|
|||
_tree->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeRenderer::clear() {
|
||||
if (_tree) {
|
||||
_tree->lockForWrite();
|
||||
_tree->eraseAllOctreeElements();
|
||||
_tree->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ public:
|
|||
|
||||
static bool renderOperation(OctreeElement* element, void* extraData);
|
||||
|
||||
/// clears the tree
|
||||
void clear();
|
||||
protected:
|
||||
Octree* _tree;
|
||||
QUuid _dataSourceUUID;
|
||||
|
|
|
@ -292,10 +292,7 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
}
|
||||
|
||||
|
||||
Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes, ParticleTree* tree) {
|
||||
|
||||
//qDebug() << "Particle::fromEditPacket() length=" << length;
|
||||
|
||||
Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes, ParticleTree* tree, bool& valid) {
|
||||
Particle newParticle; // id and _lastUpdated will get set here...
|
||||
unsigned char* dataAt = data;
|
||||
processedBytes = 0;
|
||||
|
@ -304,9 +301,6 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
|||
int octets = numberOfThreeBitSectionsInCode(data);
|
||||
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
|
||||
|
||||
//qDebug() << "Particle::fromEditPacket() lengthOfOctcode=" << lengthOfOctcode;
|
||||
//printOctalCode(data);
|
||||
|
||||
// we don't actually do anything with this octcode...
|
||||
dataAt += lengthOfOctcode;
|
||||
processedBytes += lengthOfOctcode;
|
||||
|
@ -323,8 +317,6 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
|||
|
||||
// special case for handling "new" particles
|
||||
if (isNewParticle) {
|
||||
//qDebug() << "editID == NEW_PARTICLE";
|
||||
|
||||
// If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that
|
||||
// we want to send back to the creator as an map to the actual id
|
||||
uint32_t creatorTokenID;
|
||||
|
@ -332,11 +324,8 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
|||
dataAt += sizeof(creatorTokenID);
|
||||
processedBytes += sizeof(creatorTokenID);
|
||||
|
||||
//qDebug() << "creatorTokenID:" << creatorTokenID;
|
||||
|
||||
newParticle.setCreatorTokenID(creatorTokenID);
|
||||
newParticle._newlyCreated = true;
|
||||
|
||||
newParticle.setAge(0); // this guy is new!
|
||||
|
||||
} else {
|
||||
|
@ -346,15 +335,19 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
|||
// copy existing properties before over-writing with new properties
|
||||
if (existingParticle) {
|
||||
newParticle = *existingParticle;
|
||||
//qDebug() << "newParticle = *existingParticle... calling debugDump()...";
|
||||
//existingParticle->debugDump();
|
||||
} else {
|
||||
// the user attempted to edit a particle that doesn't exist
|
||||
qDebug() << "user attempted to edit a particle that doesn't exist...";
|
||||
valid = false;
|
||||
return newParticle;
|
||||
}
|
||||
|
||||
newParticle._id = editID;
|
||||
newParticle._newlyCreated = false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// if we got this far, then our result will be valid
|
||||
valid = true;
|
||||
|
||||
|
||||
// lastEdited
|
||||
memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited));
|
||||
|
@ -840,6 +833,8 @@ ParticleProperties::ParticleProperties() :
|
|||
_inHand(false),
|
||||
_shouldDie(false),
|
||||
|
||||
_id(UNKNOWN_PARTICLE_ID),
|
||||
_idSet(false),
|
||||
_lastEdited(usecTimestampNow()),
|
||||
_positionChanged(false),
|
||||
_colorChanged(false),
|
||||
|
@ -925,6 +920,11 @@ QScriptValue ParticleProperties::copyToScriptValue(QScriptEngine* engine) const
|
|||
properties.setProperty("script", _script);
|
||||
properties.setProperty("inHand", _inHand);
|
||||
properties.setProperty("shouldDie", _shouldDie);
|
||||
|
||||
if (_idSet) {
|
||||
properties.setProperty("id", _id);
|
||||
properties.setProperty("isKnownID", (_id == UNKNOWN_PARTICLE_ID));
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
@ -1118,6 +1118,9 @@ void ParticleProperties::copyFromParticle(const Particle& particle) {
|
|||
_inHand = particle.getInHand();
|
||||
_shouldDie = particle.getShouldDie();
|
||||
|
||||
_id = particle.getID();
|
||||
_idSet = true;
|
||||
|
||||
_positionChanged = false;
|
||||
_colorChanged = false;
|
||||
_radiusChanged = false;
|
||||
|
|
|
@ -94,6 +94,9 @@ public:
|
|||
void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; _shouldDieChanged = true; }
|
||||
void setLifetime(float value) { _lifetime = value; _lifetimeChanged = true; }
|
||||
void setScript(QString updateScript) { _script = updateScript; _scriptChanged = true; }
|
||||
|
||||
/// used by ParticleScriptingInterface to return ParticleProperties for unknown particles
|
||||
void setIsUnknownID() { _id = UNKNOWN_PARTICLE_ID; _idSet = true; }
|
||||
|
||||
private:
|
||||
glm::vec3 _position;
|
||||
|
@ -107,6 +110,8 @@ private:
|
|||
bool _inHand;
|
||||
bool _shouldDie;
|
||||
|
||||
uint32_t _id;
|
||||
bool _idSet;
|
||||
uint64_t _lastEdited;
|
||||
bool _positionChanged;
|
||||
bool _colorChanged;
|
||||
|
@ -145,6 +150,7 @@ public:
|
|||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ParticleID);
|
||||
Q_DECLARE_METATYPE(QVector<ParticleID>);
|
||||
QScriptValue ParticleIDtoScriptValue(QScriptEngine* engine, const ParticleID& properties);
|
||||
void ParticleIDfromScriptValue(const QScriptValue &object, ParticleID& properties);
|
||||
|
||||
|
@ -162,7 +168,7 @@ public:
|
|||
bool inHand = NOT_IN_HAND, QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE);
|
||||
|
||||
/// creates an NEW particle from an PACKET_TYPE_PARTICLE_ADD_OR_EDIT edit data buffer
|
||||
static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes, ParticleTree* tree);
|
||||
static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes, ParticleTree* tree, bool& valid);
|
||||
|
||||
virtual ~Particle();
|
||||
virtual void init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity,
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
|
||||
ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) {
|
||||
ParticleTreeElement* rootNode = createNewElement();
|
||||
rootNode->setTree(this);
|
||||
_rootNode = rootNode;
|
||||
}
|
||||
|
||||
ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) const {
|
||||
ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) {
|
||||
ParticleTreeElement* newElement = new ParticleTreeElement(octalCode);
|
||||
newElement->setTree(this);
|
||||
return newElement;
|
||||
}
|
||||
|
||||
|
@ -160,6 +160,42 @@ const Particle* ParticleTree::findClosestParticle(glm::vec3 position, float targ
|
|||
return args.closestParticle;
|
||||
}
|
||||
|
||||
class FindAllNearPointArgs {
|
||||
public:
|
||||
glm::vec3 position;
|
||||
float targetRadius;
|
||||
QVector<const Particle*> particles;
|
||||
};
|
||||
|
||||
|
||||
bool ParticleTree::findInSphereOperation(OctreeElement* element, void* extraData) {
|
||||
FindAllNearPointArgs* args = static_cast<FindAllNearPointArgs*>(extraData);
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
|
||||
glm::vec3 penetration;
|
||||
bool sphereIntersection = particleTreeElement->getAABox().findSpherePenetration(args->position,
|
||||
args->targetRadius, penetration);
|
||||
|
||||
// If this particleTreeElement contains the point, then search it...
|
||||
if (sphereIntersection) {
|
||||
QVector<const Particle*> moreParticles = particleTreeElement->getParticles(args->position, args->targetRadius);
|
||||
args->particles << moreParticles;
|
||||
return true; // keep searching in case children have closer particles
|
||||
}
|
||||
|
||||
// if this element doesn't contain the point, then none of it's children can contain the point, so stop searching
|
||||
return false;
|
||||
}
|
||||
|
||||
QVector<const Particle*> ParticleTree::findParticles(const glm::vec3& center, float radius) {
|
||||
QVector<Particle*> result;
|
||||
FindAllNearPointArgs args = { center, radius };
|
||||
lockForRead();
|
||||
recurseTreeWithOperation(findInSphereOperation, &args);
|
||||
unlock();
|
||||
return args.particles;
|
||||
}
|
||||
|
||||
class FindByIDArgs {
|
||||
public:
|
||||
uint32_t id;
|
||||
|
@ -214,13 +250,14 @@ int ParticleTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* p
|
|||
// we handle these types of "edit" packets
|
||||
switch (packetType) {
|
||||
case PACKET_TYPE_PARTICLE_ADD_OR_EDIT: {
|
||||
//qDebug() << " got PACKET_TYPE_PARTICLE_ADD_OR_EDIT... ";
|
||||
Particle newParticle = Particle::fromEditPacket(editData, maxLength, processedBytes, this);
|
||||
storeParticle(newParticle, senderNode);
|
||||
if (newParticle.isNewlyCreated()) {
|
||||
notifyNewlyCreatedParticle(newParticle, senderNode);
|
||||
bool isValid;
|
||||
Particle newParticle = Particle::fromEditPacket(editData, maxLength, processedBytes, this, isValid);
|
||||
if (isValid) {
|
||||
storeParticle(newParticle, senderNode);
|
||||
if (newParticle.isNewlyCreated()) {
|
||||
notifyNewlyCreatedParticle(newParticle, senderNode);
|
||||
}
|
||||
}
|
||||
//qDebug() << " DONE... PACKET_TYPE_PARTICLE_ADD_OR_EDIT... ";
|
||||
} break;
|
||||
|
||||
// TODO: wire in support here for server to get PACKET_TYPE_PARTICLE_ERASE messages
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
ParticleTree(bool shouldReaverage = false);
|
||||
|
||||
/// Implements our type specific root element factory
|
||||
virtual ParticleTreeElement* createNewElement(unsigned char * octalCode = NULL) const;
|
||||
virtual ParticleTreeElement* createNewElement(unsigned char * octalCode = NULL);
|
||||
|
||||
/// Type safe version of getRoot()
|
||||
ParticleTreeElement* getRoot() { return (ParticleTreeElement*)_rootNode; }
|
||||
|
@ -42,6 +42,7 @@ public:
|
|||
void storeParticle(const Particle& particle, Node* senderNode = NULL);
|
||||
const Particle* findClosestParticle(glm::vec3 position, float targetRadius);
|
||||
const Particle* findParticleByID(uint32_t id, bool alreadyLocked = false);
|
||||
QVector<const Particle*> findParticles(const glm::vec3& center, float radius);
|
||||
|
||||
void addNewlyCreatedHook(NewlyCreatedParticleHook* hook);
|
||||
void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook);
|
||||
|
@ -58,6 +59,7 @@ private:
|
|||
static bool updateOperation(OctreeElement* element, void* extraData);
|
||||
static bool findAndUpdateOperation(OctreeElement* element, void* extraData);
|
||||
static bool findNearPointOperation(OctreeElement* element, void* extraData);
|
||||
static bool findInSphereOperation(OctreeElement* element, void* extraData);
|
||||
static bool pruneOperation(OctreeElement* element, void* extraData);
|
||||
static bool findByIDOperation(OctreeElement* element, void* extraData);
|
||||
static bool findAndDeleteOperation(OctreeElement* element, void* extraData);
|
||||
|
|
|
@ -25,7 +25,7 @@ ParticleTreeElement::~ParticleTreeElement() {
|
|||
// own type to our own tree. This means we should initialize that child with any tree and type
|
||||
// specific settings that our children must have. One example is out VoxelSystem, which
|
||||
// we know must match ours.
|
||||
OctreeElement* ParticleTreeElement::createNewElement(unsigned char* octalCode) const {
|
||||
OctreeElement* ParticleTreeElement::createNewElement(unsigned char* octalCode) {
|
||||
ParticleTreeElement* newChild = new ParticleTreeElement(octalCode);
|
||||
newChild->setTree(_myTree);
|
||||
return newChild;
|
||||
|
@ -185,6 +185,23 @@ const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) cons
|
|||
return closestParticle;
|
||||
}
|
||||
|
||||
QVector<const Particle*> ParticleTreeElement::getParticles(glm::vec3 searchPosition, float searchRadius) const {
|
||||
QVector<const Particle*> results;
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
const Particle* particle = &(*_particles)[i];
|
||||
glm::vec3 particlePosition = particle->getPosition();
|
||||
float particleRadius = particle->getRadius();
|
||||
glm::vec3 penetration;
|
||||
|
||||
// check to see that the particle (penetrator) penetrates the search area
|
||||
if (findSphereSpherePenetration(particlePosition, particleRadius, searchPosition, searchRadius, penetration)) {
|
||||
results << particle;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -31,7 +31,7 @@ class ParticleTreeElement : public OctreeElement {
|
|||
|
||||
ParticleTreeElement(unsigned char* octalCode = NULL);
|
||||
|
||||
virtual OctreeElement* createNewElement(unsigned char* octalCode = NULL) const;
|
||||
virtual OctreeElement* createNewElement(unsigned char* octalCode = NULL);
|
||||
|
||||
public:
|
||||
virtual ~ParticleTreeElement();
|
||||
|
@ -89,6 +89,7 @@ public:
|
|||
bool containsParticle(const Particle& particle) const;
|
||||
bool updateParticle(const Particle& particle);
|
||||
const Particle* getClosestParticle(glm::vec3 position) const;
|
||||
QVector<const Particle*> getParticles(glm::vec3 position, float radius) const;
|
||||
const Particle* getParticleWithID(uint32_t id) const;
|
||||
|
||||
bool removeParticleWithID(uint32_t id);
|
||||
|
|
|
@ -34,15 +34,44 @@ ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& pr
|
|||
return id;
|
||||
}
|
||||
|
||||
void ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) {
|
||||
ParticleID ParticlesScriptingInterface::identifyParticle(ParticleID particleID) {
|
||||
uint32_t actualID = particleID.id;
|
||||
if (!particleID.isKnownID) {
|
||||
actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID);
|
||||
// hmmm... we kind of want to bail if someone attempts to edit an unknown
|
||||
if (actualID == UNKNOWN_PARTICLE_ID) {
|
||||
//qDebug() << "ParticlesScriptingInterface::editParticle()... BAILING!!! particleID.creatorTokenID="
|
||||
// << particleID.creatorTokenID;
|
||||
return; // bailing early
|
||||
return particleID; // bailing early
|
||||
}
|
||||
|
||||
// found it!
|
||||
particleID.id = actualID;
|
||||
particleID.isKnownID = true;
|
||||
}
|
||||
return particleID;
|
||||
}
|
||||
|
||||
ParticleProperties ParticlesScriptingInterface::getParticleProperties(ParticleID particleID) {
|
||||
ParticleProperties results;
|
||||
ParticleID identity = identifyParticle(particleID);
|
||||
if (!identity.isKnownID) {
|
||||
results.setIsUnknownID();
|
||||
return results;
|
||||
}
|
||||
if (_particleTree) {
|
||||
const Particle* particle = _particleTree->findParticleByID(identity.id);
|
||||
results.copyFromParticle(*particle);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ParticleID ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) {
|
||||
uint32_t actualID = particleID.id;
|
||||
if (!particleID.isKnownID) {
|
||||
actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID);
|
||||
if (actualID == UNKNOWN_PARTICLE_ID) {
|
||||
return particleID; // bailing early
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,6 +100,7 @@ void ParticlesScriptingInterface::editParticle(ParticleID particleID, const Part
|
|||
}
|
||||
}
|
||||
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, particleID, properties);
|
||||
return particleID;
|
||||
}
|
||||
|
||||
|
||||
|
@ -116,3 +146,17 @@ ParticleID ParticlesScriptingInterface::findClosestParticle(const glm::vec3& cen
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
QVector<ParticleID> ParticlesScriptingInterface::findParticles(const glm::vec3& center, float radius) const {
|
||||
QVector<ParticleID> result;
|
||||
if (_particleTree) {
|
||||
QVector<const Particle*> particles = _particleTree->findParticles(center/(float)TREE_SCALE, radius/(float)TREE_SCALE);
|
||||
|
||||
foreach (const Particle* particle, particles) {
|
||||
ParticleID thisParticleID(particle->getID(), UNKNOWN_TOKEN, true);
|
||||
result << thisParticleID;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,11 +28,33 @@ public:
|
|||
ParticleTree* getParticleTree(ParticleTree*) { return _particleTree; }
|
||||
|
||||
public slots:
|
||||
/// adds a particle with the specific properties
|
||||
ParticleID addParticle(const ParticleProperties& properties);
|
||||
void editParticle(ParticleID particleID, const ParticleProperties& properties);
|
||||
|
||||
/// identify a recently created particle to determine its true ID
|
||||
ParticleID identifyParticle(ParticleID particleID);
|
||||
|
||||
/// gets the current particle properties for a specific particle
|
||||
/// this function will not find return results in script engine contexts which don't have access to particles
|
||||
ParticleProperties getParticleProperties(ParticleID particleID);
|
||||
|
||||
/// edits a particle updating only the included properties, will return the identified ParticleID in case of
|
||||
/// successful edit, if the input particleID is for an unknown particle this function will have no effect
|
||||
ParticleID editParticle(ParticleID particleID, const ParticleProperties& properties);
|
||||
|
||||
/// deletes a particle
|
||||
void deleteParticle(ParticleID particleID);
|
||||
|
||||
/// finds the closest particle to the center point, within the radius
|
||||
/// will return a ParticleID.isKnownID = false if no particles are in the radius
|
||||
/// this function will not find any particles in script engine contexts which don't have access to particles
|
||||
ParticleID findClosestParticle(const glm::vec3& center, float radius) const;
|
||||
|
||||
/// finds particles within the search sphere specified by the center point and radius
|
||||
/// this function will not find any particles in script engine contexts which don't have access to particles
|
||||
QVector<ParticleID> findParticles(const glm::vec3& center, float radius) const;
|
||||
|
||||
|
||||
private:
|
||||
void queueParticleMessage(PACKET_TYPE packetType, ParticleID particleID, const ParticleProperties& properties);
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ void ScriptEngine::init() {
|
|||
registerMetaTypes(&_engine);
|
||||
qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue);
|
||||
qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue);
|
||||
qScriptRegisterSequenceMetaType<QVector<ParticleID> >(&_engine);
|
||||
|
||||
QScriptValue agentValue = _engine.newQObject(this);
|
||||
_engine.globalObject().setProperty("Agent", agentValue);
|
||||
|
|
|
@ -24,7 +24,7 @@ VoxelTree::VoxelTree(bool shouldReaverage) : Octree(shouldReaverage) {
|
|||
_rootNode = createNewElement();
|
||||
}
|
||||
|
||||
VoxelTreeElement* VoxelTree::createNewElement(unsigned char * octalCode) const {
|
||||
VoxelTreeElement* VoxelTree::createNewElement(unsigned char * octalCode) {
|
||||
VoxelSystem* voxelSystem = NULL;
|
||||
if (_rootNode) {
|
||||
voxelSystem = ((VoxelTreeElement*)_rootNode)->getVoxelSystem();
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
|
||||
VoxelTree(bool shouldReaverage = false);
|
||||
|
||||
virtual VoxelTreeElement* createNewElement(unsigned char * octalCode = NULL) const;
|
||||
virtual VoxelTreeElement* createNewElement(unsigned char * octalCode = NULL);
|
||||
VoxelTreeElement* getRoot() { return (VoxelTreeElement*)_rootNode; }
|
||||
|
||||
void deleteVoxelAt(float x, float y, float z, float s);
|
||||
|
|
|
@ -25,7 +25,7 @@ VoxelTreeElement::~VoxelTreeElement() {
|
|||
// own type to our own tree. This means we should initialize that child with any tree and type
|
||||
// specific settings that our children must have. One example is out VoxelSystem, which
|
||||
// we know must match ours.
|
||||
OctreeElement* VoxelTreeElement::createNewElement(unsigned char* octalCode) const {
|
||||
OctreeElement* VoxelTreeElement::createNewElement(unsigned char* octalCode) {
|
||||
VoxelTreeElement* newChild = new VoxelTreeElement(octalCode);
|
||||
newChild->setVoxelSystem(getVoxelSystem()); // our child is always part of our voxel system NULL ok
|
||||
return newChild;
|
||||
|
|
|
@ -31,7 +31,7 @@ class VoxelTreeElement : public OctreeElement {
|
|||
|
||||
VoxelTreeElement(unsigned char* octalCode = NULL);
|
||||
|
||||
virtual OctreeElement* createNewElement(unsigned char* octalCode = NULL) const;
|
||||
virtual OctreeElement* createNewElement(unsigned char* octalCode = NULL);
|
||||
|
||||
public:
|
||||
virtual ~VoxelTreeElement();
|
||||
|
|
Loading…
Reference in a new issue