From 2ca628fdf1ba8b412b3239de9ef27098e843f16e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 9 Dec 2013 11:45:32 -0800 Subject: [PATCH] first cut at particle renderer cleanup particle jurisdiction listener fix storage of particles --- assignment-client/src/Agent.cpp | 5 +- domain-server/src/DomainServer.cpp | 3 + interface/CMakeLists.txt | 1 + interface/src/Application.cpp | 9 ++ interface/src/Application.h | 3 + interface/src/ParticleTreeRenderer.cpp | 37 +++++ interface/src/ParticleTreeRenderer.h | 39 ++++++ .../src/OctreeInboundPacketProcessor.cpp | 7 +- libraries/octree/src/JurisdictionListener.cpp | 14 +- libraries/octree/src/JurisdictionListener.h | 6 +- libraries/octree/src/OctreeRenderer.cpp | 129 ++++++++++++++++++ libraries/octree/src/OctreeRenderer.h | 57 ++++++++ .../src/ParticleScriptingInterface.cpp | 4 +- libraries/particles/src/ParticleTree.cpp | 13 ++ .../particles/src/ParticleTreeElement.cpp | 10 +- libraries/particles/src/ParticleTreeElement.h | 2 + libraries/shared/src/Node.cpp | 3 + 17 files changed, 333 insertions(+), 9 deletions(-) create mode 100644 interface/src/ParticleTreeRenderer.cpp create mode 100644 interface/src/ParticleTreeRenderer.h create mode 100644 libraries/octree/src/OctreeRenderer.cpp create mode 100644 libraries/octree/src/OctreeRenderer.h diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 73e51a7c6a..0fb9008cf1 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -65,7 +65,10 @@ void Agent::run() { NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_AGENT); - const char AGENT_NODE_TYPES_OF_INTEREST[1] = { NODE_TYPE_VOXEL_SERVER }; + // XXXBHG - this seems less than ideal. There might be classes (like jurisdiction listeners, that need access to + // other node types, but for them to get access to those node types, we have to add them here. It seems like + // NodeList should support adding types of interest + const NODE_TYPE AGENT_NODE_TYPES_OF_INTEREST[] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_PARTICLE_SERVER }; nodeList->setNodeTypesOfInterest(AGENT_NODE_TYPES_OF_INTEREST, sizeof(AGENT_NODE_TYPES_OF_INTEREST)); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index a4806ed8c7..ec955f5fb4 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -51,6 +51,9 @@ DomainServer::DomainServer(int argc, char* argv[]) : const char VOXEL_CONFIG_OPTION[] = "--voxelServerConfig"; _voxelServerConfig = getCmdOption(argc, (const char**) argv, VOXEL_CONFIG_OPTION); + + const char PARTICLE_CONFIG_OPTION[] = "--particleServerConfig"; + _particleServerConfig = getCmdOption(argc, (const char**) argv, PARTICLE_CONFIG_OPTION); // setup the mongoose web server struct mg_callbacks callbacks = {}; diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 51c33bfa38..31f6e74e5a 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -84,6 +84,7 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 50ba9df988..431caefa43 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3004,6 +3004,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { _voxels.render(Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures)); } } + + // render particles... + _particles.render(); // restore default, white specular glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE_SPECULAR_COLOR); @@ -4217,6 +4220,12 @@ void* Application::networkReceive(void* args) { QMetaObject::invokeMethod(&app->_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection, Q_ARG(QByteArray, QByteArray((char*) app->_incomingPacket, bytesReceived))); break; + + case PACKET_TYPE_PARTICLE_DATA: { + app->_particles.processDatagram(QByteArray((char*) app->_incomingPacket, bytesReceived), + senderSockAddr); + break; + } case PACKET_TYPE_VOXEL_DATA: case PACKET_TYPE_VOXEL_ERASE: case PACKET_TYPE_OCTREE_STATS: diff --git a/interface/src/Application.h b/interface/src/Application.h index 67cb1709c9..af2bb9d4eb 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -63,6 +63,7 @@ #include "ui/VoxelStatsDialog.h" #include "ui/RearMirrorTools.h" #include "ui/LodToolsDialog.h" +#include "ParticleTreeRenderer.h" class QAction; class QActionGroup; @@ -341,6 +342,8 @@ private: VoxelImporter _voxelImporter; VoxelSystem _sharedVoxelSystem; ViewFrustum _sharedVoxelSystemViewFrustum; + + ParticleTreeRenderer _particles; QByteArray _voxelsFilename; bool _wantToKillLocalVoxels; diff --git a/interface/src/ParticleTreeRenderer.cpp b/interface/src/ParticleTreeRenderer.cpp new file mode 100644 index 0000000000..580c8166b1 --- /dev/null +++ b/interface/src/ParticleTreeRenderer.cpp @@ -0,0 +1,37 @@ +// +// ParticleTreeRenderer.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 12/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// + +#include "InterfaceConfig.h" + +#include "ParticleTreeRenderer.h" + +ParticleTreeRenderer::ParticleTreeRenderer() : + OctreeRenderer() { +} + +ParticleTreeRenderer::~ParticleTreeRenderer() { +} + +void ParticleTreeRenderer::renderElement(OctreeElement* element) { + // actually render it here... + // we need to iterate the actual particles of the element + ParticleTreeElement* particleTreeElement = (ParticleTreeElement*)element; + + const std::vector& particles = particleTreeElement->getParticles(); + + uint16_t numberOfParticles = particles.size(); + + glBegin(GL_POINTS); + for (uint16_t i = 0; i < numberOfParticles; i++) { + const Particle& particle = particles[i]; + // render particle aspoints + glVertex3f(particle.getPosition().x, particle.getPosition().y, particle.getPosition().z); + } + glEnd(); +} diff --git a/interface/src/ParticleTreeRenderer.h b/interface/src/ParticleTreeRenderer.h new file mode 100644 index 0000000000..aae839576a --- /dev/null +++ b/interface/src/ParticleTreeRenderer.h @@ -0,0 +1,39 @@ +// +// ParticleTreeRenderer.h +// hifi +// +// Created by Brad Hefta-Gaub on 12/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// + +#ifndef __hifi__ParticleTreeRenderer__ +#define __hifi__ParticleTreeRenderer__ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// Generic client side Octree renderer class. +class ParticleTreeRenderer : public OctreeRenderer { +public: + ParticleTreeRenderer(); + virtual ~ParticleTreeRenderer(); + + virtual Octree* createTree() { return new ParticleTree(true); } + virtual NODE_TYPE getMyNodeType() const { return NODE_TYPE_PARTICLE_SERVER; } + virtual PACKET_TYPE getMyQueryMessageType() const { return PACKET_TYPE_PARTICLE_QUERY; } + virtual PACKET_TYPE getExpectedPacketType() const { return PACKET_TYPE_PARTICLE_DATA; } + virtual void renderElement(OctreeElement* element); + +protected: +}; + +#endif /* defined(__hifi__ParticleTreeRenderer__) */ \ No newline at end of file diff --git a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp index 61d2e6f6d8..fb8c3b92a8 100644 --- a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp +++ b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp @@ -42,7 +42,7 @@ void OctreeInboundPacketProcessor::resetStats() { void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, unsigned char* packetData, ssize_t packetLength) { - bool debugProcessPacket = _myServer->wantsVerboseDebug(); + bool debugProcessPacket = true; //_myServer->wantsVerboseDebug(); if (debugProcessPacket) { printf("OctreeInboundPacketProcessor::processPacket() packetData=%p packetLength=%ld\n", packetData, packetLength); @@ -66,8 +66,9 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA uint64_t lockWaitTime = 0; if (_myServer->wantsDebugReceiving()) { - printf("PROCESSING THREAD: got %c - %d command from client receivedBytes=%ld sequence=%d transitTime=%llu usecs\n", - packetType, _receivedPacketCount, packetLength, sequence, transitTime); + printf("PROCESSING THREAD: got '%c' packet - %d command from client " + "receivedBytes=%ld sequence=%d transitTime=%llu usecs\n", + packetType, _receivedPacketCount, packetLength, sequence, transitTime); } int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt); unsigned char* editData = (unsigned char*)&packetData[atByte]; diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp index 5a356c0b7c..2b34cc3c1f 100644 --- a/libraries/octree/src/JurisdictionListener.cpp +++ b/libraries/octree/src/JurisdictionListener.cpp @@ -16,12 +16,16 @@ #include "JurisdictionListener.h" -JurisdictionListener::JurisdictionListener(PacketSenderNotify* notify) : +JurisdictionListener::JurisdictionListener(NODE_TYPE type, PacketSenderNotify* notify) : PacketSender(notify, JurisdictionListener::DEFAULT_PACKETS_PER_SECOND) { + _nodeType = type; ReceivedPacketProcessor::_dontSleep = true; // we handle sleeping so this class doesn't need to NodeList* nodeList = NodeList::getInstance(); nodeList->addHook(this); + +qDebug("JurisdictionListener::JurisdictionListener(NODE_TYPE type=%c)\n", type); + } JurisdictionListener::~JurisdictionListener() { @@ -40,6 +44,8 @@ void JurisdictionListener::nodeKilled(Node* node) { } bool JurisdictionListener::queueJurisdictionRequest() { +qDebug() << "JurisdictionListener::queueJurisdictionRequest()\n"; + static unsigned char buffer[MAX_PACKET_SIZE]; unsigned char* bufferOut = &buffer[0]; ssize_t sizeOut = populateTypeAndVersion(bufferOut, PACKET_TYPE_JURISDICTION_REQUEST); @@ -47,7 +53,11 @@ bool JurisdictionListener::queueJurisdictionRequest() { NodeList* nodeList = NodeList::getInstance(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (nodeList->getNodeActiveSocketOrPing(&(*node)) && node->getType() == NODE_TYPE_VOXEL_SERVER) { + +qDebug() << "Hello..." << *node << "\n"; + + if (nodeList->getNodeActiveSocketOrPing(&(*node)) && + node->getType() == getNodeType()) { const HifiSockAddr* nodeAddress = node->getActiveSocket(); PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut); nodeCount++; diff --git a/libraries/octree/src/JurisdictionListener.h b/libraries/octree/src/JurisdictionListener.h index e8d3ec32a9..b8951683a5 100644 --- a/libraries/octree/src/JurisdictionListener.h +++ b/libraries/octree/src/JurisdictionListener.h @@ -26,7 +26,7 @@ public: static const int DEFAULT_PACKETS_PER_SECOND = 1; static const int NO_SERVER_CHECK_RATE = 60; // if no servers yet detected, keep checking at 60fps - JurisdictionListener(PacketSenderNotify* notify = NULL); + JurisdictionListener(NODE_TYPE type = NODE_TYPE_VOXEL_SERVER, PacketSenderNotify* notify = NULL); ~JurisdictionListener(); virtual bool process(); @@ -38,6 +38,9 @@ public: /// Called by NodeList to inform us that a node has been killed. void nodeKilled(Node* node); + NODE_TYPE getNodeType() const { return _nodeType; } + void setNodeType(NODE_TYPE type) { _nodeType = type; } + protected: /// Callback for processing of received packets. Will process any queued PACKET_TYPE_JURISDICTION and update the /// jurisdiction map member variable @@ -49,6 +52,7 @@ protected: private: NodeToJurisdictionMap _jurisdictions; + NODE_TYPE _nodeType; bool queueJurisdictionRequest(); }; diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp new file mode 100644 index 0000000000..1840e7564c --- /dev/null +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -0,0 +1,129 @@ +// +// OctreeRenderer.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 12/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// + +#include +#include + +#include +#include +#include "OctreeRenderer.h" + +OctreeRenderer::OctreeRenderer() { +} + +OctreeRenderer::~OctreeRenderer() { +} + +void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { + + bool showTimingDetails = false; // Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + bool extraDebugging = false; // Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging) + PerformanceWarning warn(showTimingDetails, "OctreeRenderer::processDatagram()",showTimingDetails); + + const unsigned char* packetData = (const unsigned char*)dataByteArray.constData(); + int packetLength = dataByteArray.size(); + + unsigned char command = *packetData; + int numBytesPacketHeader = numBytesForPacketHeader(packetData); + + PACKET_TYPE expectedType = getExpectedPacketType(); + + if(command == expectedType) { + PerformanceWarning warn(showTimingDetails, "OctreeRenderer::processDatagram expected PACKET_TYPE",showTimingDetails); + + const unsigned char* dataAt = packetData + numBytesPacketHeader; + + OCTREE_PACKET_FLAGS flags = (*(OCTREE_PACKET_FLAGS*)(dataAt)); + dataAt += sizeof(OCTREE_PACKET_FLAGS); + OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + + OCTREE_PACKET_SENT_TIME sentAt = (*(OCTREE_PACKET_SENT_TIME*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SENT_TIME); + + bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); + bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); + + OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); + int flightTime = arrivedAt - sentAt; + + OCTREE_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0; + int dataBytes = packetLength - OCTREE_PACKET_HEADER_SIZE; + + int subsection = 1; + while (dataBytes > 0) { + if (packetIsCompressed) { + if (dataBytes > sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE)) { + sectionLength = (*(OCTREE_PACKET_INTERNAL_SECTION_SIZE*)dataAt); + dataAt += sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + dataBytes -= sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + } else { + sectionLength = 0; + dataBytes = 0; // stop looping something is wrong + } + } else { + sectionLength = dataBytes; + } + + if (sectionLength) { + // ask the VoxelTree to read the bitstream into the tree + ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, + getDataSourceUUID()); + _tree->lockForWrite(); + OctreePacketData packetData(packetIsCompressed); + packetData.loadFinalizedContent(dataAt, sectionLength); + if (extraDebugging) { + qDebug("OctreeRenderer::processDatagram() ... Got Packet Section" + " color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d" + " subsection:%d sectionLength:%d uncompressed:%d\n", + debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), + sequence, flightTime, packetLength, dataBytes, subsection, sectionLength, packetData.getUncompressedSize()); + } + _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); + _tree->unlock(); + + dataBytes -= sectionLength; + dataAt += sectionLength; + } + } + subsection++; + } + + // setup rendering for the new items... + //setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); + + // handle bandwidth meter stuff??? seems like this would be better done in application... + //Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::VOXELS).updateValue(numBytes); +} + +void OctreeRenderer::init() { +} + +class RenderArgs { +public: + OctreeRenderer* _renderer; + ViewFrustum* _viewFrustum; +}; + +bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) { + RenderArgs* args = static_cast(extraData); + if (element->isInView(*args->_viewFrustum)) { + if (element->hasContent()) { + args->_renderer->renderElement(element); + } + return true; + } + // if not in view stop recursing + return false; +} + +void OctreeRenderer::render() { + RenderArgs args = { this, _viewFrustum }; + _tree->recurseTreeWithOperation(renderOperation, &args); +} diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h new file mode 100644 index 0000000000..e69ec76242 --- /dev/null +++ b/libraries/octree/src/OctreeRenderer.h @@ -0,0 +1,57 @@ +// +// OctreeRenderer.h +// hifi +// +// Created by Brad Hefta-Gaub on 12/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// + +#ifndef __hifi__OctreeRenderer__ +#define __hifi__OctreeRenderer__ + +#include +#include + +#include +#include +#include +#include "Octree.h" +#include "OctreePacketData.h" +#include "ViewFrustum.h" + +// Generic client side Octree renderer class. +class OctreeRenderer { +public: + OctreeRenderer(); + virtual ~OctreeRenderer(); + + virtual Octree* createTree() = 0; + virtual NODE_TYPE getMyNodeType() const = 0; + virtual PACKET_TYPE getMyQueryMessageType() const = 0; + virtual PACKET_TYPE getExpectedPacketType() const = 0; + virtual void renderElement(OctreeElement* element) = 0; + + /// process incoming data + void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); + + /// initialize and GPU/rendering related resources + void init(); + + /// render the content of the octree + virtual void render(); + + void setDataSourceUUID(const QUuid& dataSourceUUID) { _dataSourceUUID = dataSourceUUID; } + const QUuid& getDataSourceUUID() const { return _dataSourceUUID; } + ViewFrustum* getViewFrustum() const { return _viewFrustum; } + void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; } + + static bool renderOperation(OctreeElement* element, void* extraData); + +protected: + Octree* _tree; + QUuid _dataSourceUUID; + ViewFrustum* _viewFrustum; +}; + +#endif /* defined(__hifi__OctreeRenderer__) */ \ No newline at end of file diff --git a/libraries/particles/src/ParticleScriptingInterface.cpp b/libraries/particles/src/ParticleScriptingInterface.cpp index 1f3a2106e6..7353277f80 100644 --- a/libraries/particles/src/ParticleScriptingInterface.cpp +++ b/libraries/particles/src/ParticleScriptingInterface.cpp @@ -8,7 +8,9 @@ #include "ParticleScriptingInterface.h" -ParticleScriptingInterface::ParticleScriptingInterface() { +ParticleScriptingInterface::ParticleScriptingInterface() : + _jurisdictionListener(NODE_TYPE_PARTICLE_SERVER) +{ _jurisdictionListener.initialize(true); _particlePacketSender.setServerJurisdictions(_jurisdictionListener.getJurisdictions()); } diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index 2187d8075b..eb65a3009e 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -31,7 +31,15 @@ void ParticleTree::storeParticle(const Particle& particle) { glm::vec3 position = particle.getPosition(); float size = particle.getRadius(); ParticleTreeElement* element = (ParticleTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size); + +printf("ParticleTree::storeParticle() element=%p particle.getPosition()=%f,%f,%f\n", + element, + particle.getPosition().x, particle.getPosition().y, particle.getPosition().z); + element->storeParticle(particle); + + // what else do we need to do here to get reaveraging to work + _isDirty = true; } int ParticleTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* packetData, int packetLength, @@ -41,7 +49,12 @@ int ParticleTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* p // we handle these types of "edit" packets switch (packetType) { case PACKET_TYPE_PARTICLE_ADD: { + +printf("got PACKET_TYPE_PARTICLE_ADD....\n"); Particle newParticle = Particle::fromEditPacket(editData, maxLength, processedBytes); + +printf("newParticle...getPosition()=%f,%f,%f\n", newParticle.getPosition().x, newParticle.getPosition().y, newParticle.getPosition().z); + storeParticle(newParticle); // It seems like we need some way to send the ID back to the creator?? diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index b769887288..b4863b1947 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -78,7 +78,9 @@ int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, in if (bytesLeftToRead >= (numberOfParticles * expectedBytesPerParticle)) { for (uint16_t i = 0; i < numberOfParticles; i++) { - int bytesForThisParticle = _particles[i].readParticleDataFromBuffer(dataAt, bytesLeftToRead, args); + Particle tempParticle; + int bytesForThisParticle = tempParticle.readParticleDataFromBuffer(dataAt, bytesLeftToRead, args); + _particles.push_back(tempParticle); dataAt += bytesForThisParticle; bytesLeftToRead -= bytesForThisParticle; bytesRead += bytesForThisParticle; @@ -105,5 +107,11 @@ bool ParticleTreeElement::collapseChildren() { void ParticleTreeElement::storeParticle(const Particle& particle) { _particles.push_back(particle); + + markWithChangedTime(); + +printf("ParticleTreeElement::storeParticle() element=%p _particles.size()=%ld particle.getPosition()=%f,%f,%f\n", + this, _particles.size(), + particle.getPosition().x, particle.getPosition().y, particle.getPosition().z); } diff --git a/libraries/particles/src/ParticleTreeElement.h b/libraries/particles/src/ParticleTreeElement.h index f1366d9141..5d9e68cb73 100644 --- a/libraries/particles/src/ParticleTreeElement.h +++ b/libraries/particles/src/ParticleTreeElement.h @@ -69,6 +69,8 @@ public: /// shouldRender() state, the tree will remark elements as changed even in cases there the elements have not changed. virtual bool isRendered() const { return getShouldRender(); } + const std::vector& getParticles() const { return _particles; } + protected: void storeParticle(const Particle& particle); diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index bcaf64f9c6..e681a20277 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -50,6 +50,7 @@ Node::~Node() { // Names of Node Types const char* NODE_TYPE_NAME_DOMAIN = "Domain"; const char* NODE_TYPE_NAME_VOXEL_SERVER = "Voxel Server"; +const char* NODE_TYPE_NAME_PARTICLE_SERVER = "Particle Server"; const char* NODE_TYPE_NAME_AGENT = "Agent"; const char* NODE_TYPE_NAME_AUDIO_MIXER = "Audio Mixer"; const char* NODE_TYPE_NAME_AVATAR_MIXER = "Avatar Mixer"; @@ -64,6 +65,8 @@ const char* Node::getTypeName() const { return NODE_TYPE_NAME_DOMAIN; case NODE_TYPE_VOXEL_SERVER: return NODE_TYPE_NAME_VOXEL_SERVER; + case NODE_TYPE_PARTICLE_SERVER: + return NODE_TYPE_NAME_PARTICLE_SERVER; case NODE_TYPE_AGENT: return NODE_TYPE_NAME_AGENT; case NODE_TYPE_AUDIO_MIXER: