diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e6161498d6..7e0eb7c29c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -129,6 +129,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _voxelProcessor(), _voxelHideShowThread(&_voxels), _voxelEditSender(this), + _particleEditSender(this), _packetCount(0), _packetsPerSecond(0), _bytesPerSecond(0), @@ -231,6 +232,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : // Tell our voxel edit sender about our known jurisdictions _voxelEditSender.setVoxelServerJurisdictions(&_voxelServerJurisdictions); + _particleEditSender.setServerJurisdictions(&_particleServerJurisdictions); } Application::~Application() { @@ -315,6 +317,7 @@ void Application::initializeGL() { _voxelProcessor.initialize(_enableProcessVoxelsThread); _voxelEditSender.initialize(_enableProcessVoxelsThread); _voxelHideShowThread.initialize(_enableProcessVoxelsThread); + _particleEditSender.initialize(_enableProcessVoxelsThread); if (_enableProcessVoxelsThread) { qDebug("Voxel parsing thread created.\n"); } @@ -614,6 +617,9 @@ void Application::keyPressEvent(QKeyEvent* event) { bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); switch (event->key()) { + case Qt::Key_N: + shootParticle(); + break; case Qt::Key_Shift: if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode)) { _pasteMode = true; @@ -1378,6 +1384,7 @@ void Application::terminate() { _voxelProcessor.terminate(); _voxelHideShowThread.terminate(); _voxelEditSender.terminate(); + _particleEditSender.terminate(); } static Avatar* processAvatarMessageHeader(unsigned char*& packetData, size_t& dataBytes) { @@ -1476,6 +1483,33 @@ void Application::removeVoxel(glm::vec3 position, _voxels.deleteVoxelAt(voxel.x, voxel.y, voxel.z, voxel.s); } +void Application::shootParticle() { + + glm::vec3 position = _viewFrustum.getOffsetPosition(); + glm::vec3 direction = _viewFrustum.getOffsetDirection(); + glm::vec3 lookingAt = position + (direction * 0.2f); + + const float radius = 0.5 / TREE_SCALE; + xColor color = { 255, 0, 0}; + glm::vec3 velocity = lookingAt - position; + glm::vec3 gravity = DEFAULT_GRAVITY; + float damping = DEFAULT_DAMPING; + QString updateScript(""); + makeParticle(position, radius, color, velocity, gravity, damping, updateScript); +} + +void Application::makeParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, + glm::vec3 gravity, float damping, QString updateScript) { + + // setup a ParticleDetail struct with the data + ParticleDetail addParticleDetail = { position, radius, {color.red, color.green, color.blue }, + velocity, gravity, damping, updateScript }; + + // queue the packet + _particleEditSender.queueParticleEditMessages(PACKET_TYPE_PARTICLE_ADD, 1, &addParticleDetail); +} + + void Application::makeVoxel(glm::vec3 position, float scale, unsigned char red, @@ -2285,6 +2319,7 @@ void Application::updateThreads(float deltaTime) { _voxelProcessor.threadRoutine(); _voxelHideShowThread.threadRoutine(); _voxelEditSender.threadRoutine(); + _particleEditSender.threadRoutine(); } } @@ -2594,11 +2629,11 @@ void Application::updateAvatar(float deltaTime) { loadViewFrustum(_myCamera, _viewFrustum); // Update my voxel servers with my current voxel query... - queryOctree(NODE_TYPE_VOXEL_SERVER, PACKET_TYPE_VOXEL_QUERY); - queryOctree(NODE_TYPE_PARTICLE_SERVER, PACKET_TYPE_PARTICLE_QUERY); + queryOctree(NODE_TYPE_VOXEL_SERVER, PACKET_TYPE_VOXEL_QUERY, _voxelServerJurisdictions); + queryOctree(NODE_TYPE_PARTICLE_SERVER, PACKET_TYPE_PARTICLE_QUERY, _particleServerJurisdictions); } -void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType) { +void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, NodeToJurisdictionMap& jurisdictions) { // if voxels are disabled, then don't send this at all... if (!Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { @@ -2644,10 +2679,10 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType) { // if we haven't heard from this voxel server, go ahead and send it a query, so we // can get the jurisdiction... - if (_voxelServerJurisdictions.find(nodeUUID) == _voxelServerJurisdictions.end()) { + if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { unknownJurisdictionServers++; } else { - const JurisdictionMap& map = (_voxelServerJurisdictions)[nodeUUID]; + const JurisdictionMap& map = (jurisdictions)[nodeUUID]; unsigned char* rootCode = map.getRootOctalCode(); @@ -2705,13 +2740,13 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType) { // if we haven't heard from this voxel server, go ahead and send it a query, so we // can get the jurisdiction... - if (_voxelServerJurisdictions.find(nodeUUID) == _voxelServerJurisdictions.end()) { + if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { unknownView = true; // assume it's in view if (wantExtraDebugging) { qDebug() << "no known jurisdiction for node " << *node << ", assume it's visible.\n"; } } else { - const JurisdictionMap& map = (_voxelServerJurisdictions)[nodeUUID]; + const JurisdictionMap& map = (jurisdictions)[nodeUUID]; unsigned char* rootCode = map.getRootOctalCode(); @@ -4078,6 +4113,7 @@ void Application::domainChanged(QString domain) { // reset our node to stats and node to jurisdiction maps... since these must be changing... _voxelServerJurisdictions.clear(); _voxelServerSceneStats.clear(); + _particleServerJurisdictions.clear(); } void Application::nodeAdded(Node* node) { @@ -4116,6 +4152,37 @@ void Application::nodeKilled(Node* node) { } _voxelSceneStatsLock.unlock(); + } else if (node->getType() == NODE_TYPE_PARTICLE_SERVER) { + QUuid nodeUUID = node->getUUID(); + // see if this is the first we've heard of this node... + if (_particleServerJurisdictions.find(nodeUUID) != _particleServerJurisdictions.end()) { + unsigned char* rootCode = _particleServerJurisdictions[nodeUUID].getRootOctalCode(); + VoxelPositionSize rootDetails; + voxelDetailsForCode(rootCode, rootDetails); + + printf("particle server going away...... v[%f, %f, %f, %f]\n", + 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.99; + fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; + _voxelFades.push_back(fade); + } + + // If the voxel server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server + _particleServerJurisdictions.erase(nodeUUID); + } + + // also clean up scene stats for that server + _voxelSceneStatsLock.lockForWrite(); + if (_voxelServerSceneStats.find(nodeUUID) != _voxelServerSceneStats.end()) { + _voxelServerSceneStats.erase(nodeUUID); + } + _voxelSceneStatsLock.unlock(); + } else if (node->getType() == NODE_TYPE_AGENT) { Avatar* avatar = static_cast(node->getLinkedData()); if (avatar == _lookatTargetAvatar) { @@ -4147,10 +4214,10 @@ void Application::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t m } } -int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderSockAddr) { +int Application::parseOctreeStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderSockAddr) { // But, also identify the sender, and keep track of the contained jurisdiction root for this server - Node* voxelServer = NodeList::getInstance()->nodeWithAddress(senderSockAddr); + Node* server = NodeList::getInstance()->nodeWithAddress(senderSockAddr); // parse the incoming stats datas stick it in a temporary object for now, while we // determine which server it belongs to @@ -4158,8 +4225,8 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng int statsMessageLength = temp.unpackFromMessage(messageData, messageLength); // quick fix for crash... why would voxelServer be NULL? - if (voxelServer) { - QUuid nodeUUID = voxelServer->getUUID(); + if (server) { + QUuid nodeUUID = server->getUUID(); // now that we know the node ID, let's add these stats to the stats for that node... _voxelSceneStatsLock.lockForWrite(); @@ -4174,8 +4241,16 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng voxelDetailsForCode(temp.getJurisdictionRoot(), rootDetails); // see if this is the first we've heard of this node... - if (_voxelServerJurisdictions.find(nodeUUID) == _voxelServerJurisdictions.end()) { - printf("stats from new voxel server... v[%f, %f, %f, %f]\n", + NodeToJurisdictionMap* jurisdiction = NULL; + if (server->getType() == NODE_TYPE_VOXEL_SERVER) { + jurisdiction = &_voxelServerJurisdictions; + } else { + jurisdiction = &_particleServerJurisdictions; + } + + + if (jurisdiction->find(nodeUUID) == jurisdiction->end()) { + printf("stats from new server... v[%f, %f, %f, %f]\n", rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); // Add the jurisditionDetails object to the list of "fade outs" @@ -4193,7 +4268,7 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng // details from the VoxelSceneStats to construct the JurisdictionMap JurisdictionMap jurisdictionMap; jurisdictionMap.copyContents(temp.getJurisdictionRoot(), temp.getJurisdictionEndNodes()); - _voxelServerJurisdictions[nodeUUID] = jurisdictionMap; + (*jurisdiction)[nodeUUID] = jurisdictionMap; } return statsMessageLength; } diff --git a/interface/src/Application.h b/interface/src/Application.h index 64454f6898..329d50e830 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #ifndef _WIN32 @@ -117,6 +118,10 @@ public: void updateWindowTitle(); void wheelEvent(QWheelEvent* event); + + void shootParticle(); // shoots a particle in the direction you're looking + void makeParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, + glm::vec3 gravity, float damping, QString updateScript); void makeVoxel(glm::vec3 position, float scale, @@ -285,7 +290,7 @@ private: void updateAvatar(float deltaTime); void updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection); - void queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType); + void queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, NodeToJurisdictionMap& jurisdictions); void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum); glm::vec3 getSunDirection(); @@ -453,6 +458,7 @@ private: VoxelPacketProcessor _voxelProcessor; VoxelHideShowThread _voxelHideShowThread; VoxelEditPacketSender _voxelEditSender; + ParticleEditPacketSender _particleEditSender; unsigned char _incomingPacket[MAX_PACKET_SIZE]; int _packetCount; @@ -473,11 +479,12 @@ private: PieMenu _pieMenu; - int parseVoxelStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderAddress); + int parseOctreeStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderAddress); void trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderSockAddr, bool wasStatsPacket); NodeToJurisdictionMap _voxelServerJurisdictions; + NodeToJurisdictionMap _particleServerJurisdictions; NodeToVoxelSceneStats _voxelServerSceneStats; QReadWriteLock _voxelSceneStatsLock; diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 3ecbf88cef..6576b0c2fc 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -39,7 +39,7 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, uns // then process any remaining bytes as if it was another packet if (packetData[0] == PACKET_TYPE_OCTREE_STATS) { - int statsMessageLength = app->parseVoxelStats(packetData, messageLength, senderSockAddr); + int statsMessageLength = app->parseOctreeStats(packetData, messageLength, senderSockAddr); wasStatsPacket = true; if (messageLength > statsMessageLength) { packetData += statsMessageLength; diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index 0a111a1310..2c2e7cfaf8 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -110,12 +110,6 @@ void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const Hifi } 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); } class RenderArgs { diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 580e1f384e..f662f18c67 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -216,14 +216,14 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, sizeOut = 0; for (int i = 0; i < count && success; i++) { - // get the coded voxel + // get the octal code for the particle unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y, details[i].position.z, details[i].radius); int octets = numberOfThreeBitSectionsInCode(octcode); int lengthOfOctcode = bytesRequiredForCodeLength(octets); int lenfthOfEditData = lengthOfOctcode + expectedBytes(); - // make sure we have room to copy this voxel + // make sure we have room to copy this particle if (sizeOut + lenfthOfEditData > sizeIn) { success = false; } else { diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 2249fd21b6..e56697465e 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -22,8 +22,8 @@ class ParticleDetail { public: glm::vec3 position; - float radius; - rgbColor color; + float radius; + rgbColor color; glm::vec3 velocity; glm::vec3 gravity; float damping; diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index aa1a1426ec..71af796706 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -70,28 +70,14 @@ void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) { // If the particle wants to die, or if it's left our bounding box, then move it // into the arguments moving particles. These will be added back or deleted completely if (_particles[i].getShouldDie() || !_box.contains(_particles[i].getPosition())) { - - /** - glm::vec3 position = _particles[i].getPosition() * (float)TREE_SCALE; - glm::vec3 boxBRN =_box.getCorner() * (float)TREE_SCALE; - glm::vec3 boxTLF =_box.calcTopFarLeft() * (float)TREE_SCALE; - - printf("particle [%f,%f,%f] no longer contained in ParticleTreeElement() box [%f,%f,%f] -> [%f,%f,%f]\n", - position.x, position.y, position.z, - boxBRN.x, boxBRN.y, boxBRN.z, - boxTLF.x, boxTLF.y, boxTLF.z); - **/ - args._movingParticles.push_back(_particles[i]); // erase this particle _particles.erase(_particles.begin()+i); - //printf("removed particle[%d]\n",i); // reduce our index since we just removed this item i--; numberOfParticles--; - //printf("numberOfParticles=%d\n",numberOfParticles); } } }