mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 13:53:26 +02:00
Merge pull request #3614 from ZappoMan/removeParticles
Remove particles
This commit is contained in:
commit
415c7375cb
71 changed files with 633 additions and 5401 deletions
assignment-client
domain-server/src
examples
audioBall.jscollidingEntities.jscollidingParticles.jseditEntityExample.jsentityBirds.jsentityModelExample.jsfindEntitiesExample.jsflockingBirds.jsfountain.jsfrisbee.jsglobalCollisionsExample.jsgrenadeLauncher.jsgun.jsleapOfFaith.jspaintGun.jsrideAlongWithAnEntityExample.jsspaceInvadersExample.jstoyball.js
interface
libraries
entities/src
networking/src
particles
CMakeLists.txt
src
Particle.cppParticle.hParticleCollisionSystem.cppParticleCollisionSystem.hParticleEditPacketSender.cppParticleEditPacketSender.hParticleTree.cppParticleTree.hParticleTreeElement.cppParticleTreeElement.hParticleTreeHeadlessViewer.cppParticleTreeHeadlessViewer.hParticlesScriptingInterface.cppParticlesScriptingInterface.h
script-engine
shared/src
tests/octree
|
@ -6,7 +6,7 @@ include_glm()
|
|||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
audio avatars octree voxels fbx particles entities metavoxels
|
||||
audio avatars octree voxels fbx entities metavoxels
|
||||
networking animation shared script-engine embedded-webserver
|
||||
)
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <UUID.h>
|
||||
#include <VoxelConstants.h>
|
||||
|
||||
#include <ParticlesScriptingInterface.h> // TODO: consider moving to scriptengine.h
|
||||
#include <EntityScriptingInterface.h> // TODO: consider moving to scriptengine.h
|
||||
|
||||
#include "avatars/ScriptableAvatar.h"
|
||||
|
@ -38,7 +37,6 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
|
|||
Agent::Agent(const QByteArray& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_voxelEditSender(),
|
||||
_particleEditSender(),
|
||||
_entityEditSender(),
|
||||
_receivedAudioStream(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES,
|
||||
InboundAudioStream::Settings(0, false, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, false,
|
||||
|
@ -50,7 +48,6 @@ Agent::Agent(const QByteArray& packet) :
|
|||
_scriptEngine.setParent(this);
|
||||
|
||||
_scriptEngine.getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender);
|
||||
_scriptEngine.getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
|
||||
_scriptEngine.getEntityScriptingInterface()->setPacketSender(&_entityEditSender);
|
||||
}
|
||||
|
||||
|
@ -75,9 +72,6 @@ void Agent::readPendingDatagrams() {
|
|||
_scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener()->
|
||||
queueReceivedPacket(matchedNode,receivedPacket);
|
||||
break;
|
||||
case NodeType::ParticleServer:
|
||||
_scriptEngine.getParticlesScriptingInterface()->getJurisdictionListener()->
|
||||
queueReceivedPacket(matchedNode, receivedPacket);
|
||||
break;
|
||||
case NodeType::EntityServer:
|
||||
_scriptEngine.getEntityScriptingInterface()->getJurisdictionListener()->
|
||||
|
@ -86,31 +80,18 @@ void Agent::readPendingDatagrams() {
|
|||
}
|
||||
}
|
||||
|
||||
} else if (datagramPacketType == PacketTypeParticleAddResponse) {
|
||||
// this will keep creatorTokenIDs to IDs mapped correctly
|
||||
Particle::handleAddParticleResponse(receivedPacket);
|
||||
|
||||
// also give our local particle tree a chance to remap any internal locally created particles
|
||||
_particleViewer.getTree()->handleAddParticleResponse(receivedPacket);
|
||||
|
||||
// Make sure our Node and NodeList knows we've heard from this node.
|
||||
SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
sourceNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
} else if (datagramPacketType == PacketTypeEntityAddResponse) {
|
||||
// this will keep creatorTokenIDs to IDs mapped correctly
|
||||
EntityItemID::handleAddEntityResponse(receivedPacket);
|
||||
|
||||
// also give our local particle tree a chance to remap any internal locally created particles
|
||||
// also give our local entity tree a chance to remap any internal locally created entities
|
||||
_entityViewer.getTree()->handleAddEntityResponse(receivedPacket);
|
||||
|
||||
// Make sure our Node and NodeList knows we've heard from this node.
|
||||
SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
sourceNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
} else if (datagramPacketType == PacketTypeParticleData
|
||||
|| datagramPacketType == PacketTypeParticleErase
|
||||
|| datagramPacketType == PacketTypeOctreeStats
|
||||
} else if (datagramPacketType == PacketTypeOctreeStats
|
||||
|| datagramPacketType == PacketTypeVoxelData
|
||||
|| datagramPacketType == PacketTypeEntityData
|
||||
|| datagramPacketType == PacketTypeEntityErase
|
||||
|
@ -141,10 +122,6 @@ void Agent::readPendingDatagrams() {
|
|||
datagramPacketType = packetTypeForPacket(mutablePacket);
|
||||
} // fall through to piggyback message
|
||||
|
||||
if (datagramPacketType == PacketTypeParticleData || datagramPacketType == PacketTypeParticleErase) {
|
||||
_particleViewer.processDatagram(mutablePacket, sourceNode);
|
||||
}
|
||||
|
||||
if (datagramPacketType == PacketTypeEntityData || datagramPacketType == PacketTypeEntityErase) {
|
||||
_entityViewer.processDatagram(mutablePacket, sourceNode);
|
||||
}
|
||||
|
@ -191,7 +168,6 @@ void Agent::run() {
|
|||
<< NodeType::AudioMixer
|
||||
<< NodeType::AvatarMixer
|
||||
<< NodeType::VoxelServer
|
||||
<< NodeType::ParticleServer
|
||||
<< NodeType::EntityServer
|
||||
);
|
||||
|
||||
|
@ -248,11 +224,6 @@ void Agent::run() {
|
|||
_voxelViewer.init();
|
||||
_scriptEngine.getVoxelsScriptingInterface()->setVoxelTree(_voxelViewer.getTree());
|
||||
|
||||
_scriptEngine.registerGlobalObject("ParticleViewer", &_particleViewer);
|
||||
_particleViewer.setJurisdictionListener(_scriptEngine.getParticlesScriptingInterface()->getJurisdictionListener());
|
||||
_particleViewer.init();
|
||||
_scriptEngine.getParticlesScriptingInterface()->setParticleTree(_particleViewer.getTree());
|
||||
|
||||
_scriptEngine.registerGlobalObject("EntityViewer", &_entityViewer);
|
||||
_entityViewer.setJurisdictionListener(_scriptEngine.getEntityScriptingInterface()->getJurisdictionListener());
|
||||
_entityViewer.init();
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
#include <EntityEditPacketSender.h>
|
||||
#include <EntityTree.h>
|
||||
#include <EntityTreeHeadlessViewer.h>
|
||||
#include <ParticleEditPacketSender.h>
|
||||
#include <ParticleTree.h>
|
||||
#include <ParticleTreeHeadlessViewer.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <ThreadedAssignment.h>
|
||||
#include <VoxelEditPacketSender.h>
|
||||
|
@ -64,10 +61,8 @@ public slots:
|
|||
private:
|
||||
ScriptEngine _scriptEngine;
|
||||
VoxelEditPacketSender _voxelEditSender;
|
||||
ParticleEditPacketSender _particleEditSender;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
|
||||
ParticleTreeHeadlessViewer _particleViewer;
|
||||
VoxelTreeHeadlessViewer _voxelViewer;
|
||||
EntityTreeHeadlessViewer _entityViewer;
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "avatars/AvatarMixer.h"
|
||||
#include "metavoxels/MetavoxelServer.h"
|
||||
#include "entities/EntityServer.h"
|
||||
#include "particles/ParticleServer.h"
|
||||
#include "voxels/VoxelServer.h"
|
||||
|
||||
ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet) {
|
||||
|
@ -38,8 +37,6 @@ ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet
|
|||
return new Agent(packet);
|
||||
case Assignment::VoxelServerType:
|
||||
return new VoxelServer(packet);
|
||||
case Assignment::ParticleServerType:
|
||||
return new ParticleServer(packet);
|
||||
case Assignment::MetavoxelServerType:
|
||||
return new MetavoxelServer(packet);
|
||||
case Assignment::EntityServerType:
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
//
|
||||
// ParticleNodeData.h
|
||||
// assignment-client/src/particles
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ParticleNodeData_h
|
||||
#define hifi_ParticleNodeData_h
|
||||
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
#include "../octree/OctreeQueryNode.h"
|
||||
|
||||
class ParticleNodeData : public OctreeQueryNode {
|
||||
public:
|
||||
ParticleNodeData() :
|
||||
OctreeQueryNode(),
|
||||
_lastDeletedParticlesSentAt(0) { }
|
||||
|
||||
virtual PacketType getMyPacketType() const { return PacketTypeParticleData; }
|
||||
|
||||
quint64 getLastDeletedParticlesSentAt() const { return _lastDeletedParticlesSentAt; }
|
||||
void setLastDeletedParticlesSentAt(quint64 sentAt) { _lastDeletedParticlesSentAt = sentAt; }
|
||||
|
||||
private:
|
||||
quint64 _lastDeletedParticlesSentAt;
|
||||
};
|
||||
|
||||
#endif // hifi_ParticleNodeData_h
|
|
@ -1,140 +0,0 @@
|
|||
//
|
||||
// ParticleServer.cpp
|
||||
// assignment-client/src/particles
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QTimer>
|
||||
#include <ParticleTree.h>
|
||||
|
||||
#include "ParticleServer.h"
|
||||
#include "ParticleServerConsts.h"
|
||||
#include "ParticleNodeData.h"
|
||||
|
||||
const char* PARTICLE_SERVER_NAME = "Particle";
|
||||
const char* PARTICLE_SERVER_LOGGING_TARGET_NAME = "particle-server";
|
||||
const char* LOCAL_PARTICLES_PERSIST_FILE = "resources/particles.svo";
|
||||
|
||||
ParticleServer::ParticleServer(const QByteArray& packet) : OctreeServer(packet) {
|
||||
// nothing special to do here...
|
||||
}
|
||||
|
||||
ParticleServer::~ParticleServer() {
|
||||
ParticleTree* tree = (ParticleTree*)_tree;
|
||||
tree->removeNewlyCreatedHook(this);
|
||||
}
|
||||
|
||||
OctreeQueryNode* ParticleServer::createOctreeQueryNode() {
|
||||
return new ParticleNodeData();
|
||||
}
|
||||
|
||||
Octree* ParticleServer::createTree() {
|
||||
ParticleTree* tree = new ParticleTree(true);
|
||||
tree->addNewlyCreatedHook(this);
|
||||
return tree;
|
||||
}
|
||||
|
||||
void ParticleServer::beforeRun() {
|
||||
QTimer* pruneDeletedParticlesTimer = new QTimer(this);
|
||||
connect(pruneDeletedParticlesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedParticles()));
|
||||
const int PRUNE_DELETED_PARTICLES_INTERVAL_MSECS = 1 * 1000; // once every second
|
||||
pruneDeletedParticlesTimer->start(PRUNE_DELETED_PARTICLES_INTERVAL_MSECS);
|
||||
}
|
||||
|
||||
void ParticleServer::particleCreated(const Particle& newParticle, const SharedNodePointer& senderNode) {
|
||||
unsigned char outputBuffer[MAX_PACKET_SIZE];
|
||||
unsigned char* copyAt = outputBuffer;
|
||||
|
||||
int numBytesPacketHeader = populatePacketHeader(reinterpret_cast<char*>(outputBuffer), PacketTypeParticleAddResponse);
|
||||
int packetLength = numBytesPacketHeader;
|
||||
copyAt += numBytesPacketHeader;
|
||||
|
||||
// encode the creatorTokenID
|
||||
uint32_t creatorTokenID = newParticle.getCreatorTokenID();
|
||||
memcpy(copyAt, &creatorTokenID, sizeof(creatorTokenID));
|
||||
copyAt += sizeof(creatorTokenID);
|
||||
packetLength += sizeof(creatorTokenID);
|
||||
|
||||
// encode the particle ID
|
||||
uint32_t particleID = newParticle.getID();
|
||||
memcpy(copyAt, &particleID, sizeof(particleID));
|
||||
copyAt += sizeof(particleID);
|
||||
packetLength += sizeof(particleID);
|
||||
|
||||
NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, senderNode);
|
||||
}
|
||||
|
||||
|
||||
// ParticleServer will use the "special packets" to send list of recently deleted particles
|
||||
bool ParticleServer::hasSpecialPacketToSend(const SharedNodePointer& node) {
|
||||
bool shouldSendDeletedParticles = false;
|
||||
|
||||
// check to see if any new particles have been added since we last sent to this node...
|
||||
ParticleNodeData* nodeData = static_cast<ParticleNodeData*>(node->getLinkedData());
|
||||
if (nodeData) {
|
||||
quint64 deletedParticlesSentAt = nodeData->getLastDeletedParticlesSentAt();
|
||||
|
||||
ParticleTree* tree = static_cast<ParticleTree*>(_tree);
|
||||
shouldSendDeletedParticles = tree->hasParticlesDeletedSince(deletedParticlesSentAt);
|
||||
}
|
||||
|
||||
return shouldSendDeletedParticles;
|
||||
}
|
||||
|
||||
int ParticleServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) {
|
||||
unsigned char outputBuffer[MAX_PACKET_SIZE];
|
||||
size_t packetLength = 0;
|
||||
|
||||
ParticleNodeData* nodeData = static_cast<ParticleNodeData*>(node->getLinkedData());
|
||||
if (nodeData) {
|
||||
quint64 deletedParticlesSentAt = nodeData->getLastDeletedParticlesSentAt();
|
||||
quint64 deletePacketSentAt = usecTimestampNow();
|
||||
|
||||
ParticleTree* tree = static_cast<ParticleTree*>(_tree);
|
||||
bool hasMoreToSend = true;
|
||||
|
||||
// TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 particles?
|
||||
packetsSent = 0;
|
||||
while (hasMoreToSend) {
|
||||
hasMoreToSend = tree->encodeParticlesDeletedSince(queryNode->getSequenceNumber(), deletedParticlesSentAt,
|
||||
outputBuffer, MAX_PACKET_SIZE, packetLength);
|
||||
|
||||
//qDebug() << "sending PacketType_PARTICLE_ERASE packetLength:" << packetLength;
|
||||
|
||||
NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node));
|
||||
queryNode->packetSent(outputBuffer, packetLength);
|
||||
packetsSent++;
|
||||
}
|
||||
|
||||
nodeData->setLastDeletedParticlesSentAt(deletePacketSentAt);
|
||||
}
|
||||
|
||||
// TODO: caller is expecting a packetLength, what if we send more than one packet??
|
||||
return packetLength;
|
||||
}
|
||||
|
||||
void ParticleServer::pruneDeletedParticles() {
|
||||
ParticleTree* tree = static_cast<ParticleTree*>(_tree);
|
||||
if (tree->hasAnyDeletedParticles()) {
|
||||
|
||||
//qDebug() << "there are some deleted particles to consider...";
|
||||
quint64 earliestLastDeletedParticlesSent = usecTimestampNow() + 1; // in the future
|
||||
foreach (const SharedNodePointer& otherNode, NodeList::getInstance()->getNodeHash()) {
|
||||
if (otherNode->getLinkedData()) {
|
||||
ParticleNodeData* nodeData = static_cast<ParticleNodeData*>(otherNode->getLinkedData());
|
||||
quint64 nodeLastDeletedParticlesSentAt = nodeData->getLastDeletedParticlesSentAt();
|
||||
if (nodeLastDeletedParticlesSentAt < earliestLastDeletedParticlesSent) {
|
||||
earliestLastDeletedParticlesSent = nodeLastDeletedParticlesSentAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
//qDebug() << "earliestLastDeletedParticlesSent=" << earliestLastDeletedParticlesSent;
|
||||
tree->forgetParticlesDeletedBefore(earliestLastDeletedParticlesSent);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
//
|
||||
// ParticleServer.h
|
||||
// assignment-client/src/particles
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/2/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ParticleServer_h
|
||||
#define hifi_ParticleServer_h
|
||||
|
||||
#include "../octree/OctreeServer.h"
|
||||
|
||||
#include "Particle.h"
|
||||
#include "ParticleServerConsts.h"
|
||||
#include "ParticleTree.h"
|
||||
|
||||
/// Handles assignments of type ParticleServer - sending particles to various clients.
|
||||
class ParticleServer : public OctreeServer, public NewlyCreatedParticleHook {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ParticleServer(const QByteArray& packet);
|
||||
~ParticleServer();
|
||||
|
||||
// Subclasses must implement these methods
|
||||
virtual OctreeQueryNode* createOctreeQueryNode();
|
||||
virtual Octree* createTree();
|
||||
virtual char getMyNodeType() const { return NodeType::ParticleServer; }
|
||||
virtual PacketType getMyQueryMessageType() const { return PacketTypeParticleQuery; }
|
||||
virtual const char* getMyServerName() const { return PARTICLE_SERVER_NAME; }
|
||||
virtual const char* getMyLoggingServerTargetName() const { return PARTICLE_SERVER_LOGGING_TARGET_NAME; }
|
||||
virtual const char* getMyDefaultPersistFilename() const { return LOCAL_PARTICLES_PERSIST_FILE; }
|
||||
virtual PacketType getMyEditNackType() const { return PacketTypeParticleEditNack; }
|
||||
|
||||
// subclass may implement these method
|
||||
virtual void beforeRun();
|
||||
virtual bool hasSpecialPacketToSend(const SharedNodePointer& node);
|
||||
virtual int sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent);
|
||||
|
||||
virtual void particleCreated(const Particle& newParticle, const SharedNodePointer& senderNode);
|
||||
|
||||
public slots:
|
||||
void pruneDeletedParticles();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // hifi_ParticleServer_h
|
|
@ -1,19 +0,0 @@
|
|||
//
|
||||
// ParticleServerConsts.h
|
||||
// assignment-client/src/particles
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 8/21/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ParticleServerConsts_h
|
||||
#define hifi_ParticleServerConsts_h
|
||||
|
||||
extern const char* PARTICLE_SERVER_NAME;
|
||||
extern const char* PARTICLE_SERVER_LOGGING_TARGET_NAME;
|
||||
extern const char* LOCAL_PARTICLES_PERSIST_FILE;
|
||||
|
||||
#endif // hifi_ParticleServerConsts_h
|
|
@ -513,7 +513,7 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
|||
}
|
||||
|
||||
const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
|
||||
<< NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::ParticleServer << NodeType::EntityServer
|
||||
<< NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::EntityServer
|
||||
<< NodeType::MetavoxelServer;
|
||||
|
||||
void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSockAddr& senderSockAddr) {
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
// Created by Athanasios Gaitatzes on 2/10/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This script creates a particle in front of the user that stays in front of
|
||||
// the user's avatar as they move, and animates it's radius and color
|
||||
// This script creates a entity in front of the user that stays in front of
|
||||
// the user's avatar as they move, and animates it's size and color
|
||||
// in response to the audio intensity.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -18,56 +18,59 @@ Script.include("libraries/globals.js");
|
|||
var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/mexicanWhipoorwill.raw");
|
||||
var CHANCE_OF_PLAYING_SOUND = 0.01;
|
||||
|
||||
var FACTOR = 0.75;
|
||||
var FACTOR = 0.05;
|
||||
|
||||
var countParticles = 0; // the first time around we want to create the particle and thereafter to modify it.
|
||||
var particleID;
|
||||
var countEntities = 0; // the first time around we want to create the entity and thereafter to modify it.
|
||||
var entityID;
|
||||
|
||||
function updateParticle(deltaTime) {
|
||||
// the particle should be placed in front of the user's avatar
|
||||
function updateEntity(deltaTime) {
|
||||
// the entity should be placed in front of the user's avatar
|
||||
var avatarFront = Quat.getFront(MyAvatar.orientation);
|
||||
|
||||
// move particle three units in front of the avatar
|
||||
var particlePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(avatarFront, 3));
|
||||
// move entity three units in front of the avatar
|
||||
var entityPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(avatarFront, 3));
|
||||
|
||||
if (Math.random() < CHANCE_OF_PLAYING_SOUND) {
|
||||
// play a sound at the location of the particle
|
||||
// play a sound at the location of the entity
|
||||
var options = new AudioInjectionOptions();
|
||||
options.position = particlePosition;
|
||||
options.position = entityPosition;
|
||||
options.volume = 0.75;
|
||||
Audio.playSound(sound, options);
|
||||
}
|
||||
|
||||
var audioAverageLoudness = MyAvatar.audioAverageLoudness * FACTOR;
|
||||
//print ("Audio Loudness = " + MyAvatar.audioLoudness + " -- Audio Average Loudness = " + MyAvatar.audioAverageLoudness);
|
||||
print ("Audio Loudness = " + MyAvatar.audioLoudness + " -- Audio Average Loudness = " + MyAvatar.audioAverageLoudness);
|
||||
|
||||
if (countParticles < 1) {
|
||||
var particleProperies = {
|
||||
position: particlePosition // the particle should stay in front of the user's avatar as he moves
|
||||
if (countEntities < 1) {
|
||||
var entityProperties = {
|
||||
type: "Sphere",
|
||||
position: entityPosition // the entity should stay in front of the user's avatar as he moves
|
||||
, color: { red: 0, green: 255, blue: 0 }
|
||||
, radius: audioAverageLoudness
|
||||
, dimensions: {x: audioAverageLoudness, y: audioAverageLoudness, z: audioAverageLoudness }
|
||||
, velocity: { x: 0.0, y: 0.0, z: 0.0 }
|
||||
, gravity: { x: 0.0, y: 0.0, z: 0.0 }
|
||||
, damping: 0.0
|
||||
}
|
||||
|
||||
particleID = Particles.addParticle (particleProperies);
|
||||
countParticles++;
|
||||
entityID = Entities.addEntity(entityProperties);
|
||||
countEntities++;
|
||||
}
|
||||
else {
|
||||
// animates the particles radius and color in response to the changing audio intensity
|
||||
// animates the particles size and color in response to the changing audio intensity
|
||||
var newProperties = {
|
||||
position: particlePosition // the particle should stay in front of the user's avatar as he moves
|
||||
position: entityPosition // the entity should stay in front of the user's avatar as he moves
|
||||
, color: { red: 0, green: 255 * audioAverageLoudness, blue: 0 }
|
||||
, radius: audioAverageLoudness
|
||||
, dimensions: {x: audioAverageLoudness, y: audioAverageLoudness, z: audioAverageLoudness }
|
||||
};
|
||||
|
||||
Particles.editParticle (particleID, newProperties);
|
||||
Entities.editEntity(entityID, newProperties);
|
||||
}
|
||||
}
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(updateParticle);
|
||||
Script.update.connect(updateEntity);
|
||||
|
||||
// register our scriptEnding callback
|
||||
Script.scriptEnding.connect(function scriptEnding() {});
|
||||
Script.scriptEnding.connect(function scriptEnding() {
|
||||
Entities.deleteEntity(entityID);
|
||||
});
|
||||
|
|
128
examples/collidingEntities.js
Normal file
128
examples/collidingEntities.js
Normal file
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// collidingEntities.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/31/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that creates a couple entities, and sends them on a collision course.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var currentIteration = 0;
|
||||
var NUM_ITERATIONS_BEFORE_SEND = 15; // every 1/4th seconds send another
|
||||
|
||||
var numberEntitiesAdded = 0;
|
||||
var MAX_ENTITIES = 1;
|
||||
|
||||
var velocity = {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 1 };
|
||||
|
||||
var gravity = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0 };
|
||||
|
||||
var damping = 0.1;
|
||||
|
||||
var color = {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 0 };
|
||||
|
||||
function draw(deltaTime) {
|
||||
print("hello... draw()... currentIteration=" + currentIteration + "\n");
|
||||
|
||||
// on the first iteration, setup a single entity that's slowly moving
|
||||
if (currentIteration == 0) {
|
||||
var colorGreen = { red: 0, green: 255, blue: 0 };
|
||||
var startPosition = {
|
||||
x: 2,
|
||||
y: 0,
|
||||
z: 2 };
|
||||
var largeRadius = 0.5;
|
||||
var verySlow = {
|
||||
x: 0.01,
|
||||
y: 0,
|
||||
z: 0.01 };
|
||||
|
||||
var properties = {
|
||||
type: "Sphere",
|
||||
collisionsWillMove: true,
|
||||
position: startPosition,
|
||||
dimensions: {x: largeRadius, y: largeRadius, z: largeRadius},
|
||||
color: colorGreen,
|
||||
velocity: verySlow,
|
||||
gravity: gravity,
|
||||
damping: damping,
|
||||
lifetime: 20
|
||||
};
|
||||
|
||||
Entities.addEntity(properties);
|
||||
numberEntitiesAdded++;
|
||||
}
|
||||
|
||||
if (currentIteration++ % NUM_ITERATIONS_BEFORE_SEND === 0) {
|
||||
print("draw()... sending another... currentIteration=" +currentIteration + "\n");
|
||||
|
||||
var center = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0 };
|
||||
|
||||
var entitySize = 0.1;
|
||||
|
||||
print("number of entitys=" + numberEntitiesAdded +"\n");
|
||||
|
||||
var velocityStep = 0.1;
|
||||
if (velocity.x > 0) {
|
||||
velocity.x -= velocityStep;
|
||||
velocity.z += velocityStep;
|
||||
color.blue = 0;
|
||||
color.green = 255;
|
||||
} else {
|
||||
velocity.x += velocityStep;
|
||||
velocity.z -= velocityStep;
|
||||
color.blue = 255;
|
||||
color.green = 0;
|
||||
}
|
||||
|
||||
if (numberEntitiesAdded <= MAX_ENTITIES) {
|
||||
var properties = {
|
||||
type: "Sphere",
|
||||
collisionsWillMove: true,
|
||||
position: center,
|
||||
dimensions: {x: entitySize, y: entitySize, z: entitySize},
|
||||
color: color,
|
||||
velocity: velocity,
|
||||
gravity: gravity,
|
||||
damping: damping,
|
||||
lifetime: 20
|
||||
};
|
||||
Entities.addEntity(properties);
|
||||
numberEntitiesAdded++;
|
||||
} else {
|
||||
Script.stop();
|
||||
}
|
||||
|
||||
print("Particles Stats: " + Entities.getLifetimeInSeconds() + " seconds," +
|
||||
" Queued packets:" + Entities.getLifetimePacketsQueued() + "," +
|
||||
" PPS:" + Entities.getLifetimePPSQueued() + "," +
|
||||
" BPS:" + Entities.getLifetimeBPSQueued() + "," +
|
||||
" Sent packets:" + Entities.getLifetimePacketsSent() + "," +
|
||||
" PPS:" + Entities.getLifetimePPS() + "," +
|
||||
" BPS:" + Entities.getLifetimeBPS() +
|
||||
"\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
print("here...\n");
|
||||
Entities.setPacketsPerSecond(40000);
|
||||
Script.update.connect(draw);
|
||||
print("and here...\n");
|
|
@ -1,160 +0,0 @@
|
|||
//
|
||||
// collidingParticles.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/31/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that creates a couple particles, and sends them on a collision course.
|
||||
// One of the particles has a script that when it collides with another particle, it swaps colors with that particle.
|
||||
// The other particle has a script that when it collides with another particle it set's it's script to a suicide script.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var currentIteration = 0;
|
||||
var NUM_ITERATIONS_BEFORE_SEND = 15; // every 1/4th seconds send another
|
||||
|
||||
var numberParticlesAdded = 0;
|
||||
var MAX_PARTICLES = 1;
|
||||
|
||||
var velocity = {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 1 };
|
||||
|
||||
var gravity = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0 };
|
||||
|
||||
var damping = 0.1;
|
||||
|
||||
var scriptA = " " +
|
||||
" function collisionWithParticle(other, collision) { " +
|
||||
" print('collisionWithParticle(other.getID()=' + other.getID() + ')...'); " +
|
||||
" Vec3.print('penetration=', collision.penetration); " +
|
||||
" Vec3.print('contactPoint=', collision.contactPoint); " +
|
||||
" print('myID=' + Particle.getID() + '\\n'); " +
|
||||
" var colorBlack = { red: 0, green: 0, blue: 0 };" +
|
||||
" var otherColor = other.getColor();" +
|
||||
" print('otherColor=' + otherColor.red + ', ' + otherColor.green + ', ' + otherColor.blue + '\\n'); " +
|
||||
" var myColor = Particle.getColor();" +
|
||||
" print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " +
|
||||
" Particle.setColor(otherColor); " +
|
||||
" other.setColor(myColor); " +
|
||||
" } " +
|
||||
" Particle.collisionWithParticle.connect(collisionWithParticle); " +
|
||||
" ";
|
||||
|
||||
var scriptB = " " +
|
||||
" function collisionWithParticle(other, collision) { " +
|
||||
" print('collisionWithParticle(other.getID()=' + other.getID() + ')...'); " +
|
||||
" Vec3.print('penetration=', collision.penetration); " +
|
||||
" Vec3.print('contactPoint=', collision.contactPoint); " +
|
||||
" print('myID=' + Particle.getID() + '\\n'); " +
|
||||
" Particle.setScript('Particle.setShouldDie(true);'); " +
|
||||
" } " +
|
||||
" Particle.collisionWithParticle.connect(collisionWithParticle); " +
|
||||
" ";
|
||||
|
||||
var color = {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 0 };
|
||||
|
||||
function draw(deltaTime) {
|
||||
print("hello... draw()... currentIteration=" + currentIteration + "\n");
|
||||
|
||||
// on the first iteration, setup a single particle that's slowly moving
|
||||
if (currentIteration == 0) {
|
||||
var colorGreen = { red: 0, green: 255, blue: 0 };
|
||||
var startPosition = {
|
||||
x: 2,
|
||||
y: 0,
|
||||
z: 2 };
|
||||
var largeRadius = 0.5;
|
||||
var verySlow = {
|
||||
x: 0.01,
|
||||
y: 0,
|
||||
z: 0.01 };
|
||||
|
||||
var properties = {
|
||||
position: startPosition,
|
||||
radius: largeRadius,
|
||||
color: colorGreen,
|
||||
velocity: verySlow,
|
||||
gravity: gravity,
|
||||
damping: damping,
|
||||
inHand: false,
|
||||
script: scriptA
|
||||
};
|
||||
|
||||
Particles.addParticle(properties);
|
||||
print("hello... added particle... script=\n");
|
||||
print(scriptA);
|
||||
numberParticlesAdded++;
|
||||
}
|
||||
|
||||
if (currentIteration++ % NUM_ITERATIONS_BEFORE_SEND === 0) {
|
||||
print("draw()... sending another... currentIteration=" +currentIteration + "\n");
|
||||
|
||||
var center = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0 };
|
||||
|
||||
var particleSize = 0.1;
|
||||
|
||||
print("number of particles=" + numberParticlesAdded +"\n");
|
||||
|
||||
var velocityStep = 0.1;
|
||||
if (velocity.x > 0) {
|
||||
velocity.x -= velocityStep;
|
||||
velocity.z += velocityStep;
|
||||
color.blue = 0;
|
||||
color.green = 255;
|
||||
} else {
|
||||
velocity.x += velocityStep;
|
||||
velocity.z -= velocityStep;
|
||||
color.blue = 255;
|
||||
color.green = 0;
|
||||
}
|
||||
|
||||
if (numberParticlesAdded <= MAX_PARTICLES) {
|
||||
var properties = {
|
||||
position: center,
|
||||
radius: particleSize,
|
||||
color: color,
|
||||
velocity: velocity,
|
||||
gravity: gravity,
|
||||
damping: damping,
|
||||
inHand: false,
|
||||
script: scriptB
|
||||
};
|
||||
Particles.addParticle(properties);
|
||||
print("hello... added particle... script=\n");
|
||||
print(scriptB);
|
||||
numberParticlesAdded++;
|
||||
} else {
|
||||
Script.stop();
|
||||
}
|
||||
|
||||
print("Particles Stats: " + Particles.getLifetimeInSeconds() + " seconds," +
|
||||
" Queued packets:" + Particles.getLifetimePacketsQueued() + "," +
|
||||
" PPS:" + Particles.getLifetimePPSQueued() + "," +
|
||||
" BPS:" + Particles.getLifetimeBPSQueued() + "," +
|
||||
" Sent packets:" + Particles.getLifetimePacketsSent() + "," +
|
||||
" PPS:" + Particles.getLifetimePPS() + "," +
|
||||
" BPS:" + Particles.getLifetimeBPS() +
|
||||
"\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
print("here...\n");
|
||||
Particles.setPacketsPerSecond(40000);
|
||||
Script.update.connect(draw);
|
||||
print("and here...\n");
|
|
@ -17,6 +17,7 @@ var stopAfter = moveUntil + 100;
|
|||
var expectedLifetime = (moveUntil/60) + 1; // 1 second after done moving...
|
||||
|
||||
var originalProperties = {
|
||||
type: "Sphere",
|
||||
position: { x: 10,
|
||||
y: 0,
|
||||
z: 0 },
|
||||
|
@ -30,8 +31,6 @@ var originalProperties = {
|
|||
z: 0 },
|
||||
|
||||
|
||||
radius : 0.1,
|
||||
|
||||
color: { red: 0,
|
||||
green: 255,
|
||||
blue: 0 },
|
||||
|
@ -43,15 +42,15 @@ var originalProperties = {
|
|||
var positionDelta = { x: 0.05, y: 0, z: 0 };
|
||||
|
||||
|
||||
var particleID = Particles.addParticle(originalProperties);
|
||||
var entityID = Entities.addEntity(originalProperties);
|
||||
|
||||
function moveParticle(deltaTime) {
|
||||
function moveEntity(deltaTime) {
|
||||
if (count >= moveUntil) {
|
||||
|
||||
// delete it...
|
||||
if (count == moveUntil) {
|
||||
print("calling Particles.deleteParticle()");
|
||||
Particles.deleteParticle(particleID);
|
||||
print("calling Entities.deleteEntity()");
|
||||
Entities.deleteEntity(entityID);
|
||||
}
|
||||
|
||||
// stop it...
|
||||
|
@ -67,7 +66,7 @@ function moveParticle(deltaTime) {
|
|||
print("count =" + count);
|
||||
count++;
|
||||
|
||||
print("particleID.creatorTokenID = " + particleID.creatorTokenID);
|
||||
print("entityID.creatorTokenID = " + entityID.creatorTokenID);
|
||||
|
||||
var newProperties = {
|
||||
position: {
|
||||
|
@ -80,13 +79,13 @@ function moveParticle(deltaTime) {
|
|||
};
|
||||
|
||||
|
||||
//print("particleID = " + particleID);
|
||||
//print("entityID = " + entityID);
|
||||
print("newProperties.position = " + newProperties.position.x + "," + newProperties.position.y+ "," + newProperties.position.z);
|
||||
|
||||
Particles.editParticle(particleID, newProperties);
|
||||
Entities.editEntity(entityID, newProperties);
|
||||
}
|
||||
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(moveParticle);
|
||||
Script.update.connect(moveEntity);
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
// Created by Benjamin Arnold on May 29, 2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This sample script creates a swarm of tweeting bird particles that fly around the avatar.
|
||||
// This sample script creates a swarm of tweeting bird entities that fly around the avatar.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -91,15 +91,16 @@ function addBird()
|
|||
size = 0.15;
|
||||
}
|
||||
var properties = {
|
||||
type: "Sphere",
|
||||
lifetime: birdLifetime,
|
||||
position: Vec3.sum(randVector(-range, range), myPosition),
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: BIRD_GRAVITY, z: 0 },
|
||||
radius : size,
|
||||
dimensions: { x: size * 2, y: size * 2, z: size * 2 },
|
||||
color: color
|
||||
};
|
||||
|
||||
birds.push(new Bird(Particles.addParticle(properties), tweet, properties.position));
|
||||
birds.push(new Bird(Entities.addEntity(properties), tweet, properties.position));
|
||||
}
|
||||
|
||||
var numBirds = 30;
|
||||
|
@ -129,7 +130,7 @@ function updateBirds(deltaTime) {
|
|||
// Update all the birds
|
||||
for (var i = 0; i < numBirds; i++) {
|
||||
particleID = birds[i].particleID;
|
||||
var properties = Particles.getParticleProperties(particleID);
|
||||
var properties = Entities.getEntityProperties(particleID);
|
||||
|
||||
// Tweeting behavior
|
||||
if (birds[i].tweeting == 0) {
|
||||
|
@ -180,19 +181,19 @@ function updateBirds(deltaTime) {
|
|||
|
||||
properties.velocity = vInterpolate(properties.velocity, desiredVelocity, 0.2);
|
||||
// If we are near the target, we should get a new target
|
||||
if (Vec3.length(Vec3.subtract(properties.position, birds[i].targetPosition)) < (properties.radius / 5.0)) {
|
||||
if (Vec3.length(Vec3.subtract(properties.position, birds[i].targetPosition)) < (properties.dimensions.x / 5.0)) {
|
||||
birds[i].moving = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Use a cosine wave offset to make it look like its flapping.
|
||||
var offset = Math.cos(nowTimeInSeconds * BIRD_FLAP_SPEED) * properties.radius;
|
||||
var offset = Math.cos(nowTimeInSeconds * BIRD_FLAP_SPEED) * properties.dimensions.x;
|
||||
properties.position.y = properties.position.y + (offset - birds[i].previousFlapOffset);
|
||||
// Change position relative to previous offset.
|
||||
birds[i].previousFlapOffset = offset;
|
||||
|
||||
// Update the particle
|
||||
Particles.editParticle(particleID, properties);
|
||||
Entities.editEntity(particleID, properties);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
//
|
||||
// particleModelExample.js
|
||||
// entityModelExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 1/28/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates creating and editing a particle
|
||||
// This is an example script that demonstrates creating and editing a entity
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -17,40 +17,38 @@ var count = 0;
|
|||
var stopAfter = 100;
|
||||
|
||||
var modelPropertiesA = {
|
||||
type: "Model",
|
||||
position: { x: 1, y: 1, z: 1 },
|
||||
velocity: { x: 0.5, y: 0, z: 0.5 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
damping: 0,
|
||||
radius : 0.25,
|
||||
modelURL: HIFI_PUBLICK_BUCKET + "meshes/Feisar_Ship.FBX",
|
||||
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
|
||||
modelURL: HIFI_PUBLIC_BUCKET + "meshes/Feisar_Ship.FBX",
|
||||
lifetime: 20
|
||||
};
|
||||
|
||||
var modelPropertiesB = {
|
||||
type: "Model",
|
||||
position: { x: 1, y: 1.5, z: 1 },
|
||||
velocity: { x: 0.5, y: 0, z: 0.5 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
damping: 0,
|
||||
radius : 0.25,
|
||||
modelURL: HIFI_PUBLIC_BUCKET + "meshes/newInvader16x16.svo",
|
||||
modelScale: 450,
|
||||
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
|
||||
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
|
||||
modelURL: HIFI_PUBLIC_BUCKET + "meshes/orc.fbx",
|
||||
lifetime: 20
|
||||
};
|
||||
|
||||
var ballProperties = {
|
||||
type: "Sphere",
|
||||
position: { x: 1, y: 0.5, z: 1 },
|
||||
velocity: { x: 0.5, y: 0, z: 0.5 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
damping: 0,
|
||||
radius : 0.25,
|
||||
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
lifetime: 20
|
||||
};
|
||||
|
||||
var modelAParticleID = Particles.addParticle(modelPropertiesA);
|
||||
var modelBParticleID = Particles.addParticle(modelPropertiesB);
|
||||
var ballParticleID = Particles.addParticle(ballProperties);
|
||||
var modelAEntityID = Entities.addEntity(modelPropertiesA);
|
||||
var modelBEntityID = Entities.addEntity(modelPropertiesB);
|
||||
var ballEntityID = Entities.addEntity(ballProperties);
|
||||
|
||||
function endAfterAWhile(deltaTime) {
|
||||
// stop it...
|
|
@ -1,11 +1,11 @@
|
|||
//
|
||||
// findParticleExample.js
|
||||
// findEntityExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 1/24/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates "finding" particles
|
||||
// This is an example script that demonstrates "finding" entities
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -13,21 +13,23 @@
|
|||
|
||||
var iteration = 0;
|
||||
|
||||
var particleA = Particles.addParticle(
|
||||
var entityA = Entities.addEntity(
|
||||
{
|
||||
type: "Sphere",
|
||||
position: { x: 2, y: 0, z: 2 },
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
radius : 0.1,
|
||||
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
|
||||
color: { red: 0, green: 255, blue: 0 }
|
||||
});
|
||||
|
||||
var particleB = Particles.addParticle(
|
||||
var entityB = Entities.addEntity(
|
||||
{
|
||||
type: "Sphere",
|
||||
position: { x: 5, y: 0, z: 5 },
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
radius : 0.1,
|
||||
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
|
||||
color: { red: 0, green: 255, blue: 255 }
|
||||
});
|
||||
|
||||
|
@ -36,14 +38,14 @@ 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);
|
||||
print("entityA.creatorTokenID = " + entityA.creatorTokenID);
|
||||
print("entityB.creatorTokenID = " + entityB.creatorTokenID);
|
||||
|
||||
|
||||
function scriptEnding() {
|
||||
print("calling Particles.deleteParticle()");
|
||||
Particles.deleteParticle(particleA);
|
||||
Particles.deleteParticle(particleB);
|
||||
print("calling Entities.deleteEntity()");
|
||||
Entities.deleteEntity(entityA);
|
||||
Entities.deleteEntity(entityB);
|
||||
}
|
||||
|
||||
function printProperties(properties) {
|
||||
|
@ -63,7 +65,7 @@ function printProperties(properties) {
|
|||
}
|
||||
}
|
||||
|
||||
function findParticles(deltaTime) {
|
||||
function findEntities(deltaTime) {
|
||||
|
||||
// run for a while, then clean up
|
||||
// stop it...
|
||||
|
@ -76,35 +78,37 @@ function findParticles(deltaTime) {
|
|||
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);
|
||||
// Check to see if we've been notified of the actual identity of the entities we created
|
||||
if (!entityA.isKnownID) {
|
||||
var identifyA = Entities.identifyEntity(entityA);
|
||||
if (identifyA.isKnownID) {
|
||||
particleA = identifyA;
|
||||
print(">>>> identified particleA.id = " + particleA.id);
|
||||
entityA = identifyA;
|
||||
print(">>>> identified entityA.id = " + entityA.id);
|
||||
}
|
||||
}
|
||||
if (!particleB.isKnownID) {
|
||||
var identifyB = Particles.identifyParticle(particleB);
|
||||
if (!entityB.isKnownID) {
|
||||
var identifyB = Entities.identifyEntity(entityB);
|
||||
if (identifyB.isKnownID) {
|
||||
particleB = identifyB;
|
||||
print(">>>> identified particleB.id = " + particleB.id);
|
||||
entityB = identifyB;
|
||||
print(">>>> identified entityB.id = " + entityB.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);
|
||||
// also check to see if we can "find" entities...
|
||||
print("searching for entities at:" + searchAt.x + ", " + searchAt.y + ", " + searchAt.z + " radius:" + searchRadius);
|
||||
var foundEntities = Entities.findEntities(searchAt, searchRadius);
|
||||
print("found this many entities: "+ foundEntities.length);
|
||||
for (var i = 0; i < foundEntities.length; i++) {
|
||||
print(" foundEntities[" + i + "].id:" + foundEntities[i].id);
|
||||
if (foundEntities[i].id == entityA.id) {
|
||||
print(">>>> found entityA!!");
|
||||
var propertiesA = Entities.getEntityProperties(entityA);
|
||||
printProperties(propertiesA);
|
||||
}
|
||||
if (foundParticles[i].id == particleB.id) {
|
||||
print(">>>> found particleB!!");
|
||||
if (foundEntities[i].id == entityB.id) {
|
||||
print(">>>> found entityB!!");
|
||||
var propertiesB = Entities.getEntityProperties(entityB);
|
||||
printProperties(propertiesB);
|
||||
}
|
||||
}
|
||||
// move search
|
||||
|
@ -125,7 +129,7 @@ function findParticles(deltaTime) {
|
|||
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(findParticles);
|
||||
Script.update.connect(findEntities);
|
||||
|
||||
// register our scriptEnding callback
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -24,7 +24,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var birdsInFlock = 40;
|
||||
var birdsInFlock = 20;
|
||||
|
||||
var birdLifetime = 60; // 2 minutes
|
||||
var count=0; // iterations
|
||||
|
@ -60,7 +60,7 @@ var flockStartPosition = MyAvatar.position;
|
|||
var flockStartVelocity = { x: 0, y: 0, z: 0};
|
||||
var flockStartThrust = { x: 0, y: 0, z: 0}; // slightly upward against gravity
|
||||
var INITIAL_XY_VELOCITY_SCALE = 2;
|
||||
var birdRadius = 0.0925;
|
||||
var birdRadius = 0.2;
|
||||
var baseBirdColor = { red: 0, green: 255, blue: 255 };
|
||||
var glidingColor = { red: 255, green: 0, blue: 0 };
|
||||
var thrustUpwardColor = { red: 0, green: 255, blue: 0 };
|
||||
|
@ -153,12 +153,13 @@ function createBirds() {
|
|||
} else {
|
||||
velocity = { x: 0, y: 0, z: 0};
|
||||
}
|
||||
birds[i].particle = Particles.addParticle({
|
||||
birds[i].particle = Entities.addEntity({
|
||||
type: "Sphere",
|
||||
position: position,
|
||||
velocity: velocity,
|
||||
gravity: flockGravity,
|
||||
damping: 0,
|
||||
radius: birdRadius,
|
||||
dimensions: { x: birdRadius, y: birdRadius, z: birdRadius},
|
||||
color: baseBirdColor,
|
||||
lifetime: birdLifetime
|
||||
});
|
||||
|
@ -179,10 +180,10 @@ function updateBirds(deltaTime) {
|
|||
// identifyParticle() will check to see that the particle handle we have is in sync with the domain/server
|
||||
// context. If the handle is for a created particle that now has a known ID it will be updated to be a
|
||||
// handle with a known ID.
|
||||
birds[i].particle = Particles.identifyParticle(birds[i].particle);
|
||||
birds[i].particle = Entities.identifyEntity(birds[i].particle);
|
||||
|
||||
if (birds[i].particle.isKnownID) {
|
||||
birds[i].properties = Particles.getParticleProperties(birds[i].particle);
|
||||
birds[i].properties = Entities.getEntityProperties(birds[i].particle);
|
||||
if (birds[i].properties.isKnownID) {
|
||||
knownBirds++;
|
||||
averageVelocity = Vec3.sum(averageVelocity, birds[i].properties.velocity);
|
||||
|
@ -455,7 +456,7 @@ function updateBirds(deltaTime) {
|
|||
Vec3.print("birds["+i+"].newVelocity=", newVelocity);
|
||||
}
|
||||
|
||||
birds[i].particle = Particles.editParticle(birds[i].particle,{ velocity: newVelocity, color: color });
|
||||
birds[i].particle = Entities.editEntity(birds[i].particle,{ velocity: newVelocity, color: color });
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,13 +48,15 @@ function vInterpolate(a, b, fraction) {
|
|||
var position = { x: 5.0, y: 0.6, z: 5.0 };
|
||||
Voxels.setVoxel(position.x, 0, position.z, 0.5, 0, 0, 255);
|
||||
|
||||
var totalParticles = 0;
|
||||
var totalEntities = 0;
|
||||
function makeFountain(deltaTime) {
|
||||
if (Math.random() < 0.10) {
|
||||
//print("Made particle!\n");
|
||||
//print("Made entity!\n");
|
||||
var radius = (0.02 + (Math.random() * 0.05));
|
||||
var properties = {
|
||||
type: "Sphere",
|
||||
position: position,
|
||||
radius: (0.02 + (Math.random() * 0.05)),
|
||||
dimensions: { x: radius, y: radius, z: radius},
|
||||
color: { red: 0, green: 0, blue: 128 },
|
||||
velocity: { x: (Math.random() * 1.0 - 0.5),
|
||||
y: (1.0 + (Math.random() * 2.0)),
|
||||
|
@ -64,10 +66,10 @@ function makeFountain(deltaTime) {
|
|||
lifetime: 1
|
||||
}
|
||||
|
||||
Particles.addParticle(properties);
|
||||
totalParticles++;
|
||||
Entities.addEntity(properties);
|
||||
totalEntities++;
|
||||
}
|
||||
if (totalParticles > 100) {
|
||||
if (totalEntities > 100) {
|
||||
Script.stop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ function Hand(name, palm, tip, forwardButton, button3, trigger) {
|
|||
this.button3 = button3;
|
||||
this.trigger = trigger;
|
||||
this.holdingFrisbee = false;
|
||||
this.particle = false;
|
||||
this.entity = false;
|
||||
this.palmPosition = function() { return Controller.getSpatialControlPosition(this.palm); }
|
||||
this.grabButtonPressed = function() {
|
||||
return (
|
||||
|
@ -185,28 +185,29 @@ function playSound(sound, position) {
|
|||
|
||||
function cleanupFrisbees() {
|
||||
simulatedFrisbees = [];
|
||||
var particles = Particles.findParticles(MyAvatar.position, 1000);
|
||||
for (particle in particles) {
|
||||
Particles.deleteParticle(particles[particle]);
|
||||
var entities = Entities.findEntities(MyAvatar.position, 1000);
|
||||
for (entity in entities) {
|
||||
Entities.deleteEntity(entities[entity]);
|
||||
}
|
||||
}
|
||||
|
||||
function checkControllerSide(hand) {
|
||||
// If I don't currently have a frisbee in my hand, then try to catch closest one
|
||||
if (!hand.holdingFrisbee && hand.grabButtonPressed()) {
|
||||
var closestParticle = Particles.findClosestParticle(hand.palmPosition(), CATCH_RADIUS);
|
||||
var modelUrl = Particles.getParticleProperties(closestParticle).modelURL;
|
||||
if (closestParticle.isKnownID && validFrisbeeURL(Particles.getParticleProperties(closestParticle).modelURL)) {
|
||||
Particles.editParticle(closestParticle, {modelScale: 1, inHand: true, position: hand.holdPosition(), shouldDie: true});
|
||||
Particles.deleteParticle(closestParticle);
|
||||
var closestEntity = Entities.findClosestEntity(hand.palmPosition(), CATCH_RADIUS);
|
||||
var modelUrl = Entities.getEntityProperties(closestEntity).modelURL;
|
||||
if (closestEntity.isKnownID && validFrisbeeURL(Entities.getEntityProperties(closestEntity).modelURL)) {
|
||||
Entities.editEntity(closestEntity, {modelScale: 1, inHand: true, position: hand.holdPosition(), shouldDie: true});
|
||||
Entities.deleteEntity(closestEntity);
|
||||
debugPrint(hand.message + " HAND- CAUGHT SOMETHING!!");
|
||||
|
||||
var properties = {
|
||||
type: "Model",
|
||||
position: hand.holdPosition(),
|
||||
velocity: { x: 0, y: 0, z: 0},
|
||||
gravity: { x: 0, y: 0, z: 0},
|
||||
inHand: true,
|
||||
radius: FRISBEE_RADIUS,
|
||||
dimensions: { x: FRISBEE_RADIUS, y: FRISBEE_RADIUS / 5, z: FRISBEE_RADIUS },
|
||||
damping: 0.999,
|
||||
modelURL: modelUrl,
|
||||
modelScale: FRISBEE_MODEL_SCALE,
|
||||
|
@ -214,10 +215,10 @@ function checkControllerSide(hand) {
|
|||
lifetime: FRISBEE_LIFETIME
|
||||
};
|
||||
|
||||
newParticle = Particles.addParticle(properties);
|
||||
newEntity = Entities.addEntity(properties);
|
||||
|
||||
hand.holdingFrisbee = true;
|
||||
hand.particle = newParticle;
|
||||
hand.entity = newEntity;
|
||||
|
||||
playSound(catchSound, hand.holdPosition());
|
||||
|
||||
|
@ -228,11 +229,12 @@ function checkControllerSide(hand) {
|
|||
// If '3' is pressed, and not holding a frisbee, make a new one
|
||||
if (hand.grabButtonPressed() && !hand.holdingFrisbee && newfrisbeeEnabled) {
|
||||
var properties = {
|
||||
type: "Model",
|
||||
position: hand.holdPosition(),
|
||||
velocity: { x: 0, y: 0, z: 0},
|
||||
gravity: { x: 0, y: 0, z: 0},
|
||||
inHand: true,
|
||||
radius: FRISBEE_RADIUS,
|
||||
dimensions: { x: FRISBEE_RADIUS, y: FRISBEE_RADIUS / 5, z: FRISBEE_RADIUS },
|
||||
damping: 0.999,
|
||||
modelURL: frisbeeURL(),
|
||||
modelScale: FRISBEE_MODEL_SCALE,
|
||||
|
@ -240,9 +242,9 @@ function checkControllerSide(hand) {
|
|||
lifetime: FRISBEE_LIFETIME
|
||||
};
|
||||
|
||||
newParticle = Particles.addParticle(properties);
|
||||
newEntity = Entities.addEntity(properties);
|
||||
hand.holdingFrisbee = true;
|
||||
hand.particle = newParticle;
|
||||
hand.entity = newEntity;
|
||||
|
||||
// Play a new frisbee sound
|
||||
playSound(newSound, hand.holdPosition());
|
||||
|
@ -258,7 +260,7 @@ function checkControllerSide(hand) {
|
|||
position: hand.holdPosition(),
|
||||
modelRotation: hand.holdRotation()
|
||||
};
|
||||
Particles.editParticle(hand.particle, properties);
|
||||
Entities.editEntity(hand.entity, properties);
|
||||
} else {
|
||||
debugPrint(">>>>> " + hand.name + "-FRISBEE IN HAND, not grabbing, THROW!!!");
|
||||
// If frisbee just released, add velocity to it!
|
||||
|
@ -271,12 +273,12 @@ function checkControllerSide(hand) {
|
|||
modelRotation: hand.holdRotation()
|
||||
};
|
||||
|
||||
Particles.editParticle(hand.particle, properties);
|
||||
Entities.editEntity(hand.entity, properties);
|
||||
|
||||
simulatedFrisbees.push(hand.particle);
|
||||
simulatedFrisbees.push(hand.entity);
|
||||
|
||||
hand.holdingFrisbee = false;
|
||||
hand.particle = false;
|
||||
hand.entity = false;
|
||||
|
||||
playSound(throwSound, hand.holdPosition());
|
||||
}
|
||||
|
@ -323,7 +325,7 @@ function checkController(deltaTime) {
|
|||
function controlFrisbees(deltaTime) {
|
||||
var killSimulations = [];
|
||||
for (frisbee in simulatedFrisbees) {
|
||||
var properties = Particles.getParticleProperties(simulatedFrisbees[frisbee]);
|
||||
var properties = Entities.getEntityProperties(simulatedFrisbees[frisbee]);
|
||||
//get the horizon length from the velocity origin in order to get speed
|
||||
var speed = Vec3.length({x:properties.velocity.x, y:0, z:properties.velocity.z});
|
||||
if (speed < MIN_SIMULATION_SPEED) {
|
||||
|
@ -331,7 +333,7 @@ function controlFrisbees(deltaTime) {
|
|||
killSimulations.push(frisbee);
|
||||
continue;
|
||||
}
|
||||
Particles.editParticle(simulatedFrisbees[frisbee], {modelRotation: Quat.multiply(properties.modelRotation, Quat.fromPitchYawRollDegrees(0, speed * deltaTime * SPIN_MULTIPLIER, 0))});
|
||||
Entities.editEntity(simulatedFrisbees[frisbee], {modelRotation: Quat.multiply(properties.modelRotation, Quat.fromPitchYawRollDegrees(0, speed * deltaTime * SPIN_MULTIPLIER, 0))});
|
||||
|
||||
}
|
||||
for (var i = killSimulations.length - 1; i >= 0; i--) {
|
||||
|
|
|
@ -14,23 +14,23 @@
|
|||
|
||||
print("hello...");
|
||||
|
||||
function particleCollisionWithVoxel(particle, voxel, collision) {
|
||||
print("particleCollisionWithVoxel()..");
|
||||
print(" particle.getID()=" + particle.id);
|
||||
function entityCollisionWithVoxel(entity, voxel, collision) {
|
||||
print("entityCollisionWithVoxel()..");
|
||||
print(" entity.getID()=" + entity.id);
|
||||
print(" voxel color...=" + voxel.red + ", " + voxel.green + ", " + voxel.blue);
|
||||
Vec3.print('penetration=', collision.penetration);
|
||||
Vec3.print('contactPoint=', collision.contactPoint);
|
||||
}
|
||||
|
||||
function particleCollisionWithParticle(particleA, particleB, collision) {
|
||||
print("particleCollisionWithParticle()..");
|
||||
print(" particleA.getID()=" + particleA.id);
|
||||
print(" particleB.getID()=" + particleB.id);
|
||||
function entityCollisionWithEntity(entityA, entityB, collision) {
|
||||
print("entityCollisionWithParticle()..");
|
||||
print(" entityA.getID()=" + entityA.id);
|
||||
print(" entityB.getID()=" + entityB.id);
|
||||
Vec3.print('penetration=', collision.penetration);
|
||||
Vec3.print('contactPoint=', collision.contactPoint);
|
||||
}
|
||||
|
||||
Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel);
|
||||
Particles.particleCollisionWithParticle.connect(particleCollisionWithParticle);
|
||||
Entities.entityCollisionWithVoxel.connect(entityCollisionWithVoxel);
|
||||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||
|
||||
print("here... hello...");
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
//
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that turns the hydra controllers and mouse into a particle gun.
|
||||
// It reads the controller, watches for trigger pulls, and launches particles.
|
||||
// When particles collide with voxels they blow big holes out of the voxels.
|
||||
// This is an example script that turns the hydra controllers and mouse into a entity gun.
|
||||
// It reads the controller, watches for trigger pulls, and launches entities.
|
||||
// When entities collide with voxels they blow big holes out of the voxels.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -97,9 +97,11 @@ function shootBullet(position, velocity) {
|
|||
var BULLET_GRAVITY = -3.0;
|
||||
//Creates a grenade with a reasonable lifetime so that one is less likely to accidentally blow up
|
||||
//far away voxels
|
||||
Particles.addParticle(
|
||||
{ position: position,
|
||||
radius: BULLET_SIZE,
|
||||
Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: position,
|
||||
collisionsWillMove: true,
|
||||
dimensions: { x: BULLET_SIZE, y: BULLET_SIZE, z: BULLET_SIZE },
|
||||
color: { red: 10, green: 10, blue: 10 },
|
||||
velocity: velocity,
|
||||
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
|
||||
|
@ -133,9 +135,11 @@ function shootTarget() {
|
|||
velocity.y += TARGET_UP_VELOCITY;
|
||||
//printVector("velocity", velocity);
|
||||
|
||||
Particles.addParticle(
|
||||
{ position: newPosition,
|
||||
radius: TARGET_SIZE,
|
||||
Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: newPosition,
|
||||
collisionsWillMove: true,
|
||||
dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE },
|
||||
color: { red: 0, green: 200, blue: 200 },
|
||||
velocity: velocity,
|
||||
gravity: { x: 0, y: TARGET_GRAVITY, z: 0 },
|
||||
|
@ -152,13 +156,16 @@ function shootTarget() {
|
|||
|
||||
|
||||
|
||||
function particleCollisionWithVoxel(particle, voxel, collision) {
|
||||
function entityCollisionWithVoxel(entity, voxel, collision) {
|
||||
|
||||
print("entityCollisionWithVoxel....");
|
||||
|
||||
var VOXEL_SIZE = 0.5;
|
||||
// Don't make this big. I mean it.
|
||||
var CRATER_RADIUS = 5;
|
||||
var particleProperties = Particles.getParticleProperties(particle);
|
||||
var position = particleProperties.position;
|
||||
Particles.deleteParticle(particle);
|
||||
var entityProperties = Entities.getEntityProperties(entity);
|
||||
var position = entityProperties.position;
|
||||
Entities.deleteEntity(entity);
|
||||
|
||||
audioOptions.position = collision.contactPoint;
|
||||
Audio.playSound(impactSound, audioOptions);
|
||||
|
@ -186,7 +193,7 @@ function particleCollisionWithVoxel(particle, voxel, collision) {
|
|||
}
|
||||
}
|
||||
|
||||
function particleCollisionWithParticle(particle1, particle2, collision) {
|
||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||
score++;
|
||||
if (showScore) {
|
||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||
|
@ -198,8 +205,8 @@ function particleCollisionWithParticle(particle1, particle2, collision) {
|
|||
//print("hit, msecs = " + msecs);
|
||||
//Vec3.print("penetration = ", collision.penetration);
|
||||
//Vec3.print("contactPoint = ", collision.contactPoint);
|
||||
Particles.deleteParticle(particle1);
|
||||
Particles.deleteParticle(particle2);
|
||||
Entities.deleteEntity(entity1);
|
||||
Entities.deleteEntity(entity2);
|
||||
// play the sound near the camera so the shooter can hear it
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(targetHitSound, audioOptions);
|
||||
|
@ -347,8 +354,8 @@ function scriptEnding() {
|
|||
MyAvatar.detachOne(gunModel);
|
||||
}
|
||||
|
||||
Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel);
|
||||
Particles.particleCollisionWithParticle.connect(particleCollisionWithParticle);
|
||||
Entities.entityCollisionWithVoxel.connect(entityCollisionWithVoxel);
|
||||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.update.connect(update);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
// Modified by Philip on 3/3/14
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that turns the hydra controllers and mouse into a particle gun.
|
||||
// It reads the controller, watches for trigger pulls, and launches particles.
|
||||
// When particles collide with voxels they blow little holes out of the voxels.
|
||||
// This is an example script that turns the hydra controllers and mouse into a entity gun.
|
||||
// It reads the controller, watches for trigger pulls, and launches entities.
|
||||
// When entities collide with voxels they blow little holes out of the voxels.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -96,9 +96,10 @@ function printVector(string, vector) {
|
|||
function shootBullet(position, velocity) {
|
||||
var BULLET_SIZE = 0.01;
|
||||
var BULLET_GRAVITY = -0.02;
|
||||
Particles.addParticle(
|
||||
{ position: position,
|
||||
radius: BULLET_SIZE,
|
||||
Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: position,
|
||||
dimensions: { x: BULLET_SIZE, y: BULLET_SIZE, z: BULLET_SIZE },
|
||||
color: { red: 10, green: 10, blue: 10 },
|
||||
velocity: velocity,
|
||||
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
|
||||
|
@ -131,9 +132,10 @@ function shootTarget() {
|
|||
velocity.y += TARGET_UP_VELOCITY;
|
||||
//printVector("velocity", velocity);
|
||||
|
||||
Particles.addParticle(
|
||||
{ position: newPosition,
|
||||
radius: TARGET_SIZE,
|
||||
Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: newPosition,
|
||||
dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE },
|
||||
color: { red: 0, green: 200, blue: 200 },
|
||||
velocity: velocity,
|
||||
gravity: { x: 0, y: TARGET_GRAVITY, z: 0 },
|
||||
|
@ -150,11 +152,11 @@ function shootTarget() {
|
|||
|
||||
|
||||
|
||||
function particleCollisionWithVoxel(particle, voxel, collision) {
|
||||
function entityCollisionWithVoxel(entity, voxel, collision) {
|
||||
var HOLE_SIZE = 0.125;
|
||||
var particleProperties = Particles.getParticleProperties(particle);
|
||||
var position = particleProperties.position;
|
||||
Particles.deleteParticle(particle);
|
||||
var entityProperties = Entities.getEntityProperties(entity);
|
||||
var position = entityProperties.position;
|
||||
Entities.deleteEntity(entity);
|
||||
// Make a hole in this voxel
|
||||
//Vec3.print("voxel penetration", collision.penetration);
|
||||
//Vec3.print("voxel contactPoint", collision.contactPoint);
|
||||
|
@ -163,13 +165,13 @@ function particleCollisionWithVoxel(particle, voxel, collision) {
|
|||
Audio.playSound(impactSound, audioOptions);
|
||||
}
|
||||
|
||||
function particleCollisionWithParticle(particle1, particle2, collision) {
|
||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||
score++;
|
||||
if (showScore) {
|
||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||
}
|
||||
|
||||
// Sort out which particle is which
|
||||
// Sort out which entity is which
|
||||
|
||||
// Record shot time
|
||||
var endTime = new Date();
|
||||
|
@ -177,8 +179,8 @@ function particleCollisionWithParticle(particle1, particle2, collision) {
|
|||
//print("hit, msecs = " + msecs);
|
||||
//Vec3.print("penetration = ", collision.penetration);
|
||||
//Vec3.print("contactPoint = ", collision.contactPoint);
|
||||
Particles.deleteParticle(particle1);
|
||||
Particles.deleteParticle(particle2);
|
||||
Entities.deleteEntity(entity1);
|
||||
Entities.deleteEntity(entity2);
|
||||
// play the sound near the camera so the shooter can hear it
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(targetHitSound, audioOptions);
|
||||
|
@ -240,7 +242,6 @@ function update(deltaTime) {
|
|||
for (var t = 0; t < numberOfTriggers; t++) {
|
||||
var shootABullet = false;
|
||||
var triggerValue = Controller.getTriggerValue(t);
|
||||
|
||||
if (triggerPulled[t]) {
|
||||
// must release to at least 0.1
|
||||
if (triggerValue < 0.1) {
|
||||
|
@ -254,8 +255,8 @@ function update(deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (shootABullet) {
|
||||
|
||||
var palmController = t * controllersPerTrigger;
|
||||
var palmPosition = Controller.getSpatialControlPosition(palmController);
|
||||
|
||||
|
@ -324,8 +325,8 @@ function scriptEnding() {
|
|||
MyAvatar.detachOne(gunModel);
|
||||
}
|
||||
|
||||
Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel);
|
||||
Particles.particleCollisionWithParticle.connect(particleCollisionWithParticle);
|
||||
Entities.entityCollisionWithVoxel.connect(entityCollisionWithVoxel);
|
||||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.update.connect(update);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
|
|
|
@ -10,9 +10,6 @@
|
|||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var jointList = MyAvatar.getJointNames();
|
||||
var jointMappings = "\n# Joint list start";
|
||||
for (var i = 0; i < jointList.length; i++) {
|
||||
|
@ -66,24 +63,25 @@ function controlerToSkeletonOri( jointName, isRightSide, event ) {
|
|||
}
|
||||
|
||||
|
||||
var jointParticles = [];
|
||||
function updateJointParticle( joint, pos, ori, look ) {
|
||||
var jointShperes = [];
|
||||
function updateJointShpere( joint, pos, ori, look ) {
|
||||
/* print( "debug 1" );
|
||||
var jointID = jointParticles[ joint ];
|
||||
var jointID = jointShperes[ joint ];
|
||||
if ( jointID == null ) {
|
||||
print( "debug create " + joint );
|
||||
*/
|
||||
var radius = 0.005* look.r;
|
||||
var ballProperties = {
|
||||
type: "Sphere",
|
||||
position: pos,
|
||||
velocity: { x: 0, y: 0, z: 0},
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
damping: 0,
|
||||
radius : radius,
|
||||
dimensions: { x: radius, y: radius, z: radius },
|
||||
color: look.c,
|
||||
lifetime: 0.05
|
||||
};
|
||||
var atomPos = Particles.addParticle(ballProperties);
|
||||
var atomPos = Entities.addEntity(ballProperties);
|
||||
|
||||
/* // Zaxis
|
||||
var Zaxis = Vec3.multiply( Quat.getFront( ori ), - 1.5 * radius ) ;
|
||||
|
@ -91,31 +89,31 @@ function updateJointParticle( joint, pos, ori, look ) {
|
|||
ballProperties.radius = 0.35* radius;
|
||||
ballProperties.color= { red: 255, green: 255, blue: 255 };
|
||||
|
||||
var atomZ = Particles.addParticle(ballProperties);
|
||||
var atomZ = Entities.addEntity(ballProperties);
|
||||
|
||||
var up = Vec3.multiply( Quat.getUp( ori ), 1.5 * radius ) ;
|
||||
ballProperties.position = Vec3.sum(pos, up) ;
|
||||
ballProperties.radius = 0.35* radius;
|
||||
ballProperties.dimensions = { x: 0.35* radius, y: 0.35* radius, z: 0.35* radius };
|
||||
ballProperties.color= { red: 0, green: 255, blue: 0 };
|
||||
|
||||
var atomY = Particles.addParticle(ballProperties);
|
||||
var atomY = Entities.addEntity(ballProperties);
|
||||
|
||||
var right = Vec3.multiply( Quat.getRight( ori ), 1.5 * radius ) ;
|
||||
ballProperties.position = Vec3.sum(pos, right) ;
|
||||
ballProperties.radius = 0.35* radius;
|
||||
ballProperties.dimensions = { x: 0.35* radius, y: 0.35* radius, z: 0.35* radius };
|
||||
ballProperties.color= { red: 255, green: 0, blue: 225 };
|
||||
|
||||
var atomX = Particles.addParticle(ballProperties);
|
||||
var atomX = Entities.addEntity(ballProperties);
|
||||
*/
|
||||
// jointParticles[ joint ] = { p: atomPos, x: atomX, y: atomY, z: atomZ };
|
||||
// jointShperes[ joint ] = { p: atomPos, x: atomX, y: atomY, z: atomZ };
|
||||
/*
|
||||
} else {
|
||||
//print( "debug update " + joint );
|
||||
|
||||
var p = Particles.getParticleProperties( jointID.p );
|
||||
var p = Entities.getEntityProperties( jointID.p );
|
||||
p.position = pos;
|
||||
// p.lifetime = 1.0;
|
||||
Particles.editParticle( jointID.p, p );
|
||||
Entities.editEntity( jointID.p, p );
|
||||
|
||||
|
||||
}*/
|
||||
|
@ -212,7 +210,7 @@ function onSpatialEventHandler( jointName, look ) {
|
|||
// MyAvatar.setJointRotationFromBindSpace(_jointName, controlerToSkeletonOri( _jointName, _side, spatialEvent ));
|
||||
|
||||
|
||||
updateJointParticle(_jointName,
|
||||
updateJointShpere(_jointName,
|
||||
avatarToWorldPos( spatialEvent.absTranslation ),
|
||||
avatarToWorldQuat( spatialEvent.absRotation ),
|
||||
_look );
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
//
|
||||
// paintGun.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/31/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// initialize our triggers
|
||||
var triggerPulled = new Array();
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
for (t = 0; t < numberOfTriggers; t++) {
|
||||
triggerPulled[t] = false;
|
||||
}
|
||||
|
||||
function checkController(deltaTime) {
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
|
||||
// this is expected for hydras
|
||||
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
|
||||
for (var t = 0; t < numberOfTriggers; t++) {
|
||||
var shootABullet = false;
|
||||
var triggerValue = Controller.getTriggerValue(t);
|
||||
|
||||
if (triggerPulled[t]) {
|
||||
// must release to at least 0.1
|
||||
if (triggerValue < 0.1) {
|
||||
triggerPulled[t] = false; // unpulled
|
||||
}
|
||||
} else {
|
||||
// must pull to at least 0.9
|
||||
if (triggerValue > 0.9) {
|
||||
triggerPulled[t] = true; // pulled
|
||||
shootABullet = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shootABullet) {
|
||||
var palmController = t * controllersPerTrigger;
|
||||
var palmPosition = Controller.getSpatialControlPosition(palmController);
|
||||
|
||||
var fingerTipController = palmController + 1;
|
||||
var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
|
||||
|
||||
var palmToFingerTipVector =
|
||||
{ x: (fingerTipPosition.x - palmPosition.x),
|
||||
y: (fingerTipPosition.y - palmPosition.y),
|
||||
z: (fingerTipPosition.z - palmPosition.z) };
|
||||
|
||||
// just off the front of the finger tip
|
||||
var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2,
|
||||
y: fingerTipPosition.y + palmToFingerTipVector.y/2,
|
||||
z: fingerTipPosition.z + palmToFingerTipVector.z/2};
|
||||
|
||||
var linearVelocity = 25;
|
||||
|
||||
var velocity = { x: palmToFingerTipVector.x * linearVelocity,
|
||||
y: palmToFingerTipVector.y * linearVelocity,
|
||||
z: palmToFingerTipVector.z * linearVelocity };
|
||||
|
||||
// This is the script for the particles that this gun shoots.
|
||||
var script =
|
||||
" function collisionWithVoxel(voxel, collision) { " +
|
||||
" print('collisionWithVoxel(voxel)... '); " +
|
||||
" Vec3.print('penetration=', collision.penetration); " +
|
||||
" Vec3.print('contactPoint=', collision.contactPoint); " +
|
||||
" print('myID=' + Particle.getID() + '\\n'); " +
|
||||
" var voxelColor = { red: voxel.red, green: voxel.green, blue: voxel.blue };" +
|
||||
" var voxelAt = { x: voxel.x, y: voxel.y, z: voxel.z };" +
|
||||
" var voxelScale = voxel.s;" +
|
||||
" print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " +
|
||||
" var myColor = Particle.getColor();" +
|
||||
" print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " +
|
||||
" Particle.setColor(voxelColor); " +
|
||||
" Voxels.setVoxel(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale, 255, 255, 0); " +
|
||||
" print('Voxels.setVoxel(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " +
|
||||
" } " +
|
||||
" Particle.collisionWithVoxel.connect(collisionWithVoxel); ";
|
||||
|
||||
Particles.addParticle(
|
||||
{ position: position,
|
||||
radius: 0.01,
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
velocity: velocity,
|
||||
gravity: { x: 0, y: -0.1, z: 0 },
|
||||
damping: 0,
|
||||
script: script }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(checkController);
|
|
@ -1,12 +1,10 @@
|
|||
//
|
||||
// rideAlongWithAParticleExample.js
|
||||
// rideAlongWithAEntityExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 1/24/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates "finding" particles
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
@ -14,31 +12,32 @@
|
|||
var iteration = 0;
|
||||
var lengthOfRide = 2000; // in iterations
|
||||
|
||||
var particleA = Particles.addParticle(
|
||||
var entityA = Entities.addEntity(
|
||||
{
|
||||
type: "Sphere",
|
||||
position: { x: 10, y: 0, z: 10 },
|
||||
velocity: { x: 5, y: 0, z: 5 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
radius : 0.1,
|
||||
dimensions: { x: 1, y: 1, z: 1 },
|
||||
color: { red: 0, green: 255, blue: 0 },
|
||||
damping: 0,
|
||||
lifetime: (lengthOfRide * 60) + 1
|
||||
});
|
||||
|
||||
function rideWithParticle(deltaTime) {
|
||||
function rideWithEntity(deltaTime) {
|
||||
|
||||
if (iteration <= lengthOfRide) {
|
||||
|
||||
// Check to see if we've been notified of the actual identity of the particles we created
|
||||
if (!particleA.isKnownID) {
|
||||
particleA = Particles.identifyParticle(particleA);
|
||||
// Check to see if we've been notified of the actual identity of the entities we created
|
||||
if (!entityA.isKnownID) {
|
||||
entityA = Entities.identifyEntity(entityA);
|
||||
}
|
||||
|
||||
var propertiesA = Particles.getParticleProperties(particleA);
|
||||
var propertiesA = Entities.getEntityProperties(entityA);
|
||||
var newPosition = propertiesA.position;
|
||||
MyAvatar.position = { x: propertiesA.position.x,
|
||||
y: propertiesA.position.y + 2,
|
||||
z: propertiesA.position.z };
|
||||
MyAvatar.position = { x: propertiesA.position.x - 1,
|
||||
y: propertiesA.position.y + 0,
|
||||
z: propertiesA.position.z - 1 };
|
||||
} else {
|
||||
Script.stop();
|
||||
}
|
||||
|
@ -49,5 +48,5 @@ function rideWithParticle(deltaTime) {
|
|||
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(rideWithParticle);
|
||||
Script.update.connect(rideWithEntity);
|
||||
|
|
@ -95,7 +95,7 @@ var currentMoveSound = 0;
|
|||
var numberOfSounds = 4;
|
||||
var stepsPerSound = invaderStepsPerCycle / numberOfSounds;
|
||||
|
||||
// if you set this to false, sounds will come from the location of particles instead of the player's head
|
||||
// if you set this to false, sounds will come from the location of entities instead of the player's head
|
||||
var soundInMyHead = true;
|
||||
|
||||
// models...
|
||||
|
@ -134,18 +134,17 @@ invaderModels[4] = {
|
|||
|
||||
function initializeMyShip() {
|
||||
myShipProperties = {
|
||||
type: "Model",
|
||||
position: { x: middleX , y: gameAt.y, z: gameAt.z },
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
damping: 0,
|
||||
radius: shipSize,
|
||||
dimensions: { x: shipSize * 2, y: shipSize * 2, z: shipSize * 2 },
|
||||
color: { red: 0, green: 255, blue: 0 },
|
||||
modelURL: HIFI_PUBLIC_BUCKET + "meshes/myCannon16x16.svo",
|
||||
modelScale: 450,
|
||||
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
|
||||
lifetime: itemLifetimes
|
||||
};
|
||||
myShip = Particles.addParticle(myShipProperties);
|
||||
myShip = Entities.addEntity(myShipProperties);
|
||||
}
|
||||
|
||||
// calculate the correct invaderPosition for an column row
|
||||
|
@ -173,16 +172,15 @@ function initializeInvaders() {
|
|||
invaders[row] = new Array();
|
||||
for (var column = 0; column < invadersPerRow; column++) {
|
||||
invaderPosition = getInvaderPosition(row, column);
|
||||
invaders[row][column] = Particles.addParticle({
|
||||
invaders[row][column] = Entities.addEntity({
|
||||
type: "Model",
|
||||
position: invaderPosition,
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
damping: 0,
|
||||
radius: invaderSize,
|
||||
dimensions: { x: invaderSize * 2, y: invaderSize * 2, z: invaderSize * 2 },
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
modelURL: invaderModels[row].modelURL,
|
||||
modelScale: invaderModels[row].modelScale,
|
||||
modelTranslation: invaderModels[row].modelTranslation,
|
||||
lifetime: itemLifetimes
|
||||
});
|
||||
|
||||
|
@ -194,10 +192,10 @@ function initializeInvaders() {
|
|||
function moveInvaders() {
|
||||
for (var row = 0; row < numberOfRows; row++) {
|
||||
for (var column = 0; column < invadersPerRow; column++) {
|
||||
props = Particles.getParticleProperties(invaders[row][column]);
|
||||
props = Entities.getEntityProperties(invaders[row][column]);
|
||||
if (props.isKnownID) {
|
||||
invaderPosition = getInvaderPosition(row, column);
|
||||
Particles.editParticle(invaders[row][column],
|
||||
Entities.editEntity(invaders[row][column],
|
||||
{
|
||||
position: invaderPosition,
|
||||
velocity: { x: 0, y: 0, z: 0 } // always reset this, incase they got collided with
|
||||
|
@ -266,19 +264,19 @@ Script.update.connect(update);
|
|||
|
||||
function cleanupGame() {
|
||||
print("cleaning up game...");
|
||||
Particles.deleteParticle(myShip);
|
||||
print("cleanupGame() ... Particles.deleteParticle(myShip)... myShip.id="+myShip.id);
|
||||
Entities.deleteEntity(myShip);
|
||||
print("cleanupGame() ... Entities.deleteEntity(myShip)... myShip.id="+myShip.id);
|
||||
for (var row = 0; row < numberOfRows; row++) {
|
||||
for (var column = 0; column < invadersPerRow; column++) {
|
||||
Particles.deleteParticle(invaders[row][column]);
|
||||
print("cleanupGame() ... Particles.deleteParticle(invaders[row][column])... invaders[row][column].id="
|
||||
Entities.deleteEntity(invaders[row][column]);
|
||||
print("cleanupGame() ... Entities.deleteEntity(invaders[row][column])... invaders[row][column].id="
|
||||
+invaders[row][column].id);
|
||||
}
|
||||
}
|
||||
|
||||
// clean up our missile
|
||||
if (missileFired) {
|
||||
Particles.deleteParticle(myMissile);
|
||||
Entities.deleteEntity(myMissile);
|
||||
}
|
||||
|
||||
Controller.releaseKeyEvents({text: " "});
|
||||
|
@ -293,8 +291,8 @@ function endGame() {
|
|||
}
|
||||
|
||||
function moveShipTo(position) {
|
||||
myShip = Particles.identifyParticle(myShip);
|
||||
Particles.editParticle(myShip, { position: position });
|
||||
myShip = Entities.identifyEntity(myShip);
|
||||
Entities.editEntity(myShip, { position: position });
|
||||
}
|
||||
|
||||
function fireMissile() {
|
||||
|
@ -303,7 +301,7 @@ function fireMissile() {
|
|||
|
||||
// If we've fired a missile, then check to see if it's still alive
|
||||
if (missileFired) {
|
||||
var missileProperties = Particles.getParticleProperties(myMissile);
|
||||
var missileProperties = Entities.getEntityProperties(myMissile);
|
||||
print("missileProperties.isKnownID=" + missileProperties.isKnownID);
|
||||
|
||||
if (!missileProperties.isKnownID) {
|
||||
|
@ -320,13 +318,14 @@ function fireMissile() {
|
|||
y: myShipProperties.position.y + (2* shipSize),
|
||||
z: myShipProperties.position.z };
|
||||
|
||||
myMissile = Particles.addParticle(
|
||||
myMissile = Entities.addEntity(
|
||||
{
|
||||
type: "Sphere",
|
||||
position: missilePosition,
|
||||
velocity: { x: 0, y: 5, z: 0},
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
damping: 0,
|
||||
radius: missileSize,
|
||||
dimensions: { x: missileSize * 2, y: missileSize * 2, z: missileSize * 2 },
|
||||
color: { red: 0, green: 0, blue: 255 },
|
||||
lifetime: 5
|
||||
});
|
||||
|
@ -371,14 +370,14 @@ function keyPressEvent(key) {
|
|||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.captureKeyEvents({text: " "});
|
||||
|
||||
function deleteIfInvader(possibleInvaderParticle) {
|
||||
function deleteIfInvader(possibleInvaderEntity) {
|
||||
for (var row = 0; row < numberOfRows; row++) {
|
||||
for (var column = 0; column < invadersPerRow; column++) {
|
||||
invaders[row][column] = Particles.identifyParticle(invaders[row][column]);
|
||||
invaders[row][column] = Entities.identifyEntity(invaders[row][column]);
|
||||
if (invaders[row][column].isKnownID) {
|
||||
if (invaders[row][column].id == possibleInvaderParticle.id) {
|
||||
Particles.deleteParticle(possibleInvaderParticle);
|
||||
Particles.deleteParticle(myMissile);
|
||||
if (invaders[row][column].id == possibleInvaderEntity.id) {
|
||||
Entities.deleteEntity(possibleInvaderEntity);
|
||||
Entities.deleteEntity(myMissile);
|
||||
|
||||
// play the hit sound
|
||||
var options = new AudioInjectionOptions();
|
||||
|
@ -397,20 +396,20 @@ function deleteIfInvader(possibleInvaderParticle) {
|
|||
}
|
||||
}
|
||||
|
||||
function particleCollisionWithParticle(particleA, particleB, collision) {
|
||||
print("particleCollisionWithParticle() a.id="+particleA.id + " b.id=" + particleB.id);
|
||||
Vec3.print('particleCollisionWithParticle() penetration=', collision.penetration);
|
||||
Vec3.print('particleCollisionWithParticle() contactPoint=', collision.contactPoint);
|
||||
function entityCollisionWithEntity(entityA, entityB, collision) {
|
||||
print("entityCollisionWithEntity() a.id="+entityA.id + " b.id=" + entityB.id);
|
||||
Vec3.print('entityCollisionWithEntity() penetration=', collision.penetration);
|
||||
Vec3.print('entityCollisionWithEntity() contactPoint=', collision.contactPoint);
|
||||
if (missileFired) {
|
||||
myMissile = Particles.identifyParticle(myMissile);
|
||||
if (myMissile.id == particleA.id) {
|
||||
deleteIfInvader(particleB);
|
||||
} else if (myMissile.id == particleB.id) {
|
||||
deleteIfInvader(particleA);
|
||||
myMissile = Entities.identifyEntity(myMissile);
|
||||
if (myMissile.id == entityA.id) {
|
||||
deleteIfInvader(entityB);
|
||||
} else if (myMissile.id == entityB.id) {
|
||||
deleteIfInvader(entityA);
|
||||
}
|
||||
}
|
||||
}
|
||||
Particles.particleCollisionWithParticle.connect(particleCollisionWithParticle);
|
||||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||
|
||||
|
||||
// initialize the game...
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that turns the hydra controllers into a toy ball catch and throw game.
|
||||
// It reads the controller, watches for button presses and trigger pulls, and launches particles.
|
||||
// It reads the controller, watches for button presses and trigger pulls, and launches entities.
|
||||
//
|
||||
// The particles it creates have a script that when they collide with Voxels, the
|
||||
// particle will change it's color to match the voxel it hits.
|
||||
// The entities it creates have a script that when they collide with Voxels, the
|
||||
// entity will change it's color to match the voxel it hits.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -36,8 +36,8 @@ var THROWN_COLOR = { red: 128, green: 0, blue: 0 };
|
|||
|
||||
var leftBallAlreadyInHand = false;
|
||||
var rightBallAlreadyInHand = false;
|
||||
var leftHandParticle;
|
||||
var rightHandParticle;
|
||||
var leftHandEntity;
|
||||
var rightHandEntity;
|
||||
|
||||
var newSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw");
|
||||
var catchSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw");
|
||||
|
@ -90,18 +90,18 @@ function checkControllerSide(whichSide) {
|
|||
|
||||
// If I don't currently have a ball in my hand, then try to catch closest one
|
||||
if (!ballAlreadyInHand && grabButtonPressed) {
|
||||
var closestParticle = Particles.findClosestParticle(palmPosition, targetRadius);
|
||||
var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius);
|
||||
|
||||
if (closestParticle.isKnownID) {
|
||||
if (closestEntity.isKnownID) {
|
||||
|
||||
debugPrint(handMessage + " HAND- CAUGHT SOMETHING!!");
|
||||
|
||||
if (whichSide == LEFT_PALM) {
|
||||
leftBallAlreadyInHand = true;
|
||||
leftHandParticle = closestParticle;
|
||||
leftHandEntity = closestEntity;
|
||||
} else {
|
||||
rightBallAlreadyInHand = true;
|
||||
rightHandParticle = closestParticle;
|
||||
rightHandEntity = closestEntity;
|
||||
}
|
||||
var ballPosition = getBallHoldPosition(whichSide);
|
||||
var properties = { position: { x: ballPosition.x,
|
||||
|
@ -111,7 +111,7 @@ function checkControllerSide(whichSide) {
|
|||
velocity : { x: 0, y: 0, z: 0},
|
||||
lifetime : 600,
|
||||
inHand: true };
|
||||
Particles.editParticle(closestParticle, properties);
|
||||
Entities.editEntity(closestEntity, properties);
|
||||
|
||||
var options = new AudioInjectionOptions();
|
||||
options.position = ballPosition;
|
||||
|
@ -131,26 +131,28 @@ function checkControllerSide(whichSide) {
|
|||
// If '3' is pressed, and not holding a ball, make a new one
|
||||
if (grabButtonPressed && !ballAlreadyInHand) {
|
||||
var ballPosition = getBallHoldPosition(whichSide);
|
||||
var properties = { position: { x: ballPosition.x,
|
||||
y: ballPosition.y,
|
||||
z: ballPosition.z },
|
||||
var properties = {
|
||||
type: "Sphere",
|
||||
position: { x: ballPosition.x,
|
||||
y: ballPosition.y,
|
||||
z: ballPosition.z },
|
||||
velocity: { x: 0, y: 0, z: 0},
|
||||
gravity: { x: 0, y: 0, z: 0},
|
||||
inHand: true,
|
||||
radius: BALL_RADIUS,
|
||||
radius: { x: BALL_RADIUS * 2, y: BALL_RADIUS * 2, z: BALL_RADIUS * 2 },
|
||||
damping: 0.999,
|
||||
color: HELD_COLOR,
|
||||
|
||||
lifetime: 600 // 10 seconds - same as default, not needed but here as an example
|
||||
};
|
||||
|
||||
newParticle = Particles.addParticle(properties);
|
||||
newEntity = Entities.addEntity(properties);
|
||||
if (whichSide == LEFT_PALM) {
|
||||
leftBallAlreadyInHand = true;
|
||||
leftHandParticle = newParticle;
|
||||
leftHandEntity = newEntity;
|
||||
} else {
|
||||
rightBallAlreadyInHand = true;
|
||||
rightHandParticle = newParticle;
|
||||
rightHandEntity = newEntity;
|
||||
}
|
||||
|
||||
// Play a new ball sound
|
||||
|
@ -164,10 +166,10 @@ function checkControllerSide(whichSide) {
|
|||
|
||||
if (ballAlreadyInHand) {
|
||||
if (whichSide == LEFT_PALM) {
|
||||
handParticle = leftHandParticle;
|
||||
handEntity = leftHandEntity;
|
||||
whichTip = LEFT_TIP;
|
||||
} else {
|
||||
handParticle = rightHandParticle;
|
||||
handEntity = rightHandEntity;
|
||||
whichTip = RIGHT_TIP;
|
||||
}
|
||||
|
||||
|
@ -179,7 +181,7 @@ function checkControllerSide(whichSide) {
|
|||
y: ballPosition.y,
|
||||
z: ballPosition.z },
|
||||
};
|
||||
Particles.editParticle(handParticle, properties);
|
||||
Entities.editEntity(handEntity, properties);
|
||||
} else {
|
||||
debugPrint(">>>>> " + handMessage + "-BALL IN HAND, not grabbing, THROW!!!");
|
||||
// If toy ball just released, add velocity to it!
|
||||
|
@ -195,14 +197,14 @@ function checkControllerSide(whichSide) {
|
|||
gravity: { x: 0, y: -GRAVITY_STRENGTH, z: 0},
|
||||
};
|
||||
|
||||
Particles.editParticle(handParticle, properties);
|
||||
Entities.editEntity(handEntity, properties);
|
||||
|
||||
if (whichSide == LEFT_PALM) {
|
||||
leftBallAlreadyInHand = false;
|
||||
leftHandParticle = false;
|
||||
leftHandEntity = false;
|
||||
} else {
|
||||
rightBallAlreadyInHand = false;
|
||||
rightHandParticle = false;
|
||||
rightHandEntity = false;
|
||||
}
|
||||
|
||||
var options = new AudioInjectionOptions();
|
||||
|
|
|
@ -101,7 +101,7 @@ endif()
|
|||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_libraries(shared octree voxels fbx metavoxels networking particles entities avatars audio animation script-engine)
|
||||
link_hifi_libraries(shared octree voxels fbx metavoxels networking entities avatars audio animation script-engine)
|
||||
|
||||
# find any optional and required libraries
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
#include <OctalCode.h>
|
||||
#include <OctreeSceneStats.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <ParticlesScriptingInterface.h>
|
||||
#include <PerfStat.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
@ -313,12 +312,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
// tell the NodeList instance who to tell the domain server we care about
|
||||
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
|
||||
<< NodeType::VoxelServer << NodeType::ParticleServer << NodeType::EntityServer
|
||||
<< NodeType::VoxelServer << NodeType::EntityServer
|
||||
<< NodeType::MetavoxelServer);
|
||||
|
||||
// connect to the packet sent signal of the _voxelEditSender and the _particleEditSender
|
||||
// connect to the packet sent signal of the _voxelEditSender and the _entityEditSender
|
||||
connect(&_voxelEditSender, &VoxelEditPacketSender::packetSent, this, &Application::packetSent);
|
||||
connect(&_particleEditSender, &ParticleEditPacketSender::packetSent, this, &Application::packetSent);
|
||||
connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);
|
||||
|
||||
// move the silentNodeTimer to the _nodeThread
|
||||
|
@ -361,16 +359,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
// Tell our voxel edit sender about our known jurisdictions
|
||||
_voxelEditSender.setVoxelServerJurisdictions(&_voxelServerJurisdictions);
|
||||
_particleEditSender.setServerJurisdictions(&_particleServerJurisdictions);
|
||||
_entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
|
||||
|
||||
Particle::setVoxelEditPacketSender(&_voxelEditSender);
|
||||
Particle::setParticleEditPacketSender(&_particleEditSender);
|
||||
|
||||
// For now we're going to set the PPS for outbound packets to be super high, this is
|
||||
// probably not the right long term solution. But for now, we're going to do this to
|
||||
// allow you to move a particle around in your hand
|
||||
_particleEditSender.setPacketsPerSecond(3000); // super high!!
|
||||
// allow you to move an entity around in your hand
|
||||
_entityEditSender.setPacketsPerSecond(3000); // super high!!
|
||||
|
||||
checkVersion();
|
||||
|
@ -447,7 +440,6 @@ Application::~Application() {
|
|||
_octreeProcessor.terminate();
|
||||
_voxelHideShowThread.terminate();
|
||||
_voxelEditSender.terminate();
|
||||
_particleEditSender.terminate();
|
||||
_entityEditSender.terminate();
|
||||
|
||||
|
||||
|
@ -542,7 +534,6 @@ void Application::initializeGL() {
|
|||
_octreeProcessor.initialize(_enableProcessVoxelsThread);
|
||||
_voxelEditSender.initialize(_enableProcessVoxelsThread);
|
||||
_voxelHideShowThread.initialize(_enableProcessVoxelsThread);
|
||||
_particleEditSender.initialize(_enableProcessVoxelsThread);
|
||||
_entityEditSender.initialize(_enableProcessVoxelsThread);
|
||||
|
||||
if (_enableProcessVoxelsThread) {
|
||||
|
@ -798,7 +789,6 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod
|
|||
channel = BandwidthMeter::AVATARS;
|
||||
break;
|
||||
case NodeType::VoxelServer:
|
||||
case NodeType::ParticleServer:
|
||||
case NodeType::EntityServer:
|
||||
channel = BandwidthMeter::VOXELS;
|
||||
break;
|
||||
|
@ -1361,7 +1351,7 @@ void Application::dropEvent(QDropEvent *event) {
|
|||
void Application::sendPingPackets() {
|
||||
QByteArray pingPacket = NodeList::getInstance()->constructPingPacket();
|
||||
controlledBroadcastToNodes(pingPacket, NodeSet()
|
||||
<< NodeType::VoxelServer << NodeType::ParticleServer << NodeType::EntityServer
|
||||
<< NodeType::VoxelServer << NodeType::EntityServer
|
||||
<< NodeType::AudioMixer << NodeType::AvatarMixer
|
||||
<< NodeType::MetavoxelServer);
|
||||
}
|
||||
|
@ -1849,29 +1839,24 @@ void Application::init() {
|
|||
_voxels.setDisableFastVoxelPipeline(false);
|
||||
_voxels.init();
|
||||
|
||||
_particles.init();
|
||||
_particles.setViewFrustum(getViewFrustum());
|
||||
|
||||
_entities.init();
|
||||
_entities.setViewFrustum(getViewFrustum());
|
||||
|
||||
_entityCollisionSystem.init(&_entityEditSender, _entities.getTree(), _voxels.getTree(), &_audio, &_avatarManager);
|
||||
|
||||
// connect the _entityCollisionSystem to our script engine's EntityScriptingInterface
|
||||
connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithVoxel,
|
||||
ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithVoxel);
|
||||
|
||||
connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithEntity,
|
||||
ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity);
|
||||
|
||||
_entityClipboardRenderer.init();
|
||||
_entityClipboardRenderer.setViewFrustum(getViewFrustum());
|
||||
_entityClipboardRenderer.setTree(&_entityClipboard);
|
||||
|
||||
_metavoxels.init();
|
||||
|
||||
_particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_avatarManager);
|
||||
|
||||
// connect the _particleCollisionSystem to our script engine's ParticlesScriptingInterface
|
||||
connect(&_particleCollisionSystem, &ParticleCollisionSystem::particleCollisionWithVoxel,
|
||||
ScriptEngine::getParticlesScriptingInterface(), &ParticlesScriptingInterface::particleCollisionWithVoxel);
|
||||
|
||||
connect(&_particleCollisionSystem, &ParticleCollisionSystem::particleCollisionWithParticle,
|
||||
ScriptEngine::getParticlesScriptingInterface(), &ParticlesScriptingInterface::particleCollisionWithParticle);
|
||||
|
||||
_audio.init(_glWidget);
|
||||
|
||||
_rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect, _settings);
|
||||
|
@ -2088,7 +2073,6 @@ void Application::updateThreads(float deltaTime) {
|
|||
_octreeProcessor.threadRoutine();
|
||||
_voxelHideShowThread.threadRoutine();
|
||||
_voxelEditSender.threadRoutine();
|
||||
_particleEditSender.threadRoutine();
|
||||
_entityEditSender.threadRoutine();
|
||||
}
|
||||
}
|
||||
|
@ -2208,15 +2192,6 @@ void Application::update(float deltaTime) {
|
|||
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||
updateCursor(deltaTime); // Handle cursor updates
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("particles");
|
||||
_particles.update(); // update the particles...
|
||||
{
|
||||
PerformanceTimer perfTimer("collisions");
|
||||
_particleCollisionSystem.update(); // collide the particles...
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("entities");
|
||||
_entities.update(); // update the models...
|
||||
|
@ -2271,9 +2246,6 @@ void Application::update(float deltaTime) {
|
|||
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
||||
queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions);
|
||||
}
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Particles)) {
|
||||
queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions);
|
||||
}
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) {
|
||||
queryOctree(NodeType::EntityServer, PacketTypeEntityQuery, _entityServerJurisdictions);
|
||||
}
|
||||
|
@ -2331,7 +2303,6 @@ int Application::sendNackPackets() {
|
|||
|
||||
if (node->getActiveSocket() &&
|
||||
( node->getType() == NodeType::VoxelServer
|
||||
|| node->getType() == NodeType::ParticleServer
|
||||
|| node->getType() == NodeType::EntityServer)
|
||||
) {
|
||||
|
||||
|
@ -2722,11 +2693,6 @@ void Application::updateShadowMap() {
|
|||
_avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("particles");
|
||||
_particles.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("entities");
|
||||
_entities.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
|
@ -2919,14 +2885,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
_metavoxels.render();
|
||||
}
|
||||
|
||||
// render particles...
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Particles)) {
|
||||
PerformanceTimer perfTimer("particles");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... particles...");
|
||||
_particles.render();
|
||||
}
|
||||
|
||||
// render models...
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) {
|
||||
PerformanceTimer perfTimer("entities");
|
||||
|
@ -3503,13 +3461,6 @@ void Application::domainChanged(const QString& domainHostname) {
|
|||
|
||||
_octreeServerSceneStats.clear();
|
||||
|
||||
_particleServerJurisdictions.lockForWrite();
|
||||
_particleServerJurisdictions.clear();
|
||||
_particleServerJurisdictions.unlock();
|
||||
|
||||
// reset the particle renderer
|
||||
_particles.clear();
|
||||
|
||||
// reset the model renderer
|
||||
_entities.clear();
|
||||
|
||||
|
@ -3547,7 +3498,6 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
_octreeProcessor.nodeKilled(node);
|
||||
|
||||
_voxelEditSender.nodeKilled(node);
|
||||
_particleEditSender.nodeKilled(node);
|
||||
_entityEditSender.nodeKilled(node);
|
||||
|
||||
if (node->getType() == NodeType::AudioMixer) {
|
||||
|
@ -3591,43 +3541,6 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
}
|
||||
_octreeSceneStatsLock.unlock();
|
||||
|
||||
} else if (node->getType() == NodeType::ParticleServer) {
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
// see if this is the first we've heard of this node...
|
||||
_particleServerJurisdictions.lockForRead();
|
||||
if (_particleServerJurisdictions.find(nodeUUID) != _particleServerJurisdictions.end()) {
|
||||
unsigned char* rootCode = _particleServerJurisdictions[nodeUUID].getRootOctalCode();
|
||||
VoxelPositionSize rootDetails;
|
||||
voxelDetailsForCode(rootCode, rootDetails);
|
||||
_particleServerJurisdictions.unlock();
|
||||
|
||||
qDebug("particle server going away...... v[%f, %f, %f, %f]",
|
||||
rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
|
||||
|
||||
// Add the jurisditionDetails object to the list of "fade outs"
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnVoxelServerChanges)) {
|
||||
VoxelFade fade(VoxelFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE);
|
||||
fade.voxelDetails = rootDetails;
|
||||
const float slightly_smaller = 0.99f;
|
||||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||
_voxelFadesLock.lockForWrite();
|
||||
_voxelFades.push_back(fade);
|
||||
_voxelFadesLock.unlock();
|
||||
}
|
||||
|
||||
// If the particle server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server
|
||||
_particleServerJurisdictions.lockForWrite();
|
||||
_particleServerJurisdictions.erase(_particleServerJurisdictions.find(nodeUUID));
|
||||
}
|
||||
_particleServerJurisdictions.unlock();
|
||||
|
||||
// also clean up scene stats for that server
|
||||
_octreeSceneStatsLock.lockForWrite();
|
||||
if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) {
|
||||
_octreeServerSceneStats.erase(nodeUUID);
|
||||
}
|
||||
_octreeSceneStatsLock.unlock();
|
||||
|
||||
} else if (node->getType() == NodeType::EntityServer) {
|
||||
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
|
@ -3719,9 +3632,6 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin
|
|||
if (sendingNode->getType() == NodeType::VoxelServer) {
|
||||
jurisdiction = &_voxelServerJurisdictions;
|
||||
serverType = "Voxel";
|
||||
} else if (sendingNode->getType() == NodeType::ParticleServer) {
|
||||
jurisdiction = &_particleServerJurisdictions;
|
||||
serverType = "Particle";
|
||||
} else {
|
||||
jurisdiction = &_entityServerJurisdictions;
|
||||
serverType = "Entity";
|
||||
|
@ -3847,9 +3757,6 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
|
|||
scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender);
|
||||
scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree());
|
||||
scriptEngine->getVoxelsScriptingInterface()->setUndoStack(&_undoStack);
|
||||
scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
|
||||
scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree());
|
||||
|
||||
scriptEngine->getEntityScriptingInterface()->setPacketSender(&_entityEditSender);
|
||||
scriptEngine->getEntityScriptingInterface()->setEntityTree(_entities.getTree());
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
#include <NetworkPacket.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <ParticleCollisionSystem.h>
|
||||
#include <ParticleEditPacketSender.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <OctreeQuery.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
@ -64,7 +62,6 @@
|
|||
#include "devices/Visage.h"
|
||||
#include "devices/DdeFaceTracker.h"
|
||||
#include "entities/EntityTreeRenderer.h"
|
||||
#include "particles/ParticleTreeRenderer.h"
|
||||
#include "renderer/AmbientOcclusionEffect.h"
|
||||
#include "renderer/DeferredLightingEffect.h"
|
||||
#include "renderer/GeometryCache.h"
|
||||
|
@ -197,7 +194,6 @@ public:
|
|||
VoxelSystem* getVoxels() { return &_voxels; }
|
||||
VoxelTree* getVoxelTree() { return _voxels.getTree(); }
|
||||
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
|
||||
ParticleTreeRenderer* getParticles() { return &_particles; }
|
||||
MetavoxelSystem* getMetavoxels() { return &_metavoxels; }
|
||||
EntityTreeRenderer* getEntities() { return &_entities; }
|
||||
bool getImportSucceded() { return _importSucceded; }
|
||||
|
@ -286,7 +282,6 @@ public:
|
|||
|
||||
glm::vec2 getViewportDimensions() const { return glm::vec2(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); }
|
||||
NodeToJurisdictionMap& getVoxelServerJurisdictions() { return _voxelServerJurisdictions; }
|
||||
NodeToJurisdictionMap& getParticleServerJurisdictions() { return _particleServerJurisdictions; }
|
||||
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
|
||||
void pasteVoxelsToOctalCode(const unsigned char* octalCodeDestination);
|
||||
|
||||
|
@ -478,9 +473,6 @@ private:
|
|||
VoxelSystem _sharedVoxelSystem;
|
||||
ViewFrustum _sharedVoxelSystemViewFrustum;
|
||||
|
||||
ParticleTreeRenderer _particles;
|
||||
ParticleCollisionSystem _particleCollisionSystem;
|
||||
|
||||
EntityTreeRenderer _entities;
|
||||
EntityCollisionSystem _entityCollisionSystem;
|
||||
EntityTreeRenderer _entityClipboardRenderer;
|
||||
|
@ -492,7 +484,7 @@ private:
|
|||
MetavoxelSystem _metavoxels;
|
||||
|
||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels, particles)
|
||||
ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels)
|
||||
ViewFrustum _displayViewFrustum;
|
||||
ViewFrustum _shadowViewFrustum;
|
||||
quint64 _lastQueriedTime;
|
||||
|
@ -569,7 +561,6 @@ private:
|
|||
OctreePacketProcessor _octreeProcessor;
|
||||
VoxelHideShowThread _voxelHideShowThread;
|
||||
VoxelEditPacketSender _voxelEditSender;
|
||||
ParticleEditPacketSender _particleEditSender;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
|
||||
int _packetsPerSecond;
|
||||
|
@ -582,7 +573,6 @@ private:
|
|||
void trackIncomingVoxelPacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket);
|
||||
|
||||
NodeToJurisdictionMap _voxelServerJurisdictions;
|
||||
NodeToJurisdictionMap _particleServerJurisdictions;
|
||||
NodeToJurisdictionMap _entityServerJurisdictions;
|
||||
NodeToOctreeSceneStats _octreeServerSceneStats;
|
||||
QReadWriteLock _octreeSceneStatsLock;
|
||||
|
|
|
@ -70,18 +70,11 @@ void DatagramProcessor::processDatagrams() {
|
|||
|
||||
break;
|
||||
}
|
||||
case PacketTypeParticleAddResponse:
|
||||
// this will keep creatorTokenIDs to IDs mapped correctly
|
||||
Particle::handleAddParticleResponse(incomingPacket);
|
||||
application->getParticles()->getTree()->handleAddParticleResponse(incomingPacket);
|
||||
break;
|
||||
case PacketTypeEntityAddResponse:
|
||||
// this will keep creatorTokenIDs to IDs mapped correctly
|
||||
EntityItemID::handleAddEntityResponse(incomingPacket);
|
||||
application->getEntities()->getTree()->handleAddEntityResponse(incomingPacket);
|
||||
break;
|
||||
case PacketTypeParticleData:
|
||||
case PacketTypeParticleErase:
|
||||
case PacketTypeEntityData:
|
||||
case PacketTypeEntityErase:
|
||||
case PacketTypeVoxelData:
|
||||
|
@ -163,11 +156,6 @@ void DatagramProcessor::processDatagrams() {
|
|||
application->_voxelEditSender.processNackPacket(incomingPacket);
|
||||
}
|
||||
break;
|
||||
case PacketTypeParticleEditNack:
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
|
||||
application->_particleEditSender.processNackPacket(incomingPacket);
|
||||
}
|
||||
break;
|
||||
case PacketTypeEntityEditNack:
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
|
||||
application->_entityEditSender.processNackPacket(incomingPacket);
|
||||
|
|
|
@ -298,8 +298,6 @@ Menu::Menu() :
|
|||
0, true, avatar, SLOT(updateCollisionGroups()));
|
||||
addCheckableActionToQMenuAndActionHash(collisionsMenu, MenuOption::CollideWithVoxels,
|
||||
0, false, avatar, SLOT(updateCollisionGroups()));
|
||||
addCheckableActionToQMenuAndActionHash(collisionsMenu, MenuOption::CollideWithParticles,
|
||||
0, true, avatar, SLOT(updateCollisionGroups()));
|
||||
addCheckableActionToQMenuAndActionHash(collisionsMenu, MenuOption::CollideWithEnvironment,
|
||||
0, false, avatar, SLOT(updateCollisionGroups()));
|
||||
|
||||
|
@ -346,9 +344,6 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersEntityNodes,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_2, false,
|
||||
&nodeBounds, SLOT(setShowEntityNodes(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersParticleNodes,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_3, false,
|
||||
&nodeBounds, SLOT(setShowParticleNodes(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false);
|
||||
|
@ -370,7 +365,6 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Avatars, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Models, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true);
|
||||
|
||||
QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows");
|
||||
QActionGroup* shadowGroup = new QActionGroup(shadowMenu);
|
||||
|
|
|
@ -367,7 +367,6 @@ namespace MenuOption {
|
|||
const QString CollideAsRagdoll = "Collide With Self (Ragdoll)";
|
||||
const QString CollideWithAvatars = "Collide With Other Avatars";
|
||||
const QString CollideWithEnvironment = "Collide With World Boundaries";
|
||||
const QString CollideWithParticles = "Collide With Particles";
|
||||
const QString CollideWithVoxels = "Collide With Voxels";
|
||||
const QString Collisions = "Collisions";
|
||||
const QString Console = "Console...";
|
||||
|
@ -433,11 +432,10 @@ namespace MenuOption {
|
|||
const QString NameLocation = "Name this location";
|
||||
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
|
||||
const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity";
|
||||
const QString OctreeStats = "Voxel and Particle Statistics";
|
||||
const QString OctreeStats = "Voxel and Entity Statistics";
|
||||
const QString OffAxisProjection = "Off-Axis Projection";
|
||||
const QString OldVoxelCullingMode = "Old Voxel Culling Mode";
|
||||
const QString Pair = "Pair";
|
||||
const QString Particles = "Particles";
|
||||
const QString PasteToVoxel = "Paste to Voxel...";
|
||||
const QString PipelineWarnings = "Log Render Pipeline Warnings";
|
||||
const QString Preferences = "Preferences...";
|
||||
|
@ -463,7 +461,6 @@ namespace MenuOption {
|
|||
const QString SettingsExport = "Export Settings";
|
||||
const QString SettingsImport = "Import Settings";
|
||||
const QString ShowBordersEntityNodes = "Show Entity Nodes";
|
||||
const QString ShowBordersParticleNodes = "Show Particle Nodes";
|
||||
const QString ShowBordersVoxelNodes = "Show Voxel Nodes";
|
||||
const QString ShowIKConstraints = "Show IK Constraints";
|
||||
const QString SimpleShadows = "Simple";
|
||||
|
|
|
@ -1004,9 +1004,6 @@ void Avatar::updateCollisionGroups() {
|
|||
if (Menu::getInstance()->isOptionChecked(MenuOption::CollideWithVoxels)) {
|
||||
_collisionGroups |= COLLISION_GROUP_VOXELS;
|
||||
}
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CollideWithParticles)) {
|
||||
_collisionGroups |= COLLISION_GROUP_PARTICLES;
|
||||
}
|
||||
}
|
||||
|
||||
void Avatar::setScale(float scale) {
|
||||
|
|
|
@ -1971,7 +1971,6 @@ void MyAvatar::setCollisionGroups(quint32 collisionGroups) {
|
|||
menu->setIsOptionChecked(MenuOption::CollideWithEnvironment, (bool)(_collisionGroups & COLLISION_GROUP_ENVIRONMENT));
|
||||
menu->setIsOptionChecked(MenuOption::CollideWithAvatars, (bool)(_collisionGroups & COLLISION_GROUP_AVATARS));
|
||||
menu->setIsOptionChecked(MenuOption::CollideWithVoxels, (bool)(_collisionGroups & COLLISION_GROUP_VOXELS));
|
||||
menu->setIsOptionChecked(MenuOption::CollideWithParticles, (bool)(_collisionGroups & COLLISION_GROUP_PARTICLES));
|
||||
if (! (_collisionGroups & COLLISION_GROUP_VOXELS)) {
|
||||
// no collision with voxels --> disable standing on floors
|
||||
_motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
//
|
||||
// ParticleTreeRenderer.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/6/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include "Application.h"
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include "ParticleTreeRenderer.h"
|
||||
|
||||
ParticleTreeRenderer::ParticleTreeRenderer() :
|
||||
OctreeRenderer() {
|
||||
}
|
||||
|
||||
ParticleTreeRenderer::~ParticleTreeRenderer() {
|
||||
// delete the models in _particleModels
|
||||
foreach(Model* model, _particleModels) {
|
||||
delete model;
|
||||
}
|
||||
_particleModels.clear();
|
||||
}
|
||||
|
||||
void ParticleTreeRenderer::init() {
|
||||
OctreeRenderer::init();
|
||||
}
|
||||
|
||||
|
||||
void ParticleTreeRenderer::update() {
|
||||
if (_tree) {
|
||||
ParticleTree* tree = static_cast<ParticleTree*>(_tree);
|
||||
tree->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleTreeRenderer::render(RenderMode renderMode) {
|
||||
OctreeRenderer::render(renderMode);
|
||||
}
|
||||
|
||||
Model* ParticleTreeRenderer::getModel(const QString& url) {
|
||||
Model* model = NULL;
|
||||
|
||||
// if we don't already have this model then create it and initialize it
|
||||
if (_particleModels.find(url) == _particleModels.end()) {
|
||||
model = new Model();
|
||||
model->init();
|
||||
model->setURL(QUrl(url));
|
||||
_particleModels[url] = model;
|
||||
} else {
|
||||
model = _particleModels[url];
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const QList<Particle>& particles = particleTreeElement->getParticles();
|
||||
|
||||
uint16_t numberOfParticles = particles.size();
|
||||
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
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]);
|
||||
float radius = particle.getRadius() * (float)TREE_SCALE;
|
||||
|
||||
bool drawAsModel = particle.hasModel();
|
||||
|
||||
args->_itemsRendered++;
|
||||
|
||||
if (drawAsModel) {
|
||||
glPushMatrix();
|
||||
const float alpha = 1.0f;
|
||||
|
||||
Model* model = getModel(particle.getModelURL());
|
||||
glm::vec3 translationAdjustment = particle.getModelTranslation() * radius;
|
||||
|
||||
// set the position
|
||||
glm::vec3 translation = position + translationAdjustment;
|
||||
model->setTranslation(translation);
|
||||
|
||||
// set the rotation
|
||||
glm::quat rotation = particle.getModelRotation();
|
||||
model->setRotation(rotation);
|
||||
|
||||
// scale
|
||||
// TODO: need to figure out correct scale adjust, this was arbitrarily set to make a couple models work
|
||||
const float MODEL_SCALE = 0.00575f;
|
||||
glm::vec3 scale(1.0f,1.0f,1.0f);
|
||||
|
||||
float modelScale = particle.getModelScale();
|
||||
model->setScale(scale * MODEL_SCALE * radius * modelScale);
|
||||
|
||||
model->simulate(0.0f);
|
||||
|
||||
// TODO: should we allow particles to have alpha on their models?
|
||||
Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE
|
||||
? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
model->render(alpha, modelRenderMode);
|
||||
|
||||
const bool wantDebugSphere = false;
|
||||
if (wantDebugSphere) {
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
Application::getInstance()->getDeferredLightingEffect()->renderWireSphere(radius, 15, 15);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
} else {
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
Application::getInstance()->getDeferredLightingEffect()->renderSolidSphere(radius, 15, 15);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleTreeRenderer::processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
||||
if (_tree){
|
||||
_tree->lockForWrite();
|
||||
static_cast<ParticleTree*>(_tree)->processEraseMessage(dataByteArray, sourceNode);
|
||||
_tree->unlock();
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
//
|
||||
// ParticleTreeRenderer.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/6/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ParticleTreeRenderer_h
|
||||
#define hifi_ParticleTreeRenderer_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <Octree.h>
|
||||
#include <OctreePacketData.h>
|
||||
#include <OctreeRenderer.h>
|
||||
#include <ParticleTree.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include "renderer/Model.h"
|
||||
|
||||
// Generic client side Octree renderer class.
|
||||
class ParticleTreeRenderer : public OctreeRenderer {
|
||||
public:
|
||||
ParticleTreeRenderer();
|
||||
virtual ~ParticleTreeRenderer();
|
||||
|
||||
virtual Octree* createTree() { return new ParticleTree(true); }
|
||||
virtual char getMyNodeType() const { return NodeType::ParticleServer; }
|
||||
virtual PacketType getMyQueryMessageType() const { return PacketTypeParticleQuery; }
|
||||
virtual PacketType getExpectedPacketType() const { return PacketTypeParticleData; }
|
||||
virtual void renderElement(OctreeElement* element, RenderArgs* args);
|
||||
|
||||
void update();
|
||||
|
||||
ParticleTree* getTree() { return (ParticleTree*)_tree; }
|
||||
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
|
||||
virtual void init();
|
||||
virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE);
|
||||
|
||||
protected:
|
||||
Model* getModel(const QString& url);
|
||||
|
||||
QMap<QString, Model*> _particleModels;
|
||||
};
|
||||
|
||||
#endif // hifi_ParticleTreeRenderer_h
|
|
@ -5,7 +5,7 @@
|
|||
// Created by Ryan Huffman on 05/14/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This class draws a border around the different Voxel, Entity, and Particle nodes on the current domain,
|
||||
// This class draws a border around the different Voxel, Entity nodes on the current domain,
|
||||
// and a semi-transparent cube around the currently mouse-overed node.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -21,20 +21,18 @@ NodeBounds::NodeBounds(QObject* parent) :
|
|||
QObject(parent),
|
||||
_showVoxelNodes(false),
|
||||
_showEntityNodes(false),
|
||||
_showParticleNodes(false),
|
||||
_overlayText() {
|
||||
|
||||
}
|
||||
|
||||
void NodeBounds::draw() {
|
||||
if (!(_showVoxelNodes || _showEntityNodes || _showParticleNodes)) {
|
||||
if (!(_showVoxelNodes || _showEntityNodes)) {
|
||||
_overlayText[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
NodeToJurisdictionMap& voxelServerJurisdictions = Application::getInstance()->getVoxelServerJurisdictions();
|
||||
NodeToJurisdictionMap& entityServerJurisdictions = Application::getInstance()->getEntityServerJurisdictions();
|
||||
NodeToJurisdictionMap& particleServerJurisdictions = Application::getInstance()->getParticleServerJurisdictions();
|
||||
NodeToJurisdictionMap* serverJurisdictions;
|
||||
|
||||
// Compute ray to find selected nodes later on. We can't use the pre-computed ray in Application because it centers
|
||||
|
@ -63,8 +61,6 @@ void NodeBounds::draw() {
|
|||
serverJurisdictions = &voxelServerJurisdictions;
|
||||
} else if (nodeType == NodeType::EntityServer && _showEntityNodes) {
|
||||
serverJurisdictions = &entityServerJurisdictions;
|
||||
} else if (nodeType == NodeType::ParticleServer && _showParticleNodes) {
|
||||
serverJurisdictions = &particleServerJurisdictions;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
@ -90,7 +86,6 @@ void NodeBounds::draw() {
|
|||
|
||||
const float VOXEL_NODE_SCALE = 1.00f;
|
||||
const float ENTITY_NODE_SCALE = 0.99f;
|
||||
const float PARTICLE_NODE_SCALE = 0.98f;
|
||||
|
||||
float scaleFactor = rootDetails.s * TREE_SCALE;
|
||||
|
||||
|
@ -103,8 +98,6 @@ void NodeBounds::draw() {
|
|||
scaleFactor *= VOXEL_NODE_SCALE;
|
||||
} else if (nodeType == NodeType::EntityServer) {
|
||||
scaleFactor *= ENTITY_NODE_SCALE;
|
||||
} else {
|
||||
scaleFactor *= PARTICLE_NODE_SCALE;
|
||||
}
|
||||
|
||||
float red, green, blue;
|
||||
|
@ -215,7 +208,7 @@ void NodeBounds::drawNodeBorder(const glm::vec3& center, float scale, float red,
|
|||
|
||||
void NodeBounds::getColorForNodeType(NodeType_t nodeType, float& red, float& green, float& blue) {
|
||||
red = nodeType == NodeType::VoxelServer ? 1.0 : 0.0;
|
||||
green = nodeType == NodeType::ParticleServer ? 1.0 : 0.0;
|
||||
green = 0.0;
|
||||
blue = nodeType == NodeType::EntityServer ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
|
|
|
@ -229,9 +229,6 @@ void OctreeStatsDialog::showAllOctreeServers() {
|
|||
|
||||
showOctreeServersOfType(serverCount, NodeType::VoxelServer, "Voxel",
|
||||
Application::getInstance()->getVoxelServerJurisdictions());
|
||||
showOctreeServersOfType(serverCount, NodeType::ParticleServer, "Particle",
|
||||
Application::getInstance()->getParticleServerJurisdictions());
|
||||
|
||||
showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity",
|
||||
Application::getInstance()->getEntityServerJurisdictions());
|
||||
|
||||
|
|
|
@ -330,7 +330,7 @@ void Stats::display(
|
|||
int voxelServerCount = 0;
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
// TODO: this should also support particles and models
|
||||
// TODO: this should also support entities
|
||||
if (node->getType() == NodeType::VoxelServer) {
|
||||
totalPingVoxel += node->getPingMs();
|
||||
voxelServerCount++;
|
||||
|
|
|
@ -85,18 +85,6 @@ void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode,
|
|||
if (sendingNode) {
|
||||
|
||||
switch(voxelPacketType) {
|
||||
case PacketTypeParticleErase: {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Particles)) {
|
||||
app->_particles.processEraseMessage(mutablePacket, sendingNode);
|
||||
}
|
||||
} break;
|
||||
|
||||
case PacketTypeParticleData: {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Particles)) {
|
||||
app->_particles.processDatagram(mutablePacket, sendingNode);
|
||||
}
|
||||
} break;
|
||||
|
||||
case PacketTypeEntityErase: {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) {
|
||||
app->_entities.processEraseMessage(mutablePacket, sendingNode);
|
||||
|
|
|
@ -66,7 +66,7 @@ void EntityCollisionSystem::checkEntity(EntityItem* entity) {
|
|||
void EntityCollisionSystem::emitGlobalEntityCollisionWithVoxel(EntityItem* entity,
|
||||
VoxelDetail* voxelDetails, const CollisionInfo& collision) {
|
||||
EntityItemID entityItemID = entity->getEntityItemID();
|
||||
emit EntityCollisionWithVoxel(entityItemID, *voxelDetails, collision);
|
||||
emit entityCollisionWithVoxel(entityItemID, *voxelDetails, collision);
|
||||
}
|
||||
|
||||
void EntityCollisionSystem::emitGlobalEntityCollisionWithEntity(EntityItem* entityA,
|
||||
|
@ -74,7 +74,7 @@ void EntityCollisionSystem::emitGlobalEntityCollisionWithEntity(EntityItem* enti
|
|||
|
||||
EntityItemID idA = entityA->getEntityItemID();
|
||||
EntityItemID idB = entityB->getEntityItemID();
|
||||
emit EntityCollisionWithEntity(idA, idB, collision);
|
||||
emit entityCollisionWithEntity(idA, idB, collision);
|
||||
}
|
||||
|
||||
void EntityCollisionSystem::updateCollisionWithVoxels(EntityItem* entity) {
|
||||
|
|
|
@ -54,8 +54,8 @@ public:
|
|||
void updateCollisionSound(EntityItem* Entity, const glm::vec3 &penetration, float frequency);
|
||||
|
||||
signals:
|
||||
void EntityCollisionWithVoxel(const EntityItemID& entityItemID, const VoxelDetail& voxel, const CollisionInfo& penetration);
|
||||
void EntityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& penetration);
|
||||
void entityCollisionWithVoxel(const EntityItemID& entityItemID, const VoxelDetail& voxel, const CollisionInfo& penetration);
|
||||
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& penetration);
|
||||
|
||||
private:
|
||||
void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo);
|
||||
|
|
|
@ -97,6 +97,10 @@ public slots:
|
|||
|
||||
Q_INVOKABLE void dumpTree() const;
|
||||
|
||||
signals:
|
||||
void entityCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, const CollisionInfo& collision);
|
||||
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& collision);
|
||||
|
||||
private:
|
||||
void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@ Assignment::Type Assignment::typeForNodeType(NodeType_t nodeType) {
|
|||
return Assignment::AgentType;
|
||||
case NodeType::VoxelServer:
|
||||
return Assignment::VoxelServerType;
|
||||
case NodeType::ParticleServer:
|
||||
return Assignment::ParticleServerType;
|
||||
case NodeType::EntityServer:
|
||||
return Assignment::EntityServerType;
|
||||
case NodeType::MetavoxelServer:
|
||||
|
@ -137,8 +135,6 @@ const char* Assignment::getTypeName() const {
|
|||
return "agent";
|
||||
case Assignment::VoxelServerType:
|
||||
return "voxel-server";
|
||||
case Assignment::ParticleServerType:
|
||||
return "particle-server";
|
||||
case Assignment::MetavoxelServerType:
|
||||
return "metavoxel-server";
|
||||
default:
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
AvatarMixerType,
|
||||
AgentType,
|
||||
VoxelServerType,
|
||||
ParticleServerType,
|
||||
UNUSED,
|
||||
MetavoxelServerType,
|
||||
EntityServerType,
|
||||
AllTypes
|
||||
|
|
|
@ -29,7 +29,6 @@ namespace NodeType {
|
|||
void NodeType::init() {
|
||||
TypeNameHash.insert(NodeType::DomainServer, "Domain Server");
|
||||
TypeNameHash.insert(NodeType::VoxelServer, "Voxel Server");
|
||||
TypeNameHash.insert(NodeType::ParticleServer, "Particle Server");
|
||||
TypeNameHash.insert(NodeType::EntityServer, "Entity Server");
|
||||
TypeNameHash.insert(NodeType::MetavoxelServer, "Metavoxel Server");
|
||||
TypeNameHash.insert(NodeType::Agent, "Agent");
|
||||
|
|
|
@ -31,7 +31,6 @@ typedef quint8 NodeType_t;
|
|||
namespace NodeType {
|
||||
const NodeType_t DomainServer = 'D';
|
||||
const NodeType_t VoxelServer = 'V';
|
||||
const NodeType_t ParticleServer = 'P';
|
||||
const NodeType_t EntityServer = 'o'; // was ModelServer
|
||||
const NodeType_t MetavoxelServer = 'm';
|
||||
const NodeType_t EnvironmentServer = 'E';
|
||||
|
|
|
@ -71,10 +71,6 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
return 1;
|
||||
case PacketTypeOctreeStats:
|
||||
return 1;
|
||||
case PacketTypeParticleData:
|
||||
return 1;
|
||||
case PacketTypeParticleErase:
|
||||
return 1;
|
||||
|
||||
case PacketTypeEntityAddOrEdit:
|
||||
case PacketTypeEntityData:
|
||||
|
@ -126,11 +122,6 @@ QString nameForPacketType(PacketType type) {
|
|||
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeStats);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeJurisdiction);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeJurisdictionRequest);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleQuery);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleData);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleAddOrEdit);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleErase);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleAddResponse);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeMetavoxelData);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarIdentity);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarBillboard);
|
||||
|
@ -144,7 +135,6 @@ QString nameForPacketType(PacketType type) {
|
|||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelEditNack);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleEditNack);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment);
|
||||
default:
|
||||
|
|
|
@ -50,11 +50,11 @@ enum PacketType {
|
|||
PacketTypeOctreeStats, // 26
|
||||
PacketTypeJurisdiction,
|
||||
PacketTypeJurisdictionRequest,
|
||||
PacketTypeParticleQuery,
|
||||
PacketTypeParticleData,
|
||||
PacketTypeParticleAddOrEdit,
|
||||
PacketTypeParticleErase,
|
||||
PacketTypeParticleAddResponse,
|
||||
UNUSED_1,
|
||||
UNUSED_2,
|
||||
UNUSED_3,
|
||||
UNUSED_4,
|
||||
UNUSED_5,
|
||||
PacketTypeMetavoxelData,
|
||||
PacketTypeAvatarIdentity,
|
||||
PacketTypeAvatarBillboard,
|
||||
|
@ -68,7 +68,7 @@ enum PacketType {
|
|||
PacketTypeEntityAddResponse,
|
||||
PacketTypeOctreeDataNack, // 45
|
||||
PacketTypeVoxelEditNack,
|
||||
PacketTypeParticleEditNack,
|
||||
UNUSED_6,
|
||||
PacketTypeEntityEditNack, // 48
|
||||
PacketTypeSignedTransactionPayment,
|
||||
PacketTypeIceServerHeartbeat,
|
||||
|
@ -83,8 +83,8 @@ const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
|||
<< PacketTypeDomainServerRequireDTLS << PacketTypeDomainConnectRequest
|
||||
<< PacketTypeDomainList << PacketTypeDomainListRequest << PacketTypeDomainConnectionDenied
|
||||
<< PacketTypeCreateAssignment << PacketTypeRequestAssignment << PacketTypeStunResponse
|
||||
<< PacketTypeNodeJsonStats << PacketTypeVoxelQuery << PacketTypeParticleQuery << PacketTypeEntityQuery
|
||||
<< PacketTypeOctreeDataNack << PacketTypeVoxelEditNack << PacketTypeParticleEditNack << PacketTypeEntityEditNack
|
||||
<< PacketTypeNodeJsonStats << PacketTypeVoxelQuery << PacketTypeEntityQuery
|
||||
<< PacketTypeOctreeDataNack << PacketTypeVoxelEditNack << PacketTypeEntityEditNack
|
||||
<< PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse
|
||||
<< PacketTypeUnverifiedPing << PacketTypeUnverifiedPingReply;
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
set(TARGET_NAME particles)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Gui Network Script)
|
||||
|
||||
include_glm()
|
||||
|
||||
link_hifi_libraries(shared octree fbx networking animation)
|
||||
include_hifi_library_headers(script-engine)
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
File diff suppressed because it is too large
Load diff
|
@ -1,433 +0,0 @@
|
|||
//
|
||||
// Particle.h
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_Particle_h
|
||||
#define hifi_Particle_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <CollisionInfo.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <OctreePacketData.h>
|
||||
|
||||
class Particle;
|
||||
class ParticleEditPacketSender;
|
||||
class ParticleProperties;
|
||||
class ParticlesScriptingInterface;
|
||||
class ParticleScriptObject;
|
||||
class ParticleTree;
|
||||
class ScriptEngine;
|
||||
class VoxelEditPacketSender;
|
||||
class VoxelsScriptingInterface;
|
||||
struct VoxelDetail;
|
||||
|
||||
const uint32_t NEW_PARTICLE = 0xFFFFFFFF;
|
||||
const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF;
|
||||
const uint32_t UNKNOWN_PARTICLE_ID = 0xFFFFFFFF;
|
||||
|
||||
const uint16_t CONTAINS_RADIUS = 1;
|
||||
const uint16_t CONTAINS_POSITION = 2;
|
||||
const uint16_t CONTAINS_COLOR = 4;
|
||||
const uint16_t CONTAINS_VELOCITY = 8;
|
||||
const uint16_t CONTAINS_GRAVITY = 16;
|
||||
const uint16_t CONTAINS_DAMPING = 32;
|
||||
const uint16_t CONTAINS_LIFETIME = 64;
|
||||
const uint16_t CONTAINS_INHAND = 128;
|
||||
const uint16_t CONTAINS_SCRIPT = 256;
|
||||
const uint16_t CONTAINS_SHOULDDIE = 512;
|
||||
const uint16_t CONTAINS_MODEL_URL = 1024;
|
||||
const uint16_t CONTAINS_MODEL_TRANSLATION = 1024;
|
||||
const uint16_t CONTAINS_MODEL_ROTATION = 2048;
|
||||
const uint16_t CONTAINS_MODEL_SCALE = 4096;
|
||||
|
||||
const float DEFAULT_LIFETIME = 10.0f; // particles live for 10 seconds by default
|
||||
const float DEFAULT_DAMPING = 0.99f;
|
||||
const float DEFAULT_RADIUS = 0.1f / TREE_SCALE;
|
||||
const float MINIMUM_PARTICLE_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container
|
||||
const glm::vec3 DEFAULT_GRAVITY(0, (-9.8f / TREE_SCALE), 0);
|
||||
const QString DEFAULT_SCRIPT("");
|
||||
const QString DEFAULT_MODEL_URL("");
|
||||
const glm::vec3 DEFAULT_MODEL_TRANSLATION(0, 0, 0);
|
||||
const glm::quat DEFAULT_MODEL_ROTATION(0, 0, 0, 0);
|
||||
const float DEFAULT_MODEL_SCALE = 1.0f;
|
||||
const bool IN_HAND = true; // it's in a hand
|
||||
const bool NOT_IN_HAND = !IN_HAND; // it's not in a hand
|
||||
|
||||
/// A collection of properties of a particle used in the scripting API. Translates between the actual properties of a particle
|
||||
/// and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete set of
|
||||
/// particle properties via JavaScript hashes/QScriptValues
|
||||
/// all units for position, velocity, gravity, radius, etc are in meter units
|
||||
class ParticleProperties {
|
||||
public:
|
||||
ParticleProperties();
|
||||
|
||||
QScriptValue copyToScriptValue(QScriptEngine* engine) const;
|
||||
void copyFromScriptValue(const QScriptValue& object);
|
||||
|
||||
void copyToParticle(Particle& particle) const;
|
||||
void copyFromParticle(const Particle& particle);
|
||||
|
||||
const glm::vec3& getPosition() const { return _position; }
|
||||
xColor getColor() const { return _color; }
|
||||
float getRadius() const { return _radius; }
|
||||
const glm::vec3& getVelocity() const { return _velocity; }
|
||||
const glm::vec3& getGravity() const { return _gravity; }
|
||||
float getDamping() const { return _damping; }
|
||||
float getLifetime() const { return _lifetime; }
|
||||
const QString& getScript() const { return _script; }
|
||||
bool getInHand() const { return _inHand; }
|
||||
bool getShouldDie() const { return _shouldDie; }
|
||||
const QString& getModelURL() const { return _modelURL; }
|
||||
float getModelScale() const { return _modelScale; }
|
||||
const glm::vec3& getModelTranslation() const { return _modelTranslation; }
|
||||
const glm::quat& getModelRotation() const { return _modelRotation; }
|
||||
|
||||
quint64 getLastEdited() const { return _lastEdited; }
|
||||
uint16_t getChangedBits() const;
|
||||
|
||||
/// set position in meter units
|
||||
void setPosition(const glm::vec3& value) { _position = value; _positionChanged = true; }
|
||||
|
||||
/// set velocity in meter units
|
||||
void setVelocity(const glm::vec3& value) { _velocity = value; _velocityChanged = true; }
|
||||
void setColor(const xColor& value) { _color = value; _colorChanged = true; }
|
||||
void setRadius(float value) { _radius = value; _radiusChanged = true; }
|
||||
|
||||
/// set gravity in meter units
|
||||
void setGravity(const glm::vec3& value) { _gravity = value; _gravityChanged = true; }
|
||||
void setInHand(bool inHand) { _inHand = inHand; _inHandChanged = true; }
|
||||
void setDamping(float value) { _damping = value; _dampingChanged = true; }
|
||||
void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; _shouldDieChanged = true; }
|
||||
void setLifetime(float value) { _lifetime = value; _lifetimeChanged = true; }
|
||||
void setScript(const QString& updateScript) { _script = updateScript; _scriptChanged = true; }
|
||||
|
||||
// model related properties
|
||||
void setModelURL(const QString& url) { _modelURL = url; _modelURLChanged = true; }
|
||||
void setModelScale(float scale) { _modelScale = scale; _modelScaleChanged = true; }
|
||||
void setModelTranslation(const glm::vec3& translation) { _modelTranslation = translation;
|
||||
_modelTranslationChanged = true; }
|
||||
void setModelRotation(const glm::quat& rotation) { _modelRotation = rotation; _modelRotationChanged = true; }
|
||||
|
||||
/// used by ParticleScriptingInterface to return ParticleProperties for unknown particles
|
||||
void setIsUnknownID() { _id = UNKNOWN_PARTICLE_ID; _idSet = true; }
|
||||
|
||||
private:
|
||||
glm::vec3 _position;
|
||||
xColor _color;
|
||||
float _radius;
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _gravity;
|
||||
float _damping;
|
||||
float _lifetime;
|
||||
QString _script;
|
||||
bool _inHand;
|
||||
bool _shouldDie;
|
||||
QString _modelURL;
|
||||
float _modelScale;
|
||||
glm::vec3 _modelTranslation;
|
||||
glm::quat _modelRotation;
|
||||
|
||||
uint32_t _id;
|
||||
bool _idSet;
|
||||
quint64 _lastEdited;
|
||||
|
||||
bool _positionChanged;
|
||||
bool _colorChanged;
|
||||
bool _radiusChanged;
|
||||
bool _velocityChanged;
|
||||
bool _gravityChanged;
|
||||
bool _dampingChanged;
|
||||
bool _lifetimeChanged;
|
||||
bool _scriptChanged;
|
||||
bool _inHandChanged;
|
||||
bool _shouldDieChanged;
|
||||
bool _modelURLChanged;
|
||||
bool _modelScaleChanged;
|
||||
bool _modelTranslationChanged;
|
||||
bool _modelRotationChanged;
|
||||
bool _defaultSettings;
|
||||
};
|
||||
Q_DECLARE_METATYPE(ParticleProperties);
|
||||
QScriptValue ParticlePropertiesToScriptValue(QScriptEngine* engine, const ParticleProperties& properties);
|
||||
void ParticlePropertiesFromScriptValue(const QScriptValue &object, ParticleProperties& properties);
|
||||
|
||||
|
||||
/// Abstract ID for editing particles. Used in Particle JS API - When particles are created in the JS api, they are given a
|
||||
/// local creatorTokenID, the actual id for the particle is not known until the server responds to the creator with the
|
||||
/// correct mapping. This class works with the scripting API an allows the developer to edit particles they created.
|
||||
class ParticleID {
|
||||
public:
|
||||
ParticleID() :
|
||||
id(NEW_PARTICLE), creatorTokenID(UNKNOWN_TOKEN), isKnownID(false) { };
|
||||
|
||||
ParticleID(uint32_t id, uint32_t creatorTokenID, bool isKnownID) :
|
||||
id(id), creatorTokenID(creatorTokenID), isKnownID(isKnownID) { };
|
||||
|
||||
ParticleID(uint32_t id) :
|
||||
id(id), creatorTokenID(UNKNOWN_TOKEN), isKnownID(true) { };
|
||||
|
||||
uint32_t id;
|
||||
uint32_t creatorTokenID;
|
||||
bool isKnownID;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ParticleID);
|
||||
Q_DECLARE_METATYPE(QVector<ParticleID>);
|
||||
QScriptValue ParticleIDtoScriptValue(QScriptEngine* engine, const ParticleID& properties);
|
||||
void ParticleIDfromScriptValue(const QScriptValue &object, ParticleID& properties);
|
||||
|
||||
|
||||
|
||||
/// Particle class - this is the actual particle class.
|
||||
class Particle {
|
||||
|
||||
public:
|
||||
Particle();
|
||||
|
||||
Particle(const ParticleID& particleID, const ParticleProperties& properties);
|
||||
|
||||
/// creates an NEW particle from an PACKET_TYPE_PARTICLE_ADD_OR_EDIT edit data buffer
|
||||
static Particle fromEditPacket(const 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,
|
||||
glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, float lifetime = DEFAULT_LIFETIME,
|
||||
bool inHand = NOT_IN_HAND, QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE);
|
||||
|
||||
/// get position in domain scale units (0.0 - 1.0)
|
||||
const glm::vec3& getPosition() const { return _position; }
|
||||
|
||||
const rgbColor& getColor() const { return _color; }
|
||||
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||
|
||||
/// get radius in domain scale units (0.0 - 1.0)
|
||||
float getRadius() const { return _radius; }
|
||||
float getMass() const { return _mass; }
|
||||
|
||||
/// get velocity in domain scale units (0.0 - 1.0)
|
||||
const glm::vec3& getVelocity() const { return _velocity; }
|
||||
|
||||
/// get gravity in domain scale units (0.0 - 1.0)
|
||||
const glm::vec3& getGravity() const { return _gravity; }
|
||||
|
||||
bool getInHand() const { return _inHand; }
|
||||
float getDamping() const { return _damping; }
|
||||
float getLifetime() const { return _lifetime; }
|
||||
|
||||
// model related properties
|
||||
bool hasModel() const { return !_modelURL.isEmpty(); }
|
||||
const QString& getModelURL() const { return _modelURL; }
|
||||
float getModelScale() const { return _modelScale; }
|
||||
const glm::vec3& getModelTranslation() const { return _modelTranslation; }
|
||||
const glm::quat& getModelRotation() const { return _modelRotation; }
|
||||
|
||||
ParticleID getParticleID() const { return ParticleID(getID(), getCreatorTokenID(), getID() != UNKNOWN_PARTICLE_ID); }
|
||||
ParticleProperties getProperties() const;
|
||||
|
||||
/// The last updated/simulated time of this particle from the time perspective of the authoritative server/source
|
||||
quint64 getLastUpdated() const { return _lastUpdated; }
|
||||
|
||||
/// The last edited time of this particle from the time perspective of the authoritative server/source
|
||||
quint64 getLastEdited() const { return _lastEdited; }
|
||||
void setLastEdited(quint64 lastEdited) { _lastEdited = lastEdited; }
|
||||
|
||||
/// lifetime of the particle in seconds
|
||||
float getAge() const { return static_cast<float>(usecTimestampNow() - _created) / static_cast<float>(USECS_PER_SECOND); }
|
||||
float getEditedAgo() const { return static_cast<float>(usecTimestampNow() - _lastEdited) / static_cast<float>(USECS_PER_SECOND); }
|
||||
uint32_t getID() const { return _id; }
|
||||
void setID(uint32_t id) { _id = id; }
|
||||
bool getShouldDie() const { return _shouldDie; }
|
||||
QString getScript() const { return _script; }
|
||||
uint32_t getCreatorTokenID() const { return _creatorTokenID; }
|
||||
bool isNewlyCreated() const { return _newlyCreated; }
|
||||
|
||||
/// set position in domain scale units (0.0 - 1.0)
|
||||
void setPosition(const glm::vec3& value) { _position = value; }
|
||||
|
||||
/// set velocity in domain scale units (0.0 - 1.0)
|
||||
void setVelocity(const glm::vec3& value) { _velocity = value; }
|
||||
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
|
||||
void setColor(const xColor& value) {
|
||||
_color[RED_INDEX] = value.red;
|
||||
_color[GREEN_INDEX] = value.green;
|
||||
_color[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
/// set radius in domain scale units (0.0 - 1.0)
|
||||
void setRadius(float value) { _radius = value; }
|
||||
void setMass(float value);
|
||||
|
||||
/// set gravity in domain scale units (0.0 - 1.0)
|
||||
void setGravity(const glm::vec3& value) { _gravity = value; }
|
||||
void setInHand(bool inHand) { _inHand = inHand; }
|
||||
void setDamping(float value) { _damping = value; }
|
||||
void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; }
|
||||
void setLifetime(float value) { _lifetime = value; }
|
||||
void setScript(QString updateScript) { _script = updateScript; }
|
||||
void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; }
|
||||
|
||||
// model related properties
|
||||
void setModelURL(const QString& url) { _modelURL = url; }
|
||||
void setModelScale(float scale) { _modelScale = scale; }
|
||||
void setModelTranslation(const glm::vec3& translation) { _modelTranslation = translation; }
|
||||
void setModelRotation(const glm::quat& rotation) { _modelRotation = rotation; }
|
||||
|
||||
void setProperties(const ParticleProperties& properties);
|
||||
|
||||
bool appendParticleData(OctreePacketData* packetData) const;
|
||||
int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
||||
static int expectedBytes();
|
||||
|
||||
static bool encodeParticleEditMessageDetails(PacketType command, ParticleID id, const ParticleProperties& details,
|
||||
unsigned char* bufferOut, int sizeIn, int& sizeOut);
|
||||
|
||||
static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew);
|
||||
|
||||
void applyHardCollision(const CollisionInfo& collisionInfo);
|
||||
|
||||
void update(const quint64& now);
|
||||
void collisionWithParticle(Particle* other, const glm::vec3& penetration);
|
||||
void collisionWithVoxel(VoxelDetail* voxel, const glm::vec3& penetration);
|
||||
|
||||
void debugDump() const;
|
||||
|
||||
// similar to assignment/copy, but it handles keeping lifetime accurate
|
||||
void copyChangedProperties(const Particle& other);
|
||||
|
||||
static VoxelEditPacketSender* getVoxelEditPacketSender() { return _voxelEditSender; }
|
||||
static ParticleEditPacketSender* getParticleEditPacketSender() { return _particleEditSender; }
|
||||
|
||||
static void setVoxelEditPacketSender(VoxelEditPacketSender* senderInterface)
|
||||
{ _voxelEditSender = senderInterface; }
|
||||
|
||||
static void setParticleEditPacketSender(ParticleEditPacketSender* senderInterface)
|
||||
{ _particleEditSender = senderInterface; }
|
||||
|
||||
|
||||
// these methods allow you to create particles, and later edit them.
|
||||
static uint32_t getIDfromCreatorTokenID(uint32_t creatorTokenID);
|
||||
static uint32_t getNextCreatorTokenID();
|
||||
static void handleAddParticleResponse(const QByteArray& packet);
|
||||
|
||||
protected:
|
||||
static VoxelEditPacketSender* _voxelEditSender;
|
||||
static ParticleEditPacketSender* _particleEditSender;
|
||||
|
||||
void startParticleScriptContext(ScriptEngine& engine, ParticleScriptObject& particleScriptable);
|
||||
void endParticleScriptContext(ScriptEngine& engine, ParticleScriptObject& particleScriptable);
|
||||
void executeUpdateScripts();
|
||||
|
||||
void setAge(float age);
|
||||
|
||||
glm::vec3 _position;
|
||||
rgbColor _color;
|
||||
float _radius;
|
||||
float _mass;
|
||||
glm::vec3 _velocity;
|
||||
uint32_t _id;
|
||||
static uint32_t _nextID;
|
||||
bool _shouldDie;
|
||||
glm::vec3 _gravity;
|
||||
float _damping;
|
||||
float _lifetime;
|
||||
QString _script;
|
||||
bool _inHand;
|
||||
|
||||
// model related items
|
||||
QString _modelURL;
|
||||
float _modelScale;
|
||||
glm::vec3 _modelTranslation;
|
||||
glm::quat _modelRotation;
|
||||
|
||||
uint32_t _creatorTokenID;
|
||||
bool _newlyCreated;
|
||||
|
||||
quint64 _lastUpdated;
|
||||
quint64 _lastEdited;
|
||||
|
||||
// this doesn't go on the wire, we send it as lifetime
|
||||
quint64 _created;
|
||||
|
||||
// used by the static interfaces for creator token ids
|
||||
static uint32_t _nextCreatorTokenID;
|
||||
static std::map<uint32_t,uint32_t> _tokenIDsToIDs;
|
||||
};
|
||||
|
||||
/// Scriptable interface to a single Particle object. Used exclusively in the JavaScript API for interacting with single
|
||||
/// Particles.
|
||||
class ParticleScriptObject : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ParticleScriptObject(Particle* particle) { _particle = particle; }
|
||||
//~ParticleScriptObject() { qDebug() << "~ParticleScriptObject() this=" << this; }
|
||||
|
||||
void emitUpdate() { emit update(); }
|
||||
void emitCollisionWithParticle(QObject* other, const glm::vec3& penetration)
|
||||
{ emit collisionWithParticle(other, penetration); }
|
||||
void emitCollisionWithVoxel(const VoxelDetail& voxel, const glm::vec3& penetration)
|
||||
{ emit collisionWithVoxel(voxel, penetration); }
|
||||
|
||||
public slots:
|
||||
unsigned int getID() const { return _particle->getID(); }
|
||||
|
||||
/// get position in meter units
|
||||
glm::vec3 getPosition() const { return _particle->getPosition() * (float)TREE_SCALE; }
|
||||
|
||||
/// get velocity in meter units
|
||||
glm::vec3 getVelocity() const { return _particle->getVelocity() * (float)TREE_SCALE; }
|
||||
xColor getColor() const { return _particle->getXColor(); }
|
||||
|
||||
/// get gravity in meter units
|
||||
glm::vec3 getGravity() const { return _particle->getGravity() * (float)TREE_SCALE; }
|
||||
|
||||
float getDamping() const { return _particle->getDamping(); }
|
||||
|
||||
/// get radius in meter units
|
||||
float getRadius() const { return _particle->getRadius() * (float)TREE_SCALE; }
|
||||
bool getShouldDie() { return _particle->getShouldDie(); }
|
||||
float getAge() const { return _particle->getAge(); }
|
||||
float getLifetime() const { return _particle->getLifetime(); }
|
||||
ParticleProperties getProperties() const { return _particle->getProperties(); }
|
||||
|
||||
/// set position in meter units
|
||||
void setPosition(glm::vec3 value) { _particle->setPosition(value / (float)TREE_SCALE); }
|
||||
|
||||
/// set velocity in meter units
|
||||
void setVelocity(glm::vec3 value) { _particle->setVelocity(value / (float)TREE_SCALE); }
|
||||
|
||||
/// set gravity in meter units
|
||||
void setGravity(glm::vec3 value) { _particle->setGravity(value / (float)TREE_SCALE); }
|
||||
|
||||
void setDamping(float value) { _particle->setDamping(value); }
|
||||
void setColor(xColor value) { _particle->setColor(value); }
|
||||
|
||||
/// set radius in meter units
|
||||
void setRadius(float value) { _particle->setRadius(value / (float)TREE_SCALE); }
|
||||
void setShouldDie(bool value) { _particle->setShouldDie(value); }
|
||||
void setScript(const QString& script) { _particle->setScript(script); }
|
||||
void setLifetime(float value) const { return _particle->setLifetime(value); }
|
||||
void setProperties(const ParticleProperties& properties) { return _particle->setProperties(properties); }
|
||||
|
||||
signals:
|
||||
void update();
|
||||
void collisionWithVoxel(const VoxelDetail& voxel, const glm::vec3& penetration);
|
||||
void collisionWithParticle(QObject* other, const glm::vec3& penetration);
|
||||
|
||||
private:
|
||||
Particle* _particle;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // hifi_Particle_h
|
|
@ -1,278 +0,0 @@
|
|||
//
|
||||
// ParticleCollisionSystem.cpp
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <algorithm>
|
||||
#include <AbstractAudioInterface.h>
|
||||
#include <VoxelTree.h>
|
||||
#include <AvatarData.h>
|
||||
#include <HeadData.h>
|
||||
#include <HandData.h>
|
||||
|
||||
#include "Particle.h"
|
||||
#include "ParticleCollisionSystem.h"
|
||||
#include "ParticleEditPacketSender.h"
|
||||
#include "ParticleTree.h"
|
||||
|
||||
const int MAX_COLLISIONS_PER_PARTICLE = 16;
|
||||
|
||||
ParticleCollisionSystem::ParticleCollisionSystem(ParticleEditPacketSender* packetSender,
|
||||
ParticleTree* particles, VoxelTree* voxels, AbstractAudioInterface* audio,
|
||||
AvatarHashMap* avatars) : _collisions(MAX_COLLISIONS_PER_PARTICLE) {
|
||||
init(packetSender, particles, voxels, audio, avatars);
|
||||
}
|
||||
|
||||
void ParticleCollisionSystem::init(ParticleEditPacketSender* packetSender,
|
||||
ParticleTree* particles, VoxelTree* voxels, AbstractAudioInterface* audio,
|
||||
AvatarHashMap* avatars) {
|
||||
_packetSender = packetSender;
|
||||
_particles = particles;
|
||||
_voxels = voxels;
|
||||
_audio = audio;
|
||||
_avatars = avatars;
|
||||
}
|
||||
|
||||
ParticleCollisionSystem::~ParticleCollisionSystem() {
|
||||
}
|
||||
|
||||
bool ParticleCollisionSystem::updateOperation(OctreeElement* element, void* extraData) {
|
||||
ParticleCollisionSystem* system = static_cast<ParticleCollisionSystem*>(extraData);
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
|
||||
// iterate the particles...
|
||||
QList<Particle>& particles = particleTreeElement->getParticles();
|
||||
uint16_t numberOfParticles = particles.size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
Particle* particle = &particles[i];
|
||||
system->checkParticle(particle);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ParticleCollisionSystem::update() {
|
||||
// update all particles
|
||||
if (_particles->tryLockForRead()) {
|
||||
_particles->recurseTreeWithOperation(updateOperation, this);
|
||||
_particles->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ParticleCollisionSystem::checkParticle(Particle* particle) {
|
||||
updateCollisionWithVoxels(particle);
|
||||
updateCollisionWithParticles(particle);
|
||||
updateCollisionWithAvatars(particle);
|
||||
}
|
||||
|
||||
void ParticleCollisionSystem::emitGlobalParticleCollisionWithVoxel(Particle* particle,
|
||||
VoxelDetail* voxelDetails, const CollisionInfo& collision) {
|
||||
ParticleID particleID = particle->getParticleID();
|
||||
emit particleCollisionWithVoxel(particleID, *voxelDetails, collision);
|
||||
}
|
||||
|
||||
void ParticleCollisionSystem::emitGlobalParticleCollisionWithParticle(Particle* particleA,
|
||||
Particle* particleB, const CollisionInfo& collision) {
|
||||
|
||||
ParticleID idA = particleA->getParticleID();
|
||||
ParticleID idB = particleB->getParticleID();
|
||||
emit particleCollisionWithParticle(idA, idB, collision);
|
||||
}
|
||||
|
||||
void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
|
||||
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
|
||||
float radius = particle->getRadius() * (float)(TREE_SCALE);
|
||||
const float ELASTICITY = 0.4f;
|
||||
const float DAMPING = 0.05f;
|
||||
const float COLLISION_FREQUENCY = 0.5f;
|
||||
CollisionInfo collisionInfo;
|
||||
collisionInfo._damping = DAMPING;
|
||||
collisionInfo._elasticity = ELASTICITY;
|
||||
VoxelDetail* voxelDetails = NULL;
|
||||
if (_voxels->findSpherePenetration(center, radius, collisionInfo._penetration, (void**)&voxelDetails)) {
|
||||
|
||||
// let the particles run their collision scripts if they have them
|
||||
particle->collisionWithVoxel(voxelDetails, collisionInfo._penetration);
|
||||
|
||||
// findSpherePenetration() only computes the penetration but we also want some other collision info
|
||||
// so we compute it ourselves here. Note that we must multiply scale by TREE_SCALE when feeding
|
||||
// the results to systems outside of this octree reference frame.
|
||||
updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY);
|
||||
collisionInfo._contactPoint = (float)TREE_SCALE * (particle->getPosition() + particle->getRadius() * glm::normalize(collisionInfo._penetration));
|
||||
// let the global script run their collision scripts for particles if they have them
|
||||
emitGlobalParticleCollisionWithVoxel(particle, voxelDetails, collisionInfo);
|
||||
|
||||
// we must scale back down to the octree reference frame before updating the particle properties
|
||||
collisionInfo._penetration /= (float)(TREE_SCALE);
|
||||
collisionInfo._contactPoint /= (float)(TREE_SCALE);
|
||||
particle->applyHardCollision(collisionInfo);
|
||||
queueParticlePropertiesUpdate(particle);
|
||||
|
||||
delete voxelDetails; // cleanup returned details
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA) {
|
||||
glm::vec3 center = particleA->getPosition() * (float)(TREE_SCALE);
|
||||
float radius = particleA->getRadius() * (float)(TREE_SCALE);
|
||||
//const float ELASTICITY = 0.4f;
|
||||
//const float DAMPING = 0.0f;
|
||||
const float COLLISION_FREQUENCY = 0.5f;
|
||||
glm::vec3 penetration;
|
||||
Particle* particleB;
|
||||
if (_particles->findSpherePenetration(center, radius, penetration, (void**)&particleB, Octree::NoLock)) {
|
||||
// NOTE: 'penetration' is the depth that 'particleA' overlaps 'particleB'. It points from A into B.
|
||||
|
||||
// Even if the particles overlap... when the particles are already moving appart
|
||||
// we don't want to count this as a collision.
|
||||
glm::vec3 relativeVelocity = particleA->getVelocity() - particleB->getVelocity();
|
||||
if (glm::dot(relativeVelocity, penetration) > 0.0f) {
|
||||
particleA->collisionWithParticle(particleB, penetration);
|
||||
particleB->collisionWithParticle(particleA, penetration * -1.0f); // the penetration is reversed
|
||||
|
||||
CollisionInfo collision;
|
||||
collision._penetration = penetration;
|
||||
// for now the contactPoint is the average between the the two paricle centers
|
||||
collision._contactPoint = (0.5f * (float)TREE_SCALE) * (particleA->getPosition() + particleB->getPosition());
|
||||
emitGlobalParticleCollisionWithParticle(particleA, particleB, collision);
|
||||
|
||||
glm::vec3 axis = glm::normalize(penetration);
|
||||
glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis;
|
||||
|
||||
// particles that are in hand are assigned an ureasonably large mass for collisions
|
||||
// which effectively makes them immovable but allows the other ball to reflect correctly.
|
||||
const float MAX_MASS = 1.0e6f;
|
||||
float massA = (particleA->getInHand()) ? MAX_MASS : particleA->getMass();
|
||||
float massB = (particleB->getInHand()) ? MAX_MASS : particleB->getMass();
|
||||
float totalMass = massA + massB;
|
||||
|
||||
// handle particle A
|
||||
particleA->setVelocity(particleA->getVelocity() - axialVelocity * (2.0f * massB / totalMass));
|
||||
particleA->setPosition(particleA->getPosition() - 0.5f * penetration);
|
||||
ParticleProperties propertiesA;
|
||||
ParticleID idA(particleA->getID());
|
||||
propertiesA.copyFromParticle(*particleA);
|
||||
propertiesA.setVelocity(particleA->getVelocity() * (float)TREE_SCALE);
|
||||
propertiesA.setPosition(particleA->getPosition() * (float)TREE_SCALE);
|
||||
_packetSender->queueParticleEditMessage(PacketTypeParticleAddOrEdit, idA, propertiesA);
|
||||
|
||||
// handle particle B
|
||||
particleB->setVelocity(particleB->getVelocity() + axialVelocity * (2.0f * massA / totalMass));
|
||||
particleA->setPosition(particleB->getPosition() + 0.5f * penetration);
|
||||
ParticleProperties propertiesB;
|
||||
ParticleID idB(particleB->getID());
|
||||
propertiesB.copyFromParticle(*particleB);
|
||||
propertiesB.setVelocity(particleB->getVelocity() * (float)TREE_SCALE);
|
||||
propertiesB.setPosition(particleB->getPosition() * (float)TREE_SCALE);
|
||||
_packetSender->queueParticleEditMessage(PacketTypeParticleAddOrEdit, idB, propertiesB);
|
||||
|
||||
_packetSender->releaseQueuedMessages();
|
||||
|
||||
updateCollisionSound(particleA, penetration, COLLISION_FREQUENCY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||
// particles that are in hand, don't collide with avatars
|
||||
if (!_avatars || particle->getInHand()) {
|
||||
return;
|
||||
}
|
||||
|
||||
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
|
||||
float radius = particle->getRadius() * (float)(TREE_SCALE);
|
||||
const float ELASTICITY = 0.9f;
|
||||
const float DAMPING = 0.1f;
|
||||
const float COLLISION_FREQUENCY = 0.5f;
|
||||
glm::vec3 penetration;
|
||||
|
||||
_collisions.clear();
|
||||
foreach (const AvatarSharedPointer& avatarPointer, _avatars->getAvatarHash()) {
|
||||
AvatarData* avatar = avatarPointer.data();
|
||||
|
||||
float totalRadius = avatar->getBoundingRadius() + radius;
|
||||
glm::vec3 relativePosition = center - avatar->getPosition();
|
||||
if (glm::dot(relativePosition, relativePosition) > (totalRadius * totalRadius)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (avatar->findSphereCollisions(center, radius, _collisions)) {
|
||||
int numCollisions = _collisions.size();
|
||||
for (int i = 0; i < numCollisions; ++i) {
|
||||
CollisionInfo* collision = _collisions.getCollision(i);
|
||||
collision->_damping = DAMPING;
|
||||
collision->_elasticity = ELASTICITY;
|
||||
|
||||
collision->_addedVelocity /= (float)(TREE_SCALE);
|
||||
glm::vec3 relativeVelocity = collision->_addedVelocity - particle->getVelocity();
|
||||
|
||||
if (glm::dot(relativeVelocity, collision->_penetration) <= 0.f) {
|
||||
// only collide when particle and collision point are moving toward each other
|
||||
// (doing this prevents some "collision snagging" when particle penetrates the object)
|
||||
updateCollisionSound(particle, collision->_penetration, COLLISION_FREQUENCY);
|
||||
collision->_penetration /= (float)(TREE_SCALE);
|
||||
particle->applyHardCollision(*collision);
|
||||
queueParticlePropertiesUpdate(particle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleCollisionSystem::queueParticlePropertiesUpdate(Particle* particle) {
|
||||
// queue the result for sending to the particle server
|
||||
ParticleProperties properties;
|
||||
ParticleID particleID(particle->getID());
|
||||
properties.copyFromParticle(*particle);
|
||||
|
||||
properties.setPosition(particle->getPosition() * (float)TREE_SCALE);
|
||||
properties.setVelocity(particle->getVelocity() * (float)TREE_SCALE);
|
||||
_packetSender->queueParticleEditMessage(PacketTypeParticleAddOrEdit, particleID, properties);
|
||||
}
|
||||
|
||||
|
||||
void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency) {
|
||||
|
||||
// consider whether to have the collision make a sound
|
||||
const float AUDIBLE_COLLISION_THRESHOLD = 0.3f;
|
||||
const float COLLISION_LOUDNESS = 1.f;
|
||||
const float DURATION_SCALING = 0.004f;
|
||||
const float NOISE_SCALING = 0.1f;
|
||||
glm::vec3 velocity = particle->getVelocity() * (float)(TREE_SCALE);
|
||||
|
||||
/*
|
||||
// how do we want to handle this??
|
||||
//
|
||||
glm::vec3 gravity = particle->getGravity() * (float)(TREE_SCALE);
|
||||
|
||||
if (glm::length(gravity) > EPSILON) {
|
||||
// If gravity is on, remove the effect of gravity on velocity for this
|
||||
// frame, so that we are not constantly colliding with the surface
|
||||
velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity);
|
||||
}
|
||||
*/
|
||||
float normalSpeed = glm::dot(velocity, glm::normalize(penetration));
|
||||
// NOTE: it is possible for normalSpeed to be NaN at this point
|
||||
// (sometimes the average penetration of a bunch of voxels is a zero length vector which cannot be normalized)
|
||||
// however the check below will fail (NaN comparisons always fail) and everything will be fine.
|
||||
|
||||
if (normalSpeed > AUDIBLE_COLLISION_THRESHOLD) {
|
||||
// Volume is proportional to collision velocity
|
||||
// Base frequency is modified upward by the angle of the collision
|
||||
// Noise is a function of the angle of collision
|
||||
// Duration of the sound is a function of both base frequency and velocity of impact
|
||||
float tangentialSpeed = glm::length(velocity) - normalSpeed;
|
||||
_audio->startCollisionSound( std::min(COLLISION_LOUDNESS * normalSpeed, 1.f),
|
||||
frequency * (1.f + tangentialSpeed / normalSpeed),
|
||||
std::min(tangentialSpeed / normalSpeed * NOISE_SCALING, 1.f),
|
||||
1.f - DURATION_SCALING * powf(frequency, 0.5f) / normalSpeed, false);
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
//
|
||||
// ParticleCollisionSystem.h
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ParticleCollisionSystem_h
|
||||
#define hifi_ParticleCollisionSystem_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <AvatarHashMap.h>
|
||||
#include <CollisionInfo.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <OctreePacketData.h>
|
||||
|
||||
#include "Particle.h"
|
||||
|
||||
class AbstractAudioInterface;
|
||||
class AvatarData;
|
||||
class ParticleEditPacketSender;
|
||||
class ParticleTree;
|
||||
class VoxelTree;
|
||||
|
||||
const glm::vec3 NO_ADDED_VELOCITY = glm::vec3(0);
|
||||
|
||||
class ParticleCollisionSystem : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ParticleCollisionSystem(ParticleEditPacketSender* packetSender = NULL, ParticleTree* particles = NULL,
|
||||
VoxelTree* voxels = NULL, AbstractAudioInterface* audio = NULL,
|
||||
AvatarHashMap* avatars = NULL);
|
||||
|
||||
void init(ParticleEditPacketSender* packetSender, ParticleTree* particles, VoxelTree* voxels,
|
||||
AbstractAudioInterface* audio = NULL, AvatarHashMap* _avatars = NULL);
|
||||
|
||||
~ParticleCollisionSystem();
|
||||
|
||||
void update();
|
||||
|
||||
void checkParticle(Particle* particle);
|
||||
void updateCollisionWithVoxels(Particle* particle);
|
||||
void updateCollisionWithParticles(Particle* particle);
|
||||
void updateCollisionWithAvatars(Particle* particle);
|
||||
void queueParticlePropertiesUpdate(Particle* particle);
|
||||
void updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency);
|
||||
|
||||
signals:
|
||||
void particleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel, const CollisionInfo& penetration);
|
||||
void particleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB, const CollisionInfo& penetration);
|
||||
|
||||
private:
|
||||
static bool updateOperation(OctreeElement* element, void* extraData);
|
||||
void emitGlobalParticleCollisionWithVoxel(Particle* particle, VoxelDetail* voxelDetails, const CollisionInfo& penetration);
|
||||
void emitGlobalParticleCollisionWithParticle(Particle* particleA, Particle* particleB, const CollisionInfo& penetration);
|
||||
|
||||
ParticleEditPacketSender* _packetSender;
|
||||
ParticleTree* _particles;
|
||||
VoxelTree* _voxels;
|
||||
AbstractAudioInterface* _audio;
|
||||
AvatarHashMap* _avatars;
|
||||
CollisionList _collisions;
|
||||
};
|
||||
|
||||
#endif // hifi_ParticleCollisionSystem_h
|
|
@ -1,61 +0,0 @@
|
|||
//
|
||||
// ParticleEditPacketSender.cpp
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <PerfStat.h>
|
||||
#include <OctalCode.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include "ParticleEditPacketSender.h"
|
||||
#include "Particle.h"
|
||||
|
||||
|
||||
void ParticleEditPacketSender::sendEditParticleMessage(PacketType type, ParticleID particleID, const ParticleProperties& properties) {
|
||||
// allows app to disable sending if for example voxels have been disabled
|
||||
if (!_shouldSend) {
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
static unsigned char bufferOut[MAX_PACKET_SIZE];
|
||||
int sizeOut = 0;
|
||||
|
||||
// This encodes the voxel edit message into a buffer...
|
||||
if (Particle::encodeParticleEditMessageDetails(type, particleID, properties, &bufferOut[0], _maxPacketSize, sizeOut)){
|
||||
// If we don't have voxel jurisdictions, then we will simply queue up these packets and wait till we have
|
||||
// jurisdictions for processing
|
||||
if (!serversExist()) {
|
||||
queuePendingPacketToNodes(type, bufferOut, sizeOut);
|
||||
} else {
|
||||
queuePacketToNodes(bufferOut, sizeOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEditPacketSender::adjustEditPacketForClockSkew(PacketType type,
|
||||
unsigned char* codeColorBuffer, size_t length, int clockSkew) {
|
||||
Particle::adjustEditPacketForClockSkew(codeColorBuffer, length, clockSkew);
|
||||
}
|
||||
|
||||
|
||||
void ParticleEditPacketSender::queueParticleEditMessage(PacketType type, ParticleID particleID,
|
||||
const ParticleProperties& properties) {
|
||||
if (!_shouldSend) {
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
// use MAX_PACKET_SIZE since it's static and guaranteed to be larger than _maxPacketSize
|
||||
static unsigned char bufferOut[MAX_PACKET_SIZE];
|
||||
int sizeOut = 0;
|
||||
|
||||
if (Particle::encodeParticleEditMessageDetails(type, particleID, properties, &bufferOut[0], _maxPacketSize, sizeOut)) {
|
||||
queueOctreeEditMessage(type, bufferOut, sizeOut);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
//
|
||||
// ParticleEditPacketSender.h
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ParticleEditPacketSender_h
|
||||
#define hifi_ParticleEditPacketSender_h
|
||||
|
||||
#include <OctreeEditPacketSender.h>
|
||||
#include "Particle.h"
|
||||
|
||||
/// Utility for processing, packing, queueing and sending of outbound edit voxel messages.
|
||||
class ParticleEditPacketSender : public OctreeEditPacketSender {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/// Send particle add message immediately
|
||||
/// NOTE: ParticleProperties assumes that all distances are in meter units
|
||||
void sendEditParticleMessage(PacketType type, ParticleID particleID, const ParticleProperties& properties);
|
||||
|
||||
/// Queues an array of several voxel edit messages. Will potentially send a pending multi-command packet. Determines
|
||||
/// which voxel-server node or nodes the packet should be sent to. Can be called even before voxel servers are known, in
|
||||
/// which case up to MaxPendingMessages will be buffered and processed when voxel servers are known.
|
||||
/// NOTE: ParticleProperties assumes that all distances are in meter units
|
||||
void queueParticleEditMessage(PacketType type, ParticleID particleID, const ParticleProperties& properties);
|
||||
|
||||
// My server type is the particle server
|
||||
virtual char getMyNodeType() const { return NodeType::ParticleServer; }
|
||||
virtual void adjustEditPacketForClockSkew(PacketType type, unsigned char* codeColorBuffer, size_t length, int clockSkew);
|
||||
};
|
||||
#endif // hifi_ParticleEditPacketSender_h
|
|
@ -1,658 +0,0 @@
|
|||
//
|
||||
// ParticleTree.cpp
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ParticleTree.h"
|
||||
|
||||
ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) {
|
||||
_rootElement = createNewElement();
|
||||
}
|
||||
|
||||
ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) {
|
||||
ParticleTreeElement* newElement = new ParticleTreeElement(octalCode);
|
||||
newElement->setTree(this);
|
||||
return newElement;
|
||||
}
|
||||
|
||||
bool ParticleTree::handlesEditPacketType(PacketType packetType) const {
|
||||
// we handle these types of "edit" packets
|
||||
switch (packetType) {
|
||||
case PacketTypeParticleAddOrEdit:
|
||||
case PacketTypeParticleErase:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class FindAndDeleteParticlesArgs {
|
||||
public:
|
||||
QList<uint32_t> _idsToDelete;
|
||||
};
|
||||
|
||||
bool ParticleTree::findAndDeleteOperation(OctreeElement* element, void* extraData) {
|
||||
//qDebug() << "findAndDeleteOperation()";
|
||||
|
||||
FindAndDeleteParticlesArgs* args = static_cast< FindAndDeleteParticlesArgs*>(extraData);
|
||||
|
||||
// if we've found and deleted all our target particles, then we can stop looking
|
||||
if (args->_idsToDelete.size() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
|
||||
//qDebug() << "findAndDeleteOperation() args->_idsToDelete.size():" << args->_idsToDelete.size();
|
||||
|
||||
for (QList<uint32_t>::iterator it = args->_idsToDelete.begin(); it != args->_idsToDelete.end(); it++) {
|
||||
uint32_t particleID = *it;
|
||||
//qDebug() << "findAndDeleteOperation() particleID:" << particleID;
|
||||
|
||||
if (particleTreeElement->removeParticleWithID(particleID)) {
|
||||
// if the particle was in this element, then remove it from our search list.
|
||||
//qDebug() << "findAndDeleteOperation() it = args->_idsToDelete.erase(it)";
|
||||
it = args->_idsToDelete.erase(it);
|
||||
}
|
||||
|
||||
if (it == args->_idsToDelete.end()) {
|
||||
//qDebug() << "findAndDeleteOperation() breaking";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we've found and deleted all our target particles, then we can stop looking
|
||||
if (args->_idsToDelete.size() <= 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
// Note: updateParticle() will only operate on correctly found particles
|
||||
if (particleTreeElement->updateParticle(args->searchParticle)) {
|
||||
args->found = true;
|
||||
return false; // stop searching
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ParticleTree::storeParticle(const Particle& particle, const SharedNodePointer& senderNode) {
|
||||
// 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 = std::max(MINIMUM_PARTICLE_ELEMENT_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;
|
||||
}
|
||||
|
||||
class FindAndUpdateParticleWithIDandPropertiesArgs {
|
||||
public:
|
||||
const ParticleID& particleID;
|
||||
const ParticleProperties& properties;
|
||||
bool found;
|
||||
};
|
||||
|
||||
bool ParticleTree::findAndUpdateWithIDandPropertiesOperation(OctreeElement* element, void* extraData) {
|
||||
FindAndUpdateParticleWithIDandPropertiesArgs* args = static_cast<FindAndUpdateParticleWithIDandPropertiesArgs*>(extraData);
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
// Note: updateParticle() will only operate on correctly found particles
|
||||
if (particleTreeElement->updateParticle(args->particleID, args->properties)) {
|
||||
args->found = true;
|
||||
return false; // stop searching
|
||||
}
|
||||
|
||||
// if we've found our particle stop searching
|
||||
if (args->found) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ParticleTree::updateParticle(const ParticleID& particleID, const ParticleProperties& properties) {
|
||||
// First, look for the existing particle in the tree..
|
||||
FindAndUpdateParticleWithIDandPropertiesArgs args = { particleID, properties, false };
|
||||
recurseTreeWithOperation(findAndUpdateWithIDandPropertiesOperation, &args);
|
||||
// if we found it in the tree, then mark the tree as dirty
|
||||
if (args.found) {
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleTree::addParticle(const ParticleID& particleID, const ParticleProperties& properties) {
|
||||
// This only operates on locally created particles
|
||||
if (particleID.isKnownID) {
|
||||
return; // not allowed
|
||||
}
|
||||
Particle particle(particleID, properties);
|
||||
glm::vec3 position = particle.getPosition();
|
||||
float size = std::max(MINIMUM_PARTICLE_ELEMENT_SIZE, particle.getRadius());
|
||||
|
||||
ParticleTreeElement* element = (ParticleTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size);
|
||||
element->storeParticle(particle);
|
||||
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
void ParticleTree::deleteParticle(const ParticleID& particleID) {
|
||||
if (particleID.isKnownID) {
|
||||
FindAndDeleteParticlesArgs args;
|
||||
args._idsToDelete.push_back(particleID.id);
|
||||
recurseTreeWithOperation(findAndDeleteOperation, &args);
|
||||
}
|
||||
}
|
||||
|
||||
// scans the tree and handles mapping locally created particles to know IDs.
|
||||
// in the event that this tree is also viewing the scene, then we need to also
|
||||
// search the tree to make sure we don't have a duplicate particle from the viewing
|
||||
// operation.
|
||||
bool ParticleTree::findAndUpdateParticleIDOperation(OctreeElement* element, void* extraData) {
|
||||
bool keepSearching = true;
|
||||
|
||||
FindAndUpdateParticleIDArgs* args = static_cast<FindAndUpdateParticleIDArgs*>(extraData);
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
|
||||
// Note: updateParticleID() will only operate on correctly found particles
|
||||
particleTreeElement->updateParticleID(args);
|
||||
|
||||
// if we've found and replaced both the creatorTokenID and the viewedParticle, then we
|
||||
// can stop looking, otherwise we will keep looking
|
||||
if (args->creatorTokenFound && args->viewedParticleFound) {
|
||||
keepSearching = false;
|
||||
}
|
||||
|
||||
return keepSearching;
|
||||
}
|
||||
|
||||
void ParticleTree::handleAddParticleResponse(const QByteArray& packet) {
|
||||
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
||||
|
||||
const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data()) + numBytesPacketHeader;
|
||||
|
||||
uint32_t creatorTokenID;
|
||||
memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID));
|
||||
dataAt += sizeof(creatorTokenID);
|
||||
|
||||
uint32_t particleID;
|
||||
memcpy(&particleID, dataAt, sizeof(particleID));
|
||||
dataAt += sizeof(particleID);
|
||||
|
||||
// update particles in our tree
|
||||
bool assumeParticleFound = !getIsViewing(); // if we're not a viewing tree, then we don't have to find the actual particle
|
||||
FindAndUpdateParticleIDArgs args = {
|
||||
particleID,
|
||||
creatorTokenID,
|
||||
false,
|
||||
assumeParticleFound,
|
||||
getIsViewing()
|
||||
};
|
||||
|
||||
const bool wantDebug = false;
|
||||
if (wantDebug) {
|
||||
qDebug() << "looking for creatorTokenID=" << creatorTokenID << " particleID=" << particleID
|
||||
<< " getIsViewing()=" << getIsViewing();
|
||||
}
|
||||
lockForWrite();
|
||||
recurseTreeWithOperation(findAndUpdateParticleIDOperation, &args);
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
class FindNearPointArgs {
|
||||
public:
|
||||
glm::vec3 position;
|
||||
float targetRadius;
|
||||
bool found;
|
||||
const Particle* closestParticle;
|
||||
float closestParticleDistance;
|
||||
};
|
||||
|
||||
|
||||
bool ParticleTree::findNearPointOperation(OctreeElement* element, void* extraData) {
|
||||
FindNearPointArgs* args = static_cast<FindNearPointArgs*>(extraData);
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
|
||||
glm::vec3 penetration;
|
||||
bool sphereIntersection = particleTreeElement->getAACube().findSpherePenetration(args->position,
|
||||
args->targetRadius, penetration);
|
||||
|
||||
// If this particleTreeElement contains the point, then search it...
|
||||
if (sphereIntersection) {
|
||||
const Particle* thisClosestParticle = particleTreeElement->getClosestParticle(args->position);
|
||||
|
||||
// we may have gotten NULL back, meaning no particle was available
|
||||
if (thisClosestParticle) {
|
||||
glm::vec3 particlePosition = thisClosestParticle->getPosition();
|
||||
float distanceFromPointToParticle = glm::distance(particlePosition, args->position);
|
||||
|
||||
// If we're within our target radius
|
||||
if (distanceFromPointToParticle <= args->targetRadius) {
|
||||
// we are closer than anything else we've found
|
||||
if (distanceFromPointToParticle < args->closestParticleDistance) {
|
||||
args->closestParticle = thisClosestParticle;
|
||||
args->closestParticleDistance = distanceFromPointToParticle;
|
||||
args->found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we should be able to optimize this...
|
||||
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;
|
||||
}
|
||||
|
||||
const Particle* ParticleTree::findClosestParticle(glm::vec3 position, float targetRadius) {
|
||||
FindNearPointArgs args = { position, targetRadius, false, NULL, FLT_MAX };
|
||||
lockForRead();
|
||||
recurseTreeWithOperation(findNearPointOperation, &args);
|
||||
unlock();
|
||||
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);
|
||||
glm::vec3 penetration;
|
||||
bool sphereIntersection = element->getAACube().findSpherePenetration(args->position,
|
||||
args->targetRadius, penetration);
|
||||
|
||||
// If this element contains the point, then search it...
|
||||
if (sphereIntersection) {
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
particleTreeElement->getParticles(args->position, args->targetRadius, args->particles);
|
||||
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;
|
||||
}
|
||||
|
||||
void ParticleTree::findParticles(const glm::vec3& center, float radius, QVector<const Particle*>& foundParticles) {
|
||||
FindAllNearPointArgs args = { center, radius };
|
||||
lockForRead();
|
||||
recurseTreeWithOperation(findInSphereOperation, &args);
|
||||
unlock();
|
||||
// swap the two lists of particle pointers instead of copy
|
||||
foundParticles.swap(args.particles);
|
||||
}
|
||||
|
||||
class FindParticlesInCubeArgs {
|
||||
public:
|
||||
FindParticlesInCubeArgs(const AACube& cube)
|
||||
: _cube(cube), _foundParticles() {
|
||||
}
|
||||
|
||||
AACube _cube;
|
||||
QVector<Particle*> _foundParticles;
|
||||
};
|
||||
|
||||
bool ParticleTree::findInCubeOperation(OctreeElement* element, void* extraData) {
|
||||
FindParticlesInCubeArgs* args = static_cast< FindParticlesInCubeArgs*>(extraData);
|
||||
const AACube& elementBox = element->getAACube();
|
||||
if (elementBox.touches(args->_cube)) {
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
particleTreeElement->getParticles(args->_cube, args->_foundParticles);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ParticleTree::findParticles(const AACube& cube, QVector<Particle*> foundParticles) {
|
||||
FindParticlesInCubeArgs args(cube);
|
||||
lockForRead();
|
||||
recurseTreeWithOperation(findInCubeOperation, &args);
|
||||
unlock();
|
||||
// swap the two lists of particle pointers instead of copy
|
||||
foundParticles.swap(args._foundParticles);
|
||||
}
|
||||
|
||||
class FindByIDArgs {
|
||||
public:
|
||||
uint32_t id;
|
||||
bool found;
|
||||
const Particle* foundParticle;
|
||||
};
|
||||
|
||||
|
||||
bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) {
|
||||
//qDebug() << "ParticleTree::findByIDOperation()....";
|
||||
|
||||
FindByIDArgs* args = static_cast<FindByIDArgs*>(extraData);
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
|
||||
// if already found, stop looking
|
||||
if (args->found) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// as the tree element if it has this particle
|
||||
const Particle* foundParticle = particleTreeElement->getParticleWithID(args->id);
|
||||
if (foundParticle) {
|
||||
args->foundParticle = foundParticle;
|
||||
args->found = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// keep looking
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const Particle* ParticleTree::findParticleByID(uint32_t id, bool alreadyLocked) {
|
||||
FindByIDArgs args = { id, false, NULL };
|
||||
|
||||
if (!alreadyLocked) {
|
||||
lockForRead();
|
||||
}
|
||||
recurseTreeWithOperation(findByIDOperation, &args);
|
||||
if (!alreadyLocked) {
|
||||
unlock();
|
||||
}
|
||||
return args.foundParticle;
|
||||
}
|
||||
|
||||
|
||||
int ParticleTree::processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) {
|
||||
|
||||
int processedBytes = 0;
|
||||
// we handle these types of "edit" packets
|
||||
switch (packetType) {
|
||||
case PacketTypeParticleAddOrEdit: {
|
||||
bool isValid;
|
||||
Particle newParticle = Particle::fromEditPacket(editData, maxLength, processedBytes, this, isValid);
|
||||
if (isValid) {
|
||||
storeParticle(newParticle, senderNode);
|
||||
if (newParticle.isNewlyCreated()) {
|
||||
notifyNewlyCreatedParticle(newParticle, senderNode);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
// TODO: wire in support here for server to get PACKET_TYPE_PARTICLE_ERASE messages
|
||||
// instead of using PACKET_TYPE_PARTICLE_ADD_OR_EDIT messages to delete particles
|
||||
case PacketTypeParticleErase:
|
||||
processedBytes = 0;
|
||||
break;
|
||||
default:
|
||||
processedBytes = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return processedBytes;
|
||||
}
|
||||
|
||||
void ParticleTree::notifyNewlyCreatedParticle(const Particle& newParticle, const SharedNodePointer& senderNode) {
|
||||
_newlyCreatedHooksLock.lockForRead();
|
||||
for (size_t i = 0; i < _newlyCreatedHooks.size(); i++) {
|
||||
_newlyCreatedHooks[i]->particleCreated(newParticle, senderNode);
|
||||
}
|
||||
_newlyCreatedHooksLock.unlock();
|
||||
}
|
||||
|
||||
void ParticleTree::addNewlyCreatedHook(NewlyCreatedParticleHook* hook) {
|
||||
_newlyCreatedHooksLock.lockForWrite();
|
||||
_newlyCreatedHooks.push_back(hook);
|
||||
_newlyCreatedHooksLock.unlock();
|
||||
}
|
||||
|
||||
void ParticleTree::removeNewlyCreatedHook(NewlyCreatedParticleHook* hook) {
|
||||
_newlyCreatedHooksLock.lockForWrite();
|
||||
for (size_t i = 0; i < _newlyCreatedHooks.size(); i++) {
|
||||
if (_newlyCreatedHooks[i] == hook) {
|
||||
_newlyCreatedHooks.erase(_newlyCreatedHooks.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_newlyCreatedHooksLock.unlock();
|
||||
}
|
||||
|
||||
|
||||
bool ParticleTree::updateOperation(OctreeElement* element, void* extraData) {
|
||||
ParticleTreeUpdateArgs* args = static_cast<ParticleTreeUpdateArgs*>(extraData);
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
particleTreeElement->update(*args);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParticleTree::pruneOperation(OctreeElement* element, void* extraData) {
|
||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
ParticleTreeElement* childAt = particleTreeElement->getChildAtIndex(i);
|
||||
if (childAt && childAt->isLeaf() && !childAt->hasParticles()) {
|
||||
particleTreeElement->deleteChildAtIndex(i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ParticleTree::update() {
|
||||
lockForWrite();
|
||||
_isDirty = true;
|
||||
|
||||
ParticleTreeUpdateArgs args = { };
|
||||
recurseTreeWithOperation(updateOperation, &args);
|
||||
|
||||
// now add back any of the particles that moved elements....
|
||||
int movingParticles = args._movingParticles.size();
|
||||
for (int i = 0; i < movingParticles; i++) {
|
||||
bool shouldDie = args._movingParticles[i].getShouldDie();
|
||||
|
||||
// if the particle is still inside our total bounds, then re-add it
|
||||
AACube treeBounds = getRoot()->getAACube();
|
||||
|
||||
if (!shouldDie && treeBounds.contains(args._movingParticles[i].getPosition())) {
|
||||
storeParticle(args._movingParticles[i]);
|
||||
} else {
|
||||
uint32_t particleID = args._movingParticles[i].getID();
|
||||
quint64 deletedAt = usecTimestampNow();
|
||||
_recentlyDeletedParticlesLock.lockForWrite();
|
||||
_recentlyDeletedParticleIDs.insert(deletedAt, particleID);
|
||||
_recentlyDeletedParticlesLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// prune the tree...
|
||||
recurseTreeWithOperation(pruneOperation, NULL);
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
bool ParticleTree::hasParticlesDeletedSince(quint64 sinceTime) {
|
||||
// we can probably leverage the ordered nature of QMultiMap to do this quickly...
|
||||
bool hasSomethingNewer = false;
|
||||
|
||||
_recentlyDeletedParticlesLock.lockForRead();
|
||||
QMultiMap<quint64, uint32_t>::const_iterator iterator = _recentlyDeletedParticleIDs.constBegin();
|
||||
while (iterator != _recentlyDeletedParticleIDs.constEnd()) {
|
||||
//qDebug() << "considering... time/key:" << iterator.key();
|
||||
if (iterator.key() > sinceTime) {
|
||||
//qDebug() << "YES newer... time/key:" << iterator.key();
|
||||
hasSomethingNewer = true;
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
_recentlyDeletedParticlesLock.unlock();
|
||||
return hasSomethingNewer;
|
||||
}
|
||||
|
||||
// sinceTime is an in/out parameter - it will be side effected with the last time sent out
|
||||
bool ParticleTree::encodeParticlesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime, unsigned char* outputBuffer,
|
||||
size_t maxLength, size_t& outputLength) {
|
||||
|
||||
bool hasMoreToSend = true;
|
||||
|
||||
unsigned char* copyAt = outputBuffer;
|
||||
size_t numBytesPacketHeader = populatePacketHeader(reinterpret_cast<char*>(outputBuffer), PacketTypeParticleErase);
|
||||
copyAt += numBytesPacketHeader;
|
||||
outputLength = numBytesPacketHeader;
|
||||
|
||||
// pack in flags
|
||||
OCTREE_PACKET_FLAGS flags = 0;
|
||||
memcpy(copyAt, &flags, sizeof(OCTREE_PACKET_FLAGS));
|
||||
copyAt += sizeof(OCTREE_PACKET_FLAGS);
|
||||
outputLength += sizeof(OCTREE_PACKET_FLAGS);
|
||||
|
||||
// pack in sequence number
|
||||
memcpy(copyAt, &sequenceNumber, sizeof(OCTREE_PACKET_SEQUENCE));
|
||||
copyAt += sizeof(OCTREE_PACKET_SEQUENCE);
|
||||
outputLength += sizeof(OCTREE_PACKET_SEQUENCE);
|
||||
|
||||
// pack in timestamp
|
||||
OCTREE_PACKET_SENT_TIME now = usecTimestampNow();
|
||||
memcpy(copyAt, &now, sizeof(OCTREE_PACKET_SENT_TIME));
|
||||
copyAt += sizeof(OCTREE_PACKET_SENT_TIME);
|
||||
outputLength += sizeof(OCTREE_PACKET_SENT_TIME);
|
||||
|
||||
|
||||
uint16_t numberOfIds = 0; // placeholder for now
|
||||
unsigned char* numberOfIDsAt = copyAt;
|
||||
memcpy(copyAt, &numberOfIds, sizeof(numberOfIds));
|
||||
copyAt += sizeof(numberOfIds);
|
||||
outputLength += sizeof(numberOfIds);
|
||||
|
||||
// we keep a multi map of particle IDs to timestamps, we only want to include the particle IDs that have been
|
||||
// deleted since we last sent to this node
|
||||
_recentlyDeletedParticlesLock.lockForRead();
|
||||
QMultiMap<quint64, uint32_t>::const_iterator iterator = _recentlyDeletedParticleIDs.constBegin();
|
||||
while (iterator != _recentlyDeletedParticleIDs.constEnd()) {
|
||||
QList<uint32_t> values = _recentlyDeletedParticleIDs.values(iterator.key());
|
||||
for (int valueItem = 0; valueItem < values.size(); ++valueItem) {
|
||||
|
||||
// if the timestamp is more recent then out last sent time, include it
|
||||
if (iterator.key() > sinceTime) {
|
||||
uint32_t particleID = values.at(valueItem);
|
||||
memcpy(copyAt, &particleID, sizeof(particleID));
|
||||
copyAt += sizeof(particleID);
|
||||
outputLength += sizeof(particleID);
|
||||
numberOfIds++;
|
||||
|
||||
// check to make sure we have room for one more id...
|
||||
if (outputLength + sizeof(uint32_t) > maxLength) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check to make sure we have room for one more id...
|
||||
if (outputLength + sizeof(uint32_t) > maxLength) {
|
||||
|
||||
// let our caller know how far we got
|
||||
sinceTime = iterator.key();
|
||||
break;
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
|
||||
// if we got to the end, then we're done sending
|
||||
if (iterator == _recentlyDeletedParticleIDs.constEnd()) {
|
||||
hasMoreToSend = false;
|
||||
}
|
||||
_recentlyDeletedParticlesLock.unlock();
|
||||
|
||||
// replace the correct count for ids included
|
||||
memcpy(numberOfIDsAt, &numberOfIds, sizeof(numberOfIds));
|
||||
|
||||
return hasMoreToSend;
|
||||
}
|
||||
|
||||
// called by the server when it knows all nodes have been sent deleted packets
|
||||
|
||||
void ParticleTree::forgetParticlesDeletedBefore(quint64 sinceTime) {
|
||||
//qDebug() << "forgetParticlesDeletedBefore()";
|
||||
QSet<quint64> keysToRemove;
|
||||
|
||||
_recentlyDeletedParticlesLock.lockForWrite();
|
||||
QMultiMap<quint64, uint32_t>::iterator iterator = _recentlyDeletedParticleIDs.begin();
|
||||
|
||||
// First find all the keys in the map that are older and need to be deleted
|
||||
while (iterator != _recentlyDeletedParticleIDs.end()) {
|
||||
if (iterator.key() <= sinceTime) {
|
||||
keysToRemove << iterator.key();
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
|
||||
// Now run through the keysToRemove and remove them
|
||||
foreach (quint64 value, keysToRemove) {
|
||||
//qDebug() << "removing the key, _recentlyDeletedParticleIDs.remove(value); time/key:" << value;
|
||||
_recentlyDeletedParticleIDs.remove(value);
|
||||
}
|
||||
|
||||
_recentlyDeletedParticlesLock.unlock();
|
||||
}
|
||||
|
||||
|
||||
void ParticleTree::processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
||||
|
||||
const unsigned char* packetData = (const unsigned char*)dataByteArray.constData();
|
||||
const unsigned char* dataAt = packetData;
|
||||
size_t packetLength = dataByteArray.size();
|
||||
|
||||
size_t numBytesPacketHeader = numBytesForPacketHeader(dataByteArray);
|
||||
size_t processedBytes = numBytesPacketHeader;
|
||||
dataAt += numBytesPacketHeader;
|
||||
|
||||
dataAt += sizeof(OCTREE_PACKET_FLAGS);
|
||||
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
|
||||
dataAt += sizeof(OCTREE_PACKET_SENT_TIME);
|
||||
|
||||
uint16_t numberOfIds = 0; // placeholder for now
|
||||
memcpy(&numberOfIds, dataAt, sizeof(numberOfIds));
|
||||
dataAt += sizeof(numberOfIds);
|
||||
processedBytes += sizeof(numberOfIds);
|
||||
|
||||
if (numberOfIds > 0) {
|
||||
FindAndDeleteParticlesArgs args;
|
||||
|
||||
for (size_t i = 0; i < numberOfIds; i++) {
|
||||
if (processedBytes + sizeof(uint32_t) > packetLength) {
|
||||
break; // bail to prevent buffer overflow
|
||||
}
|
||||
|
||||
uint32_t particleID = 0; // placeholder for now
|
||||
memcpy(&particleID, dataAt, sizeof(particleID));
|
||||
dataAt += sizeof(particleID);
|
||||
processedBytes += sizeof(particleID);
|
||||
|
||||
args._idsToDelete.push_back(particleID);
|
||||
}
|
||||
|
||||
// calling recurse to actually delete the particles
|
||||
recurseTreeWithOperation(findAndDeleteOperation, &args);
|
||||
}
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
//
|
||||
// ParticleTree.h
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ParticleTree_h
|
||||
#define hifi_ParticleTree_h
|
||||
|
||||
#include <Octree.h>
|
||||
#include "ParticleTreeElement.h"
|
||||
|
||||
class NewlyCreatedParticleHook {
|
||||
public:
|
||||
virtual void particleCreated(const Particle& newParticle, const SharedNodePointer& senderNode) = 0;
|
||||
};
|
||||
|
||||
class ParticleTree : public Octree {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ParticleTree(bool shouldReaverage = false);
|
||||
|
||||
/// Implements our type specific root element factory
|
||||
virtual ParticleTreeElement* createNewElement(unsigned char * octalCode = NULL);
|
||||
|
||||
/// Type safe version of getRoot()
|
||||
ParticleTreeElement* getRoot() { return static_cast<ParticleTreeElement*>(_rootElement); }
|
||||
|
||||
|
||||
// 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
|
||||
virtual bool getWantSVOfileVersions() const { return true; }
|
||||
virtual PacketType expectedDataPacketType() const { return PacketTypeParticleData; }
|
||||
virtual bool handlesEditPacketType(PacketType packetType) const;
|
||||
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode);
|
||||
|
||||
virtual void update();
|
||||
|
||||
void storeParticle(const Particle& particle, const SharedNodePointer& senderNode = SharedNodePointer());
|
||||
void updateParticle(const ParticleID& particleID, const ParticleProperties& properties);
|
||||
void addParticle(const ParticleID& particleID, const ParticleProperties& properties);
|
||||
void deleteParticle(const ParticleID& particleID);
|
||||
const Particle* findClosestParticle(glm::vec3 position, float targetRadius);
|
||||
const Particle* findParticleByID(uint32_t id, bool alreadyLocked = false);
|
||||
|
||||
/// finds all particles that touch a sphere
|
||||
/// \param center the center of the sphere
|
||||
/// \param radius the radius of the sphere
|
||||
/// \param foundParticles[out] vector of const Particle*
|
||||
/// \remark Side effect: any initial contents in foundParticles will be lost
|
||||
void findParticles(const glm::vec3& center, float radius, QVector<const Particle*>& foundParticles);
|
||||
|
||||
/// finds all particles that touch a box
|
||||
/// \param box the query box
|
||||
/// \param foundParticles[out] vector of non-const Particle*
|
||||
/// \remark Side effect: any initial contents in particles will be lost
|
||||
void findParticles(const AACube& box, QVector<Particle*> foundParticles);
|
||||
|
||||
void addNewlyCreatedHook(NewlyCreatedParticleHook* hook);
|
||||
void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook);
|
||||
|
||||
bool hasAnyDeletedParticles() const { return _recentlyDeletedParticleIDs.size() > 0; }
|
||||
bool hasParticlesDeletedSince(quint64 sinceTime);
|
||||
bool encodeParticlesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime, unsigned char* packetData, size_t maxLength, size_t& outputLength);
|
||||
void forgetParticlesDeletedBefore(quint64 sinceTime);
|
||||
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
void handleAddParticleResponse(const QByteArray& packet);
|
||||
|
||||
private:
|
||||
|
||||
static bool updateOperation(OctreeElement* element, void* extraData);
|
||||
static bool findAndUpdateOperation(OctreeElement* element, void* extraData);
|
||||
static bool findAndUpdateWithIDandPropertiesOperation(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);
|
||||
static bool findAndUpdateParticleIDOperation(OctreeElement* element, void* extraData);
|
||||
|
||||
static bool findInCubeOperation(OctreeElement* element, void* extraData);
|
||||
|
||||
void notifyNewlyCreatedParticle(const Particle& newParticle, const SharedNodePointer& senderNode);
|
||||
|
||||
QReadWriteLock _newlyCreatedHooksLock;
|
||||
std::vector<NewlyCreatedParticleHook*> _newlyCreatedHooks;
|
||||
|
||||
|
||||
QReadWriteLock _recentlyDeletedParticlesLock;
|
||||
QMultiMap<quint64, uint32_t> _recentlyDeletedParticleIDs;
|
||||
};
|
||||
|
||||
#endif // hifi_ParticleTree_h
|
|
@ -1,343 +0,0 @@
|
|||
//
|
||||
// ParticleTreeElement.cpp
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <GeometryUtil.h>
|
||||
|
||||
#include "ParticleTree.h"
|
||||
#include "ParticleTreeElement.h"
|
||||
|
||||
ParticleTreeElement::ParticleTreeElement(unsigned char* octalCode) : OctreeElement(), _particles(NULL) {
|
||||
init(octalCode);
|
||||
};
|
||||
|
||||
ParticleTreeElement::~ParticleTreeElement() {
|
||||
_voxelMemoryUsage -= sizeof(ParticleTreeElement);
|
||||
QList<Particle>* tmpParticles = _particles;
|
||||
_particles = NULL;
|
||||
delete tmpParticles;
|
||||
}
|
||||
|
||||
// This will be called primarily on addChildAt(), which means we're adding a child of our
|
||||
// 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) {
|
||||
ParticleTreeElement* newChild = new ParticleTreeElement(octalCode);
|
||||
newChild->setTree(_myTree);
|
||||
return newChild;
|
||||
}
|
||||
|
||||
void ParticleTreeElement::init(unsigned char* octalCode) {
|
||||
OctreeElement::init(octalCode);
|
||||
_particles = new QList<Particle>;
|
||||
_voxelMemoryUsage += sizeof(ParticleTreeElement);
|
||||
}
|
||||
|
||||
ParticleTreeElement* ParticleTreeElement::addChildAtIndex(int index) {
|
||||
ParticleTreeElement* newElement = (ParticleTreeElement*)OctreeElement::addChildAtIndex(index);
|
||||
newElement->setTree(_myTree);
|
||||
return newElement;
|
||||
}
|
||||
|
||||
|
||||
OctreeElement::AppendState ParticleTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const {
|
||||
bool success = true; // assume the best...
|
||||
|
||||
// write our particles out...
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
success = packetData->appendValue(numberOfParticles);
|
||||
|
||||
if (success) {
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
const Particle& particle = (*_particles)[i];
|
||||
success = particle.appendParticleData(packetData);
|
||||
if (!success) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success ? OctreeElement::COMPLETED : OctreeElement::NONE;
|
||||
}
|
||||
|
||||
void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) {
|
||||
markWithChangedTime();
|
||||
// TODO: early exit when _particles is empty
|
||||
|
||||
// update our contained particles
|
||||
QList<Particle>::iterator particleItr = _particles->begin();
|
||||
while(particleItr != _particles->end()) {
|
||||
Particle& particle = (*particleItr);
|
||||
particle.update(_lastChanged);
|
||||
|
||||
// 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 (particle.getShouldDie() || !_cube.contains(particle.getPosition())) {
|
||||
args._movingParticles.push_back(particle);
|
||||
|
||||
// erase this particle
|
||||
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 {
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We've considered making "inHand" particles not collide, if we want to do that,
|
||||
// we should change this setting... but now, we do allow inHand particles to collide
|
||||
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 (particle.getInHand()) {
|
||||
++particleItr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (findSphereSpherePenetration(center, radius, particleCenter, particleRadius, penetration)) {
|
||||
// return true on first valid particle penetration
|
||||
*penetratedObject = (void*)(&particle);
|
||||
return true;
|
||||
}
|
||||
++particleItr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
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) {
|
||||
qDebug("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s",
|
||||
particle.getID(), (changedOnServer ? "CHANGED" : "same"),
|
||||
(localOlder ? "OLDER" : "NEWER"),
|
||||
difference, debug::valueOf(particle.isNewlyCreated()) );
|
||||
}
|
||||
thisParticle.copyChangedProperties(particle);
|
||||
} else {
|
||||
if (wantDebug) {
|
||||
qDebug(">>> IGNORING SERVER!!! Would've caused jutter! <<< "
|
||||
"local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s",
|
||||
particle.getID(), (changedOnServer ? "CHANGED" : "same"),
|
||||
(localOlder ? "OLDER" : "NEWER"),
|
||||
difference, debug::valueOf(particle.isNewlyCreated()) );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParticleTreeElement::updateParticle(const ParticleID& particleID, const ParticleProperties& properties) {
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
// note: unlike storeParticle() which is called from inbound packets, this is only called by local editors
|
||||
// and therefore we can be confident that this change is higher priority and should be honored
|
||||
Particle& thisParticle = (*_particles)[i];
|
||||
|
||||
bool found = false;
|
||||
if (particleID.isKnownID) {
|
||||
found = thisParticle.getID() == particleID.id;
|
||||
} else {
|
||||
found = thisParticle.getCreatorTokenID() == particleID.creatorTokenID;
|
||||
}
|
||||
if (found) {
|
||||
thisParticle.setProperties(properties);
|
||||
|
||||
const bool wantDebug = false;
|
||||
if (wantDebug) {
|
||||
uint64_t now = usecTimestampNow();
|
||||
int elapsed = now - thisParticle.getLastEdited();
|
||||
|
||||
qDebug() << "ParticleTreeElement::updateParticle() AFTER update... edited AGO=" << elapsed <<
|
||||
"now=" << now << " thisParticle.getLastEdited()=" << thisParticle.getLastEdited();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ParticleTreeElement::updateParticleID(FindAndUpdateParticleIDArgs* args) {
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
Particle& thisParticle = (*_particles)[i];
|
||||
|
||||
if (!args->creatorTokenFound) {
|
||||
// first, we're looking for matching creatorTokenIDs, if we find that, then we fix it to know the actual ID
|
||||
if (thisParticle.getCreatorTokenID() == args->creatorTokenID) {
|
||||
thisParticle.setID(args->particleID);
|
||||
args->creatorTokenFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if we're in an isViewing tree, we also need to look for an kill any viewed particles
|
||||
if (!args->viewedParticleFound && args->isViewing) {
|
||||
if (thisParticle.getCreatorTokenID() == UNKNOWN_TOKEN && thisParticle.getID() == args->particleID) {
|
||||
_particles->removeAt(i); // remove the particle at this index
|
||||
numberOfParticles--; // this means we have 1 fewer particle in this list
|
||||
i--; // and we actually want to back up i as well.
|
||||
args->viewedParticleFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) const {
|
||||
const Particle* closestParticle = NULL;
|
||||
float closestParticleDistance = FLT_MAX;
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
float distanceToParticle = glm::distance(position, (*_particles)[i].getPosition());
|
||||
if (distanceToParticle < closestParticleDistance) {
|
||||
closestParticle = &(*_particles)[i];
|
||||
}
|
||||
}
|
||||
return closestParticle;
|
||||
}
|
||||
|
||||
void ParticleTreeElement::getParticles(const glm::vec3& searchPosition, float searchRadius, QVector<const Particle*>& foundParticles) const {
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
const Particle* particle = &(*_particles)[i];
|
||||
float distance = glm::length(particle->getPosition() - searchPosition);
|
||||
if (distance < searchRadius + particle->getRadius()) {
|
||||
foundParticles.push_back(particle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleTreeElement::getParticles(const AACube& box, QVector<Particle*>& foundParticles) {
|
||||
QList<Particle>::iterator particleItr = _particles->begin();
|
||||
QList<Particle>::iterator particleEnd = _particles->end();
|
||||
AACube particleCube;
|
||||
while(particleItr != particleEnd) {
|
||||
Particle* particle = &(*particleItr);
|
||||
float radius = particle->getRadius();
|
||||
// NOTE: we actually do box-box collision queries here, which is sloppy but good enough for now
|
||||
// TODO: decide whether to replace particleBox-box query with sphere-box (requires a square root
|
||||
// but will be slightly more accurate).
|
||||
particleCube.setBox(particle->getPosition() - glm::vec3(radius), 2.f * radius);
|
||||
if (particleCube.touches(_cube)) {
|
||||
foundParticles.push_back(particle);
|
||||
}
|
||||
++particleItr;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
if ((*_particles)[i].getID() == id) {
|
||||
foundParticle = &(*_particles)[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return foundParticle;
|
||||
}
|
||||
|
||||
bool ParticleTreeElement::removeParticleWithID(uint32_t id) {
|
||||
bool foundParticle = false;
|
||||
if (_particles) {
|
||||
uint16_t numberOfParticles = _particles->size();
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
if ((*_particles)[i].getID() == id) {
|
||||
foundParticle = true;
|
||||
_particles->removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundParticle;
|
||||
}
|
||||
|
||||
int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args) {
|
||||
|
||||
const unsigned char* dataAt = data;
|
||||
int bytesRead = 0;
|
||||
uint16_t numberOfParticles = 0;
|
||||
int expectedBytesPerParticle = Particle::expectedBytes();
|
||||
|
||||
if (bytesLeftToRead >= (int)sizeof(numberOfParticles)) {
|
||||
// read our particles in....
|
||||
numberOfParticles = *(uint16_t*)dataAt;
|
||||
dataAt += sizeof(numberOfParticles);
|
||||
bytesLeftToRead -= (int)sizeof(numberOfParticles);
|
||||
bytesRead += sizeof(numberOfParticles);
|
||||
|
||||
if (bytesLeftToRead >= (int)(numberOfParticles * expectedBytesPerParticle)) {
|
||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||
Particle tempParticle;
|
||||
int bytesForThisParticle = tempParticle.readParticleDataFromBuffer(dataAt, bytesLeftToRead, args);
|
||||
_myTree->storeParticle(tempParticle);
|
||||
dataAt += bytesForThisParticle;
|
||||
bytesLeftToRead -= bytesForThisParticle;
|
||||
bytesRead += bytesForThisParticle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
// will average a "common reduced LOD view" from the the child elements...
|
||||
void ParticleTreeElement::calculateAverageFromChildren() {
|
||||
// nothing to do here yet...
|
||||
}
|
||||
|
||||
// will detect if children are leaves AND collapsable into the parent node
|
||||
// and in that case will collapse children and make this node
|
||||
// a leaf, returns TRUE if all the leaves are collapsed into a
|
||||
// single node
|
||||
bool ParticleTreeElement::collapseChildren() {
|
||||
// nothing to do here yet...
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ParticleTreeElement::storeParticle(const Particle& particle) {
|
||||
_particles->push_back(particle);
|
||||
markWithChangedTime();
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
//
|
||||
// ParticleTreeElement.h
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ParticleTreeElement_h
|
||||
#define hifi_ParticleTreeElement_h
|
||||
|
||||
//#include <vector>
|
||||
|
||||
#include <OctreeElement.h>
|
||||
#include <QList>
|
||||
|
||||
#include "Particle.h"
|
||||
#include "ParticleTree.h"
|
||||
|
||||
class ParticleTree;
|
||||
class ParticleTreeElement;
|
||||
|
||||
class ParticleTreeUpdateArgs {
|
||||
public:
|
||||
QList<Particle> _movingParticles;
|
||||
};
|
||||
|
||||
class FindAndUpdateParticleIDArgs {
|
||||
public:
|
||||
uint32_t particleID;
|
||||
uint32_t creatorTokenID;
|
||||
bool creatorTokenFound;
|
||||
bool viewedParticleFound;
|
||||
bool isViewing;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ParticleTreeElement : public OctreeElement {
|
||||
friend class ParticleTree; // to allow createElement to new us...
|
||||
|
||||
ParticleTreeElement(unsigned char* octalCode = NULL);
|
||||
|
||||
virtual OctreeElement* createNewElement(unsigned char* octalCode = NULL);
|
||||
|
||||
public:
|
||||
virtual ~ParticleTreeElement();
|
||||
|
||||
// type safe versions of OctreeElement methods
|
||||
ParticleTreeElement* getChildAtIndex(int index) { return (ParticleTreeElement*)OctreeElement::getChildAtIndex(index); }
|
||||
|
||||
// methods you can and should override to implement your tree functionality
|
||||
|
||||
/// Adds a child to the current element. Override this if there is additional child initialization your class needs.
|
||||
virtual ParticleTreeElement* addChildAtIndex(int index);
|
||||
|
||||
/// Override this to implement LOD averaging on changes to the tree.
|
||||
virtual void calculateAverageFromChildren();
|
||||
|
||||
/// Override this to implement LOD collapsing and identical child pruning on changes to the tree.
|
||||
virtual bool collapseChildren();
|
||||
|
||||
/// Should this element be considered to have content in it. This will be used in collision and ray casting methods.
|
||||
/// By default we assume that only leaves are actual content, but some octrees may have different semantics.
|
||||
virtual bool hasContent() const { return isLeaf(); }
|
||||
|
||||
/// Override this to break up large octree elements when an edit operation is performed on a smaller octree element.
|
||||
/// For example, if the octrees represent solid cubes and a delete of a smaller octree element is done then the
|
||||
/// meaningful split would be to break the larger cube into smaller cubes of the same color/texture.
|
||||
virtual void splitChildren() { }
|
||||
|
||||
/// Override to indicate that this element requires a split before editing lower elements in the octree
|
||||
virtual bool requiresSplit() const { return false; }
|
||||
|
||||
/// Override to serialize the state of this element. This is used for persistance and for transmission across the network.
|
||||
virtual OctreeElement::AppendState appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const;
|
||||
|
||||
/// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading
|
||||
/// from the network.
|
||||
virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
||||
|
||||
/// Override to indicate that the item is currently rendered in the rendering engine. By default we assume that if
|
||||
/// the element should be rendered, then your rendering engine is rendering. But some rendering engines my have cases
|
||||
/// 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 !hasParticles(); }
|
||||
|
||||
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
||||
glm::vec3& penetration, void** penetratedObject) const;
|
||||
|
||||
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; }
|
||||
|
||||
bool updateParticle(const Particle& particle);
|
||||
bool updateParticle(const ParticleID& particleID, const ParticleProperties& properties);
|
||||
void updateParticleID(FindAndUpdateParticleIDArgs* args);
|
||||
|
||||
const Particle* getClosestParticle(glm::vec3 position) const;
|
||||
|
||||
/// finds all particles that touch a sphere
|
||||
/// \param position the center of the query sphere
|
||||
/// \param radius the radius of the query sphere
|
||||
/// \param particles[out] vector of const Particle*
|
||||
void getParticles(const glm::vec3& position, float radius, QVector<const Particle*>& foundParticles) const;
|
||||
|
||||
/// finds all particles that touch a box
|
||||
/// \param box the query box
|
||||
/// \param particles[out] vector of non-const Particle*
|
||||
void getParticles(const AACube& box, QVector<Particle*>& foundParticles);
|
||||
|
||||
const Particle* getParticleWithID(uint32_t id) const;
|
||||
|
||||
bool removeParticleWithID(uint32_t id);
|
||||
|
||||
protected:
|
||||
virtual void init(unsigned char * octalCode);
|
||||
|
||||
void storeParticle(const Particle& particle);
|
||||
|
||||
ParticleTree* _myTree;
|
||||
QList<Particle>* _particles;
|
||||
};
|
||||
|
||||
#endif // hifi_ParticleTreeElement_h
|
|
@ -1,38 +0,0 @@
|
|||
//
|
||||
// ParticleTreeHeadlessViewer.cpp
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/26/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ParticleTreeHeadlessViewer.h"
|
||||
|
||||
ParticleTreeHeadlessViewer::ParticleTreeHeadlessViewer() :
|
||||
OctreeHeadlessViewer() {
|
||||
}
|
||||
|
||||
ParticleTreeHeadlessViewer::~ParticleTreeHeadlessViewer() {
|
||||
}
|
||||
|
||||
void ParticleTreeHeadlessViewer::init() {
|
||||
OctreeHeadlessViewer::init();
|
||||
}
|
||||
|
||||
|
||||
void ParticleTreeHeadlessViewer::update() {
|
||||
if (_tree) {
|
||||
ParticleTree* tree = static_cast<ParticleTree*>(_tree);
|
||||
if (tree->tryLockForWrite()) {
|
||||
tree->update();
|
||||
tree->unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleTreeHeadlessViewer::processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
||||
static_cast<ParticleTree*>(_tree)->processEraseMessage(dataByteArray, sourceNode);
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
//
|
||||
// ParticleTreeHeadlessViewer.h
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/26/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ParticleTreeHeadlessViewer_h
|
||||
#define hifi_ParticleTreeHeadlessViewer_h
|
||||
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <Octree.h>
|
||||
#include <OctreePacketData.h>
|
||||
#include <OctreeHeadlessViewer.h>
|
||||
#include "ParticleTree.h"
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
// Generic client side Octree renderer class.
|
||||
class ParticleTreeHeadlessViewer : public OctreeHeadlessViewer {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ParticleTreeHeadlessViewer();
|
||||
virtual ~ParticleTreeHeadlessViewer();
|
||||
|
||||
virtual Octree* createTree() { return new ParticleTree(true); }
|
||||
virtual char getMyNodeType() const { return NodeType::ParticleServer; }
|
||||
virtual PacketType getMyQueryMessageType() const { return PacketTypeParticleQuery; }
|
||||
virtual PacketType getExpectedPacketType() const { return PacketTypeParticleData; }
|
||||
|
||||
void update();
|
||||
|
||||
ParticleTree* getTree() { return (ParticleTree*)_tree; }
|
||||
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
|
||||
virtual void init();
|
||||
};
|
||||
|
||||
#endif // hifi_ParticleTreeHeadlessViewer_h
|
|
@ -1,176 +0,0 @@
|
|||
//
|
||||
// ParticlesScriptingInterface.cpp
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/6/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ParticlesScriptingInterface.h"
|
||||
#include "ParticleTree.h"
|
||||
|
||||
ParticlesScriptingInterface::ParticlesScriptingInterface() :
|
||||
_nextCreatorTokenID(0),
|
||||
_particleTree(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void ParticlesScriptingInterface::queueParticleMessage(PacketType packetType,
|
||||
ParticleID particleID, const ParticleProperties& properties) {
|
||||
getParticlePacketSender()->queueParticleEditMessage(packetType, particleID, properties);
|
||||
}
|
||||
|
||||
ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& properties) {
|
||||
|
||||
// The application will keep track of creatorTokenID
|
||||
uint32_t creatorTokenID = Particle::getNextCreatorTokenID();
|
||||
|
||||
ParticleID id(NEW_PARTICLE, creatorTokenID, false );
|
||||
|
||||
// queue the packet
|
||||
queueParticleMessage(PacketTypeParticleAddOrEdit, id, properties);
|
||||
|
||||
// If we have a local particle tree set, then also update it.
|
||||
if (_particleTree) {
|
||||
_particleTree->lockForWrite();
|
||||
_particleTree->addParticle(id, properties);
|
||||
_particleTree->unlock();
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
ParticleID ParticlesScriptingInterface::identifyParticle(ParticleID particleID) {
|
||||
uint32_t actualID = particleID.id;
|
||||
|
||||
if (!particleID.isKnownID) {
|
||||
actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID);
|
||||
if (actualID == UNKNOWN_PARTICLE_ID) {
|
||||
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) {
|
||||
_particleTree->lockForRead();
|
||||
const Particle* particle = _particleTree->findParticleByID(identity.id, true);
|
||||
if (particle) {
|
||||
results.copyFromParticle(*particle);
|
||||
} else {
|
||||
results.setIsUnknownID();
|
||||
}
|
||||
_particleTree->unlock();
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ParticleID ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) {
|
||||
uint32_t actualID = particleID.id;
|
||||
|
||||
// if the particle is unknown, attempt to look it up
|
||||
if (!particleID.isKnownID) {
|
||||
actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID);
|
||||
}
|
||||
|
||||
// if at this point, we know the id, send the update to the particle server
|
||||
if (actualID != UNKNOWN_PARTICLE_ID) {
|
||||
particleID.id = actualID;
|
||||
particleID.isKnownID = true;
|
||||
queueParticleMessage(PacketTypeParticleAddOrEdit, particleID, properties);
|
||||
}
|
||||
|
||||
// If we have a local particle tree set, then also update it. We can do this even if we don't know
|
||||
// the actual id, because we can edit out local particles just with creatorTokenID
|
||||
if (_particleTree) {
|
||||
_particleTree->lockForWrite();
|
||||
_particleTree->updateParticle(particleID, properties);
|
||||
_particleTree->unlock();
|
||||
}
|
||||
|
||||
return particleID;
|
||||
}
|
||||
|
||||
|
||||
// TODO: This deleteParticle() method uses the PacketType_PARTICLE_ADD_OR_EDIT message to send
|
||||
// a changed particle with a shouldDie() property set to true. This works and is currently the only
|
||||
// way to tell the particle server to delete a particle. But we should change this to use the PacketType_PARTICLE_ERASE
|
||||
// message which takes a list of particle id's to delete.
|
||||
void ParticlesScriptingInterface::deleteParticle(ParticleID particleID) {
|
||||
|
||||
// setup properties to kill the particle
|
||||
ParticleProperties properties;
|
||||
properties.setShouldDie(true);
|
||||
|
||||
uint32_t actualID = particleID.id;
|
||||
|
||||
// if the particle is unknown, attempt to look it up
|
||||
if (!particleID.isKnownID) {
|
||||
actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID);
|
||||
}
|
||||
|
||||
// if at this point, we know the id, send the update to the particle server
|
||||
if (actualID != UNKNOWN_PARTICLE_ID) {
|
||||
particleID.id = actualID;
|
||||
particleID.isKnownID = true;
|
||||
queueParticleMessage(PacketTypeParticleAddOrEdit, particleID, properties);
|
||||
}
|
||||
|
||||
// If we have a local particle tree set, then also update it.
|
||||
if (_particleTree) {
|
||||
_particleTree->lockForWrite();
|
||||
_particleTree->deleteParticle(particleID);
|
||||
_particleTree->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
ParticleID ParticlesScriptingInterface::findClosestParticle(const glm::vec3& center, float radius) const {
|
||||
ParticleID result(UNKNOWN_PARTICLE_ID, UNKNOWN_TOKEN, false);
|
||||
if (_particleTree) {
|
||||
_particleTree->lockForRead();
|
||||
const Particle* closestParticle = _particleTree->findClosestParticle(center/(float)TREE_SCALE,
|
||||
radius/(float)TREE_SCALE);
|
||||
_particleTree->unlock();
|
||||
if (closestParticle) {
|
||||
result.id = closestParticle->getID();
|
||||
result.isKnownID = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
QVector<ParticleID> ParticlesScriptingInterface::findParticles(const glm::vec3& center, float radius) const {
|
||||
QVector<ParticleID> result;
|
||||
if (_particleTree) {
|
||||
_particleTree->lockForRead();
|
||||
QVector<const Particle*> particles;
|
||||
_particleTree->findParticles(center/(float)TREE_SCALE, radius/(float)TREE_SCALE, particles);
|
||||
_particleTree->unlock();
|
||||
|
||||
foreach (const Particle* particle, particles) {
|
||||
ParticleID thisParticleID(particle->getID(), UNKNOWN_TOKEN, true);
|
||||
result << thisParticleID;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
//
|
||||
// ParticlesScriptingInterface.h
|
||||
// libraries/particles/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/6/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ParticlesScriptingInterface_h
|
||||
#define hifi_ParticlesScriptingInterface_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <CollisionInfo.h>
|
||||
|
||||
#include <OctreeScriptingInterface.h>
|
||||
#include "ParticleEditPacketSender.h"
|
||||
|
||||
/// handles scripting of Particle commands from JS passed to assigned clients
|
||||
class ParticlesScriptingInterface : public OctreeScriptingInterface {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ParticlesScriptingInterface();
|
||||
|
||||
ParticleEditPacketSender* getParticlePacketSender() const { return (ParticleEditPacketSender*)getPacketSender(); }
|
||||
virtual NodeType_t getServerNodeType() const { return NodeType::ParticleServer; }
|
||||
virtual OctreeEditPacketSender* createPacketSender() { return new ParticleEditPacketSender(); }
|
||||
|
||||
void setParticleTree(ParticleTree* particleTree) { _particleTree = particleTree; }
|
||||
ParticleTree* getParticleTree(ParticleTree*) { return _particleTree; }
|
||||
|
||||
public slots:
|
||||
/// adds a particle with the specific properties
|
||||
ParticleID addParticle(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;
|
||||
|
||||
signals:
|
||||
void particleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel, const CollisionInfo& collision);
|
||||
void particleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB, const CollisionInfo& collision);
|
||||
|
||||
private:
|
||||
void queueParticleMessage(PacketType packetType, ParticleID particleID, const ParticleProperties& properties);
|
||||
|
||||
uint32_t _nextCreatorTokenID;
|
||||
ParticleTree* _particleTree;
|
||||
};
|
||||
|
||||
#endif // hifi_ParticlesScriptingInterface_h
|
|
@ -5,7 +5,7 @@ setup_hifi_library(Gui Network Script Widgets)
|
|||
|
||||
include_glm()
|
||||
|
||||
link_hifi_libraries(shared octree voxels fbx particles entities animation)
|
||||
link_hifi_libraries(shared octree voxels fbx entities animation)
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <ParticlesScriptingInterface.h>
|
||||
#include <Sound.h>
|
||||
#include <UUID.h>
|
||||
#include <VoxelConstants.h>
|
||||
|
@ -43,7 +42,6 @@
|
|||
#include "XMLHttpRequestClass.h"
|
||||
|
||||
VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface;
|
||||
ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface;
|
||||
EntityScriptingInterface ScriptEngine::_entityScriptingInterface;
|
||||
|
||||
static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
|
@ -236,7 +234,6 @@ void ScriptEngine::init() {
|
|||
_isInitialized = true;
|
||||
|
||||
_voxelsScriptingInterface.init();
|
||||
_particlesScriptingInterface.init();
|
||||
|
||||
// register various meta-types
|
||||
registerMetaTypes(this);
|
||||
|
@ -248,10 +245,6 @@ void ScriptEngine::init() {
|
|||
registerAvatarTypes(this);
|
||||
Bitstream::registerTypes(this);
|
||||
|
||||
qScriptRegisterMetaType(this, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue);
|
||||
qScriptRegisterMetaType(this, ParticleIDtoScriptValue, ParticleIDfromScriptValue);
|
||||
qScriptRegisterSequenceMetaType<QVector<ParticleID> >(this);
|
||||
|
||||
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue);
|
||||
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
|
||||
qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);
|
||||
|
@ -286,7 +279,6 @@ void ScriptEngine::init() {
|
|||
registerGlobalObject("Audio", &_audioScriptingInterface);
|
||||
registerGlobalObject("Controller", _controllerScriptingInterface);
|
||||
registerGlobalObject("Entities", &_entityScriptingInterface);
|
||||
registerGlobalObject("Particles", &_particlesScriptingInterface);
|
||||
registerGlobalObject("Quat", &_quatLibrary);
|
||||
registerGlobalObject("Vec3", &_vec3Library);
|
||||
registerGlobalObject("Uuid", &_uuidLibrary);
|
||||
|
@ -299,14 +291,12 @@ void ScriptEngine::init() {
|
|||
globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT)));
|
||||
globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS)));
|
||||
globalObject().setProperty("COLLISION_GROUP_VOXELS", newVariant(QVariant(COLLISION_GROUP_VOXELS)));
|
||||
globalObject().setProperty("COLLISION_GROUP_PARTICLES", newVariant(QVariant(COLLISION_GROUP_PARTICLES)));
|
||||
|
||||
globalObject().setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY)));
|
||||
globalObject().setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY)));
|
||||
|
||||
// let the VoxelPacketSender know how frequently we plan to call it
|
||||
_voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS);
|
||||
_particlesScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS);
|
||||
}
|
||||
|
||||
QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
|
||||
|
@ -421,16 +411,6 @@ void ScriptEngine::run() {
|
|||
}
|
||||
}
|
||||
|
||||
if (_particlesScriptingInterface.getParticlePacketSender()->serversExist()) {
|
||||
// release the queue of edit voxel messages.
|
||||
_particlesScriptingInterface.getParticlePacketSender()->releaseQueuedMessages();
|
||||
|
||||
// since we're in non-threaded mode, call process so that the packets are sent
|
||||
if (!_particlesScriptingInterface.getParticlePacketSender()->isThreaded()) {
|
||||
_particlesScriptingInterface.getParticlePacketSender()->process();
|
||||
}
|
||||
}
|
||||
|
||||
if (_entityScriptingInterface.getEntityPacketSender()->serversExist()) {
|
||||
// release the queue of edit voxel messages.
|
||||
_entityScriptingInterface.getEntityPacketSender()->releaseQueuedMessages();
|
||||
|
@ -568,16 +548,6 @@ void ScriptEngine::run() {
|
|||
}
|
||||
}
|
||||
|
||||
if (_particlesScriptingInterface.getParticlePacketSender()->serversExist()) {
|
||||
// release the queue of edit voxel messages.
|
||||
_particlesScriptingInterface.getParticlePacketSender()->releaseQueuedMessages();
|
||||
|
||||
// since we're in non-threaded mode, call process so that the packets are sent
|
||||
if (!_particlesScriptingInterface.getParticlePacketSender()->isThreaded()) {
|
||||
_particlesScriptingInterface.getParticlePacketSender()->process();
|
||||
}
|
||||
}
|
||||
|
||||
if (_entityScriptingInterface.getEntityPacketSender()->serversExist()) {
|
||||
// release the queue of edit entity messages.
|
||||
_entityScriptingInterface.getEntityPacketSender()->releaseQueuedMessages();
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "Vec3.h"
|
||||
|
||||
class EntityScriptingInterface;
|
||||
class ParticlesScriptingInterface;
|
||||
class VoxelsScriptingInterface;
|
||||
|
||||
const QString NO_SCRIPT("");
|
||||
|
@ -51,9 +50,6 @@ public:
|
|||
/// Access the VoxelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
|
||||
static VoxelsScriptingInterface* getVoxelsScriptingInterface() { return &_voxelsScriptingInterface; }
|
||||
|
||||
/// Access the ParticlesScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
|
||||
static ParticlesScriptingInterface* getParticlesScriptingInterface() { return &_particlesScriptingInterface; }
|
||||
|
||||
/// Access the EntityScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
|
||||
static EntityScriptingInterface* getEntityScriptingInterface() { return &_entityScriptingInterface; }
|
||||
|
||||
|
@ -143,7 +139,6 @@ private:
|
|||
void stopTimer(QTimer* timer);
|
||||
|
||||
static VoxelsScriptingInterface _voxelsScriptingInterface;
|
||||
static ParticlesScriptingInterface _particlesScriptingInterface;
|
||||
static EntityScriptingInterface _entityScriptingInterface;
|
||||
|
||||
AbstractControllerScriptingInterface* _controllerScriptingInterface;
|
||||
|
|
|
@ -23,7 +23,6 @@ class Shape;
|
|||
const quint32 COLLISION_GROUP_ENVIRONMENT = 1U << 0;
|
||||
const quint32 COLLISION_GROUP_AVATARS = 1U << 1;
|
||||
const quint32 COLLISION_GROUP_VOXELS = 1U << 2;
|
||||
const quint32 COLLISION_GROUP_PARTICLES = 1U << 3;
|
||||
const quint32 VALID_COLLISION_GROUPS = 0x0f;
|
||||
|
||||
// CollisionInfo contains details about the collision between two things: BodyA and BodyB.
|
||||
|
|
|
@ -5,6 +5,6 @@ setup_hifi_project(Script Network)
|
|||
include_glm()
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared octree voxels fbx metavoxels networking particles entities avatars audio animation script-engine)
|
||||
link_hifi_libraries(shared octree voxels fbx metavoxels networking entities avatars audio animation script-engine)
|
||||
|
||||
link_shared_dependencies()
|
||||
|
|
|
@ -25,30 +25,30 @@
|
|||
|
||||
#include "OctreeTests.h"
|
||||
|
||||
enum ParticlePropertyList {
|
||||
PARTICLE_PROP_PAGED_PROPERTY,
|
||||
PARTICLE_PROP_CUSTOM_PROPERTIES_INCLUDED,
|
||||
PARTICLE_PROP_VISIBLE,
|
||||
PARTICLE_PROP_POSITION,
|
||||
PARTICLE_PROP_RADIUS,
|
||||
PARTICLE_PROP_MODEL_URL,
|
||||
PARTICLE_PROP_ROTATION,
|
||||
PARTICLE_PROP_COLOR,
|
||||
PARTICLE_PROP_SCRIPT,
|
||||
PARTICLE_PROP_ANIMATION_URL,
|
||||
PARTICLE_PROP_ANIMATION_FPS,
|
||||
PARTICLE_PROP_ANIMATION_FRAME_INDEX,
|
||||
PARTICLE_PROP_ANIMATION_PLAYING,
|
||||
PARTICLE_PROP_SHOULD_BE_DELETED,
|
||||
PARTICLE_PROP_VELOCITY,
|
||||
PARTICLE_PROP_GRAVITY,
|
||||
PARTICLE_PROP_DAMPING,
|
||||
PARTICLE_PROP_MASS,
|
||||
PARTICLE_PROP_LIFETIME,
|
||||
PARTICLE_PROP_PAUSE_SIMULATION,
|
||||
enum ExamplePropertyList {
|
||||
EXAMPLE_PROP_PAGED_PROPERTY,
|
||||
EXAMPLE_PROP_CUSTOM_PROPERTIES_INCLUDED,
|
||||
EXAMPLE_PROP_VISIBLE,
|
||||
EXAMPLE_PROP_POSITION,
|
||||
EXAMPLE_PROP_RADIUS,
|
||||
EXAMPLE_PROP_MODEL_URL,
|
||||
EXAMPLE_PROP_ROTATION,
|
||||
EXAMPLE_PROP_COLOR,
|
||||
EXAMPLE_PROP_SCRIPT,
|
||||
EXAMPLE_PROP_ANIMATION_URL,
|
||||
EXAMPLE_PROP_ANIMATION_FPS,
|
||||
EXAMPLE_PROP_ANIMATION_FRAME_INDEX,
|
||||
EXAMPLE_PROP_ANIMATION_PLAYING,
|
||||
EXAMPLE_PROP_SHOULD_BE_DELETED,
|
||||
EXAMPLE_PROP_VELOCITY,
|
||||
EXAMPLE_PROP_GRAVITY,
|
||||
EXAMPLE_PROP_DAMPING,
|
||||
EXAMPLE_PROP_MASS,
|
||||
EXAMPLE_PROP_LIFETIME,
|
||||
EXAMPLE_PROP_PAUSE_SIMULATION,
|
||||
};
|
||||
|
||||
typedef PropertyFlags<ParticlePropertyList> ParticlePropertyFlags;
|
||||
typedef PropertyFlags<ExamplePropertyList> ExamplePropertyFlags;
|
||||
|
||||
|
||||
void OctreeTests::propertyFlagsTests(bool verbose) {
|
||||
|
@ -96,17 +96,16 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 2: ParticlePropertyFlags: using setHasProperty()";
|
||||
qDebug() << "Test 2: ExamplePropertyFlags: using setHasProperty()";
|
||||
}
|
||||
testsTaken++;
|
||||
|
||||
ParticlePropertyFlags props2;
|
||||
props2.setHasProperty(PARTICLE_PROP_VISIBLE);
|
||||
props2.setHasProperty(PARTICLE_PROP_ANIMATION_URL);
|
||||
props2.setHasProperty(PARTICLE_PROP_ANIMATION_FPS);
|
||||
props2.setHasProperty(PARTICLE_PROP_ANIMATION_FRAME_INDEX);
|
||||
props2.setHasProperty(PARTICLE_PROP_ANIMATION_PLAYING);
|
||||
props2.setHasProperty(PARTICLE_PROP_PAUSE_SIMULATION);
|
||||
EntityPropertyFlags props2;
|
||||
props2.setHasProperty(PROP_VISIBLE);
|
||||
props2.setHasProperty(PROP_ANIMATION_URL);
|
||||
props2.setHasProperty(PROP_ANIMATION_FPS);
|
||||
props2.setHasProperty(PROP_ANIMATION_FRAME_INDEX);
|
||||
props2.setHasProperty(PROP_ANIMATION_PLAYING);
|
||||
|
||||
QByteArray encoded = props2.encode();
|
||||
|
||||
|
@ -122,17 +121,15 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 2: ParticlePropertyFlags: using setHasProperty()";
|
||||
qDebug() << "FAILED - Test 2: ExamplePropertyFlags: using setHasProperty()";
|
||||
}
|
||||
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "Test 2b: remove flag with setHasProperty() PARTICLE_PROP_PAUSE_SIMULATION";
|
||||
qDebug() << "Test 2b: remove flag with setHasProperty() PROP_PAUSE_SIMULATION";
|
||||
}
|
||||
testsTaken++;
|
||||
|
||||
props2.setHasProperty(PARTICLE_PROP_PAUSE_SIMULATION, false);
|
||||
|
||||
encoded = props2.encode();
|
||||
|
||||
if (verbose) {
|
||||
|
@ -147,24 +144,24 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 2b: remove flag with setHasProperty() PARTICLE_PROP_PAUSE_SIMULATION";
|
||||
qDebug() << "FAILED - Test 2b: remove flag with setHasProperty() EXAMPLE_PROP_PAUSE_SIMULATION";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 3: ParticlePropertyFlags: using | operator";
|
||||
qDebug() << "Test 3: ExamplePropertyFlags: using | operator";
|
||||
}
|
||||
testsTaken++;
|
||||
|
||||
ParticlePropertyFlags props;
|
||||
ExamplePropertyFlags props;
|
||||
|
||||
props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE)
|
||||
| ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL)
|
||||
| ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS)
|
||||
| ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX)
|
||||
| ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING)
|
||||
| ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION);
|
||||
props = ExamplePropertyFlags(EXAMPLE_PROP_VISIBLE)
|
||||
| ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_URL)
|
||||
| ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FPS)
|
||||
| ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FRAME_INDEX)
|
||||
| ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_PLAYING)
|
||||
| ExamplePropertyFlags(EXAMPLE_PROP_PAUSE_SIMULATION);
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
|
||||
|
@ -179,16 +176,16 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 3: ParticlePropertyFlags: using | operator";
|
||||
qDebug() << "FAILED - Test 3: ExamplePropertyFlags: using | operator";
|
||||
}
|
||||
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "Test 3b: remove flag with -= PARTICLE_PROP_PAUSE_SIMULATION";
|
||||
qDebug() << "Test 3b: remove flag with -= EXAMPLE_PROP_PAUSE_SIMULATION";
|
||||
}
|
||||
testsTaken++;
|
||||
|
||||
props -= PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
props -= EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
encoded = props.encode();
|
||||
|
||||
|
@ -204,25 +201,25 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 3b: remove flag with -= PARTICLE_PROP_PAUSE_SIMULATION";
|
||||
qDebug() << "FAILED - Test 3b: remove flag with -= EXAMPLE_PROP_PAUSE_SIMULATION";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 3c: ParticlePropertyFlags: using |= operator";
|
||||
qDebug() << "Test 3c: ExamplePropertyFlags: using |= operator";
|
||||
}
|
||||
testsTaken++;
|
||||
|
||||
ParticlePropertyFlags props;
|
||||
ExamplePropertyFlags props;
|
||||
|
||||
props |= PARTICLE_PROP_VISIBLE;
|
||||
props |= PARTICLE_PROP_ANIMATION_URL;
|
||||
props |= PARTICLE_PROP_ANIMATION_FPS;
|
||||
props |= PARTICLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props |= PARTICLE_PROP_ANIMATION_PLAYING;
|
||||
props |= PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
props |= EXAMPLE_PROP_VISIBLE;
|
||||
props |= EXAMPLE_PROP_ANIMATION_URL;
|
||||
props |= EXAMPLE_PROP_ANIMATION_FPS;
|
||||
props |= EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props |= EXAMPLE_PROP_ANIMATION_PLAYING;
|
||||
props |= EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
|
||||
|
@ -238,24 +235,24 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - 3c: ParticlePropertyFlags: using |= operator";
|
||||
qDebug() << "FAILED - 3c: ExamplePropertyFlags: using |= operator";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 4: ParticlePropertyFlags: using + operator";
|
||||
qDebug() << "Test 4: ExamplePropertyFlags: using + operator";
|
||||
}
|
||||
testsTaken++;
|
||||
|
||||
ParticlePropertyFlags props;
|
||||
ExamplePropertyFlags props;
|
||||
|
||||
props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE)
|
||||
+ ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL)
|
||||
+ ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS)
|
||||
+ ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX)
|
||||
+ ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING)
|
||||
+ ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION);
|
||||
props = ExamplePropertyFlags(EXAMPLE_PROP_VISIBLE)
|
||||
+ ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_URL)
|
||||
+ ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FPS)
|
||||
+ ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FRAME_INDEX)
|
||||
+ ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_PLAYING)
|
||||
+ ExamplePropertyFlags(EXAMPLE_PROP_PAUSE_SIMULATION);
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
|
||||
|
@ -271,23 +268,23 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 4: ParticlePropertyFlags: using + operator";
|
||||
qDebug() << "FAILED - Test 4: ExamplePropertyFlags: using + operator";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 5: ParticlePropertyFlags: using += operator";
|
||||
qDebug() << "Test 5: ExamplePropertyFlags: using += operator";
|
||||
}
|
||||
testsTaken++;
|
||||
ParticlePropertyFlags props;
|
||||
ExamplePropertyFlags props;
|
||||
|
||||
props += PARTICLE_PROP_VISIBLE;
|
||||
props += PARTICLE_PROP_ANIMATION_URL;
|
||||
props += PARTICLE_PROP_ANIMATION_FPS;
|
||||
props += PARTICLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props += PARTICLE_PROP_ANIMATION_PLAYING;
|
||||
props += PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
props += EXAMPLE_PROP_VISIBLE;
|
||||
props += EXAMPLE_PROP_ANIMATION_URL;
|
||||
props += EXAMPLE_PROP_ANIMATION_FPS;
|
||||
props += EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props += EXAMPLE_PROP_ANIMATION_PLAYING;
|
||||
props += EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
|
||||
|
@ -303,24 +300,24 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 5: ParticlePropertyFlags: using += operator";
|
||||
qDebug() << "FAILED - Test 5: ExamplePropertyFlags: using += operator";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 6: ParticlePropertyFlags: using = ... << operator";
|
||||
qDebug() << "Test 6: ExamplePropertyFlags: using = ... << operator";
|
||||
}
|
||||
testsTaken++;
|
||||
|
||||
ParticlePropertyFlags props;
|
||||
ExamplePropertyFlags props;
|
||||
|
||||
props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE)
|
||||
<< ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL)
|
||||
<< ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS)
|
||||
<< ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX)
|
||||
<< ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING)
|
||||
<< ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION);
|
||||
props = ExamplePropertyFlags(EXAMPLE_PROP_VISIBLE)
|
||||
<< ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_URL)
|
||||
<< ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FPS)
|
||||
<< ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_FRAME_INDEX)
|
||||
<< ExamplePropertyFlags(EXAMPLE_PROP_ANIMATION_PLAYING)
|
||||
<< ExamplePropertyFlags(EXAMPLE_PROP_PAUSE_SIMULATION);
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
|
||||
|
@ -336,24 +333,24 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 6: ParticlePropertyFlags: using = ... << operator";
|
||||
qDebug() << "FAILED - Test 6: ExamplePropertyFlags: using = ... << operator";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 7: ParticlePropertyFlags: using <<= operator";
|
||||
qDebug() << "Test 7: ExamplePropertyFlags: using <<= operator";
|
||||
}
|
||||
testsTaken++;
|
||||
|
||||
ParticlePropertyFlags props;
|
||||
ExamplePropertyFlags props;
|
||||
|
||||
props <<= PARTICLE_PROP_VISIBLE;
|
||||
props <<= PARTICLE_PROP_ANIMATION_URL;
|
||||
props <<= PARTICLE_PROP_ANIMATION_FPS;
|
||||
props <<= PARTICLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props <<= PARTICLE_PROP_ANIMATION_PLAYING;
|
||||
props <<= PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
props <<= EXAMPLE_PROP_VISIBLE;
|
||||
props <<= EXAMPLE_PROP_ANIMATION_URL;
|
||||
props <<= EXAMPLE_PROP_ANIMATION_FPS;
|
||||
props <<= EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props <<= EXAMPLE_PROP_ANIMATION_PLAYING;
|
||||
props <<= EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
|
||||
|
@ -369,24 +366,24 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 7: ParticlePropertyFlags: using <<= operator";
|
||||
qDebug() << "FAILED - Test 7: ExamplePropertyFlags: using <<= operator";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 8: ParticlePropertyFlags: using << enum operator";
|
||||
qDebug() << "Test 8: ExamplePropertyFlags: using << enum operator";
|
||||
}
|
||||
testsTaken++;
|
||||
|
||||
ParticlePropertyFlags props;
|
||||
ExamplePropertyFlags props;
|
||||
|
||||
props << PARTICLE_PROP_VISIBLE;
|
||||
props << PARTICLE_PROP_ANIMATION_URL;
|
||||
props << PARTICLE_PROP_ANIMATION_FPS;
|
||||
props << PARTICLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props << PARTICLE_PROP_ANIMATION_PLAYING;
|
||||
props << PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
props << EXAMPLE_PROP_VISIBLE;
|
||||
props << EXAMPLE_PROP_ANIMATION_URL;
|
||||
props << EXAMPLE_PROP_ANIMATION_FPS;
|
||||
props << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props << EXAMPLE_PROP_ANIMATION_PLAYING;
|
||||
props << EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
|
||||
|
@ -402,26 +399,26 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 8: ParticlePropertyFlags: using << enum operator";
|
||||
qDebug() << "FAILED - Test 8: ExamplePropertyFlags: using << enum operator";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 9: ParticlePropertyFlags: using << flags operator ";
|
||||
qDebug() << "Test 9: ExamplePropertyFlags: using << flags operator ";
|
||||
}
|
||||
testsTaken++;
|
||||
|
||||
ParticlePropertyFlags props;
|
||||
ParticlePropertyFlags props2;
|
||||
ExamplePropertyFlags props;
|
||||
ExamplePropertyFlags props2;
|
||||
|
||||
props << PARTICLE_PROP_VISIBLE;
|
||||
props << PARTICLE_PROP_ANIMATION_URL;
|
||||
props << PARTICLE_PROP_ANIMATION_FPS;
|
||||
props << EXAMPLE_PROP_VISIBLE;
|
||||
props << EXAMPLE_PROP_ANIMATION_URL;
|
||||
props << EXAMPLE_PROP_ANIMATION_FPS;
|
||||
|
||||
props2 << PARTICLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props2 << PARTICLE_PROP_ANIMATION_PLAYING;
|
||||
props2 << PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
props2 << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props2 << EXAMPLE_PROP_ANIMATION_PLAYING;
|
||||
props2 << EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
props << props2;
|
||||
|
||||
|
@ -439,15 +436,15 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 9: ParticlePropertyFlags: using << flags operator";
|
||||
qDebug() << "FAILED - Test 9: ExamplePropertyFlags: using << flags operator";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 10: ParticlePropertyFlags comparison";
|
||||
qDebug() << "Test 10: ExamplePropertyFlags comparison";
|
||||
}
|
||||
ParticlePropertyFlags propsA;
|
||||
ExamplePropertyFlags propsA;
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "!propsA:" << (!propsA) << "{ expect true }";
|
||||
|
@ -459,15 +456,15 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 10a: ParticlePropertyFlags comparison, uninitialized !propsA";
|
||||
qDebug() << "FAILED - Test 10a: ExamplePropertyFlags comparison, uninitialized !propsA";
|
||||
}
|
||||
|
||||
propsA << PARTICLE_PROP_VISIBLE;
|
||||
propsA << PARTICLE_PROP_ANIMATION_URL;
|
||||
propsA << PARTICLE_PROP_ANIMATION_FPS;
|
||||
propsA << PARTICLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
propsA << PARTICLE_PROP_ANIMATION_PLAYING;
|
||||
propsA << PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
propsA << EXAMPLE_PROP_VISIBLE;
|
||||
propsA << EXAMPLE_PROP_ANIMATION_URL;
|
||||
propsA << EXAMPLE_PROP_ANIMATION_FPS;
|
||||
propsA << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
propsA << EXAMPLE_PROP_ANIMATION_PLAYING;
|
||||
propsA << EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "!propsA:" << (!propsA) << "{ expect false }";
|
||||
|
@ -479,16 +476,16 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 10b: ParticlePropertyFlags comparison, initialized !propsA";
|
||||
qDebug() << "FAILED - Test 10b: ExamplePropertyFlags comparison, initialized !propsA";
|
||||
}
|
||||
|
||||
ParticlePropertyFlags propsB;
|
||||
propsB << PARTICLE_PROP_VISIBLE;
|
||||
propsB << PARTICLE_PROP_ANIMATION_URL;
|
||||
propsB << PARTICLE_PROP_ANIMATION_FPS;
|
||||
propsB << PARTICLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
propsB << PARTICLE_PROP_ANIMATION_PLAYING;
|
||||
propsB << PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
ExamplePropertyFlags propsB;
|
||||
propsB << EXAMPLE_PROP_VISIBLE;
|
||||
propsB << EXAMPLE_PROP_ANIMATION_URL;
|
||||
propsB << EXAMPLE_PROP_ANIMATION_FPS;
|
||||
propsB << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
propsB << EXAMPLE_PROP_ANIMATION_PLAYING;
|
||||
propsB << EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect true }";
|
||||
|
@ -501,7 +498,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 10c: ParticlePropertyFlags comparison, propsA == propsB";
|
||||
qDebug() << "FAILED - Test 10c: ExamplePropertyFlags comparison, propsA == propsB";
|
||||
}
|
||||
|
||||
testsTaken++;
|
||||
|
@ -511,14 +508,14 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 10d: ParticlePropertyFlags comparison, propsA != propsB";
|
||||
qDebug() << "FAILED - Test 10d: ExamplePropertyFlags comparison, propsA != propsB";
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "AFTER propsB -= PARTICLE_PROP_PAUSE_SIMULATION...";
|
||||
qDebug() << "AFTER propsB -= EXAMPLE_PROP_PAUSE_SIMULATION...";
|
||||
}
|
||||
|
||||
propsB -= PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
propsB -= EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect false }";
|
||||
|
@ -531,7 +528,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 10e: ParticlePropertyFlags comparison, AFTER propsB -= PARTICLE_PROP_PAUSE_SIMULATION";
|
||||
qDebug() << "FAILED - Test 10e: ExamplePropertyFlags comparison, AFTER propsB -= EXAMPLE_PROP_PAUSE_SIMULATION";
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
|
@ -549,18 +546,18 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 10f: ParticlePropertyFlags comparison, AFTER propsB = propsA";
|
||||
qDebug() << "FAILED - Test 10f: ExamplePropertyFlags comparison, AFTER propsB = propsA";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 11: ParticlePropertyFlags testing individual properties";
|
||||
qDebug() << "Test 11: ExamplePropertyFlags testing individual properties";
|
||||
}
|
||||
ParticlePropertyFlags props;
|
||||
ExamplePropertyFlags props;
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "ParticlePropertyFlags props;";
|
||||
qDebug() << "ExamplePropertyFlags props;";
|
||||
}
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
|
@ -578,36 +575,36 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 11a: ParticlePropertyFlags testing individual properties";
|
||||
qDebug() << "FAILED - Test 11a: ExamplePropertyFlags testing individual properties";
|
||||
}
|
||||
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "Test 11b: props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE))
|
||||
qDebug() << "Test 11b: props.getHasProperty(EXAMPLE_PROP_VISIBLE)" << (props.getHasProperty(EXAMPLE_PROP_VISIBLE))
|
||||
<< "{ expect false }";
|
||||
}
|
||||
testsTaken++;
|
||||
bool resultB = props.getHasProperty(PARTICLE_PROP_VISIBLE);
|
||||
bool resultB = props.getHasProperty(EXAMPLE_PROP_VISIBLE);
|
||||
bool expectedB = false;
|
||||
if (resultB == expectedB) {
|
||||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 11b: props.getHasProperty(PARTICLE_PROP_VISIBLE)";
|
||||
qDebug() << "FAILED - Test 11b: props.getHasProperty(EXAMPLE_PROP_VISIBLE)";
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "props << PARTICLE_PROP_VISIBLE;";
|
||||
qDebug() << "props << EXAMPLE_PROP_VISIBLE;";
|
||||
}
|
||||
props << PARTICLE_PROP_VISIBLE;
|
||||
props << EXAMPLE_PROP_VISIBLE;
|
||||
testsTaken++;
|
||||
bool resultC = props.getHasProperty(PARTICLE_PROP_VISIBLE);
|
||||
bool resultC = props.getHasProperty(EXAMPLE_PROP_VISIBLE);
|
||||
bool expectedC = true;
|
||||
if (resultC == expectedC) {
|
||||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 11c: props.getHasProperty(PARTICLE_PROP_VISIBLE) after props << PARTICLE_PROP_VISIBLE";
|
||||
qDebug() << "FAILED - Test 11c: props.getHasProperty(EXAMPLE_PROP_VISIBLE) after props << EXAMPLE_PROP_VISIBLE";
|
||||
}
|
||||
|
||||
encoded = props.encode();
|
||||
|
@ -615,7 +612,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
if (verbose) {
|
||||
qDebug() << "props... encoded=";
|
||||
outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
|
||||
qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE))
|
||||
qDebug() << "props.getHasProperty(EXAMPLE_PROP_VISIBLE)" << (props.getHasProperty(EXAMPLE_PROP_VISIBLE))
|
||||
<< "{ expect true }";
|
||||
}
|
||||
|
||||
|
@ -627,19 +624,19 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 11c: ParticlePropertyFlags testing individual properties";
|
||||
qDebug() << "FAILED - Test 11c: ExamplePropertyFlags testing individual properties";
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "props << PARTICLE_PROP_ANIMATION_URL;";
|
||||
qDebug() << "props << EXAMPLE_PROP_ANIMATION_URL;";
|
||||
}
|
||||
props << PARTICLE_PROP_ANIMATION_URL;
|
||||
props << EXAMPLE_PROP_ANIMATION_URL;
|
||||
|
||||
encoded = props.encode();
|
||||
if (verbose) {
|
||||
qDebug() << "props... encoded=";
|
||||
outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
|
||||
qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE))
|
||||
qDebug() << "props.getHasProperty(EXAMPLE_PROP_VISIBLE)" << (props.getHasProperty(EXAMPLE_PROP_VISIBLE))
|
||||
<< "{ expect true }";
|
||||
}
|
||||
char expectedBytesD[] = { (char)136, (char)16 };
|
||||
|
@ -650,61 +647,61 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 11d: ParticlePropertyFlags testing individual properties";
|
||||
qDebug() << "FAILED - Test 11d: ExamplePropertyFlags testing individual properties";
|
||||
}
|
||||
testsTaken++;
|
||||
bool resultE = props.getHasProperty(PARTICLE_PROP_VISIBLE);
|
||||
bool resultE = props.getHasProperty(EXAMPLE_PROP_VISIBLE);
|
||||
bool expectedE = true;
|
||||
if (resultE == expectedE) {
|
||||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 11e: props.getHasProperty(PARTICLE_PROP_VISIBLE) after props << PARTICLE_PROP_ANIMATION_URL";
|
||||
qDebug() << "FAILED - Test 11e: props.getHasProperty(EXAMPLE_PROP_VISIBLE) after props << EXAMPLE_PROP_ANIMATION_URL";
|
||||
}
|
||||
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "props << ... more ...";
|
||||
}
|
||||
props << PARTICLE_PROP_ANIMATION_FPS;
|
||||
props << PARTICLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props << PARTICLE_PROP_ANIMATION_PLAYING;
|
||||
props << PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
props << EXAMPLE_PROP_ANIMATION_FPS;
|
||||
props << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props << EXAMPLE_PROP_ANIMATION_PLAYING;
|
||||
props << EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
encoded = props.encode();
|
||||
if (verbose) {
|
||||
qDebug() << "props... encoded=";
|
||||
outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
|
||||
qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE))
|
||||
qDebug() << "props.getHasProperty(EXAMPLE_PROP_VISIBLE)" << (props.getHasProperty(EXAMPLE_PROP_VISIBLE))
|
||||
<< "{ expect true }";
|
||||
}
|
||||
testsTaken++;
|
||||
bool resultF = props.getHasProperty(PARTICLE_PROP_VISIBLE);
|
||||
bool resultF = props.getHasProperty(EXAMPLE_PROP_VISIBLE);
|
||||
bool expectedF = true;
|
||||
if (resultF == expectedF) {
|
||||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 11f: props.getHasProperty(PARTICLE_PROP_VISIBLE) after props << more";
|
||||
qDebug() << "FAILED - Test 11f: props.getHasProperty(EXAMPLE_PROP_VISIBLE) after props << more";
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "ParticlePropertyFlags propsB = props & PARTICLE_PROP_VISIBLE;";
|
||||
qDebug() << "ExamplePropertyFlags propsB = props & EXAMPLE_PROP_VISIBLE;";
|
||||
}
|
||||
ParticlePropertyFlags propsB = props & PARTICLE_PROP_VISIBLE;
|
||||
ExamplePropertyFlags propsB = props & EXAMPLE_PROP_VISIBLE;
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "propsB.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsB.getHasProperty(PARTICLE_PROP_VISIBLE))
|
||||
qDebug() << "propsB.getHasProperty(EXAMPLE_PROP_VISIBLE)" << (propsB.getHasProperty(EXAMPLE_PROP_VISIBLE))
|
||||
<< "{ expect true }";
|
||||
}
|
||||
testsTaken++;
|
||||
bool resultG = propsB.getHasProperty(PARTICLE_PROP_VISIBLE);
|
||||
bool resultG = propsB.getHasProperty(EXAMPLE_PROP_VISIBLE);
|
||||
bool expectedG = true;
|
||||
if (resultG == expectedG) {
|
||||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 11g: propsB = props & PARTICLE_PROP_VISIBLE";
|
||||
qDebug() << "FAILED - Test 11g: propsB = props & EXAMPLE_PROP_VISIBLE";
|
||||
}
|
||||
|
||||
encoded = propsB.encode();
|
||||
|
@ -720,20 +717,20 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 11h: ParticlePropertyFlags testing individual properties";
|
||||
qDebug() << "FAILED - Test 11h: ExamplePropertyFlags testing individual properties";
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "ParticlePropertyFlags propsC = ~propsB;";
|
||||
qDebug() << "ExamplePropertyFlags propsC = ~propsB;";
|
||||
}
|
||||
ParticlePropertyFlags propsC = ~propsB;
|
||||
ExamplePropertyFlags propsC = ~propsB;
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "propsC.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsC.getHasProperty(PARTICLE_PROP_VISIBLE))
|
||||
qDebug() << "propsC.getHasProperty(EXAMPLE_PROP_VISIBLE)" << (propsC.getHasProperty(EXAMPLE_PROP_VISIBLE))
|
||||
<< "{ expect false }";
|
||||
}
|
||||
testsTaken++;
|
||||
bool resultI = propsC.getHasProperty(PARTICLE_PROP_VISIBLE);
|
||||
bool resultI = propsC.getHasProperty(EXAMPLE_PROP_VISIBLE);
|
||||
bool expectedI = false;
|
||||
if (resultI == expectedI) {
|
||||
testsPassed++;
|
||||
|
@ -751,16 +748,16 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 12: ParticlePropertyFlags: decode tests";
|
||||
qDebug() << "Test 12: ExamplePropertyFlags: decode tests";
|
||||
}
|
||||
ParticlePropertyFlags props;
|
||||
ExamplePropertyFlags props;
|
||||
|
||||
props << PARTICLE_PROP_VISIBLE;
|
||||
props << PARTICLE_PROP_ANIMATION_URL;
|
||||
props << PARTICLE_PROP_ANIMATION_FPS;
|
||||
props << PARTICLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props << PARTICLE_PROP_ANIMATION_PLAYING;
|
||||
props << PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
props << EXAMPLE_PROP_VISIBLE;
|
||||
props << EXAMPLE_PROP_ANIMATION_URL;
|
||||
props << EXAMPLE_PROP_ANIMATION_FPS;
|
||||
props << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props << EXAMPLE_PROP_ANIMATION_PLAYING;
|
||||
props << EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
if (verbose) {
|
||||
|
@ -769,7 +766,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
qDebug() << "encoded.size()=" << encoded.size();
|
||||
}
|
||||
|
||||
ParticlePropertyFlags propsDecoded;
|
||||
ExamplePropertyFlags propsDecoded;
|
||||
propsDecoded.decode(encoded);
|
||||
|
||||
if (verbose) {
|
||||
|
@ -812,7 +809,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
qDebug() << "encoded.size()=" << encoded.size() << "includes extra garbage";
|
||||
}
|
||||
|
||||
ParticlePropertyFlags propsDecodedExtra;
|
||||
ExamplePropertyFlags propsDecodedExtra;
|
||||
propsDecodedExtra.decode(encoded);
|
||||
|
||||
if (verbose) {
|
||||
|
@ -838,16 +835,16 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "Test 13: ParticlePropertyFlags: QByteArray << / >> tests";
|
||||
qDebug() << "Test 13: ExamplePropertyFlags: QByteArray << / >> tests";
|
||||
}
|
||||
ParticlePropertyFlags props;
|
||||
ExamplePropertyFlags props;
|
||||
|
||||
props << PARTICLE_PROP_VISIBLE;
|
||||
props << PARTICLE_PROP_ANIMATION_URL;
|
||||
props << PARTICLE_PROP_ANIMATION_FPS;
|
||||
props << PARTICLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props << PARTICLE_PROP_ANIMATION_PLAYING;
|
||||
props << PARTICLE_PROP_PAUSE_SIMULATION;
|
||||
props << EXAMPLE_PROP_VISIBLE;
|
||||
props << EXAMPLE_PROP_ANIMATION_URL;
|
||||
props << EXAMPLE_PROP_ANIMATION_FPS;
|
||||
props << EXAMPLE_PROP_ANIMATION_FRAME_INDEX;
|
||||
props << EXAMPLE_PROP_ANIMATION_PLAYING;
|
||||
props << EXAMPLE_PROP_PAUSE_SIMULATION;
|
||||
|
||||
if (verbose) {
|
||||
qDebug() << "testing encoded << props";
|
||||
|
@ -859,7 +856,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
outputBufferBits((const unsigned char*)encoded.constData(), encoded.size());
|
||||
}
|
||||
|
||||
ParticlePropertyFlags propsDecoded;
|
||||
ExamplePropertyFlags propsDecoded;
|
||||
if (verbose) {
|
||||
qDebug() << "testing encoded >> propsDecoded";
|
||||
}
|
||||
|
@ -876,7 +873,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
testsPassed++;
|
||||
} else {
|
||||
testsFailed++;
|
||||
qDebug() << "FAILED - Test 13: ParticlePropertyFlags: QByteArray << / >> tests";
|
||||
qDebug() << "FAILED - Test 13: ExamplePropertyFlags: QByteArray << / >> tests";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue