From 4ea9bbc309fdb60fdd07c7a7161a0ebb7be07ab2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 30 Dec 2014 18:08:58 -0800 Subject: [PATCH] first major pass at voxelEctomy --- assignment-client/src/Agent.h | 2 - assignment-client/src/AssignmentFactory.cpp | 3 - assignment-client/src/voxels/VoxelNodeData.h | 25 - assignment-client/src/voxels/VoxelServer.cpp | 102 - assignment-client/src/voxels/VoxelServer.h | 62 - .../src/voxels/VoxelServerConsts.h | 21 - interface/src/Application.cpp | 107 +- interface/src/Application.h | 23 +- interface/src/DatagramProcessor.cpp | 5 - interface/src/Menu.cpp | 32 - interface/src/Menu.h | 2 - interface/src/avatar/Avatar.cpp | 1 + interface/src/avatar/MyAvatar.cpp | 15 +- interface/src/avatar/SkeletonModel.cpp | 1 + .../scripting/ClipboardScriptingInterface.cpp | 118 -- .../scripting/ClipboardScriptingInterface.h | 24 - interface/src/ui/ApplicationOverlay.cpp | 1 + interface/src/ui/NodeBounds.cpp | 17 +- interface/src/ui/NodeBounds.h | 3 - interface/src/ui/OctreeStatsDialog.cpp | 23 +- interface/src/ui/OctreeStatsDialog.h | 1 - interface/src/ui/PreferencesDialog.cpp | 2 +- interface/src/ui/ScriptEditorWidget.cpp | 1 + interface/src/ui/ScriptEditorWindow.cpp | 2 + interface/src/ui/Stats.cpp | 40 +- interface/src/ui/VoxelImportDialog.cpp | 362 ---- interface/src/ui/VoxelImportDialog.h | 81 - .../src/ui/overlays/LocalVoxelsOverlay.cpp | 127 -- .../src/ui/overlays/LocalVoxelsOverlay.h | 54 - interface/src/ui/overlays/Overlays.cpp | 3 - .../src/voxels/OctreePacketProcessor.cpp | 16 +- interface/src/voxels/VoxelHideShowThread.cpp | 47 - interface/src/voxels/VoxelHideShowThread.h | 35 - interface/src/voxels/VoxelImporter.cpp | 119 -- interface/src/voxels/VoxelImporter.h | 51 - interface/src/voxels/VoxelSystem.cpp | 1661 ----------------- interface/src/voxels/VoxelSystem.h | 246 --- .../src/EntityTreeRenderer.cpp | 11 - .../src/EntityTreeRenderer.h | 1 - .../entities/src/EntityCollisionSystem.cpp | 45 +- .../entities/src/EntityCollisionSystem.h | 8 +- libraries/entities/src/EntityItem.cpp | 2 - libraries/entities/src/EntityItem.h | 1 - .../entities/src/EntityScriptingInterface.h | 7 +- libraries/fbx/src/FBXReader.cpp | 166 -- libraries/fbx/src/FBXReader.h | 3 - libraries/render-utils/src/GeometryCache.cpp | 9 +- libraries/script-engine/src/LocalVoxels.cpp | 165 -- libraries/script-engine/src/LocalVoxels.h | 102 - libraries/script-engine/src/ScriptEngine.cpp | 40 +- libraries/script-engine/src/ScriptEngine.h | 7 +- libraries/voxels/src/LocalVoxelsList.cpp | 63 - libraries/voxels/src/LocalVoxelsList.h | 62 - .../voxels/src/VoxelEditPacketSender.cpp | 155 -- libraries/voxels/src/VoxelEditPacketSender.h | 63 - libraries/voxels/src/VoxelTree.cpp | 591 ------ libraries/voxels/src/VoxelTree.h | 87 - libraries/voxels/src/VoxelTreeCommands.cpp | 160 -- libraries/voxels/src/VoxelTreeCommands.h | 51 - libraries/voxels/src/VoxelTreeElement.cpp | 253 --- libraries/voxels/src/VoxelTreeElement.h | 123 -- .../voxels/src/VoxelTreeHeadlessViewer.cpp | 24 - .../voxels/src/VoxelTreeHeadlessViewer.h | 42 - .../voxels/src/VoxelsScriptingInterface.cpp | 215 --- .../voxels/src/VoxelsScriptingInterface.h | 108 -- 65 files changed, 43 insertions(+), 5956 deletions(-) delete mode 100644 assignment-client/src/voxels/VoxelNodeData.h delete mode 100644 assignment-client/src/voxels/VoxelServer.cpp delete mode 100644 assignment-client/src/voxels/VoxelServer.h delete mode 100644 assignment-client/src/voxels/VoxelServerConsts.h delete mode 100644 interface/src/ui/VoxelImportDialog.cpp delete mode 100644 interface/src/ui/VoxelImportDialog.h delete mode 100644 interface/src/ui/overlays/LocalVoxelsOverlay.cpp delete mode 100644 interface/src/ui/overlays/LocalVoxelsOverlay.h delete mode 100644 interface/src/voxels/VoxelHideShowThread.cpp delete mode 100644 interface/src/voxels/VoxelHideShowThread.h delete mode 100644 interface/src/voxels/VoxelImporter.cpp delete mode 100644 interface/src/voxels/VoxelImporter.h delete mode 100644 interface/src/voxels/VoxelSystem.cpp delete mode 100644 interface/src/voxels/VoxelSystem.h delete mode 100644 libraries/script-engine/src/LocalVoxels.cpp delete mode 100644 libraries/script-engine/src/LocalVoxels.h delete mode 100644 libraries/voxels/src/LocalVoxelsList.cpp delete mode 100644 libraries/voxels/src/LocalVoxelsList.h delete mode 100644 libraries/voxels/src/VoxelEditPacketSender.cpp delete mode 100644 libraries/voxels/src/VoxelEditPacketSender.h delete mode 100644 libraries/voxels/src/VoxelTree.cpp delete mode 100644 libraries/voxels/src/VoxelTree.h delete mode 100644 libraries/voxels/src/VoxelTreeCommands.cpp delete mode 100644 libraries/voxels/src/VoxelTreeCommands.h delete mode 100644 libraries/voxels/src/VoxelTreeElement.cpp delete mode 100644 libraries/voxels/src/VoxelTreeElement.h delete mode 100644 libraries/voxels/src/VoxelTreeHeadlessViewer.cpp delete mode 100644 libraries/voxels/src/VoxelTreeHeadlessViewer.h delete mode 100644 libraries/voxels/src/VoxelsScriptingInterface.cpp delete mode 100644 libraries/voxels/src/VoxelsScriptingInterface.h diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 61780f515d..ffae3c6c21 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include "MixedAudioStream.h" diff --git a/assignment-client/src/AssignmentFactory.cpp b/assignment-client/src/AssignmentFactory.cpp index 63c87313fe..78e905edfa 100644 --- a/assignment-client/src/AssignmentFactory.cpp +++ b/assignment-client/src/AssignmentFactory.cpp @@ -17,7 +17,6 @@ #include "avatars/AvatarMixer.h" #include "metavoxels/MetavoxelServer.h" #include "entities/EntityServer.h" -#include "voxels/VoxelServer.h" ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet) { QDataStream packetStream(packet); @@ -35,8 +34,6 @@ ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet return new AvatarMixer(packet); case Assignment::AgentType: return new Agent(packet); - case Assignment::VoxelServerType: - return new VoxelServer(packet); case Assignment::MetavoxelServerType: return new MetavoxelServer(packet); case Assignment::EntityServerType: diff --git a/assignment-client/src/voxels/VoxelNodeData.h b/assignment-client/src/voxels/VoxelNodeData.h deleted file mode 100644 index dada32ac3e..0000000000 --- a/assignment-client/src/voxels/VoxelNodeData.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// VoxelNodeData.h -// assignment-client/src/voxels -// -// Created by Stephen Birarda on 3/21/13. -// 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_VoxelNodeData_h -#define hifi_VoxelNodeData_h - -#include - -#include "../octree/OctreeQueryNode.h" - -class VoxelNodeData : public OctreeQueryNode { -public: - VoxelNodeData() : OctreeQueryNode() { } - virtual PacketType getMyPacketType() const { return PacketTypeVoxelData; } -}; - -#endif // hifi_VoxelNodeData_h diff --git a/assignment-client/src/voxels/VoxelServer.cpp b/assignment-client/src/voxels/VoxelServer.cpp deleted file mode 100644 index a83e3e99e3..0000000000 --- a/assignment-client/src/voxels/VoxelServer.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// -// VoxelServer.cpp -// assignment-client/src/voxels -// -// Created by Brad Hefta-Gaub on 9/16/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 - -#include "VoxelServer.h" -#include "VoxelServerConsts.h" -#include "VoxelNodeData.h" - -const char* VOXEL_SERVER_NAME = "Voxel"; -const char* VOXEL_SERVER_LOGGING_TARGET_NAME = "voxel-server"; -const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo"; - -VoxelServer::VoxelServer(const QByteArray& packet) : OctreeServer(packet) { - // nothing special to do here... -} - -VoxelServer::~VoxelServer() { - // nothing special to do here... -} - -OctreeQueryNode* VoxelServer::createOctreeQueryNode() { - return new VoxelNodeData(); -} - -Octree* VoxelServer::createTree() { - return new VoxelTree(true); -} - -bool VoxelServer::hasSpecialPacketToSend(const SharedNodePointer& node) { - bool shouldSendEnvironments = _sendEnvironments && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, OCTREE_SEND_INTERVAL_USECS); - return shouldSendEnvironments; -} - -int VoxelServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { - - unsigned char* copyAt = _tempOutputBuffer; - - int numBytesPacketHeader = populatePacketHeader(reinterpret_cast(_tempOutputBuffer), PacketTypeEnvironmentData); - copyAt += numBytesPacketHeader; - int envPacketLength = numBytesPacketHeader; - - // pack in flags - OCTREE_PACKET_FLAGS flags = 0; - OCTREE_PACKET_FLAGS* flagsAt = (OCTREE_PACKET_FLAGS*)copyAt; - *flagsAt = flags; - copyAt += sizeof(OCTREE_PACKET_FLAGS); - envPacketLength += sizeof(OCTREE_PACKET_FLAGS); - - // pack in sequence number - OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)copyAt; - *sequenceAt = queryNode->getSequenceNumber(); - copyAt += sizeof(OCTREE_PACKET_SEQUENCE); - envPacketLength += sizeof(OCTREE_PACKET_SEQUENCE); - - // pack in timestamp - OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); - OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)copyAt; - *timeAt = now; - copyAt += sizeof(OCTREE_PACKET_SENT_TIME); - envPacketLength += sizeof(OCTREE_PACKET_SENT_TIME); - - int environmentsToSend = getSendMinimalEnvironment() ? 1 : getEnvironmentDataCount(); - - for (int i = 0; i < environmentsToSend; i++) { - envPacketLength += getEnvironmentData(i)->getBroadcastData(_tempOutputBuffer + envPacketLength); - } - - NodeList::getInstance()->writeDatagram((char*) _tempOutputBuffer, envPacketLength, SharedNodePointer(node)); - queryNode->packetSent(_tempOutputBuffer, envPacketLength); - packetsSent = 1; - - return envPacketLength; -} - - -void VoxelServer::readAdditionalConfiguration(const QJsonObject& settingsSectionObject) { - // should we send environments? Default is yes, but this command line suppresses sending - readOptionBool(QString("sendEnvironments"), settingsSectionObject, _sendEnvironments); - bool dontSendEnvironments = !_sendEnvironments; - if (dontSendEnvironments) { - qDebug("Sending environments suppressed..."); - } else { - // should we send environments? Default is yes, but this command line suppresses sending - //const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment"; - //_sendMinimalEnvironment = cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT); - - readOptionBool(QString("minimalEnvironment"), settingsSectionObject, _sendMinimalEnvironment); - qDebug("Using Minimal Environment=%s", debug::valueOf(_sendMinimalEnvironment)); - } - qDebug("Sending environments=%s", debug::valueOf(_sendEnvironments)); - - NodeList::getInstance()->addNodeTypeToInterestSet(NodeType::AnimationServer); -} diff --git a/assignment-client/src/voxels/VoxelServer.h b/assignment-client/src/voxels/VoxelServer.h deleted file mode 100644 index 4d21695f33..0000000000 --- a/assignment-client/src/voxels/VoxelServer.h +++ /dev/null @@ -1,62 +0,0 @@ -// -// VoxelServer.h -// assignment-client/src/voxels -// -// 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_VoxelServer_h -#define hifi_VoxelServer_h - -#include -#include -#include - -#include -#include - -#include "../octree/OctreeServer.h" - -#include "VoxelServerConsts.h" - -/// Handles assignments of type VoxelServer - sending voxels to various clients. -class VoxelServer : public OctreeServer { -public: - VoxelServer(const QByteArray& packet); - ~VoxelServer(); - - bool wantSendEnvironments() const { return _sendEnvironments; } - bool getSendMinimalEnvironment() const { return _sendMinimalEnvironment; } - EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; } - int getEnvironmentDataCount() const { return sizeof(_environmentData)/sizeof(EnvironmentData); } - - // Subclasses must implement these methods - virtual OctreeQueryNode* createOctreeQueryNode(); - virtual char getMyNodeType() const { return NodeType::VoxelServer; } - virtual PacketType getMyQueryMessageType() const { return PacketTypeVoxelQuery; } - virtual const char* getMyServerName() const { return VOXEL_SERVER_NAME; } - virtual const char* getMyLoggingServerTargetName() const { return VOXEL_SERVER_LOGGING_TARGET_NAME; } - virtual const char* getMyDefaultPersistFilename() const { return LOCAL_VOXELS_PERSIST_FILE; } - virtual PacketType getMyEditNackType() const { return PacketTypeVoxelEditNack; } - virtual QString getMyDomainSettingsKey() const { return QString("voxel_server_settings"); } - - // subclass may implement these method - virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent); - -protected: - virtual Octree* createTree(); - virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject); - -private: - bool _sendEnvironments; - bool _sendMinimalEnvironment; - EnvironmentData _environmentData[3]; - unsigned char _tempOutputBuffer[MAX_PACKET_SIZE]; -}; - -#endif // hifi_VoxelServer_h diff --git a/assignment-client/src/voxels/VoxelServerConsts.h b/assignment-client/src/voxels/VoxelServerConsts.h deleted file mode 100644 index 5764e7d4cf..0000000000 --- a/assignment-client/src/voxels/VoxelServerConsts.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// VoxelServerConsts.h -// assignment-client/src/voxels -// -// 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_VoxelServerConsts_h -#define hifi_VoxelServerConsts_h - -extern const char* VOXEL_SERVER_NAME; -extern const char* VOXEL_SERVER_LOGGING_TARGET_NAME; -extern const char* LOCAL_VOXELS_PERSIST_FILE; - -const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000; - -#endif // hifi_VoxelServerConsts_h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 729b8f990c..40b6c4003a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -169,7 +169,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _isTouchPressed(false), _mousePressed(false), _audio(), - _enableProcessVoxelsThread(true), + _enableProcessOctreeThread(true), _octreeProcessor(), _packetsPerSecond(0), _bytesPerSecond(0), @@ -311,7 +311,7 @@ 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::EntityServer + << NodeType::EntityServer << NodeType::MetavoxelServer); // connect to the packet sent signal of the _entityEditSender @@ -539,9 +539,9 @@ void Application::initializeGL() { init(); qDebug( "init() complete."); - // create thread for parsing of voxel data independent of the main network and rendering threads - _octreeProcessor.initialize(_enableProcessVoxelsThread); - _entityEditSender.initialize(_enableProcessVoxelsThread); + // create thread for parsing of octee data independent of the main network and rendering threads + _octreeProcessor.initialize(_enableProcessOctreeThread); + _entityEditSender.initialize(_enableProcessOctreeThread); // call our timer function every second QTimer* timer = new QTimer(this); @@ -1731,20 +1731,14 @@ void Application::init() { _entities.setViewFrustum(getViewFrustum()); EntityTree* entityTree = _entities.getTree(); - _entityCollisionSystem.init(&_entityEditSender, entityTree, NULL, &_audio, &_avatarManager); + _entityCollisionSystem.init(&_entityEditSender, entityTree, &_audio, &_avatarManager); entityTree->setSimulation(&_entityCollisionSystem); - // 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); // connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts - connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithVoxel, - &_entities, &EntityTreeRenderer::entityCollisionWithVoxel); - connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithEntity, &_entities, &EntityTreeRenderer::entityCollisionWithEntity); @@ -1951,10 +1945,8 @@ void Application::updateThreads(float deltaTime) { PerformanceWarning warn(showWarnings, "Application::updateThreads()"); // parse voxel packets - if (!_enableProcessVoxelsThread) { + if (!_enableProcessOctreeThread) { _octreeProcessor.threadRoutine(); - _voxelHideShowThread.threadRoutine(); - _voxelEditSender.threadRoutine(); _entityEditSender.threadRoutine(); } } @@ -2134,9 +2126,6 @@ void Application::update(float deltaTime) { if (queryIsDue || viewIsDifferentEnough) { _lastQueriedTime = now; - if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { - queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); - } if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) { queryOctree(NodeType::EntityServer, PacketTypeEntityQuery, _entityServerJurisdictions); } @@ -2837,14 +2826,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly, RenderAr glColor3f(1,0,0); DependencyManager::get()->renderSphere(originSphereRadius, 15, 15); - // Draw voxels - if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { - PerformanceTimer perfTimer("voxels"); - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::displaySide() ... voxels..."); - _voxels.render(); - } - // also, metavoxels if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) { PerformanceTimer perfTimer("metavoxels"); @@ -3308,20 +3289,6 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) { } } -void Application::deleteVoxels(const VoxelDetail& voxel) { - deleteVoxelAt(voxel); -} - -void Application::deleteVoxelAt(const VoxelDetail& voxel) { - if (voxel.s != 0) { - // sending delete to the server is sufficient, server will send new version so we see updates soon enough - _voxelEditSender.sendVoxelEditMessage(PacketTypeVoxelErase, voxel); - - // delete it locally to see the effect immediately (and in case no voxel server is present) - _voxels.getTree()->deleteVoxelAt(voxel.x, voxel.y, voxel.z, voxel.s); - } -} - void Application::resetSensors() { DependencyManager::get()->reset(); DependencyManager::get()->reset(); @@ -3422,10 +3389,6 @@ void Application::clearDomainOctreeDetails() { _environment.resetToDefault(); // reset our node to stats and node to jurisdiction maps... since these must be changing... - _voxelServerJurisdictions.lockForWrite(); - _voxelServerJurisdictions.clear(); - _voxelServerJurisdictions.unlock(); - _entityServerJurisdictions.lockForWrite(); _entityServerJurisdictions.clear(); _entityServerJurisdictions.unlock(); @@ -3437,8 +3400,6 @@ void Application::clearDomainOctreeDetails() { // reset the model renderer _entities.clear(); - // reset the voxels renderer - _voxels.killLocalVoxels(); } void Application::domainChanged(const QString& domainHostname) { @@ -3475,51 +3436,13 @@ void Application::nodeKilled(SharedNodePointer node) { _octreeProcessor.nodeKilled(node); - _voxelEditSender.nodeKilled(node); _entityEditSender.nodeKilled(node); if (node->getType() == NodeType::AudioMixer) { QMetaObject::invokeMethod(&_audio, "audioMixerKilled"); } - if (node->getType() == NodeType::VoxelServer) { - QUuid nodeUUID = node->getUUID(); - // see if this is the first we've heard of this node... - _voxelServerJurisdictions.lockForRead(); - if (_voxelServerJurisdictions.find(nodeUUID) != _voxelServerJurisdictions.end()) { - unsigned char* rootCode = _voxelServerJurisdictions[nodeUUID].getRootOctalCode(); - VoxelPositionSize rootDetails; - voxelDetailsForCode(rootCode, rootDetails); - _voxelServerJurisdictions.unlock(); - - qDebug("voxel 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 voxel server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server - _voxelServerJurisdictions.lockForWrite(); - _voxelServerJurisdictions.erase(_voxelServerJurisdictions.find(nodeUUID)); - } - _voxelServerJurisdictions.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) { + if (node->getType() == NodeType::EntityServer) { QUuid nodeUUID = node->getUUID(); // see if this is the first we've heard of this node... @@ -3563,7 +3486,7 @@ void Application::nodeKilled(SharedNodePointer node) { } } -void Application::trackIncomingVoxelPacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket) { +void Application::trackIncomingOctreePacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket) { // Attempt to identify the sender from it's address. if (sendingNode) { @@ -3607,10 +3530,7 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin // see if this is the first we've heard of this node... NodeToJurisdictionMap* jurisdiction = NULL; QString serverType; - if (sendingNode->getType() == NodeType::VoxelServer) { - jurisdiction = &_voxelServerJurisdictions; - serverType = "Voxel"; - } else { + if (sendingNode->getType() == NodeType::EntityServer) { jurisdiction = &_entityServerJurisdictions; serverType = "Entity"; } @@ -3704,9 +3624,6 @@ void joystickFromScriptValue(const QScriptValue &object, Joystick* &out) { void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) { // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so // we can use the same ones from the application. - scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender); - scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree()); - scriptEngine->getVoxelsScriptingInterface()->setUndoStack(&_undoStack); scriptEngine->getEntityScriptingInterface()->setPacketSender(&_entityEditSender); scriptEngine->getEntityScriptingInterface()->setEntityTree(_entities.getTree()); @@ -3968,10 +3885,6 @@ void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject qDebug() << "Voxel costs are" << satoshisPerVoxel << "per voxel and" << satoshisPerMeterCubed << "per meter cubed"; qDebug() << "Destination wallet UUID for voxel payments is" << voxelWalletUUID; - - _voxelEditSender.setSatoshisPerVoxel(satoshisPerVoxel); - _voxelEditSender.setSatoshisPerMeterCubed(satoshisPerMeterCubed); - _voxelEditSender.setDestinationWalletUUID(voxelWalletUUID); } QString Application::getPreviousScriptLocation() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 1191752650..75cc07400f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -36,7 +36,6 @@ #include #include #include -#include #include "Audio.h" #include "Camera.h" @@ -69,7 +68,6 @@ #include "ui/ApplicationOverlay.h" #include "ui/RunningScriptsWidget.h" #include "ui/ToolWindow.h" -#include "ui/VoxelImportDialog.h" #include "voxels/VoxelFade.h" #include "voxels/OctreePacketProcessor.h" @@ -121,7 +119,6 @@ class Application : public QApplication, public AbstractViewStateInterface, Abst Q_OBJECT friend class OctreePacketProcessor; - friend class VoxelEditPacketSender; friend class DatagramProcessor; public: @@ -162,15 +159,6 @@ public: bool event(QEvent* event); bool eventFilter(QObject* object, QEvent* event); - void makeVoxel(glm::vec3 position, - float scale, - unsigned char red, - unsigned char green, - unsigned char blue, - bool isDestructive); - - void removeVoxel(glm::vec3 position, float scale); - bool isThrottleRendering() const { return DependencyManager::get()->isThrottleRendering(); } MyAvatar* getAvatar() { return _myAvatar; } @@ -429,12 +417,7 @@ private: void updateShadowMap(); void renderRearViewMirror(const QRect& region, bool billboard = false); void renderViewFrustum(ViewFrustum& viewFrustum); - void checkBandwidthMeterClick(); - - void deleteVoxelAt(const VoxelDetail& voxel); - void eyedropperVoxelUnderCursor(); - void setMenuShortcutsEnabled(bool enabled); static void attachNewHeadToNode(Node *newNode); @@ -485,7 +468,7 @@ private: float _trailingAudioLoudness; - OctreeQuery _octreeQuery; // NodeData derived class for querying voxels from voxel server + OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers AvatarManager _avatarManager; MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be) @@ -533,7 +516,7 @@ private: Audio _audio; - bool _enableProcessVoxelsThread; + bool _enableProcessOctreeThread; OctreePacketProcessor _octreeProcessor; EntityEditPacketSender _entityEditSender; @@ -544,7 +527,7 @@ private: float _idleLoopMeasuredJitter; int parseOctreeStats(const QByteArray& packet, const SharedNodePointer& sendingNode); - void trackIncomingVoxelPacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket); + void trackIncomingOctreePacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket); NodeToJurisdictionMap _entityServerJurisdictions; NodeToOctreeSceneStats _octreeServerSceneStats; diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 96680423ed..1b7e27776e 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -167,11 +167,6 @@ void DatagramProcessor::processDatagrams() { } break; } - case PacketTypeVoxelEditNack: - if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { - application->_voxelEditSender.processNackPacket(incomingPacket); - } - break; case PacketTypeEntityEditNack: if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { application->_entityEditSender.processNackPacket(incomingPacket); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 3e9bdde1ff..f7e8df90e4 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -635,11 +635,6 @@ Menu::Menu() : connect(appInstance->getAudio(), SIGNAL(muteToggled()), this, SLOT(audioMuteToggled())); - addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel, - Qt::CTRL | Qt::SHIFT | Qt::Key_V, - this, - SLOT(pasteToVoxel())); - #ifndef Q_OS_MAC QMenu* helpMenu = addMenu("Help"); QAction* helpAction = helpMenu->addAction(MenuOption::AboutApp); @@ -1259,33 +1254,6 @@ void Menu::nameLocation() { _newLocationDialog->showNormal(); } -void Menu::pasteToVoxel() { - QInputDialog pasteToOctalCodeDialog(Application::getInstance()->getWindow()); - pasteToOctalCodeDialog.setWindowTitle("Paste to Voxel"); - pasteToOctalCodeDialog.setLabelText("Octal Code:"); - QString octalCode = ""; - pasteToOctalCodeDialog.setTextValue(octalCode); - pasteToOctalCodeDialog.setWindowFlags(Qt::Sheet); - pasteToOctalCodeDialog.resize(pasteToOctalCodeDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, - pasteToOctalCodeDialog.size().height()); - - int dialogReturn = pasteToOctalCodeDialog.exec(); - if (dialogReturn == QDialog::Accepted && !pasteToOctalCodeDialog.textValue().isEmpty()) { - // we got an octalCode to paste to... - QString locationToPaste = pasteToOctalCodeDialog.textValue(); - unsigned char* octalCodeDestination = hexStringToOctalCode(locationToPaste); - - // check to see if it was a legit octcode... - if (locationToPaste == octalCodeToHexString(octalCodeDestination)) { - Application::getInstance()->pasteVoxelsToOctalCode(octalCodeDestination); - } else { - qDebug() << "Problem with octcode..."; - } - } - - sendFakeEnterEvent(); -} - void Menu::toggleLoginMenuItem() { AccountManager& accountManager = AccountManager::getInstance(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index a3e32b3682..3fa3d7372d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -190,7 +190,6 @@ public slots: void importSettings(); void exportSettings(); void toggleAddressBar(); - void pasteToVoxel(); void toggleLoginMenuItem(); void toggleSixense(bool shouldEnable); @@ -428,7 +427,6 @@ namespace MenuOption { const QString OffAxisProjection = "Off-Axis Projection"; const QString OldVoxelCullingMode = "Old Voxel Culling Mode"; const QString Pair = "Pair"; - const QString PasteToVoxel = "Paste to Voxel..."; const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString Preferences = "Preferences..."; const QString Quit = "Quit"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 3e57fc7dba..6a659abf93 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -41,6 +41,7 @@ #include "ModelReferential.h" #include "Physics.h" #include "Recorder.h" +#include "Util.h" #include "world.h" #include "devices/OculusManager.h" diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 81d00bae74..f34f5f2c67 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -42,6 +42,7 @@ #include "Recorder.h" #include "devices/Faceshift.h" #include "devices/OculusManager.h" +#include "Util.h" using namespace std; @@ -1459,20 +1460,6 @@ static CollisionList myCollisions(64); void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { - quint64 now = usecTimestampNow(); - if (_voxelShapeManager.needsUpdate(now)) { - // We use a multiple of the avatar's boundingRadius as the size of the cube of interest. - float cubeScale = 6.0f * getBoundingRadius(); - glm::vec3 corner = getPosition() - glm::vec3(0.5f * cubeScale); - AACube boundingCube(corner, cubeScale); - - // query the VoxelTree for cubes that touch avatar's boundingCube - CubeList cubes; - if (Application::getInstance()->getVoxelTree()->findContentInCube(boundingCube, cubes)) { - _voxelShapeManager.updateVoxels(now, cubes); - } - } - // TODO: Andrew to do ground/walking detection in ragdoll mode if (!Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { const float MAX_VOXEL_COLLISION_SPEED = 100.0f; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index b707861677..77cbfd4e87 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -21,6 +21,7 @@ #include "Menu.h" #include "SkeletonModel.h" #include "SkeletonRagdoll.h" +#include "Util.h" enum StandingFootState { LEFT_FOOT, diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index 23ec175d09..30cd3ba44d 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -15,124 +15,6 @@ ClipboardScriptingInterface::ClipboardScriptingInterface() { connect(this, SIGNAL(readyToImport()), Application::getInstance(), SLOT(importVoxels())); } -void ClipboardScriptingInterface::cutVoxel(const VoxelDetail& sourceVoxel) { - cutVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); -} - -void ClipboardScriptingInterface::cutVoxel(float x, float y, float z, float s) { - VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - s / (float)TREE_SCALE }; - Application::getInstance()->cutVoxels(sourceVoxel); -} - -void ClipboardScriptingInterface::copyVoxel(const VoxelDetail& sourceVoxel) { - copyVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); -} - -void ClipboardScriptingInterface::copyVoxel(float x, float y, float z, float s) { - VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - s / (float)TREE_SCALE }; - Application::getInstance()->copyVoxels(sourceVoxel); -} - -void ClipboardScriptingInterface::pasteVoxel(const VoxelDetail& destinationVoxel) { - pasteVoxel(destinationVoxel.x, destinationVoxel.y, destinationVoxel.z, destinationVoxel.s); -} - -void ClipboardScriptingInterface::pasteVoxel(float x, float y, float z, float s) { - VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - s / (float)TREE_SCALE }; - - Application::getInstance()->pasteVoxels(sourceVoxel); -} - -void ClipboardScriptingInterface::deleteVoxel(const VoxelDetail& sourceVoxel) { - deleteVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); -} - -void ClipboardScriptingInterface::deleteVoxel(float x, float y, float z, float s) { - VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - s / (float)TREE_SCALE }; - Application::getInstance()->deleteVoxels(sourceVoxel); -} - -void ClipboardScriptingInterface::exportVoxel(const VoxelDetail& sourceVoxel) { - exportVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); -} - -void ClipboardScriptingInterface::exportVoxel(float x, float y, float z, float s) { - VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - s / (float)TREE_SCALE }; - - Application::getInstance()->exportVoxels(sourceVoxel); -} - -bool ClipboardScriptingInterface::importVoxels() { - qDebug() << "Importing ... "; - QEventLoop loop; - connect(Application::getInstance(), SIGNAL(importDone()), &loop, SLOT(quit())); - emit readyToImport(); - loop.exec(); - - return Application::getInstance()->getImportSucceded(); -} - -bool ClipboardScriptingInterface::importVoxels(const QString& filename) { - qDebug() << "Importing ... "; - - VoxelImporter* importer = Application::getInstance()->getVoxelImporter(); - - if (!importer->validImportFile(filename)) { - return false; - } - - QEventLoop loop; - connect(importer, SIGNAL(importDone()), &loop, SLOT(quit())); - importer->import(filename); - loop.exec(); - - return true; -} - -bool ClipboardScriptingInterface::importVoxels(const QString& filename, float x, float y, float z, float s) { - bool success = importVoxels(filename); - - if (success) { - pasteVoxel(x, y, z, s); - } - - return success; -} - -bool ClipboardScriptingInterface::importVoxels(const QString& filename, const VoxelDetail& destinationVoxel) { - return importVoxels(filename, destinationVoxel.x, destinationVoxel.y, destinationVoxel.z, destinationVoxel.s); -} - -void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) { - nudgeVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s, nudgeVec); -} - -void ClipboardScriptingInterface::nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec) { - glm::vec3 nudgeVecInTreeSpace = nudgeVec / (float)TREE_SCALE; - VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - s / (float)TREE_SCALE }; - - Application::getInstance()->nudgeVoxelsByVector(sourceVoxel, nudgeVecInTreeSpace); -} - - bool ClipboardScriptingInterface::exportEntities(const QString& filename, float x, float y, float z, float s) { return Application::getInstance()->exportEntities(filename, x, y, z, s); } diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index 98afc8d6a1..bc270210dc 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -12,7 +12,6 @@ #define hifi_ClipboardScriptingInterface_h #include -#include class ClipboardScriptingInterface : public QObject { Q_OBJECT @@ -23,29 +22,6 @@ signals: void readyToImport(); public slots: - void cutVoxel(const VoxelDetail& sourceVoxel); - void cutVoxel(float x, float y, float z, float s); - - void copyVoxel(const VoxelDetail& sourceVoxel); - void copyVoxel(float x, float y, float z, float s); - - void pasteVoxel(const VoxelDetail& destinationVoxel); - void pasteVoxel(float x, float y, float z, float s); - - void deleteVoxel(const VoxelDetail& sourceVoxel); - void deleteVoxel(float x, float y, float z, float s); - - void exportVoxel(const VoxelDetail& sourceVoxel); - void exportVoxel(float x, float y, float z, float s); - - bool importVoxels(); - bool importVoxels(const QString& filename); - bool importVoxels(const QString& filename, float x, float y, float z, float s); - bool importVoxels(const QString& filename, const VoxelDetail& destinationVoxel); - - void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); - void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec); - bool importEntities(const QString& filename); bool exportEntities(const QString& filename, float x, float y, float z, float s); void pasteEntities(float x, float y, float z, float s); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 120c5b3043..24fbc35457 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -20,6 +20,7 @@ #include "ApplicationOverlay.h" #include "devices/OculusManager.h" +#include "Util.h" #include "ui/Stats.h" // Used to fade the UI diff --git a/interface/src/ui/NodeBounds.cpp b/interface/src/ui/NodeBounds.cpp index fe8a394fe4..a2688cba8e 100644 --- a/interface/src/ui/NodeBounds.cpp +++ b/interface/src/ui/NodeBounds.cpp @@ -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 nodes on the current domain, +// This class draws a border around the different 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,19 +21,17 @@ NodeBounds::NodeBounds(QObject* parent) : QObject(parent), - _showVoxelNodes(false), _showEntityNodes(false), _overlayText() { } void NodeBounds::draw() { - if (!(_showVoxelNodes || _showEntityNodes)) { + if (!_showEntityNodes) { _overlayText[0] = '\0'; return; } - NodeToJurisdictionMap& voxelServerJurisdictions = Application::getInstance()->getVoxelServerJurisdictions(); NodeToJurisdictionMap& entityServerJurisdictions = Application::getInstance()->getEntityServerJurisdictions(); NodeToJurisdictionMap* serverJurisdictions; @@ -54,9 +52,7 @@ void NodeBounds::draw() { nodeList->eachNode([&](const SharedNodePointer& node){ NodeType_t nodeType = node->getType(); - if (nodeType == NodeType::VoxelServer && _showVoxelNodes) { - serverJurisdictions = &voxelServerJurisdictions; - } else if (nodeType == NodeType::EntityServer && _showEntityNodes) { + if (nodeType == NodeType::EntityServer && _showEntityNodes) { serverJurisdictions = &entityServerJurisdictions; } else { return; @@ -81,7 +77,6 @@ void NodeBounds::draw() { glm::vec3 center = serverBounds.getVertex(BOTTOM_RIGHT_NEAR) + ((serverBounds.getVertex(TOP_LEFT_FAR) - serverBounds.getVertex(BOTTOM_RIGHT_NEAR)) / 2.0f); - const float VOXEL_NODE_SCALE = 1.00f; const float ENTITY_NODE_SCALE = 0.99f; float scaleFactor = rootDetails.s * TREE_SCALE; @@ -91,9 +86,7 @@ void NodeBounds::draw() { scaleFactor *= 0.92 + (rootDetails.s * 0.08); // Scale different node types slightly differently because it's common for them to overlap. - if (nodeType == NodeType::VoxelServer) { - scaleFactor *= VOXEL_NODE_SCALE; - } else if (nodeType == NodeType::EntityServer) { + if (nodeType == NodeType::EntityServer) { scaleFactor *= ENTITY_NODE_SCALE; } @@ -205,7 +198,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; + red = nodeType == 0.0; green = 0.0; blue = nodeType == NodeType::EntityServer ? 1.0 : 0.0; } diff --git a/interface/src/ui/NodeBounds.h b/interface/src/ui/NodeBounds.h index 39f98200d1..66255a6432 100644 --- a/interface/src/ui/NodeBounds.h +++ b/interface/src/ui/NodeBounds.h @@ -23,7 +23,6 @@ class NodeBounds : public QObject { public: NodeBounds(QObject* parent = NULL); - bool getShowVoxelNodes() { return _showVoxelNodes; } bool getShowEntityNodes() { return _showEntityNodes; } bool getShowParticleNodes() { return _showParticleNodes; } @@ -31,7 +30,6 @@ public: void drawOverlay(); public slots: - void setShowVoxelNodes(bool value) { _showVoxelNodes = value; } void setShowEntityNodes(bool value) { _showEntityNodes = value; } void setShowParticleNodes(bool value) { _showParticleNodes = value; } @@ -40,7 +38,6 @@ protected: void getColorForNodeType(NodeType_t nodeType, float& red, float& green, float& blue); private: - bool _showVoxelNodes; bool _showEntityNodes; bool _showParticleNodes; char _overlayText[MAX_OVERLAY_TEXT_LENGTH + 1]; diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index 403b8827bd..1980aa3ed6 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -49,7 +49,6 @@ OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* mo _serverVoxels = AddStatItem("Elements on Servers"); _localVoxels = AddStatItem("Local Elements"); _localVoxelsMemory = AddStatItem("Elements Memory"); - _voxelsRendered = AddStatItem("Voxels Rendered"); _sendingMode = AddStatItem("Sending Mode"); layout()->setSizeConstraint(QLayout::SetFixedSize); @@ -122,31 +121,15 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { // Update labels - VoxelSystem* voxels = Application::getInstance()->getVoxels(); QLabel* label; QLocale locale(QLocale::English); std::stringstream statsValue; statsValue.precision(4); - // Voxels Rendered - label = _labels[_voxelsRendered]; - statsValue << "Max: " << voxels->getMaxVoxels() / 1000.0f << "K " << - "Drawn: " << voxels->getVoxelsWritten() / 1000.0f << "K " << - "Abandoned: " << voxels->getAbandonedVoxels() / 1000.0f << "K " << - "ReadBuffer: " << voxels->getVoxelsRendered() / 1000.0f << "K " << - "Changed: " << voxels->getVoxelsUpdated() / 1000.0f << "K "; - label->setText(statsValue.str().c_str()); - - // Voxels Memory Usage + // Octree Elements Memory Usage label = _labels[_localVoxelsMemory]; statsValue.str(""); - statsValue << - "Elements RAM: " << OctreeElement::getTotalMemoryUsage() / 1000000.0f << "MB " - "Geometry RAM: " << voxels->getVoxelMemoryUsageRAM() / 1000000.0f << "MB " << - "VBO: " << voxels->getVoxelMemoryUsageVBO() / 1000000.0f << "MB "; - if (voxels->hasVoxelMemoryUsageGPU()) { - statsValue << "GPU: " << voxels->getVoxelMemoryUsageGPU() / 1000000.0f << "MB "; - } + statsValue << "Elements RAM: " << OctreeElement::getTotalMemoryUsage() / 1000000.0f << "MB "; label->setText(statsValue.str().c_str()); // Local Voxels @@ -227,8 +210,6 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { void OctreeStatsDialog::showAllOctreeServers() { int serverCount = 0; - showOctreeServersOfType(serverCount, NodeType::VoxelServer, "Voxel", - Application::getInstance()->getVoxelServerJurisdictions()); showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity", Application::getInstance()->getEntityServerJurisdictions()); diff --git a/interface/src/ui/OctreeStatsDialog.h b/interface/src/ui/OctreeStatsDialog.h index 2488667a09..2db1430d28 100644 --- a/interface/src/ui/OctreeStatsDialog.h +++ b/interface/src/ui/OctreeStatsDialog.h @@ -63,7 +63,6 @@ private: int _serverVoxels; int _localVoxels; int _localVoxelsMemory; - int _voxelsRendered; int _voxelServerLables[MAX_VOXEL_SERVERS]; int _voxelServerLabelsCount; details _extraServerDetails[MAX_VOXEL_SERVERS]; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 7baacd3d5a..b00d697a1c 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include "Application.h" #include "MainWindow.h" @@ -214,7 +215,6 @@ void PreferencesDialog::savePreferences() { myAvatar->setLeanScale(ui.leanScaleSpin->value()); myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value()); - Application::getInstance()->getVoxels()->setMaxVoxels(ui.maxVoxelsSpin->value()); GLCanvas::SharedPointer glCanvas = DependencyManager::get(); Application::getInstance()->resizeGL(glCanvas->width(), glCanvas->height()); diff --git a/interface/src/ui/ScriptEditorWidget.cpp b/interface/src/ui/ScriptEditorWidget.cpp index b55c753061..f4a509baa6 100644 --- a/interface/src/ui/ScriptEditorWidget.cpp +++ b/interface/src/ui/ScriptEditorWidget.cpp @@ -13,6 +13,7 @@ #include "ScriptEditorWidget.h" #include +#include #include #include #include diff --git a/interface/src/ui/ScriptEditorWindow.cpp b/interface/src/ui/ScriptEditorWindow.cpp index 895d725699..0496040724 100644 --- a/interface/src/ui/ScriptEditorWindow.cpp +++ b/interface/src/ui/ScriptEditorWindow.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "ui_scriptEditorWindow.h" #include "ScriptEditorWindow.h" #include "ScriptEditorWidget.h" diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index eced2d87fd..3881760a7e 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -471,8 +471,6 @@ void Stats::display( verticalOffset = 0; horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3; - VoxelSystem* voxels = Application::getInstance()->getVoxels(); - lines = _expanded ? 14 : 3; drawBackground(backgroundColor, horizontalOffset, 0, glCanvas->width() - horizontalOffset, @@ -510,38 +508,6 @@ void Stats::display( drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); } - voxelStats.str(""); - voxelStats.precision(4); - voxelStats << "Voxels Drawn: " << voxels->getVoxelsWritten() / 1000.0f << "K " << - "Abandoned: " << voxels->getAbandonedVoxels() / 1000.0f << "K "; - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); - - if (_expanded) { - // Local Voxel Memory Usage - voxelStats.str(""); - voxelStats << " Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.0f << "MB"; - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); - - voxelStats.str(""); - voxelStats << - " Geometry RAM: " << voxels->getVoxelMemoryUsageRAM() / 1000000.0f << "MB / " << - "VBO: " << voxels->getVoxelMemoryUsageVBO() / 1000000.0f << "MB"; - if (voxels->hasVoxelMemoryUsageGPU()) { - voxelStats << " / GPU: " << voxels->getVoxelMemoryUsageGPU() / 1000000.0f << "MB"; - } - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); - - // Voxel Rendering - voxelStats.str(""); - voxelStats.precision(4); - voxelStats << " Voxel Rendering Slots Max: " << voxels->getMaxVoxels() / 1000.0f << "K"; - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); - } - // iterate all the current voxel stats, and list their sending modes, and total voxel counts std::stringstream sendingMode(""); sendingMode << "Octree Sending Mode: ["; @@ -612,7 +578,7 @@ void Stats::display( } QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); - unsigned long localTotal = VoxelTreeElement::getNodeCount(); + unsigned long localTotal = OctreeElement::getNodeCount(); QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); // Server Octree Elements @@ -641,8 +607,8 @@ void Stats::display( drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); // Local Voxels - unsigned long localInternal = VoxelTreeElement::getInternalNodeCount(); - unsigned long localLeaves = VoxelTreeElement::getLeafNodeCount(); + unsigned long localInternal = OctreeElement::getInternalNodeCount(); + unsigned long localLeaves = OctreeElement::getLeafNodeCount(); QString localInternalString = locale.toString((uint)localInternal); QString localLeavesString = locale.toString((uint)localLeaves); diff --git a/interface/src/ui/VoxelImportDialog.cpp b/interface/src/ui/VoxelImportDialog.cpp deleted file mode 100644 index 930fed133d..0000000000 --- a/interface/src/ui/VoxelImportDialog.cpp +++ /dev/null @@ -1,362 +0,0 @@ -// -// VoxelImportDialog.cpp -// interface/src/ui -// -// Created by Clement Brisset 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 "InterfaceConfig.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include "Application.h" - -#include "VoxelImportDialog.h" -#include "voxels/VoxelImporter.h" - -const QString SETTINGS_GROUP_NAME = "VoxelImport"; -const QString IMPORT_DIALOG_SETTINGS_KEY = "VoxelImportDialogSettings"; - -const QString WINDOW_NAME = QObject::tr("Import Voxels"); -const QString IMPORT_BUTTON_NAME = QObject::tr("Import Voxels"); -const QString LOADING_BUTTON_NAME = QObject::tr("Loading ..."); -const QString PLACE_BUTTON_NAME = QObject::tr("Place voxels"); -const QString IMPORT_INFO = QObject::tr("Import %1 as voxels"); -const QString CANCEL_BUTTON_NAME = QObject::tr("Cancel"); - -const QString DOWNLOAD_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); -const int SHORT_FILE_EXTENSION = 4; -const int SECOND_INDEX_LETTER = 1; - -QIcon HiFiIconProvider::icon(QFileIconProvider::IconType type) const { - - // types - // Computer, Desktop, Trashcan, Network, Drive, Folder, File - QString typeString; - - switch (type) { - case QFileIconProvider::Computer: - typeString = "computer"; - break; - - case QFileIconProvider::Desktop: - typeString = "desktop"; - break; - - case QFileIconProvider::Trashcan: - case QFileIconProvider::Network: - case QFileIconProvider::Drive: - case QFileIconProvider::Folder: - typeString = "folder"; - break; - - default: - typeString = "file"; - break; - } - - return QIcon(PathUtils::resourcesPath() + "icons/" + typeString + ".svg"); -} - -QIcon HiFiIconProvider::icon(const QFileInfo &info) const { - const QString ext = info.suffix().toLower(); - - if (info.isDir()) { - if (info.absoluteFilePath() == QDir::homePath()) { - return QIcon(PathUtils::resourcesPath() + "icons/home.svg"); - } else if (info.absoluteFilePath() == QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)) { - return QIcon(PathUtils::resourcesPath() + "icons/desktop.svg"); - } else if (info.absoluteFilePath() == QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)) { - return QIcon(PathUtils::resourcesPath() + "icons/documents.svg"); - } - return QIcon(PathUtils::resourcesPath() + "icons/folder.svg"); - } - - QFileInfo iconFile(PathUtils::resourcesPath() + "icons/" + iconsMap[ext]); - if (iconFile.exists() && iconFile.isFile()) { - return QIcon(iconFile.filePath()); - } - - return QIcon(PathUtils::resourcesPath() + "icons/file.svg"); -} - -QString HiFiIconProvider::type(const QFileInfo &info) const { - if (info.isFile()) { - if (info.suffix().size() > SHORT_FILE_EXTENSION) { - // Capitalize extension - return info.suffix().left(SECOND_INDEX_LETTER).toUpper() + info.suffix().mid(SECOND_INDEX_LETTER); - } - return info.suffix().toUpper(); - } - - return QFileIconProvider::type(info); -} - -VoxelImportDialog::VoxelImportDialog(QWidget* parent) : - QFileDialog(parent, WINDOW_NAME, DOWNLOAD_LOCATION, NULL), - _cancelButton(CANCEL_BUTTON_NAME, this), - _importButton(IMPORT_BUTTON_NAME, this), - _importer(Application::getInstance()->getVoxelImporter()), - _mode(importMode), - _progressBar(this), - _didImport(false) { - - setOption(QFileDialog::DontUseNativeDialog, true); - setFileMode(QFileDialog::ExistingFile); - setViewMode(QFileDialog::Detail); - - setImportTypes(); - setLayout(); - - _progressBar.setRange(0, 100); - - connect(&_importButton, SIGNAL(pressed()), this, SLOT(accept())); - connect(&_cancelButton, SIGNAL(pressed()), this, SLOT(cancel())); - connect(this, SIGNAL(currentChanged(QString)), SLOT(saveCurrentFile(QString))); -} - -void VoxelImportDialog::cancel() { - switch (getMode()) { - case importMode: - _importer->cancel(); - close(); - break; - default: - _importer->reset(); - setMode(importMode); - break; - } - emit canceled(); -} - -void VoxelImportDialog::saveSettings(QSettings* settings) { - settings->beginGroup(SETTINGS_GROUP_NAME); - settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, saveState()); - settings->endGroup(); -} - -void VoxelImportDialog::loadSettings(QSettings* settings) { - settings->beginGroup(SETTINGS_GROUP_NAME); - restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray()); - settings->endGroup(); -} - -bool VoxelImportDialog::prompt() { - reset(); - exec(); - return _didImport; -} - -void VoxelImportDialog::reset() { - setMode(importMode); - _didImport = false; -} - -void VoxelImportDialog::setMode(dialogMode mode) { - dialogMode previousMode = _mode; - _mode = mode; - - switch (_mode) { - case importMode: - _progressBar.setValue(0); - _importButton.setEnabled(true); - _importButton.setText(IMPORT_BUTTON_NAME); - findChild("sidebar")->setEnabled(true); - findChild("treeView")->setEnabled(true); - findChild("backButton")->setEnabled(true); - findChild("forwardButton")->setEnabled(true); - findChild("toParentButton")->setEnabled(true); - break; - case loadingMode: - // Connect to VoxelImporter signals - connect(_importer, SIGNAL(importProgress(int)), this, SLOT(updateProgressBar(int))); - connect(_importer, SIGNAL(importDone()), this, SLOT(afterImport())); - - _importButton.setEnabled(false); - _importButton.setText(LOADING_BUTTON_NAME); - findChild("sidebar")->setEnabled(false); - findChild("treeView")->setEnabled(false); - findChild("backButton")->setEnabled(false); - findChild("forwardButton")->setEnabled(false); - findChild("toParentButton")->setEnabled(false); - break; - case finishedMode: - if (previousMode == loadingMode) { - // Disconnect from VoxelImporter signals - disconnect(_importer, SIGNAL(importProgress(int)), this, SLOT(setProgressBarValue(int))); - disconnect(_importer, SIGNAL(importDone()), this, SLOT(afterImport())); - } - setMode(importMode); - break; - } -} - -void VoxelImportDialog::setProgressBarValue(int value) { - _progressBar.setValue(value); -} - -void VoxelImportDialog::accept() { - if (getMode() == importMode) { - QString filename = getCurrentFile(); - - // If file is invalid we ignore the call - if (!_importer->validImportFile(filename)) { - return; - } - // Let's prepare the dialog window for import - setMode(loadingMode); - - _importer->import(filename); - } -} - -void VoxelImportDialog::afterImport() { - setMode(finishedMode); - _didImport = true; - close(); -} - -void VoxelImportDialog::saveCurrentFile(QString filename) { - _currentFile = QFileInfo(filename).isFile() ? filename : ""; -} - -void VoxelImportDialog::setLayout() { - QGridLayout* gridLayout = (QGridLayout*) layout(); - gridLayout->addWidget(&_progressBar, 2, 0, 2, 1); - gridLayout->addWidget(&_cancelButton, 2, 1, 2, 1); - gridLayout->addWidget(&_importButton, 2, 2, 2, 1); - - // set ObjectName used in qss for styling - _progressBar.setObjectName("progressBar"); - _importButton.setObjectName("importButton"); - _cancelButton.setObjectName("cancelButton"); - - // set fixed size - _importButton.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _cancelButton.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _cancelButton.setFlat(true); - int progressBarHeight = 7; - _progressBar.setFixedHeight(progressBarHeight); - _progressBar.setTextVisible(false); - - QGridLayout* subLayout = new QGridLayout(); - subLayout->addWidget(findChild("lookInLabel"), 0, 0, 1, 5); - - QSize BUTTON_SIZE = QSize(43, 33); - QPushButton* button = (QPushButton*) findChild("backButton"); - button->setIcon(QIcon()); - button->setFixedSize(BUTTON_SIZE); - subLayout->addWidget(button, 1, 0, 1, 1); - - button = (QPushButton*) findChild("forwardButton"); - button->setIcon(QIcon()); - button->setFixedSize(BUTTON_SIZE); - subLayout->addWidget(button, 1, 1, 1, 1); - - button = (QPushButton*) findChild("toParentButton"); - button->setIcon(QIcon()); - button->setFixedSize(BUTTON_SIZE); - subLayout->addWidget(button, 1, 2, 1, 1); - - gridLayout->addLayout(subLayout, 0, 0, 1, 1); - - // hide unused embedded widgets in QFileDialog - QWidget* widget = findChild("lookInCombo"); - widget->hide(); - - widget = findChild("newFolderButton"); - widget->hide(); - - widget = findChild("listModeButton"); - widget->hide(); - - widget = findChild("detailModeButton"); - widget->hide(); - - widget = findChild("fileNameEdit"); - widget->hide(); - - widget = findChild("fileTypeCombo"); - widget->hide(); - - widget = findChild("fileTypeLabel"); - widget->hide(); - - widget = findChild("fileNameLabel"); - widget->hide(); - - widget = findChild("buttonBox"); - widget->hide(); - - QSplitter* splitter = findChild("splitter"); - splitter->setHandleWidth(0); - - // remove blue outline on Mac - widget = findChild("sidebar"); - widget->setAttribute(Qt::WA_MacShowFocusRect, false); - - widget = findChild("treeView"); - widget->setAttribute(Qt::WA_MacShowFocusRect, false); - - QFile styleSheet(PathUtils::resourcesPath() + "styles/import_dialog.qss"); - if (styleSheet.open(QIODevice::ReadOnly)) { - QDir::setCurrent(PathUtils::resourcesPath()); - setStyleSheet(styleSheet.readAll()); - } - -} - -void VoxelImportDialog::setImportTypes() { - QFile config(PathUtils::resourcesPath() + "config/config.json"); - config.open(QFile::ReadOnly | QFile::Text); - QJsonDocument document = QJsonDocument::fromJson(config.readAll()); - if (!document.isNull() && !document.isEmpty()) { - - QString importFormatsInfo; - QString importFormatsFilterList; - QHash iconsMap; - - QJsonObject configObject = document.object(); - if (!configObject.isEmpty()) { - QJsonArray fileFormats = configObject["importFormats"].toArray(); - int formatsCounter = 0; - foreach (const QJsonValue& fileFormat, fileFormats) { - QJsonObject fileFormatObject = fileFormat.toObject(); - - QString ext(fileFormatObject["extension"].toString()); - QString icon(fileFormatObject.value("icon").toString()); - - if (formatsCounter > 0) { - importFormatsInfo.append(","); - } - - // set ' or' on last import type text - if (formatsCounter == fileFormats.count() - 1) { - importFormatsInfo.append(" or"); - } - - importFormatsFilterList.append(QString("*.%1 ").arg(ext)); - importFormatsInfo.append(" .").append(ext); - iconsMap[ext] = icon; - formatsCounter++; - } - } - - // set custom file icons - setIconProvider(new HiFiIconProvider(iconsMap)); - setNameFilter(importFormatsFilterList); - - setLabelText(QFileDialog::LookIn, QString(IMPORT_INFO).arg(importFormatsInfo)); - } -} diff --git a/interface/src/ui/VoxelImportDialog.h b/interface/src/ui/VoxelImportDialog.h deleted file mode 100644 index 54faf7449a..0000000000 --- a/interface/src/ui/VoxelImportDialog.h +++ /dev/null @@ -1,81 +0,0 @@ -// -// VoxelImportDialog.h -// interface/src/ui -// -// Created by Clement Brisset 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_VoxelImportDialog_h -#define hifi_VoxelImportDialog_h - -#include "InterfaceConfig.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include "voxels/VoxelImporter.h" - -class HiFiIconProvider : public QFileIconProvider { -public: - HiFiIconProvider(const QHash map) { iconsMap = map; }; - virtual QIcon icon(IconType type) const; - virtual QIcon icon(const QFileInfo &info) const; - virtual QString type(const QFileInfo &info) const; - QHash iconsMap; -}; - -enum dialogMode { - importMode, - loadingMode, - finishedMode -}; - -class VoxelImportDialog : public QFileDialog { - Q_OBJECT - -public: - VoxelImportDialog(QWidget* parent = NULL); - - QString getCurrentFile() const { return _currentFile; } - dialogMode getMode() const { return _mode; } - - void setMode(dialogMode mode); - void reset(); - bool prompt(); - void loadSettings(QSettings* settings); - void saveSettings(QSettings* settings); - -signals: - void canceled(); - -private slots: - void setProgressBarValue(int value); - void accept(); - void cancel(); - void saveCurrentFile(QString filename); - void afterImport(); - -private: - QPushButton _cancelButton; - QString _currentFile; - QPushButton _importButton; - VoxelImporter* _importer; - dialogMode _mode; - QProgressBar _progressBar; - bool _didImport; - - void setLayout(); - void setImportTypes(); -}; - -#endif // hifi_VoxelImportDialog_h diff --git a/interface/src/ui/overlays/LocalVoxelsOverlay.cpp b/interface/src/ui/overlays/LocalVoxelsOverlay.cpp deleted file mode 100644 index b3dac02468..0000000000 --- a/interface/src/ui/overlays/LocalVoxelsOverlay.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// -// LocalVoxelsOverlay.cpp -// interface/src/ui/overlays -// -// Created by Clément Brisset on 2/28/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 this before QGLWidget, which includes an earlier version of OpenGL -#include "InterfaceConfig.h" - -#include -#include - -#include - -#include "Application.h" -#include "LocalVoxelsOverlay.h" -#include "voxels/VoxelSystem.h" - -QMap LocalVoxelsOverlay::_voxelSystemMap; - -LocalVoxelsOverlay::LocalVoxelsOverlay() : - Volume3DOverlay(), - _voxelCount(0) -{ -} - -LocalVoxelsOverlay::LocalVoxelsOverlay(const LocalVoxelsOverlay* localVoxelsOverlay) : - Volume3DOverlay(localVoxelsOverlay), - _voxelCount(localVoxelsOverlay->_voxelCount) -{ -} - -LocalVoxelsOverlay::~LocalVoxelsOverlay() { - _voxelSystem->changeTree(new VoxelTree()); - _voxelSystem.clear(); - if (_voxelSystemMap.value(_treeName).isNull()) { - _voxelSystemMap.remove(_treeName); - } - _tree.clear(); - LocalVoxelsList::getInstance()->remove(_treeName); -} - -void LocalVoxelsOverlay::update(float deltatime) { - if (!_voxelSystem->isInitialized()) { - _voxelSystem->init(); - } - - _tree->lockForRead(); - if (_visible && _voxelCount != _tree->getOctreeElementsCount()) { - _voxelCount = _tree->getOctreeElementsCount(); - _voxelSystem->forceRedrawEntireTree(); - } - _tree->unlock(); -} - -void LocalVoxelsOverlay::render(RenderArgs* args) { - glm::vec3 dimensions = getDimensions(); - float size = glm::length(dimensions); - if (_visible && size > 0 && _voxelSystem && _voxelSystem->isInitialized()) { - - float glowLevel = getGlowLevel(); - Glower* glower = NULL; - if (glowLevel > 0.0f) { - glower = new Glower(glowLevel); - } - - glPushMatrix(); { - glTranslatef(_position.x, _position.y, _position.z); - glScalef(dimensions.x, dimensions.y, dimensions.z); - _voxelSystem->render(); - } glPopMatrix(); - - if (glower) { - delete glower; - } - } -} - -void LocalVoxelsOverlay::setProperties(const QScriptValue &properties) { - Volume3DOverlay::setProperties(properties); - - if (properties.property("scale").isValid()) { - setSize(properties.property("scale").toVariant().toFloat()); - } - - QScriptValue treeName = properties.property("name"); - if (treeName.isValid()) { - if ((_treeName = treeName.toString()) == DOMAIN_TREE_NAME) { - qDebug() << "addOverlay(): Can't create overlay from domain tree"; - return; - } - _tree = LocalVoxelsList::getInstance()->getTree(_treeName); - if (_tree.isNull()) { - qDebug() << "addOverlay(): Invalid tree name"; - return; - } - - _voxelSystem = _voxelSystemMap[_treeName]; - if (_voxelSystem.isNull()) { - _voxelSystem = StrongVoxelSystemPointer(new VoxelSystem(1, - DEFAULT_MAX_VOXELS_PER_SYSTEM, - _tree.data())); - _voxelSystemMap.insert(_treeName, _voxelSystem); - } - } -} - -LocalVoxelsOverlay* LocalVoxelsOverlay::createClone() const { - return new LocalVoxelsOverlay(this); -} - -QScriptValue LocalVoxelsOverlay::getProperty(const QString& property) { - if (property == "scale") { - return vec3toScriptValue(_scriptEngine, getDimensions()); - } - if (property == "name") { - return _treeName; - } - - return Volume3DOverlay::getProperty(property); -} - diff --git a/interface/src/ui/overlays/LocalVoxelsOverlay.h b/interface/src/ui/overlays/LocalVoxelsOverlay.h deleted file mode 100644 index 4afa44f9be..0000000000 --- a/interface/src/ui/overlays/LocalVoxelsOverlay.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// LocalVoxelsOverlay.h -// interface/src/ui/overlays -// -// Created by Clément Brisset on 2/28/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_LocalVoxelsOverlay_h -#define hifi_LocalVoxelsOverlay_h - -// include this before QGLWidget, which includes an earlier version of OpenGL -#include "InterfaceConfig.h" - -#include -#include -#include -#include -#include - -#include - -#include "Volume3DOverlay.h" - -typedef QSharedPointer StrongVoxelSystemPointer; -typedef QWeakPointer WeakVoxelSystemPointer; - -class LocalVoxelsOverlay : public Volume3DOverlay { - Q_OBJECT -public: - LocalVoxelsOverlay(); - LocalVoxelsOverlay(const LocalVoxelsOverlay* localVoxelsOverlay); - ~LocalVoxelsOverlay(); - - virtual void update(float deltatime); - virtual void render(RenderArgs* args); - - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); - - virtual LocalVoxelsOverlay* createClone() const; -private: - static QMap _voxelSystemMap; // treeName/voxelSystem - - QString _treeName; - StrongVoxelTreePointer _tree; // so that the tree doesn't get freed - unsigned long _voxelCount; - StrongVoxelSystemPointer _voxelSystem; -}; - -#endif // hifi_LocalVoxelsOverlay_h diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index ace4ecf353..46be62649b 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -21,7 +21,6 @@ #include "ImageOverlay.h" #include "Line3DOverlay.h" #include "LocalModelsOverlay.h" -#include "LocalVoxelsOverlay.h" #include "ModelOverlay.h" #include "Overlays.h" #include "Rectangle3DOverlay.h" @@ -166,8 +165,6 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope thisOverlay = new Line3DOverlay(); } else if (type == "grid") { thisOverlay = new Grid3DOverlay(); - } else if (type == "localvoxels") { - thisOverlay = new LocalVoxelsOverlay(); } else if (type == "localmodels") { thisOverlay = new LocalModelsOverlay(Application::getInstance()->getEntityClipboardRenderer()); } else if (type == "model") { diff --git a/interface/src/voxels/OctreePacketProcessor.cpp b/interface/src/voxels/OctreePacketProcessor.cpp index 9f53492e70..cae38834f7 100644 --- a/interface/src/voxels/OctreePacketProcessor.cpp +++ b/interface/src/voxels/OctreePacketProcessor.cpp @@ -32,12 +32,6 @@ void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, bool wasStatsPacket = false; - // check to see if the UI thread asked us to kill the voxel tree. since we're the only thread allowed to do that - if (app->_wantToKillLocalVoxels) { - app->_voxels.killLocalVoxels(); - app->_wantToKillLocalVoxels = false; - } - PacketType voxelPacketType = packetTypeForPacket(mutablePacket); // note: PacketType_OCTREE_STATS can have PacketType_VOXEL_DATA @@ -80,7 +74,7 @@ void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, } - app->trackIncomingVoxelPacket(mutablePacket, sendingNode, wasStatsPacket); + app->trackIncomingOctreePacket(mutablePacket, sendingNode, wasStatsPacket); if (sendingNode) { @@ -101,12 +95,8 @@ void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, app->_environment.parseData(*sendingNode->getActiveSocket(), mutablePacket); } break; - default : { - if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { - app->_voxels.setDataSourceUUID(sendingNode->getUUID()); - app->_voxels.parseData(mutablePacket); - app->_voxels.setDataSourceUUID(QUuid()); - } + default: { + // nothing to do } break; } } diff --git a/interface/src/voxels/VoxelHideShowThread.cpp b/interface/src/voxels/VoxelHideShowThread.cpp deleted file mode 100644 index 089da0d1da..0000000000 --- a/interface/src/voxels/VoxelHideShowThread.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// -// VoxelHideShowThread.cpp -// interface/src/voxels -// -// Created by Brad Hefta-Gaub on 12/1/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 -#include -#include -#include - -#include "Application.h" -#include "VoxelHideShowThread.h" - -VoxelHideShowThread::VoxelHideShowThread(VoxelSystem* theSystem) : - _theSystem(theSystem) { -} - -bool VoxelHideShowThread::process() { - const quint64 MSECS_TO_USECS = 1000; - const quint64 SECS_TO_USECS = 1000 * MSECS_TO_USECS; - const quint64 FRAME_RATE = 60; - const quint64 USECS_PER_FRAME = SECS_TO_USECS / FRAME_RATE; // every 60fps - - quint64 start = usecTimestampNow(); - _theSystem->checkForCulling(); - quint64 end = usecTimestampNow(); - quint64 elapsed = end - start; - - bool showExtraDebugging = Application::getInstance()->getLogger()->extraDebugging(); - if (showExtraDebugging && elapsed > USECS_PER_FRAME) { - qDebug() << "VoxelHideShowThread::process()... checkForCulling took" << elapsed; - } - - if (isStillRunning()) { - if (elapsed < USECS_PER_FRAME) { - quint64 sleepFor = USECS_PER_FRAME - elapsed; - usleep(sleepFor); - } - } - return isStillRunning(); // keep running till they terminate us -} diff --git a/interface/src/voxels/VoxelHideShowThread.h b/interface/src/voxels/VoxelHideShowThread.h deleted file mode 100644 index 6aa3c108ba..0000000000 --- a/interface/src/voxels/VoxelHideShowThread.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// VoxelHideShowThread.h -// interface/src/voxels -// -// Created by Brad Hefta-Gaub on 12/1/13. -// Copyright 2013 High Fidelity, Inc. -// -// Threaded or non-threaded voxel persistence -// -// 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_VoxelHideShowThread_h -#define hifi_VoxelHideShowThread_h - -#include -#include "VoxelSystem.h" - -/// Generalized threaded processor for handling received inbound packets. -class VoxelHideShowThread : public GenericThread { - Q_OBJECT -public: - - VoxelHideShowThread(VoxelSystem* theSystem); - -protected: - /// Implements generic processing behavior for this thread. - virtual bool process(); - -private: - VoxelSystem* _theSystem; -}; - -#endif // hifi_VoxelHideShowThread_h diff --git a/interface/src/voxels/VoxelImporter.cpp b/interface/src/voxels/VoxelImporter.cpp deleted file mode 100644 index b713813fb0..0000000000 --- a/interface/src/voxels/VoxelImporter.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// -// VoxelImporter.cpp -// interface/src/voxels -// -// Created by Clement Brisset on 8/9/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 this before QGLWidget, which includes an earlier version of OpenGL -#include "InterfaceConfig.h" - -#include -#include - -#include -#include - -#include "voxels/VoxelImporter.h" - -const QStringList SUPPORTED_EXTENSIONS = QStringList() << "png" << "svo" << "schematic"; - -class ImportTask : public QObject, public QRunnable { -public: - ImportTask(const QString &filename); - void run(); - -private: - QString _filename; -}; - -VoxelImporter::VoxelImporter() : - _voxelTree(true), - _task(NULL) -{ - LocalVoxelsList::getInstance()->addPersistantTree(IMPORT_TREE_NAME, &_voxelTree); - - connect(&_voxelTree, SIGNAL(importProgress(int)), this, SIGNAL(importProgress(int))); -} - -VoxelImporter::~VoxelImporter() { - cleanupTask(); -} - -void VoxelImporter::cancel() { - if (_task) { - disconnect(_task, 0, 0, 0); - } - reset(); -} - -void VoxelImporter::reset() { - _voxelTree.eraseAllOctreeElements(); - cleanupTask(); -} - -void VoxelImporter::import(const QString& filename) { - // If present, abort existing import - if (_task) { - cleanupTask(); - } - - // If not already done, we switch to the local tree - if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) { - Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree); - } - - // Creation and launch of the import task on the thread pool - _task = new ImportTask(filename); - connect(_task, SIGNAL(destroyed()), SLOT(finishImport())); - QThreadPool::globalInstance()->start(_task); -} - -void VoxelImporter::cleanupTask() { - // If a task is running, we cancel it and put the pointer to null - if (_task) { - _task = NULL; - _voxelTree.cancelImport(); - } -} - -void VoxelImporter::finishImport() { - cleanupTask(); - emit importDone(); -} - -bool VoxelImporter::validImportFile(const QString& filename) { - QFileInfo fileInfo = QFileInfo(filename); - return fileInfo.isFile() && SUPPORTED_EXTENSIONS.indexOf(fileInfo.suffix().toLower()) != -1; -} - -ImportTask::ImportTask(const QString &filename) - : _filename(filename) -{ - setAutoDelete(true); -} - -void ImportTask::run() { - VoxelSystem* voxelSystem = Application::getInstance()->getSharedVoxelSystem(); - // We start by cleaning up the shared voxel system just in case - voxelSystem->killLocalVoxels(); - - // Then we call the right method for the job - if (_filename.endsWith(".png", Qt::CaseInsensitive)) { - voxelSystem->getTree()->readFromSquareARGB32Pixels(_filename.toLocal8Bit().data()); - } else if (_filename.endsWith(".svo", Qt::CaseInsensitive)) { - voxelSystem->getTree()->readFromSVOFile(_filename.toLocal8Bit().data()); - } else if (_filename.endsWith(".schematic", Qt::CaseInsensitive)) { - voxelSystem->getTree()->readFromSchematicFile(_filename.toLocal8Bit().data()); - } else { - // We should never get here. - qDebug() << "[ERROR] Invalid file extension." << endl; - } - - // Here we reaverage the tree so that it is ready for preview - voxelSystem->getTree()->reaverageOctreeElements(); -} diff --git a/interface/src/voxels/VoxelImporter.h b/interface/src/voxels/VoxelImporter.h deleted file mode 100644 index 21ebbeea2e..0000000000 --- a/interface/src/voxels/VoxelImporter.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// VoxelImporter.h -// interface/src/voxels -// -// Created by Clement Brisset on 8/9/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_VoxelImporter_h -#define hifi_VoxelImporter_h - -#include -#include -#include - -#include "voxels/VoxelSystem.h" - -class ImportTask; - -class VoxelImporter : public QObject { - Q_OBJECT -public: - VoxelImporter(); - ~VoxelImporter(); - - void reset(); - void cancel(); - VoxelTree* getVoxelTree() { return &_voxelTree; } - bool validImportFile(const QString& filename); - -public slots: - void import(const QString& filename); - -signals: - void importDone(); - void importProgress(int); - -private: - VoxelTree _voxelTree; - ImportTask* _task; - - void cleanupTask(); - -private slots: - void finishImport(); -}; - -#endif // hifi_VoxelImporter_h diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp deleted file mode 100644 index 114b6ba481..0000000000 --- a/interface/src/voxels/VoxelSystem.cpp +++ /dev/null @@ -1,1661 +0,0 @@ -// -// VoxelSystem.cpp -// interface/src/voxels -// -// Created by Philip on 12/31/12. -// Copyright 2012 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 -#include -#include // to load voxels from file -#include // to load voxels from file - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "Application.h" -#include "Menu.h" -#include "VoxelConstants.h" -#include "VoxelSystem.h" - -const bool VoxelSystem::DONT_BAIL_EARLY = false; - -float identityVerticesGlobalNormals[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 }; - -float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, //0-7 - 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, //8-15 - 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 }; // 16-23 - -GLfloat identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1, - 0,0,+1, 0,0,+1, 0,0,+1, 0,0,+1, - 0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0, - 0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0, - -1,0,0, +1,0,0, +1,0,0, -1,0,0, - -1,0,0, +1,0,0, +1,0,0, -1,0,0 }; - -GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- - 8,9,13, 8,13,12, // Y- - 16,23,19, 16,20,23, // X- - 17,18,22, 17,22,21, // X+ - 10,11,15, 10,15,14, // Y+ - 4,5,6, 4,6,7 }; // Z+ - -GLubyte identityIndicesTop[] = { 2, 3, 7, 2, 7, 6 }; -GLubyte identityIndicesBottom[] = { 0, 1, 5, 0, 5, 4 }; -GLubyte identityIndicesLeft[] = { 0, 7, 3, 0, 4, 7 }; -GLubyte identityIndicesRight[] = { 1, 2, 6, 1, 6, 5 }; -GLubyte identityIndicesFront[] = { 0, 2, 1, 0, 3, 2 }; -GLubyte identityIndicesBack[] = { 4, 5, 6, 4, 6, 7 }; - -static glm::vec3 grayColor = glm::vec3(0.3f, 0.3f, 0.3f); - -VoxelSystem::VoxelSystem(float treeScale, int maxVoxels, VoxelTree* tree) - : NodeData(), - _treeScale(treeScale), - _maxVoxels(maxVoxels), - _initialized(false), - _writeArraysLock(QReadWriteLock::Recursive), - _readArraysLock(QReadWriteLock::Recursive), - _drawHaze(false), - _farHazeDistance(300.0f), - _hazeColor(grayColor) -{ - - _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; - _writeRenderFullVBO = true; - _readRenderFullVBO = true; - _tree = (tree) ? tree : new VoxelTree(); - - _tree->getRoot()->setVoxelSystem(this); - - VoxelTreeElement::addDeleteHook(this); - VoxelTreeElement::addUpdateHook(this); - _falseColorizeBySource = false; - _dataSourceUUID = QUuid(); - _voxelServerCount = 0; - - _viewFrustum = Application::getInstance()->getViewFrustum(); - - _readVerticesArray = NULL; - _writeVerticesArray = NULL; - _readColorsArray = NULL; - _writeColorsArray = NULL; - _writeVoxelDirtyArray = NULL; - _readVoxelDirtyArray = NULL; - - _inSetupNewVoxelsForDrawing = false; - _useFastVoxelPipeline = false; - - _culledOnce = false; - _inhideOutOfView = false; - - _lastKnownVoxelSizeScale = DEFAULT_OCTREE_SIZE_SCALE; - _lastKnownBoundaryLevelAdjust = 0; -} - -void VoxelSystem::elementDeleted(OctreeElement* element) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - if (voxel->getVoxelSystem() == this) { - if ((_voxelsInWriteArrays != 0)) { - forceRemoveNodeFromArrays(voxel); - } else { - if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { - qDebug("VoxelSystem::elementDeleted() while _voxelsInWriteArrays==0, is that expected? "); - } - } - } -} - -void VoxelSystem::setDisableFastVoxelPipeline(bool disableFastVoxelPipeline) { - _useFastVoxelPipeline = !disableFastVoxelPipeline; - setupNewVoxelsForDrawing(); -} - -void VoxelSystem::elementUpdated(OctreeElement* element) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - - // If we're in SetupNewVoxelsForDrawing() or _writeRenderFullVBO then bail.. - if (!_useFastVoxelPipeline || _inSetupNewVoxelsForDrawing || _writeRenderFullVBO) { - return; - } - - if (voxel->getVoxelSystem() == this) { - bool shouldRender = false; // assume we don't need to render it - // if it's colored, we might need to render it! - float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale(); - int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); - shouldRender = voxel->calculateShouldRender(_viewFrustum, voxelSizeScale, boundaryLevelAdjust); - - if (voxel->getShouldRender() != shouldRender) { - voxel->setShouldRender(shouldRender); - } - - if (!voxel->isLeaf()) { - - // As we check our children, see if any of them went from shouldRender to NOT shouldRender - // then we probably dropped LOD and if we don't have color, we want to average our children - // for a new color. - int childrenGotHiddenCount = 0; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - VoxelTreeElement* childVoxel = voxel->getChildAtIndex(i); - if (childVoxel) { - bool wasShouldRender = childVoxel->getShouldRender(); - bool isShouldRender = childVoxel->calculateShouldRender(_viewFrustum, voxelSizeScale, boundaryLevelAdjust); - if (wasShouldRender && !isShouldRender) { - childrenGotHiddenCount++; - } - } - } - if (childrenGotHiddenCount > 0) { - voxel->calculateAverageFromChildren(); - } - } - - const bool REUSE_INDEX = true; - const bool DONT_FORCE_REDRAW = false; - updateNodeInArrays(voxel, REUSE_INDEX, DONT_FORCE_REDRAW); - _voxelsUpdated++; - - voxel->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. - - setupNewVoxelsForDrawingSingleNode(); - } -} - -// returns an available index, starts by reusing a previously freed index, but if there isn't one available -// it will use the end of the VBO array and grow our accounting of that array. -// and makes the index available for some other node to use -glBufferIndex VoxelSystem::getNextBufferIndex() { - glBufferIndex output = GLBUFFER_INDEX_UNKNOWN; - // if there's a free index, use it... - if (_freeIndexes.size() > 0) { - _freeIndexLock.lock(); - output = _freeIndexes.back(); - _freeIndexes.pop_back(); - _freeIndexLock.unlock(); - } else { - output = _voxelsInWriteArrays; - _voxelsInWriteArrays++; - } - return output; -} - -// Release responsibility of the buffer/vbo index from the VoxelTreeElement, and makes the index available for some other node to use -// will also "clean up" the index data for the buffer/vbo slot, so that if it's in the middle of the draw range, the triangles -// will be "invisible" -void VoxelSystem::freeBufferIndex(glBufferIndex index) { - if (_voxelsInWriteArrays == 0) { - qDebug() << "freeBufferIndex() called when _voxelsInWriteArrays == 0!"; - } - - // make the index available for next node that needs to be drawn - _freeIndexLock.lock(); - _freeIndexes.push_back(index); - _freeIndexLock.unlock(); - - // make the VBO slot "invisible" in case this slot is not used - const glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); - const float voxelScale = 0; - const nodeColor BLACK = {0, 0, 0, 0}; - updateArraysDetails(index, startVertex, voxelScale, BLACK); -} - -// This will run through the list of _freeIndexes and reset their VBO array values to be "invisible". -void VoxelSystem::clearFreeBufferIndexes() { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "clearFreeBufferIndexes()"); - _voxelsInWriteArrays = 0; // reset our VBO - - // clear out freeIndexes - { - PerformanceWarning warn(showWarnings,"clearFreeBufferIndexes() : _freeIndexLock.lock()"); - _freeIndexLock.lock(); - } - { - PerformanceWarning warn(showWarnings,"clearFreeBufferIndexes() : _freeIndexes.clear()"); - _freeIndexes.clear(); - } - _freeIndexLock.unlock(); -} - -VoxelSystem::~VoxelSystem() { - VoxelTreeElement::removeDeleteHook(this); - VoxelTreeElement::removeUpdateHook(this); - - cleanupVoxelMemory(); - delete _tree; -} - - -// This is called by the main application thread on both the initialization of the application and when -// the preferences dialog box is called/saved -void VoxelSystem::setMaxVoxels(unsigned long maxVoxels) { - if (maxVoxels == _maxVoxels) { - return; - } - bool wasInitialized = _initialized; - if (wasInitialized) { - clearAllNodesBufferIndex(); - cleanupVoxelMemory(); - } - _maxVoxels = maxVoxels; - if (wasInitialized) { - initVoxelMemory(); - } - if (wasInitialized) { - forceRedrawEntireTree(); - } -} - -void VoxelSystem::cleanupVoxelMemory() { - if (_initialized) { - _readArraysLock.lockForWrite(); - _initialized = false; // no longer initialized - // Destroy glBuffers - glDeleteBuffers(1, &_vboVerticesID); - glDeleteBuffers(1, &_vboColorsID); - - glDeleteBuffers(1, &_vboIndicesTop); - glDeleteBuffers(1, &_vboIndicesBottom); - glDeleteBuffers(1, &_vboIndicesLeft); - glDeleteBuffers(1, &_vboIndicesRight); - glDeleteBuffers(1, &_vboIndicesFront); - glDeleteBuffers(1, &_vboIndicesBack); - - delete[] _readVerticesArray; - delete[] _writeVerticesArray; - delete[] _readColorsArray; - delete[] _writeColorsArray; - - _readVerticesArray = NULL; - _writeVerticesArray = NULL; - _readColorsArray = NULL; - _writeColorsArray = NULL; - - delete[] _writeVoxelDirtyArray; - delete[] _readVoxelDirtyArray; - _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL; - _readArraysLock.unlock(); - - } -} - -void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]) { - GLuint* indicesArray = new GLuint[INDICES_PER_FACE * _maxVoxels]; - - // populate the indicesArray - // this will not change given new voxels, so we can set it all up now - for (unsigned long n = 0; n < _maxVoxels; n++) { - // fill the indices array - int voxelIndexOffset = n * INDICES_PER_FACE; - GLuint* currentIndicesPos = indicesArray + voxelIndexOffset; - int startIndex = (n * GLOBAL_NORMALS_VERTICES_PER_VOXEL); - - for (int i = 0; i < INDICES_PER_FACE; i++) { - // add indices for this side of the cube - currentIndicesPos[i] = startIndex + faceIdentityIndices[i]; - } - } - - glGenBuffers(1, &faceVBOID); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, faceVBOID); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - INDICES_PER_FACE * sizeof(GLuint) * _maxVoxels, - indicesArray, GL_STATIC_DRAW); - _memoryUsageVBO += INDICES_PER_FACE * sizeof(GLuint) * _maxVoxels; - - // delete the indices and normals arrays that are no longer needed - delete[] indicesArray; -} - -void VoxelSystem::initVoxelMemory() { - _readArraysLock.lockForWrite(); - _writeArraysLock.lockForWrite(); - - _memoryUsageRAM = 0; - _memoryUsageVBO = 0; // our VBO allocations as we know them - - // Global Normals mode uses a technique of not including normals on any voxel vertices, and instead - // rendering the voxel faces in 6 passes that use a global call to glNormal3f() - setupFaceIndices(_vboIndicesTop, identityIndicesTop); - setupFaceIndices(_vboIndicesBottom, identityIndicesBottom); - setupFaceIndices(_vboIndicesLeft, identityIndicesLeft); - setupFaceIndices(_vboIndicesRight, identityIndicesRight); - setupFaceIndices(_vboIndicesFront, identityIndicesFront); - setupFaceIndices(_vboIndicesBack, identityIndicesBack); - - // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel - int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; - glGenBuffers(1, &_vboVerticesID); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); - _memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels; - - // VBO for colorsArray - glGenBuffers(1, &_vboColorsID); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); - _memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels; - - // we will track individual dirty sections with these arrays of bools - _writeVoxelDirtyArray = new bool[_maxVoxels]; - memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); - _memoryUsageRAM += (sizeof(bool) * _maxVoxels); - - _readVoxelDirtyArray = new bool[_maxVoxels]; - memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); - _memoryUsageRAM += (sizeof(bool) * _maxVoxels); - - // prep the data structures for incoming voxel data - _writeVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels); - _readVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels); - - _writeColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels); - _readColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels); - - // create our simple fragment shader if we're the first system to init - if (!_program.isLinked()) { - _program.addShaderFromSourceFile(QGLShader::Vertex, - PathUtils::resourcesPath() + "shaders/voxel.vert"); - _program.addShaderFromSourceFile(QGLShader::Fragment, - PathUtils::resourcesPath() + "shaders/voxel.frag"); - _program.link(); - } - _initialized = true; - - _writeArraysLock.unlock(); - _readArraysLock.unlock(); - - // fog for haze - if (_drawHaze) { - GLfloat fogColor[] = {_hazeColor.x, _hazeColor.y, _hazeColor.z, 1.0f}; - glFogi(GL_FOG_MODE, GL_LINEAR); - glFogfv(GL_FOG_COLOR, fogColor); - glFogf(GL_FOG_START, 0.0f); - glFogf(GL_FOG_END, _farHazeDistance); - } -} - -int VoxelSystem::parseData(const QByteArray& packet) { - bool showTimingDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData()",showTimingDetails); - - PacketType command = packetTypeForPacket(packet); - int numBytesPacketHeader = numBytesForPacketHeader(packet); - switch(command) { - case PacketTypeVoxelData: { - PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData() PacketType_VOXEL_DATA part...",showTimingDetails); - - const unsigned char* dataAt = reinterpret_cast(packet.data()) + 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; - unsigned int dataBytes = packet.size() - (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_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) { - PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData() section"); - // 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 (Application::getInstance()->getLogger()->extraDebugging()) { - qDebug("VoxelSystem::parseData() ... Got Packet Section" - " color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%u" - " subsection:%d sectionLength:%d uncompressed:%d", - debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), - sequence, flightTime, packet.size(), dataBytes, subsection, sectionLength, - packetData.getUncompressedSize()); - } - _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); - _tree->unlock(); - - dataBytes -= sectionLength; - dataAt += sectionLength; - } - } - subsection++; - } - default: - break; - } - if (!_useFastVoxelPipeline || _writeRenderFullVBO) { - setupNewVoxelsForDrawing(); - } else { - setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); - } - - Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::VOXELS).updateValue(packet.size()); - - return packet.size(); -} - -void VoxelSystem::setupNewVoxelsForDrawing() { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "setupNewVoxelsForDrawing()"); - - if (!_initialized) { - return; // bail early if we're not initialized - } - - quint64 start = usecTimestampNow(); - quint64 sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; - - bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging - if (!iAmDebugging && sinceLastTime <= std::max((float) _setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { - return; // bail early, it hasn't been long enough since the last time we ran - } - - _inSetupNewVoxelsForDrawing = true; - - bool didWriteFullVBO = _writeRenderFullVBO; - if (_tree->isDirty()) { - static char buffer[64] = { 0 }; - if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { - sprintf(buffer, "newTreeToArrays() _writeRenderFullVBO=%s", debug::valueOf(_writeRenderFullVBO)); - }; - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); - _callsToTreesToArrays++; - - if (_writeRenderFullVBO) { - clearFreeBufferIndexes(); - } - _voxelsUpdated = newTreeToArrays(_tree->getRoot()); - _tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean - - _writeRenderFullVBO = false; - } else { - _voxelsUpdated = 0; - } - - // lock on the buffer write lock so we can't modify the data when the GPU is reading it - _readArraysLock.lockForWrite(); - - if (_voxelsUpdated) { - _voxelsDirty=true; - } - - // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated - copyWrittenDataToReadArrays(didWriteFullVBO); - _readArraysLock.unlock(); - - quint64 end = usecTimestampNow(); - int elapsedmsec = (end - start) / 1000; - _setupNewVoxelsForDrawingLastFinished = end; - _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; - _inSetupNewVoxelsForDrawing = false; - - bool extraDebugging = Application::getInstance()->getLogger()->extraDebugging(); - if (extraDebugging) { - qDebug("setupNewVoxelsForDrawing()... _voxelsUpdated=%lu...",_voxelsUpdated); - _viewFrustum->printDebugDetails(); - } -} - -void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "setupNewVoxelsForDrawingSingleNode() xxxxx"); - - quint64 start = usecTimestampNow(); - quint64 sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; - - bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging - if (allowBailEarly && !iAmDebugging && - sinceLastTime <= std::max((float) _setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { - return; // bail early, it hasn't been long enough since the last time we ran - } - - // lock on the buffer write lock so we can't modify the data when the GPU is reading it - { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" ); - _readArraysLock.lockForWrite(); - } - - _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty - - // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated - copyWrittenDataToReadArrays(_writeRenderFullVBO); - - // after... - _voxelsUpdated = 0; - _readArraysLock.unlock(); - - quint64 end = usecTimestampNow(); - int elapsedmsec = (end - start) / 1000; - _setupNewVoxelsForDrawingLastFinished = end; - _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; -} - - - -class recreateVoxelGeometryInViewArgs { -public: - VoxelSystem* thisVoxelSystem; - ViewFrustum thisViewFrustum; - unsigned long nodesScanned; - float voxelSizeScale; - int boundaryLevelAdjust; - - recreateVoxelGeometryInViewArgs(VoxelSystem* voxelSystem) : - thisVoxelSystem(voxelSystem), - thisViewFrustum(*voxelSystem->getViewFrustum()), - nodesScanned(0), - voxelSizeScale(Menu::getInstance()->getVoxelSizeScale()), - boundaryLevelAdjust(Menu::getInstance()->getBoundaryLevelAdjust()) - { - } -}; - -// The goal of this operation is to remove any old references to old geometry, and if the voxel -// should be visible, create new geometry for it. -bool VoxelSystem::recreateVoxelGeometryInViewOperation(OctreeElement* element, void* extraData) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - recreateVoxelGeometryInViewArgs* args = (recreateVoxelGeometryInViewArgs*)extraData; - - args->nodesScanned++; - - // reset the old geometry... - // note: this doesn't "mark the voxel as changed", so it only releases the old buffer index thereby forgetting the - // old geometry - voxel->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - - bool shouldRender = voxel->calculateShouldRender(&args->thisViewFrustum, args->voxelSizeScale, args->boundaryLevelAdjust); - bool inView = voxel->isInView(args->thisViewFrustum); - voxel->setShouldRender(inView && shouldRender); - if (shouldRender && inView) { - // recreate the geometry - args->thisVoxelSystem->updateNodeInArrays(voxel, false, true); // DONT_REUSE_INDEX, FORCE_REDRAW - } - - return true; // keep recursing! -} - - -// TODO: other than cleanupRemovedVoxels() is there anyplace we attempt to detect too many abandoned slots??? -void VoxelSystem::recreateVoxelGeometryInView() { - - qDebug() << "recreateVoxelGeometryInView()..."; - - recreateVoxelGeometryInViewArgs args(this); - _writeArraysLock.lockForWrite(); // don't let anyone read or write our write arrays until we're done - _tree->lockForRead(); // don't let anyone change our tree structure until we're run - - // reset our write arrays bookkeeping to think we've got no voxels in it - clearFreeBufferIndexes(); - - // do we need to reset out _writeVoxelDirtyArray arrays?? - memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); - - _tree->recurseTreeWithOperation(recreateVoxelGeometryInViewOperation,(void*)&args); - _tree->unlock(); - _writeArraysLock.unlock(); -} - -void VoxelSystem::checkForCulling() { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "checkForCulling()"); - quint64 start = usecTimestampNow(); - - // track how long its been since we were last moving. If we have recently moved then only use delta frustums, if - // it's been a long time since we last moved, then go ahead and do a full frustum cull. - if (isViewChanging()) { - _lastViewIsChanging = start; - } - quint64 sinceLastMoving = (start - _lastViewIsChanging) / 1000; - bool enoughTime = (sinceLastMoving >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)); - - // These has changed events will occur before we stop. So we need to remember this for when we finally have stopped - // moving long enough to be enoughTime - if (hasViewChanged()) { - _hasRecentlyChanged = true; - } - - // If we have recently changed, but it's been enough time since we last moved, then we will do a full frustum - // hide/show culling pass - bool forceFullFrustum = enoughTime && _hasRecentlyChanged; - - // in hide mode, we only track the full frustum culls, because we don't care about the partials. - if (forceFullFrustum) { - _lastViewCulling = start; - _hasRecentlyChanged = false; - } - - // This would be a good place to do a special processing pass, for example, switching the LOD of the scene - bool fullRedraw = (_lastKnownVoxelSizeScale != Menu::getInstance()->getVoxelSizeScale() || - _lastKnownBoundaryLevelAdjust != Menu::getInstance()->getBoundaryLevelAdjust()); - - _lastKnownVoxelSizeScale = Menu::getInstance()->getVoxelSizeScale(); - _lastKnownBoundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); - - if (fullRedraw) { - // this will remove all old geometry and recreate the correct geometry for all in view voxels - recreateVoxelGeometryInView(); - } else { - hideOutOfView(forceFullFrustum); - } - - if (forceFullFrustum) { - quint64 endViewCulling = usecTimestampNow(); - _lastViewCullingElapsed = (endViewCulling - start) / 1000; - } -} - -void VoxelSystem::copyWrittenDataToReadArraysFullVBOs() { - copyWrittenDataSegmentToReadArrays(0, _voxelsInWriteArrays - 1); - _voxelsInReadArrays = _voxelsInWriteArrays; - - // clear our dirty flags - memset(_writeVoxelDirtyArray, false, _voxelsInWriteArrays * sizeof(bool)); - - // let the reader know to get the full array - _readRenderFullVBO = true; -} - -void VoxelSystem::copyWrittenDataToReadArraysPartialVBOs() { - glBufferIndex segmentStart = 0; - bool inSegment = false; - for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) { - bool thisVoxelDirty = _writeVoxelDirtyArray[i]; - _readVoxelDirtyArray[i] |= thisVoxelDirty; - _writeVoxelDirtyArray[i] = false; - if (!inSegment) { - if (thisVoxelDirty) { - segmentStart = i; - inSegment = true; - } - } else { - if (!thisVoxelDirty) { - // If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before - // this one and so that's where the "segment" ends - copyWrittenDataSegmentToReadArrays(segmentStart, i - 1); - inSegment = false; - } - } - } - - // if we got to the end of the array, and we're in an active dirty segment... - if (inSegment) { - copyWrittenDataSegmentToReadArrays(segmentStart, _voxelsInWriteArrays - 1); - } - - // update our length - _voxelsInReadArrays = _voxelsInWriteArrays; -} - -void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) { - int segmentLength = (segmentEnd - segmentStart) + 1; - // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel - int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; - - GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat); - GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * vertexPointsPerVoxel); - GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * vertexPointsPerVoxel); - memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); - - segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte); - GLubyte* readColorsAt = _readColorsArray + (segmentStart * vertexPointsPerVoxel); - GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * vertexPointsPerVoxel); - memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); -} - -void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { - static unsigned int lockForReadAttempt = 0; - static unsigned int lockForWriteAttempt = 0; - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "copyWrittenDataToReadArrays()"); - - // attempt to get the writeArraysLock for reading and the readArraysLock for writing - // so we can copy from the write to the read... if we fail, that's ok, we'll get it the next - // time around, the only side effect is the VBOs won't be updated this frame - const int WAIT_FOR_LOCK_IN_MS = 5; - if (_readArraysLock.tryLockForWrite(WAIT_FOR_LOCK_IN_MS)) { - lockForWriteAttempt = 0; - if (_writeArraysLock.tryLockForRead(WAIT_FOR_LOCK_IN_MS)) { - lockForReadAttempt = 0; - if (_voxelsDirty && _voxelsUpdated) { - if (fullVBOs) { - copyWrittenDataToReadArraysFullVBOs(); - } else { - copyWrittenDataToReadArraysPartialVBOs(); - } - } - _writeArraysLock.unlock(); - } else { - lockForReadAttempt++; - // only report error of first failure - if (lockForReadAttempt == 1) { - qDebug() << "couldn't get _writeArraysLock.LockForRead()..."; - } - } - _readArraysLock.unlock(); - } else { - lockForWriteAttempt++; - // only report error of first failure - if (lockForWriteAttempt == 1) { - qDebug() << "couldn't get _readArraysLock.LockForWrite()..."; - } - } -} - -int VoxelSystem::newTreeToArrays(VoxelTreeElement* voxel) { - int voxelsUpdated = 0; - bool shouldRender = false; // assume we don't need to render it - // if it's colored, we might need to render it! - float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale();; - int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); - shouldRender = voxel->calculateShouldRender(_viewFrustum, voxelSizeScale, boundaryLevelAdjust); - - voxel->setShouldRender(shouldRender); - // let children figure out their renderness - if (!voxel->isLeaf()) { - - // As we check our children, see if any of them went from shouldRender to NOT shouldRender - // then we probably dropped LOD and if we don't have color, we want to average our children - // for a new color. - int childrenGotHiddenCount = 0; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - VoxelTreeElement* childVoxel = voxel->getChildAtIndex(i); - if (childVoxel) { - bool wasShouldRender = childVoxel->getShouldRender(); - voxelsUpdated += newTreeToArrays(childVoxel); - bool isShouldRender = childVoxel->getShouldRender(); - if (wasShouldRender && !isShouldRender) { - childrenGotHiddenCount++; - } - } - } - if (childrenGotHiddenCount > 0) { - voxel->calculateAverageFromChildren(); - } - } - - // update their geometry in the array. depending on our over all mode (fullVBO or not) we will reuse or not reuse the index - if (_writeRenderFullVBO) { - const bool DONT_REUSE_INDEX = false; - const bool FORCE_REDRAW = true; - voxelsUpdated += updateNodeInArrays(voxel, DONT_REUSE_INDEX, FORCE_REDRAW); - } else { - const bool REUSE_INDEX = true; - const bool DONT_FORCE_REDRAW = false; - voxelsUpdated += updateNodeInArrays(voxel, REUSE_INDEX, DONT_FORCE_REDRAW); - } - voxel->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. - - return voxelsUpdated; -} - -// called as response to elementDeleted() in fast pipeline case. The node -// is being deleted, but it's state is such that it thinks it should render -// and therefore we can't use the normal render calculations. This method -// will forcibly remove it from the VBOs because we know better!!! -int VoxelSystem::forceRemoveNodeFromArrays(VoxelTreeElement* node) { - - if (!_initialized) { - return 0; - } - - // if the node is not in the VBOs then we have nothing to do! - if (node->isKnownBufferIndex()) { - // If this node has not yet been written to the array, then add it to the end of the array. - glBufferIndex nodeIndex = node->getBufferIndex(); - node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - freeBufferIndex(nodeIndex); // NOTE: This will make the node invisible! - return 1; // updated! - } - return 0; // not-updated -} - -int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, bool forceDraw) { - // If we've run out of room, then just bail... - if (_voxelsInWriteArrays >= _maxVoxels && (_freeIndexes.size() == 0)) { - // We need to think about what else we can do in this case. This basically means that all of our available - // VBO slots are used up, but we're trying to render more voxels. At this point, if this happens we'll just - // not render these Voxels. We need to think about ways to keep the entire scene intact but maybe lower quality - // possibly shifting down to lower LOD or something. This debug message is to help identify, if/when/how this - // state actually occurs. - if (Application::getInstance()->getLogger()->extraDebugging()) { - qDebug("OH NO! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)"); - } - return 0; - } - - if (!_initialized) { - return 0; - } - - // If we've changed any attributes (our renderness, our color, etc), or we've been told to force a redraw - // then update the Arrays... - if (forceDraw || node->isDirty()) { - // If we're should render, use our legit location and scale, - if (node->getShouldRender()) { - glm::vec3 startVertex = node->getCorner(); - float voxelScale = node->getScale(); - - glBufferIndex nodeIndex = GLBUFFER_INDEX_UNKNOWN; - if (reuseIndex && node->isKnownBufferIndex()) { - nodeIndex = node->getBufferIndex(); - } else { - nodeIndex = getNextBufferIndex(); - node->setBufferIndex(nodeIndex); - node->setVoxelSystem(this); - } - - // populate the array with points for the 8 vertices and RGB color for each added vertex - updateArraysDetails(nodeIndex, startVertex, voxelScale, node->getColor()); - return 1; // updated! - } else { - // If we shouldn't render, and we're in reuseIndex mode, then free our index, this only operates - // on nodes with known index values, so it's safe to call for any node. - if (reuseIndex) { - return forceRemoveNodeFromArrays(node); - } - } - } - return 0; // not-updated -} - -void VoxelSystem::updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& startVertex, - float voxelScale, const nodeColor& color) { - - if (_initialized && nodeIndex <= _maxVoxels) { - _writeVoxelDirtyArray[nodeIndex] = true; - - if (_writeVerticesArray && _writeColorsArray) { - int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; - for (int j = 0; j < vertexPointsPerVoxel; j++ ) { - GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * vertexPointsPerVoxel); - GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * vertexPointsPerVoxel); - *(writeVerticesAt+j) = startVertex[j % 3] + (identityVerticesGlobalNormals[j] * voxelScale); - *(writeColorsAt +j) = color[j % 3]; - } - } - } -} - -glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const { - const float* identityVertex = identityVertices + index * 3; - return startVertex + glm::vec3(identityVertex[0], identityVertex[1], identityVertex[2]) * voxelScale; -} - -ProgramObject VoxelSystem::_program; -ProgramObject VoxelSystem::_perlinModulateProgram; - -void VoxelSystem::init() { - if (_initialized) { - qDebug("[ERROR] VoxelSystem is already initialized."); - return; - } - - _callsToTreesToArrays = 0; - _setupNewVoxelsForDrawingLastFinished = 0; - _setupNewVoxelsForDrawingLastElapsed = 0; - _lastViewCullingElapsed = _lastViewCulling = _lastAudit = _lastViewIsChanging = 0; - _hasRecentlyChanged = false; - - _voxelsDirty = false; - _voxelsInWriteArrays = 0; - _voxelsInReadArrays = 0; - - // VBO for the verticesArray - _initialMemoryUsageGPU = getFreeMemoryGPU(); - initVoxelMemory(); - -} - -void VoxelSystem::changeTree(VoxelTree* newTree) { - _tree = newTree; - - _tree->setDirtyBit(); - _tree->getRoot()->setVoxelSystem(this); - - setupNewVoxelsForDrawing(); -} - -void VoxelSystem::updateFullVBOs() { - bool outputWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(outputWarning, "updateFullVBOs()"); - - { - static char buffer[128] = { 0 }; - if (outputWarning) { - sprintf(buffer, "updateFullVBOs() : updateVBOSegment(0, _voxelsInReadArrays=%lu);", _voxelsInReadArrays); - }; - - PerformanceWarning warn(outputWarning,buffer); - updateVBOSegment(0, _voxelsInReadArrays); - } - - { - PerformanceWarning warn(outputWarning,"updateFullVBOs() : memset(_readVoxelDirtyArray...)"); - // consider the _readVoxelDirtyArray[] clean! - memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool)); - } -} - -void VoxelSystem::updatePartialVBOs() { - glBufferIndex segmentStart = 0; - bool inSegment = false; - for (glBufferIndex i = 0; i < _voxelsInReadArrays; i++) { - bool thisVoxelDirty = _readVoxelDirtyArray[i]; - if (!inSegment) { - if (thisVoxelDirty) { - segmentStart = i; - inSegment = true; - _readVoxelDirtyArray[i] = false; // consider us clean! - } - } else { - if (!thisVoxelDirty) { - // If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before - // this one and so that's where the "segment" ends - updateVBOSegment(segmentStart, i - 1); - inSegment = false; - } - _readVoxelDirtyArray[i] = false; // consider us clean! - } - } - - // if we got to the end of the array, and we're in an active dirty segment... - if (inSegment) { - updateVBOSegment(segmentStart, _voxelsInReadArrays - 1); - inSegment = false; - } -} - -void VoxelSystem::updateVBOs() { - static char buffer[40] = { 0 }; - if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { - sprintf(buffer, "updateVBOs() _readRenderFullVBO=%s", debug::valueOf(_readRenderFullVBO)); - }; - // would like to include _callsToTreesToArrays - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); - if (_voxelsDirty) { - - // attempt to lock the read arrays, to for copying from them to the actual GPU VBOs. - // if we fail to get the lock, that's ok, our VBOs will update on the next frame... - const int WAIT_FOR_LOCK_IN_MS = 5; - if (_readArraysLock.tryLockForRead(WAIT_FOR_LOCK_IN_MS)) { - if (_readRenderFullVBO) { - updateFullVBOs(); - } else { - updatePartialVBOs(); - } - _voxelsDirty = false; - _readRenderFullVBO = false; - _readArraysLock.unlock(); - } else { - qDebug() << "updateVBOs().... couldn't get _readArraysLock.tryLockForRead()"; - } - } - _callsToTreesToArrays = 0; // clear it -} - -// this should only be called on the main application thread during render -void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) { - bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarning, "updateVBOSegment()"); - - int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * vertexPointsPerVoxel); - - { - PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);"); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - } - - { - PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboVerticesID);"); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - } - - segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte); - segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * vertexPointsPerVoxel); - - { - PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);"); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - } - - { - PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboColorsID);"); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); - } -} - -void VoxelSystem::render() { - bool texture = Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures); - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "render()"); - - // If we got here and we're not initialized then bail! - if (!_initialized) { - return; - } - - updateVBOs(); - - if (_drawHaze) { - glEnable(GL_FOG); - } - - { - PerformanceWarning warn(showWarnings, "render().. TRIANGLES..."); - - { - PerformanceWarning warn(showWarnings,"render().. setup before glDrawRangeElementsEXT()..."); - - // tell OpenGL where to find vertex and color information - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glVertexPointer(3, GL_FLOAT, 0, 0); - - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); - - applyScaleAndBindProgram(texture); - - // for performance, enable backface culling and disable blending - glEnable(GL_CULL_FACE); - glDisable(GL_BLEND); - - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } - - // draw voxels in 6 passes - - { - PerformanceWarning warn(showWarnings, "render().. glDrawRangeElementsEXT()..."); - - glNormal3f(0,1.0f,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - - glNormal3f(0,-1.0f,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - - glNormal3f(-1.0f,0,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - - glNormal3f(1.0f,0,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - - glNormal3f(0,0,-1.0f); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - - glNormal3f(0,0,1.0f); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBack); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - } - { - PerformanceWarning warn(showWarnings, "render().. cleanup after glDrawRangeElementsEXT()..."); - - glDisable(GL_CULL_FACE); - glEnable(GL_BLEND); - - removeScaleAndReleaseProgram(texture); - - // deactivate vertex and color arrays after drawing - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - // bind with 0 to switch back to normal operation - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - } - - if (_drawHaze) { - glDisable(GL_FOG); - } -} - -void VoxelSystem::applyScaleAndBindProgram(bool texture) { - if (texture) { - bindPerlinModulateProgram(); - glBindTexture(GL_TEXTURE_2D, DependencyManager::get()->getPermutationNormalTextureID()); - } else { - _program.bind(); - } - - glPushMatrix(); - glScalef(_treeScale, _treeScale, _treeScale); - - DependencyManager::get()->setPrimaryDrawBuffers(true, true); -} - -void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { - // scale back down to 1 so heads aren't massive - glPopMatrix(); - - if (texture) { - _perlinModulateProgram.release(); - glBindTexture(GL_TEXTURE_2D, 0); - } else { - _program.release(); - } - - DependencyManager::get()->setPrimaryDrawBuffers(true, false); -} - -int VoxelSystem::_nodeCount = 0; - -void VoxelSystem::killLocalVoxels() { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "VoxelSystem::killLocalVoxels()"); - _tree->lockForWrite(); - VoxelSystem* voxelSystem = _tree->getRoot()->getVoxelSystem(); - _tree->eraseAllOctreeElements(); - _tree->getRoot()->setVoxelSystem(voxelSystem); - _tree->unlock(); - clearFreeBufferIndexes(); - _voxelsInReadArrays = 0; // do we need to do this? - setupNewVoxelsForDrawing(); -} - -// only called on main thread -bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData) { - _nodeCount++; - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - voxel->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - return true; -} - -// only called on main thread, and also always followed by a call to cleanupVoxelMemory() -// you shouldn't be calling this on any other thread or without also cleaning up voxel memory -void VoxelSystem::clearAllNodesBufferIndex() { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "VoxelSystem::clearAllNodesBufferIndex()"); - _nodeCount = 0; - _tree->lockForRead(); // we won't change the tree so it's ok to treat this as a read - _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation); - clearFreeBufferIndexes(); // this should be called too - _tree->unlock(); - if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { - qDebug("clearing buffer index of %d nodes", _nodeCount); - } -} - -bool VoxelSystem::forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData) { - _nodeCount++; - element->setDirtyBit(); - return true; -} - -void VoxelSystem::forceRedrawEntireTree() { - _nodeCount = 0; - _tree->recurseTreeWithOperation(forceRedrawEntireTreeOperation); - qDebug("forcing redraw of %d nodes", _nodeCount); - _tree->setDirtyBit(); - setupNewVoxelsForDrawing(); -} - -bool VoxelSystem::isViewChanging() { - bool result = false; // assume the best - - // If our viewFrustum has changed since our _lastKnownViewFrustum - if (!_lastKnownViewFrustum.isVerySimilar(_viewFrustum)) { - result = true; - _lastKnownViewFrustum = *_viewFrustum; // save last known - } - return result; -} - -bool VoxelSystem::hasViewChanged() { - bool result = false; // assume the best - - // If we're still changing, report no change yet. - if (isViewChanging()) { - return false; - } - - // If our viewFrustum has changed since our _lastKnownViewFrustum - if (!_lastStableViewFrustum.isVerySimilar(_viewFrustum)) { - result = true; - _lastStableViewFrustum = *_viewFrustum; // save last stable - } - return result; -} - -// combines the removeOutOfView args into a single class -class hideOutOfViewArgs { -public: - VoxelSystem* thisVoxelSystem; - VoxelTree* tree; - ViewFrustum thisViewFrustum; - ViewFrustum lastViewFrustum; - bool culledOnce; - bool wantDeltaFrustums; - unsigned long nodesScanned; - unsigned long nodesRemoved; - unsigned long nodesInside; - unsigned long nodesIntersect; - unsigned long nodesOutside; - unsigned long nodesInsideInside; - unsigned long nodesIntersectInside; - unsigned long nodesOutsideInside; - unsigned long nodesInsideOutside; - unsigned long nodesOutsideOutside; - unsigned long nodesShown; - - hideOutOfViewArgs(VoxelSystem* voxelSystem, VoxelTree* tree, - bool culledOnce, bool widenViewFrustum, bool wantDeltaFrustums) : - thisVoxelSystem(voxelSystem), - tree(tree), - thisViewFrustum(*voxelSystem->getViewFrustum()), - lastViewFrustum(*voxelSystem->getLastCulledViewFrustum()), - culledOnce(culledOnce), - wantDeltaFrustums(wantDeltaFrustums), - nodesScanned(0), - nodesRemoved(0), - nodesInside(0), - nodesIntersect(0), - nodesOutside(0), - nodesInsideInside(0), - nodesIntersectInside(0), - nodesOutsideInside(0), - nodesInsideOutside(0), - nodesOutsideOutside(0), - nodesShown(0) - { - // Widen the FOV for trimming - if (widenViewFrustum) { - float originalFOV = thisViewFrustum.getFieldOfView(); - float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; - thisViewFrustum.setFieldOfView(wideFOV); - thisViewFrustum.calculate(); - } - } -}; - -void VoxelSystem::hideOutOfView(bool forceFullFrustum) { - - // don't re-enter... - if (_inhideOutOfView) { - return; - } - - _inhideOutOfView = true; - - bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showDebugDetails, "hideOutOfView()"); - bool widenFrustum = true; - - - // When using "delta" view frustums and only hide/show items that are in the difference - // between the two view frustums. There are some potential problems with this mode. - // - // 1) This work well for rotating, but what about moving forward? - // In the move forward case, you'll get new voxel details, but those - // new voxels will be in the last view. - // - // 2) Also, voxels will arrive from the network that are OUTSIDE of the view - // frustum... these won't get hidden... and so we can't assume they are correctly - // hidden... - // - // Both these problems are solved by intermittently calling this with forceFullFrustum set - // to true. This will essentially clean up the improperly hidden or shown voxels. - // - bool wantDeltaFrustums = !forceFullFrustum; - hideOutOfViewArgs args(this, this->_tree, _culledOnce, widenFrustum, wantDeltaFrustums); - - const bool wantViewFrustumDebugging = false; // change to true for additional debugging - if (wantViewFrustumDebugging) { - args.thisViewFrustum.printDebugDetails(); - if (_culledOnce) { - args.lastViewFrustum.printDebugDetails(); - } - } - - if (!forceFullFrustum && _culledOnce && args.lastViewFrustum.isVerySimilar(args.thisViewFrustum)) { - _inhideOutOfView = false; - return; - } - - { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "VoxelSystem::... recurseTreeWithOperation(hideOutOfViewOperation)"); - _tree->lockForRead(); - _tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args); - _tree->unlock(); - } - _lastCulledViewFrustum = args.thisViewFrustum; // save last stable - _culledOnce = true; - - if (args.nodesRemoved) { - _tree->setDirtyBit(); - setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); - } - - bool extraDebugDetails = false; // Application::getInstance()->getLogger()->extraDebugging(); - if (extraDebugDetails) { - qDebug("hideOutOfView() scanned=%ld removed=%ld show=%ld inside=%ld intersect=%ld outside=%ld", - args.nodesScanned, args.nodesRemoved, args.nodesShown, args.nodesInside, - args.nodesIntersect, args.nodesOutside - ); - qDebug("inside/inside=%ld intersect/inside=%ld outside/outside=%ld", - args.nodesInsideInside, args.nodesIntersectInside, args.nodesOutsideOutside - ); - - qDebug() << "args.thisViewFrustum...."; - args.thisViewFrustum.printDebugDetails(); - } - _inhideOutOfView = false; -} - -bool VoxelSystem::hideAllSubTreeOperation(OctreeElement* element, void* extraData) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData; - - // If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine - // how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not - // consider that case. - ViewFrustum::location inLastCulledFrustum; - - if (args->culledOnce && args->wantDeltaFrustums) { - inLastCulledFrustum = voxel->inFrustum(args->lastViewFrustum); - - // if this node is fully OUTSIDE our last culled view frustum, then we don't need to recurse further - if (inLastCulledFrustum == ViewFrustum::OUTSIDE) { - args->nodesOutsideOutside++; - return false; - } - } - - args->nodesOutside++; - if (voxel->isKnownBufferIndex()) { - args->nodesRemoved++; - VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; - thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->forceRemoveNodeFromArrays(voxel); - thisVoxelSystem->setupNewVoxelsForDrawingSingleNode(); - } - - return true; -} - -bool VoxelSystem::showAllSubTreeOperation(OctreeElement* element, void* extraData) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData; - - // If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine - // how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not - // consider that case. - if (args->culledOnce && args->wantDeltaFrustums) { - ViewFrustum::location inLastCulledFrustum = voxel->inFrustum(args->lastViewFrustum); - - // if this node is fully inside our last culled view frustum, then we don't need to recurse further - if (inLastCulledFrustum == ViewFrustum::INSIDE) { - args->nodesInsideInside++; - return false; - } - } - - args->nodesInside++; - - float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale(); - int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); - bool shouldRender = voxel->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale, boundaryLevelAdjust); - voxel->setShouldRender(shouldRender); - - if (shouldRender && !voxel->isKnownBufferIndex()) { - // These are both needed to force redraw... - voxel->setDirtyBit(); - voxel->markWithChangedTime(); - args->nodesShown++; - } - - return true; // keep recursing! -} - -// "hide" voxels in the VBOs that are still in the tree that but not in view. -// We don't remove them from the tree, we don't delete them, we do remove them -// from the VBOs and mark them as such in the tree. -bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData; - - // If we're still recursing the tree using this operator, then we don't know if we're inside or outside... - // so before we move forward we need to determine our frustum location - ViewFrustum::location inFrustum = voxel->inFrustum(args->thisViewFrustum); - - // If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine - // how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not - // consider that case. - ViewFrustum::location inLastCulledFrustum = ViewFrustum::OUTSIDE; // assume outside, but should get reset to actual value - - if (args->culledOnce && args->wantDeltaFrustums) { - inLastCulledFrustum = voxel->inFrustum(args->lastViewFrustum); - } - - // ok, now do some processing for this node... - switch (inFrustum) { - case ViewFrustum::OUTSIDE: { - // If this node is outside the current view, then we might want to hide it... unless it was previously OUTSIDE, - // if it was previously outside, then we can safely assume it's already hidden, and we can also safely assume - // that all of it's children are outside both of our views, in which case we can just stop recursing... - if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::OUTSIDE) { - args->nodesScanned++; - args->nodesOutsideOutside++; - return false; // stop recursing this branch! - } - - // if this node is fully OUTSIDE the view, but previously intersected and/or was inside the last view, then - // we need to hide it. Additionally we know that ALL of it's children are also fully OUTSIDE so we can recurse - // the children and simply mark them as hidden - args->tree->recurseElementWithOperation(voxel, hideAllSubTreeOperation, args ); - return false; - - } break; - case ViewFrustum::INSIDE: { - // If this node is INSIDE the current view, then we might want to show it... unless it was previously INSIDE, - // if it was previously INSIDE, then we can safely assume it's already shown, and we can also safely assume - // that all of it's children are INSIDE both of our views, in which case we can just stop recursing... - if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::INSIDE) { - args->nodesScanned++; - args->nodesInsideInside++; - return false; // stop recursing this branch! - } - - // if this node is fully INSIDE the view, but previously INTERSECTED and/or was OUTSIDE the last view, then - // we need to show it. Additionally we know that ALL of it's children are also fully INSIDE so we can recurse - // the children and simply mark them as visible (as appropriate based on LOD) - args->tree->recurseElementWithOperation(voxel, showAllSubTreeOperation, args); - return false; - } break; - case ViewFrustum::INTERSECT: { - args->nodesScanned++; - // If this node INTERSECTS the current view, then we might want to show it... unless it was previously INSIDE - // the last known view, in which case it will already be visible, and we know that all it's children are also - // previously INSIDE and visible. So in this case stop recursing - if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::INSIDE) { - args->nodesIntersectInside++; - return false; // stop recursing this branch! - } - - args->nodesIntersect++; - - // if the child node INTERSECTs the view, then we want to check to see if it thinks it should render - // if it should render but is missing it's VBO index, then we want to flip it on, and we can stop recursing from - // here because we know will block any children anyway - - float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale(); - int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); - bool shouldRender = voxel->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale, boundaryLevelAdjust); - voxel->setShouldRender(shouldRender); - - if (voxel->getShouldRender() && !voxel->isKnownBufferIndex()) { - voxel->setDirtyBit(); // will this make it draw? - voxel->markWithChangedTime(); // both are needed to force redraw - args->nodesShown++; - return false; - } - - // If it INTERSECTS but shouldn't be displayed, then it's probably a parent and it is at least partially in view. - // So we DO want to recurse the children because some of them may not be in view... nothing specifically to do, - // just keep iterating the children - return true; - - } break; - } // switch - - return true; // keep going! -} - - -void VoxelSystem::nodeAdded(SharedNodePointer node) { - if (node->getType() == NodeType::VoxelServer) { - qDebug("VoxelSystem... voxel server %s added...", node->getUUID().toString().toLocal8Bit().constData()); - _voxelServerCount++; - } -} - -bool VoxelSystem::killSourceVoxelsOperation(OctreeElement* element, void* extraData) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - QUuid killedNodeID = *(QUuid*)extraData; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - VoxelTreeElement* childNode = voxel->getChildAtIndex(i); - if (childNode) { - if (childNode->matchesSourceUUID(killedNodeID)) { - voxel->safeDeepDeleteChildAtIndex(i); - } - } - } - return true; -} - -void VoxelSystem::nodeKilled(SharedNodePointer node) { - if (node->getType() == NodeType::VoxelServer) { - _voxelServerCount--; - QUuid nodeUUID = node->getUUID(); - qDebug("VoxelSystem... voxel server %s removed...", nodeUUID.toString().toLocal8Bit().constData()); - } -} - -unsigned long VoxelSystem::getFreeMemoryGPU() { - // We can't ask all GPUs how much memory they have in use, but we can ask them about how much is free. - // So, we can record the free memory before we create our VBOs and the free memory after, and get a basic - // idea how how much we're using. - - _hasMemoryUsageGPU = false; // assume the worst - unsigned long freeMemory = 0; - const int NUM_RESULTS = 4; // see notes, these APIs return up to 4 results - GLint results[NUM_RESULTS] = { 0, 0, 0, 0}; - - // ATI - // http://www.opengl.org/registry/specs/ATI/meminfo.txt - // - // TEXTURE_FREE_MEMORY_ATI 0x87FC - // RENDERBUFFER_FREE_MEMORY_ATI 0x87FD - const GLenum VBO_FREE_MEMORY_ATI = 0x87FB; - glGetIntegerv(VBO_FREE_MEMORY_ATI, &results[0]); - GLenum errorATI = glGetError(); - - if (errorATI == GL_NO_ERROR) { - _hasMemoryUsageGPU = true; - freeMemory = results[0]; - } else { - - // NVIDIA - // http://developer.download.nvidia.com/opengl/specs/GL_NVX_gpu_memory_info.txt - // - //const GLenum GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX = 0x9047; - //const GLenum GPU_MEMORY_INFO_EVICTION_COUNT_NVX = 0x904A; - //const GLenum GPU_MEMORY_INFO_EVICTED_MEMORY_NVX = 0x904B; - //const GLenum GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX = 0x9048; - - const GLenum GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX = 0x9049; - results[0] = 0; - glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &results[0]); - freeMemory += results[0]; - GLenum errorNVIDIA = glGetError(); - - if (errorNVIDIA == GL_NO_ERROR) { - _hasMemoryUsageGPU = true; - freeMemory = results[0]; - } - } - - const unsigned long BYTES_PER_KBYTE = 1024; - return freeMemory * BYTES_PER_KBYTE; // API results in KB, we want it in bytes -} - -unsigned long VoxelSystem::getVoxelMemoryUsageGPU() { - unsigned long currentFreeMemory = getFreeMemoryGPU(); - return (_initialMemoryUsageGPU - currentFreeMemory); -} - -void VoxelSystem::bindPerlinModulateProgram() { - if (!_perlinModulateProgram.isLinked()) { - _perlinModulateProgram.addShaderFromSourceFile(QGLShader::Vertex, - PathUtils::resourcesPath() + "shaders/perlin_modulate.vert"); - _perlinModulateProgram.addShaderFromSourceFile(QGLShader::Fragment, - PathUtils::resourcesPath() + "shaders/perlin_modulate.frag"); - _perlinModulateProgram.link(); - - _perlinModulateProgram.bind(); - _perlinModulateProgram.setUniformValue("permutationNormalTexture", 0); - - } else { - _perlinModulateProgram.bind(); - } -} - diff --git a/interface/src/voxels/VoxelSystem.h b/interface/src/voxels/VoxelSystem.h deleted file mode 100644 index b6413a0f68..0000000000 --- a/interface/src/voxels/VoxelSystem.h +++ /dev/null @@ -1,246 +0,0 @@ -// -// VoxelSystem.h -// interface/src/voxels -// -// Created by Philip on 12/31/12. -// Copyright 2012 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_VoxelSystem_h -#define hifi_VoxelSystem_h - -#include "InterfaceConfig.h" -#include - -#include - -#include -#include -#include -#include - -#include "Camera.h" -#include "Util.h" -#include "world.h" - -class ProgramObject; - -const int NUM_CHILDREN = 8; - - -class VoxelSystem : public NodeData, public OctreeElementDeleteHook, public OctreeElementUpdateHook { - Q_OBJECT - - friend class VoxelHideShowThread; - -public: - VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = DEFAULT_MAX_VOXELS_PER_SYSTEM, VoxelTree* tree = NULL); - ~VoxelSystem(); - - void setDataSourceUUID(const QUuid& dataSourceUUID) { _dataSourceUUID = dataSourceUUID; } - const QUuid& getDataSourceUUID() const { return _dataSourceUUID; } - - int parseData(const QByteArray& packet); - - bool isInitialized() { return _initialized; } - virtual void init(); - void render(); - - void changeTree(VoxelTree* newTree); - VoxelTree* getTree() const { return _tree; } - ViewFrustum* getViewFrustum() const { return _viewFrustum; } - void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; } - unsigned long getVoxelsUpdated() const { return _voxelsUpdated; } - unsigned long getVoxelsRendered() const { return _voxelsInReadArrays; } - unsigned long getVoxelsWritten() const { return _voxelsInWriteArrays; } - unsigned long getAbandonedVoxels() const { return _freeIndexes.size(); } - - ViewFrustum* getLastCulledViewFrustum() { return &_lastCulledViewFrustum; } - - void setMaxVoxels(unsigned long maxVoxels); - long int getMaxVoxels() const { return _maxVoxels; } - unsigned long getVoxelMemoryUsageRAM() const { return _memoryUsageRAM; } - unsigned long getVoxelMemoryUsageVBO() const { return _memoryUsageVBO; } - bool hasVoxelMemoryUsageGPU() const { return _hasMemoryUsageGPU; } - unsigned long getVoxelMemoryUsageGPU(); - - void killLocalVoxels(); - - virtual void hideOutOfView(bool forceFullFrustum = false); - bool hasViewChanged(); - bool isViewChanging(); - - virtual void elementDeleted(OctreeElement* element); - virtual void elementUpdated(OctreeElement* element); - -public slots: - void nodeAdded(SharedNodePointer node); - void nodeKilled(SharedNodePointer node); - - - // Methods that recurse tree - void forceRedrawEntireTree(); - void clearAllNodesBufferIndex(); - - void setDisableFastVoxelPipeline(bool disableFastVoxelPipeline); - -protected: - float _treeScale; - unsigned long _maxVoxels; - VoxelTree* _tree; - - void setupNewVoxelsForDrawing(); - static const bool DONT_BAIL_EARLY; // by default we will bail early, if you want to force not bailing, then use this - void setupNewVoxelsForDrawingSingleNode(bool allowBailEarly = true); - - /// called on the hide/show thread to hide any out of view voxels and show any newly in view voxels. - void checkForCulling(); - - /// single pass to remove old VBO data and fill it with correct current view, used when switching LOD or needing to force - /// a full redraw of everything in view - void recreateVoxelGeometryInView(); - - glm::vec3 computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const; - - virtual void updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& startVertex, - float voxelScale, const nodeColor& color); - virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); - virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); - - - virtual void applyScaleAndBindProgram(bool texture); /// used in render() to apply shadows and textures - virtual void removeScaleAndReleaseProgram(bool texture); /// stop the shaders for shadows and textures - -private: - // disallow copying of VoxelSystem objects - VoxelSystem(const VoxelSystem&); - VoxelSystem& operator= (const VoxelSystem&); - - bool _initialized; - int _callsToTreesToArrays; - - // Operation functions for tree recursion methods - static int _nodeCount; - static bool killSourceVoxelsOperation(OctreeElement* element, void* extraData); - static bool forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData); - static bool clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData); - static bool hideOutOfViewOperation(OctreeElement* element, void* extraData); - static bool hideAllSubTreeOperation(OctreeElement* element, void* extraData); - static bool showAllSubTreeOperation(OctreeElement* element, void* extraData); - static bool getVoxelEnclosingOperation(OctreeElement* element, void* extraData); - static bool recreateVoxelGeometryInViewOperation(OctreeElement* element, void* extraData); - - int updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, bool forceDraw); - int forceRemoveNodeFromArrays(VoxelTreeElement* node); - - void copyWrittenDataToReadArraysFullVBOs(); - void copyWrittenDataToReadArraysPartialVBOs(); - - void updateVBOs(); - - unsigned long getFreeMemoryGPU(); - - // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here - static float _maxDistance; - static float _minDistance; - - GLfloat* _readVerticesArray; - GLubyte* _readColorsArray; - - QReadWriteLock _writeArraysLock; - QReadWriteLock _readArraysLock; - - - GLfloat* _writeVerticesArray; - GLubyte* _writeColorsArray; - bool* _writeVoxelDirtyArray; - bool* _readVoxelDirtyArray; - unsigned long _voxelsUpdated; - unsigned long _voxelsInReadArrays; - unsigned long _voxelsInWriteArrays; - - bool _writeRenderFullVBO; - bool _readRenderFullVBO; - - int _setupNewVoxelsForDrawingLastElapsed; - quint64 _setupNewVoxelsForDrawingLastFinished; - quint64 _lastViewCulling; - quint64 _lastViewIsChanging; - quint64 _lastAudit; - int _lastViewCullingElapsed; - bool _hasRecentlyChanged; - - void initVoxelMemory(); - void cleanupVoxelMemory(); - - GLuint _vboVoxelsID; /// when using voxel shader, we'll use this VBO - GLuint _vboVoxelsIndicesID; /// when using voxel shader, we'll use this VBO for our indexes - - GLuint _vboVerticesID; - GLuint _vboColorsID; - - GLuint _vboIndicesTop; - GLuint _vboIndicesBottom; - GLuint _vboIndicesLeft; - GLuint _vboIndicesRight; - GLuint _vboIndicesFront; - GLuint _vboIndicesBack; - - ViewFrustum _lastKnownViewFrustum; - ViewFrustum _lastStableViewFrustum; - ViewFrustum* _viewFrustum; - - ViewFrustum _lastCulledViewFrustum; // used for hide/show visible passes - bool _culledOnce; - - void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]); - - int newTreeToArrays(VoxelTreeElement* currentNode); - - void copyWrittenDataToReadArrays(bool fullVBOs); - - void updateFullVBOs(); // all voxels in the VBO - void updatePartialVBOs(); // multiple segments, only dirty voxels - - bool _voxelsDirty; - - static ProgramObject _program; - static ProgramObject _perlinModulateProgram; - - static void bindPerlinModulateProgram(); - - int _hookID; - std::vector _freeIndexes; - QMutex _freeIndexLock; - - void freeBufferIndex(glBufferIndex index); - void clearFreeBufferIndexes(); - glBufferIndex getNextBufferIndex(); - - bool _falseColorizeBySource; - QUuid _dataSourceUUID; - - int _voxelServerCount; - unsigned long _memoryUsageRAM; - unsigned long _memoryUsageVBO; - unsigned long _initialMemoryUsageGPU; - bool _hasMemoryUsageGPU; - - bool _inSetupNewVoxelsForDrawing; - bool _useFastVoxelPipeline; - - bool _inhideOutOfView; - - float _lastKnownVoxelSizeScale; - int _lastKnownBoundaryLevelAdjust; - - // haze - bool _drawHaze; - float _farHazeDistance; - glm::vec3 _hazeColor; -}; - -#endif // hifi_VoxelSystem_h diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 9f1185cfb9..66078b387d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -887,17 +887,6 @@ void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const } } -void EntityTreeRenderer::entityCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, - const Collision& collision) { - QScriptValue entityScript = getPreviouslyLoadedEntityScript(entityID); - if (entityScript.property("collisionWithVoxel").isValid()) { - QScriptValueList args; - args << entityID.toScriptValue(_entitiesScriptEngine); - args << collisionToScriptValue(_entitiesScriptEngine, collision); - entityScript.property("collisionWithVoxel").call(entityScript, args); - } -} - void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { QScriptValue entityScriptA = loadEntityScript(idA); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 92cc2c4dcc..2f88e854da 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -102,7 +102,6 @@ public slots: void deletingEntity(const EntityItemID& entityID); void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID); void entitySciptChanging(const EntityItemID& entityID); - void entityCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, const Collision& collision); void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); // optional slots that can be wired to menu items diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index f0ffbefb46..cf6398847c 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -30,19 +29,17 @@ const int MAX_COLLISIONS_PER_Entity = 16; EntityCollisionSystem::EntityCollisionSystem() : SimpleEntitySimulation(), _packetSender(NULL), - _voxels(NULL), _audio(NULL), _avatars(NULL), _collisions(MAX_COLLISIONS_PER_Entity) { } void EntityCollisionSystem::init(EntityEditPacketSender* packetSender, - EntityTree* entities, VoxelTree* voxels, AbstractAudioInterface* audio, + EntityTree* entities, AbstractAudioInterface* audio, AvatarHashMap* avatars) { assert(entities); setEntityTree(entities); _packetSender = packetSender; - _voxels = voxels; _audio = audio; _avatars = avatars; } @@ -64,17 +61,10 @@ void EntityCollisionSystem::updateCollisions() { void EntityCollisionSystem::checkEntity(EntityItem* entity) { - updateCollisionWithVoxels(entity); updateCollisionWithEntities(entity); updateCollisionWithAvatars(entity); } -void EntityCollisionSystem::emitGlobalEntityCollisionWithVoxel(EntityItem* entity, - VoxelDetail* voxelDetails, const Collision& collision) { - EntityItemID entityItemID = entity->getEntityItemID(); - emit entityCollisionWithVoxel(entityItemID, *voxelDetails, collision); -} - void EntityCollisionSystem::emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const Collision& collision) { @@ -83,39 +73,6 @@ void EntityCollisionSystem::emitGlobalEntityCollisionWithEntity(EntityItem* enti emit entityCollisionWithEntity(idA, idB, collision); } -void EntityCollisionSystem::updateCollisionWithVoxels(EntityItem* entity) { - - if (entity->getIgnoreForCollisions() || !entity->getCollisionsWillMove()) { - return; // bail early if this entity is to be ignored or wont move - } - - glm::vec3 center = entity->getPosition() * (float)(TREE_SCALE); - float radius = entity->getRadius() * (float)(TREE_SCALE); - const float ELASTICITY = 0.4f; - const float DAMPING = 0.05f; - CollisionInfo collisionInfo; - collisionInfo._damping = DAMPING; - collisionInfo._elasticity = ELASTICITY; - VoxelDetail* voxelDetails = NULL; - if (_voxels->findSpherePenetration(center, radius, collisionInfo._penetration, (void**)&voxelDetails)) { - - // 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. - collisionInfo._contactPoint = (float)TREE_SCALE * (entity->getPosition() + entity->getRadius() * glm::normalize(collisionInfo._penetration)); - // let the global script run their collision scripts for Entities if they have them - Collision collision(collisionInfo._contactPoint, collisionInfo._penetration); - emitGlobalEntityCollisionWithVoxel(entity, voxelDetails, collision); - - // we must scale back down to the octree reference frame before updating the Entity properties - collisionInfo._penetration /= (float)(TREE_SCALE); - collisionInfo._contactPoint /= (float)(TREE_SCALE); - - applyHardCollision(entity, collisionInfo); - delete voxelDetails; // cleanup returned details - } -} - void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { if (entityA->getIgnoreForCollisions()) { diff --git a/libraries/entities/src/EntityCollisionSystem.h b/libraries/entities/src/EntityCollisionSystem.h index 48b7c17ead..593c5efd74 100644 --- a/libraries/entities/src/EntityCollisionSystem.h +++ b/libraries/entities/src/EntityCollisionSystem.h @@ -22,7 +22,6 @@ #include #include #include -#include #include "EntityItem.h" #include "SimpleEntitySimulation.h" @@ -31,14 +30,13 @@ class AbstractAudioInterface; class AvatarData; class EntityEditPacketSender; class EntityTree; -class VoxelTree; class EntityCollisionSystem : public QObject, public SimpleEntitySimulation { Q_OBJECT public: EntityCollisionSystem(); - void init(EntityEditPacketSender* packetSender, EntityTree* entities, VoxelTree* voxels, + void init(EntityEditPacketSender* packetSender, EntityTree* entities, AbstractAudioInterface* audio = NULL, AvatarHashMap* _avatars = NULL); ~EntityCollisionSystem(); @@ -46,25 +44,21 @@ public: void updateCollisions(); void checkEntity(EntityItem* Entity); - void updateCollisionWithVoxels(EntityItem* Entity); void updateCollisionWithEntities(EntityItem* Entity); void updateCollisionWithAvatars(EntityItem* Entity); void queueEntityPropertiesUpdate(EntityItem* Entity); void updateCollisionSound(EntityItem* Entity, const glm::vec3 &penetration, float frequency); signals: - void entityCollisionWithVoxel(const EntityItemID& entityItemID, const VoxelDetail& voxel, const Collision& collision); void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); private: void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo); static bool updateOperation(OctreeElement* element, void* extraData); - void emitGlobalEntityCollisionWithVoxel(EntityItem* Entity, VoxelDetail* voxelDetails, const Collision& penetration); void emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const Collision& penetration); EntityEditPacketSender* _packetSender; - VoxelTree* _voxels; AbstractAudioInterface* _audio; AvatarHashMap* _avatars; CollisionList _collisions; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 348efac9a3..1b9e0d6f86 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -16,8 +16,6 @@ #include #include #include // usecTimestampNow() -#include -#include #include "EntityScriptingInterface.h" #include "EntityItem.h" diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0d0aa96706..4ac7e69bad 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -22,7 +22,6 @@ #include // for EncodeBitstreamParams class #include // for OctreeElement::AppendState #include -#include #include "EntityItemID.h" #include "EntityItemProperties.h" diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 20aaf09f9a..e0fc721516 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -87,12 +87,12 @@ public slots: /// this function will not find any models in script engine contexts which don't have access to models Q_INVOKABLE QVector findEntities(const glm::vec3& center, float radius) const; - /// If the scripting context has visible voxels, this will determine a ray intersection, the results - /// may be inaccurate if the engine is unable to access the visible voxels, in which case result.accurate + /// If the scripting context has visible entities, this will determine a ray intersection, the results + /// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate /// will be false. Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false); - /// If the scripting context has visible voxels, this will determine a ray intersection, and will block in + /// If the scripting context has visible entities, this will determine a ray intersection, and will block in /// order to return an accurate result Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking = false); @@ -102,7 +102,6 @@ public slots: Q_INVOKABLE void dumpTree() const; signals: - void entityCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, const Collision& collision); void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); void mousePressOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index c747bf6d9e..9532f44acf 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -26,8 +26,6 @@ #include #include -#include - #include "FBXReader.h" @@ -2544,167 +2542,3 @@ FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool l FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) { return extractFBXGeometry(parseFBX(device), mapping, loadLightmaps, lightmapLevel); } - -bool addMeshVoxelsOperation(OctreeElement* element, void* extraData) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - if (!voxel->isLeaf()) { - return true; - } - FBXMesh& mesh = *static_cast(extraData); - FBXMeshPart& part = mesh.parts[0]; - - const int FACE_COUNT = 6; - const int VERTICES_PER_FACE = 4; - const int VERTEX_COUNT = FACE_COUNT * VERTICES_PER_FACE; - const float EIGHT_BIT_MAXIMUM = 255.0f; - glm::vec3 color = glm::vec3(voxel->getColor()[0], voxel->getColor()[1], voxel->getColor()[2]) / EIGHT_BIT_MAXIMUM; - QString colorName; - colorName.sprintf("%d,%d,%d",(int)voxel->getColor()[0], (int)voxel->getColor()[1], (int)voxel->getColor()[2]); - part.materialID = colorName; - for (int i = 0; i < VERTEX_COUNT; i++) { - part.quadIndices.append(part.quadIndices.size()); - mesh.colors.append(color); - } - glm::vec3 corner = voxel->getCorner(); - float scale = voxel->getScale(); - - mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z)); - mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z + scale)); - mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z + scale)); - mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z)); - for (int i = 0; i < VERTICES_PER_FACE; i++) { - mesh.normals.append(glm::vec3(-1.0f, 0.0f, 0.0f)); - } - - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z)); - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z)); - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z + scale)); - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z + scale)); - for (int i = 0; i < VERTICES_PER_FACE; i++) { - mesh.normals.append(glm::vec3(1.0f, 0.0f, 0.0f)); - } - - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z)); - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z + scale)); - mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z + scale)); - mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z)); - for (int i = 0; i < VERTICES_PER_FACE; i++) { - mesh.normals.append(glm::vec3(0.0f, -1.0f, 0.0f)); - } - - mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z)); - mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z + scale)); - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z + scale)); - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z)); - for (int i = 0; i < VERTICES_PER_FACE; i++) { - mesh.normals.append(glm::vec3(0.0f, 1.0f, 0.0f)); - } - - mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z)); - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z)); - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z)); - mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z)); - for (int i = 0; i < VERTICES_PER_FACE; i++) { - mesh.normals.append(glm::vec3(0.0f, 0.0f, -1.0f)); - } - - mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z + scale)); - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z + scale)); - mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z + scale)); - mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z + scale)); - for (int i = 0; i < VERTICES_PER_FACE; i++) { - mesh.normals.append(glm::vec3(0.0f, 0.0f, 1.0f)); - } - mesh.meshExtents.maximum = glm::vec3(1.0f, 1.0f, 1.0f); - - return true; -} - -FBXGeometry readSVO(const QByteArray& model) { - FBXGeometry geometry; - - // we have one joint - FBXJoint joint = { false }; - joint.parentIndex = -1; - geometry.joints.append(joint); - - // and one mesh with one cluster and one part - FBXMesh mesh; - mesh.isEye = false; - - FBXCluster cluster = { 0 }; - mesh.clusters.append(cluster); - - FBXMeshPart part; - part.diffuseColor = glm::vec3(1.0f, 1.0f, 1.0f); - part.shininess = 96.0f; - part.opacity = 1.0f; - mesh.parts.append(part); - - VoxelTree tree; - - unsigned char* dataAt = (unsigned char*)model.data(); - size_t dataSize = model.size(); - - PacketVersion gotVersion = 0; - - // NOTE: SPECIAL CASE for old voxel svo files. The old voxel SVO files didn't have header - // details. They started with the the octalcode for the root. Which was always 00 which matches PacketTypeUnknown - unsigned char* firstByteAt = (unsigned char*)model.data(); - unsigned char firstByteValue = *firstByteAt; - if (tree.expectedDataPacketType() == PacketTypeVoxelData && firstByteValue == 0) { - qDebug() << "Detected OLD Voxels format."; - gotVersion = 0; - } else if (tree.getWantSVOfileVersions()) { - // skip the type/version - dataAt += sizeof(PacketType); - dataSize -= sizeof(PacketType); - - gotVersion = *dataAt; - dataAt += sizeof(PacketVersion); - dataSize -= sizeof(PacketVersion); - } - bool hasBufferBreaks = tree.versionHasSVOfileBreaks(gotVersion); - - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, - SharedNodePointer(), false, gotVersion); - - if (!hasBufferBreaks) { - tree.readBitstreamToTree(dataAt, dataSize, args); - } else { - const unsigned long MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2; - while (dataSize > 0) { - quint16 chunkLength = 0; - - chunkLength = *dataAt; - dataAt += sizeof(chunkLength); - dataSize -= sizeof(chunkLength); - - if (chunkLength > dataSize) { - qDebug() << "UNEXPECTED chunk size of:" << chunkLength - << "greater than remaining length:" << dataSize; - break; - } - - if (chunkLength > MAX_CHUNK_LENGTH) { - qDebug() << "UNEXPECTED chunk size of:" << chunkLength - << "greater than MAX_CHUNK_LENGTH:" << MAX_CHUNK_LENGTH; - break; - } - - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, - SharedNodePointer(), false, gotVersion); - - tree.readBitstreamToTree(dataAt, chunkLength, args); - dataAt += chunkLength; - dataSize -= chunkLength; - } - } - tree.recurseTreeWithOperation(addMeshVoxelsOperation, &mesh); - - geometry.meshes.append(mesh); - - geometry.meshExtents.maximum = glm::vec3(1.0f, 1.0f, 1.0f); - - return geometry; -} diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 3d07d29e7d..44b2bfe4a5 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -283,7 +283,4 @@ FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool l /// \exception QString if an error occurs in parsing FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f); -/// Reads SVO geometry from the supplied model data. -FBXGeometry readSVO(const QByteArray& model); - #endif // hifi_FBXReader_h diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 7e415a5d0d..b703921099 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1367,14 +1367,7 @@ void GeometryReader::run() { if (urlValid) { // Let's read the binaries from the network FBXGeometry fbxgeo; - if (_url.path().toLower().endsWith(".svo")) { - QByteArray fileBinary = _reply->readAll(); - if (fileBinary.isEmpty() || fileBinary.isNull()) { - throw QString("Read File binary is empty?!"); - } - fbxgeo = readSVO(fileBinary); - - } else if (_url.path().toLower().endsWith(".fbx")) { + if (_url.path().toLower().endsWith(".fbx")) { bool grabLightmaps = true; float lightmapLevel = 1.0f; // HACK: For monday 12/01/2014 we need to kill lighmaps loading in starchamber... diff --git a/libraries/script-engine/src/LocalVoxels.cpp b/libraries/script-engine/src/LocalVoxels.cpp deleted file mode 100644 index 9a6fb2b6d1..0000000000 --- a/libraries/script-engine/src/LocalVoxels.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// -// LocalVoxels.cpp -// libraries/script-engine/src -// -// Created by Clément Brisset on 2/24/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 "LocalVoxels.h" - -LocalVoxels::LocalVoxels(QString name) : - QObject(NULL), - _name(name), - _tree(new VoxelTree(true)) -{ - LocalVoxelsList::getInstance()->insert(_name, _tree); -} - -LocalVoxels::~LocalVoxels() { - _tree.clear(); - LocalVoxelsList::getInstance()->remove(_name); -} - -VoxelDetail LocalVoxels::getVoxelAt(float x, float y, float z, float scale) { - // setup a VoxelDetail struct with the data - VoxelDetail result = {0,0,0,0,0,0,0}; - if (_tree) { - _tree->lockForRead(); - - VoxelTreeElement* voxel = static_cast(_tree->getOctreeElementAt(x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - scale / (float)TREE_SCALE)); - _tree->unlock(); - if (voxel) { - // Note: these need to be in voxel space because the VoxelDetail -> js converter will upscale - result.x = voxel->getCorner().x; - result.y = voxel->getCorner().y; - result.z = voxel->getCorner().z; - result.s = voxel->getScale(); - result.red = voxel->getColor()[RED_INDEX]; - result.green = voxel->getColor()[GREEN_INDEX]; - result.blue = voxel->getColor()[BLUE_INDEX]; - } - } - return result; -} - -void LocalVoxels::setVoxelNonDestructive(float x, float y, float z, float scale, - uchar red, uchar green, uchar blue) { - if (_name == DOMAIN_TREE_NAME) { - qDebug() << "LocalVoxels::setVoxelNonDestructive(): Please use the \"Voxels\" interface to modify the domain tree."; - return; - } - if (_tree ) { - _tree->createVoxel(x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - scale / (float)TREE_SCALE, - red, green, blue, false); - } -} - -void LocalVoxels::setVoxel(float x, float y, float z, float scale, - uchar red, uchar green, uchar blue) { - if (_name == DOMAIN_TREE_NAME) { - qDebug() << "LocalVoxels::setVoxel(): Please use the \"Voxels\" interface to modify the domain tree."; - return; - } - if (_tree ) { - _tree->createVoxel(x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - scale / (float)TREE_SCALE, - red, green, blue, true); - } -} - -void LocalVoxels::eraseVoxel(float x, float y, float z, float scale) { - if (_name == DOMAIN_TREE_NAME) { - qDebug() << "LocalVoxels::eraseVoxel(): Please use the \"Voxels\" interface to modify the domain tree."; - return; - } - if (_tree ) { - _tree->deleteVoxelAt(x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - scale / (float)TREE_SCALE); - } -} - -void LocalVoxels::copyTo(float x, float y, float z, float scale, const QString destination) { - if (destination == DOMAIN_TREE_NAME) { - qDebug() << "LocalVoxels::copyTo(): Please use the \"Voxels\" interface to modify the domain tree."; - return; - } - StrongVoxelTreePointer destinationTree = LocalVoxelsList::getInstance()->getTree(destination); - VoxelTreeElement* destinationNode = destinationTree->getVoxelAt(x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - scale / (float)TREE_SCALE); - destinationTree->copyFromTreeIntoSubTree(_tree.data(), destinationNode); -} - -void LocalVoxels::pasteFrom(float x, float y, float z, float scale, const QString source) { - if (_name == DOMAIN_TREE_NAME) { - qDebug() << "LocalVoxels::pasteFrom(): Please use the \"Voxels\" interface to modify the domain tree."; - return; - } - StrongVoxelTreePointer sourceTree = LocalVoxelsList::getInstance()->getTree(source); - VoxelTreeElement* sourceNode = _tree->getVoxelAt(x / (float)TREE_SCALE, - y / (float)TREE_SCALE, - z / (float)TREE_SCALE, - scale / (float)TREE_SCALE); - _tree->copySubTreeIntoNewTree(sourceNode, sourceTree.data(), true); -} - -RayToVoxelIntersectionResult LocalVoxels::findRayIntersection(const PickRay& ray) { - return findRayIntersectionWorker(ray, Octree::TryLock); -} - -RayToVoxelIntersectionResult LocalVoxels::findRayIntersectionBlocking(const PickRay& ray) { - return findRayIntersectionWorker(ray, Octree::Lock); -} - -RayToVoxelIntersectionResult LocalVoxels::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType) { - RayToVoxelIntersectionResult result; - if (_tree) { - OctreeElement* element; - result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, NULL, - lockType, &result.accurate); - if (result.intersects) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - result.voxel.x = voxel->getCorner().x; - result.voxel.y = voxel->getCorner().y; - result.voxel.z = voxel->getCorner().z; - result.voxel.s = voxel->getScale(); - result.voxel.red = voxel->getColor()[0]; - result.voxel.green = voxel->getColor()[1]; - result.voxel.blue = voxel->getColor()[2]; - result.intersection = ray.origin + (ray.direction * result.distance); - } - } - return result; -} - -glm::vec3 LocalVoxels::getFaceVector(const QString& face) { - if (face == "MIN_X_FACE") { - return glm::vec3(-1, 0, 0); - } else if (face == "MAX_X_FACE") { - return glm::vec3(1, 0, 0); - } else if (face == "MIN_Y_FACE") { - return glm::vec3(0, -1, 0); - } else if (face == "MAX_Y_FACE") { - return glm::vec3(0, 1, 0); - } else if (face == "MIN_Z_FACE") { - return glm::vec3(0, 0, -1); - } else if (face == "MAX_Z_FACE") { - return glm::vec3(0, 0, 1); - } - return glm::vec3(0, 0, 0); //error case -} diff --git a/libraries/script-engine/src/LocalVoxels.h b/libraries/script-engine/src/LocalVoxels.h deleted file mode 100644 index f6f52aa264..0000000000 --- a/libraries/script-engine/src/LocalVoxels.h +++ /dev/null @@ -1,102 +0,0 @@ -// -// LocalVoxels.h -// libraries/script-engine/src -// -// Created by Clément Brisset on 2/24/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_LocalVoxels_h -#define hifi_LocalVoxels_h - -#include - -#include -#include - - -/// object allowing JS scripters to use their own local trees -class LocalVoxels : public QObject { - Q_OBJECT - -public: - LocalVoxels(QString name); - ~LocalVoxels(); - - /// checks the local voxel tree for a voxel at the specified location and scale - /// \param x the x-coordinate of the voxel (in meter units) - /// \param y the y-coordinate of the voxel (in meter units) - /// \param z the z-coordinate of the voxel (in meter units) - /// \param scale the scale of the voxel (in meter units) - Q_INVOKABLE VoxelDetail getVoxelAt(float x, float y, float z, float scale); - - /// creates a non destructive voxel in the local tree - /// \param x the x-coordinate of the voxel (in meter units) - /// \param y the y-coordinate of the voxel (in meter units) - /// \param z the z-coordinate of the voxel (in meter units) - /// \param scale the scale of the voxel (in meter units) - /// \param red the R value for RGB color of voxel - /// \param green the G value for RGB color of voxel - /// \param blue the B value for RGB color of voxel - Q_INVOKABLE void setVoxelNonDestructive(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); - - /// creates a voxel in the local tree - /// \param x the x-coordinate of the voxel (in meter units) - /// \param y the y-coordinate of the voxel (in meter units) - /// \param z the z-coordinate of the voxel (in meter units) - /// \param scale the scale of the voxel (in meter units) - /// \param red the R value for RGB color of voxel - /// \param green the G value for RGB color of voxel - /// \param blue the B value for RGB color of voxel - Q_INVOKABLE void setVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); - - /// erase the voxel and its children at the given coordinate - /// \param x the x-coordinate of the voxel (in meter units) - /// \param y the y-coordinate of the voxel (in meter units) - /// \param z the z-coordinate of the voxel (in meter units) - /// \param scale the scale of the voxel (in meter units) - Q_INVOKABLE void eraseVoxel(float x, float y, float z, float scale); - - /// copy the given subtree onto destination's root node - /// \param x the x-coordinate of the subtree (in meter units) - /// \param y the y-coordinate of the subtree (in meter units) - /// \param z the z-coordinate of the subtree (in meter units) - /// \param scale the scale of the subtree (in meter units) - /// \param destination LocalVoxels' destination tree - Q_INVOKABLE void copyTo(float x, float y, float z, float scale, const QString destination); - - ///copy source in the given subtree - /// \param x the x-coordinate of the subtree (in meter units) - /// \param y the y-coordinate of the subtree (in meter units) - /// \param z the z-coordinate of the subtree (in meter units) - /// \param scale the scale of the subtree (in meter units) - /// \param source LocalVoxels' source tree - Q_INVOKABLE void pasteFrom(float x, float y, float z, float scale, const QString source); - - /// If the scripting context has visible voxels, this will determine a ray intersection, the results - /// may be inaccurate if the engine is unable to access the visible voxels, in which case result.accurate - /// will be false. - Q_INVOKABLE RayToVoxelIntersectionResult findRayIntersection(const PickRay& ray); - - /// If the scripting context has visible voxels, this will determine a ray intersection, and will block in - /// order to return an accurate result - Q_INVOKABLE RayToVoxelIntersectionResult findRayIntersectionBlocking(const PickRay& ray); - - /// returns a voxel space axis aligned vector for the face, useful in doing voxel math - Q_INVOKABLE glm::vec3 getFaceVector(const QString& face); - -private: - /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode - RayToVoxelIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType); - - QString _name; - StrongVoxelTreePointer _tree; -}; - - - - -#endif // hifi_LocalVoxels_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index ac6291469e..c7be5a973b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -28,22 +28,19 @@ #include #include #include -#include -#include +//#include #include "AnimationObject.h" #include "ArrayBufferViewClass.h" #include "DataViewClass.h" #include "EventTypes.h" #include "MenuItemProperties.h" -#include "LocalVoxels.h" #include "ScriptEngine.h" #include "TypedArrays.h" #include "XMLHttpRequestClass.h" #include "MIDIEvent.h" -VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; EntityScriptingInterface ScriptEngine::_entityScriptingInterface; static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ @@ -200,8 +197,6 @@ void ScriptEngine::handleScriptDownload() { } } -Q_SCRIPT_DECLARE_QMETAOBJECT(LocalVoxels, QString) - void ScriptEngine::init() { if (_isInitialized) { return; // only initialize once @@ -209,12 +204,9 @@ void ScriptEngine::init() { _isInitialized = true; - _voxelsScriptingInterface.init(); - // register various meta-types registerMetaTypes(this); registerMIDIMetaTypes(this); - registerVoxelMetaTypes(this); registerEventTypes(this); registerMenuItemProperties(this); registerAnimationTypes(this); @@ -237,9 +229,6 @@ void ScriptEngine::init() { QScriptValue printConstructorValue = newFunction(debugPrint); globalObject().setProperty("print", printConstructorValue); - QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); - globalObject().setProperty("LocalVoxels", localVoxelsValue); - QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor); globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); @@ -257,19 +246,14 @@ void ScriptEngine::init() { registerGlobalObject("Uuid", &_uuidLibrary); registerGlobalObject("AnimationCache", DependencyManager::get().data()); - registerGlobalObject("Voxels", &_voxelsScriptingInterface); - // constants globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); 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("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); } QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { @@ -379,18 +363,8 @@ void ScriptEngine::run() { break; } - if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) { - // release the queue of edit voxel messages. - _voxelsScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages(); - - // since we're in non-threaded mode, call process so that the packets are sent - if (!_voxelsScriptingInterface.getVoxelPacketSender()->isThreaded()) { - _voxelsScriptingInterface.getVoxelPacketSender()->process(); - } - } - if (_entityScriptingInterface.getEntityPacketSender()->serversExist()) { - // release the queue of edit voxel messages. + // release the queue of edit entity messages. _entityScriptingInterface.getEntityPacketSender()->releaseQueuedMessages(); // since we're in non-threaded mode, call process so that the packets are sent @@ -516,16 +490,6 @@ void ScriptEngine::run() { // kill the avatar identity timer delete _avatarIdentityTimer; - if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) { - // release the queue of edit voxel messages. - _voxelsScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages(); - - // since we're in non-threaded mode, call process so that the packets are sent - if (!_voxelsScriptingInterface.getVoxelPacketSender()->isThreaded()) { - _voxelsScriptingInterface.getVoxelPacketSender()->process(); - } - } - if (_entityScriptingInterface.getEntityPacketSender()->serversExist()) { // release the queue of edit entity messages. _entityScriptingInterface.getEntityPacketSender()->releaseQueuedMessages(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 7474ac8725..10f419937a 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include "AbstractControllerScriptingInterface.h" #include "ArrayBufferClass.h" @@ -31,7 +31,6 @@ #include "Vec3.h" class EntityScriptingInterface; -class VoxelsScriptingInterface; const QString NO_SCRIPT(""); @@ -44,9 +43,6 @@ public: const QString& fileNameString = QString(""), AbstractControllerScriptingInterface* controllerScriptingInterface = NULL); - /// Access the VoxelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener - static VoxelsScriptingInterface* getVoxelsScriptingInterface() { return &_voxelsScriptingInterface; } - /// Access the EntityScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener static EntityScriptingInterface* getEntityScriptingInterface() { return &_entityScriptingInterface; } @@ -141,7 +137,6 @@ private: QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); - static VoxelsScriptingInterface _voxelsScriptingInterface; static EntityScriptingInterface _entityScriptingInterface; AbstractControllerScriptingInterface* _controllerScriptingInterface; diff --git a/libraries/voxels/src/LocalVoxelsList.cpp b/libraries/voxels/src/LocalVoxelsList.cpp deleted file mode 100644 index 55becb0976..0000000000 --- a/libraries/voxels/src/LocalVoxelsList.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// -// LocalVoxelsList.cpp -// libraries/voxels/src -// -// Created by Clément Brisset on 2/24/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 "LocalVoxelsList.h" - -static void doNothing(VoxelTree* t) { - // do nothing -} - -LocalVoxelsList* LocalVoxelsList::_instance = NULL; - -LocalVoxelsList* LocalVoxelsList::getInstance() { - if (!_instance) { - _instance = new LocalVoxelsList(); - } - - return _instance; -} - -LocalVoxelsList::LocalVoxelsList() { -} - -LocalVoxelsList::~LocalVoxelsList() { - _instance = NULL; -} - -StrongVoxelTreePointer LocalVoxelsList::getTree(QString treeName) { - return _trees.value(treeName); -} - -void LocalVoxelsList::addPersistantTree(QString treeName, VoxelTree* tree) { - StrongVoxelTreePointer treePtr(tree, doNothing); - _persistantTrees.push_back(treePtr); - _trees.insert(treeName, treePtr); -} - -void LocalVoxelsList::insert(QString treeName, StrongVoxelTreePointer& tree) { - // If the key don't already exist or the value is null - if (!_trees.contains(treeName) || !_trees.value(treeName)) { - _trees.insert(treeName, tree); - qDebug() << "LocalVoxelsList : added local tree (" << treeName << ")"; - } else { - // if not we replace the tree created by the user with the existing one - tree = _trees.value(treeName); - qDebug() << "[WARNING] LocalVoxelsList : local tree already exist (" << treeName << ")"; - } -} - -void LocalVoxelsList::remove(QString treeName) { - // if the tree is not used anymore (no strong pointer) - if (!_trees.value(treeName)) { - // then remove it from the list - _trees.remove(treeName); - } -} diff --git a/libraries/voxels/src/LocalVoxelsList.h b/libraries/voxels/src/LocalVoxelsList.h deleted file mode 100644 index d22d72446f..0000000000 --- a/libraries/voxels/src/LocalVoxelsList.h +++ /dev/null @@ -1,62 +0,0 @@ -// -// LocalVoxelsList.h -// libraries/voxels/src -// -// Created by Clément Brisset on 2/24/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_LocalVoxelsList_h -#define hifi_LocalVoxelsList_h - -#include -#include -#include -#include - -#include "VoxelTree.h" - -typedef QSharedPointer StrongVoxelTreePointer; -typedef QWeakPointer WeakVoxelTreePointer; - -static const QString DOMAIN_TREE_NAME = "domain"; -static const QString CLIPBOARD_TREE_NAME = "clipboard"; -static const QString IMPORT_TREE_NAME = "import"; - -/// Handles the the storage and cleanup of local named trees used by JS -class LocalVoxelsList { -public: - static LocalVoxelsList* getInstance(); - ~LocalVoxelsList(); - - /// Lookup up a tree in the QHash and return a strong pointer to it. - /// \param treeName name of the tree to look up - StrongVoxelTreePointer getTree(QString treeName); - - /// Add a that will stay in the list until destruction of the instance and won't be destroyed then either. - /// \param treeName name to give to the tree in the list - /// \param tree standard pointer to the tree - void addPersistantTree(QString treeName, VoxelTree* tree); - - /// insert a local tree in the list - /// \param treeName name to give to the tree in the list - /// \param tree strong pointer to the tree - void insert(QString treeName, StrongVoxelTreePointer& tree); - - /// remove a tree from the list if it's not being used anymore - /// \param treeName name of the tree to remove - void remove(QString treeName); - -private: - static LocalVoxelsList* _instance; - LocalVoxelsList(); - - QHash _trees; - - QList _persistantTrees; -}; - -#endif // hifi_LocalVoxelsList_h diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp deleted file mode 100644 index 50d6617278..0000000000 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// -// VoxelEditPacketSender.cpp -// libraries/voxels/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 -#include -#include -#include -#include "VoxelEditPacketSender.h" - -#define GUESS_OF_VOXELCODE_SIZE 10 -#define MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE 1500 -#define SIZE_OF_COLOR_DATA sizeof(rgbColor) -/// creates an "insert" or "remove" voxel message for a voxel code corresponding to the closest voxel which encloses a cube -/// with lower corners at x,y,z, having side of length S. The input values x,y,z range 0.0 <= v < 1.0 message should be either -/// PacketTypeVoxelSet, PacketTypeVoxelSetDestructive, or PacketTypeVoxelErase. The buffer is returned to caller becomes -/// responsibility of caller and MUST be deleted by caller. -bool createVoxelEditMessage(PacketType command, short int sequence, - int voxelCount, const VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut) { - - bool success = true; // assume the best - int messageSize = MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE; // just a guess for now - unsigned char* messageBuffer = new unsigned char[messageSize]; - - int numBytesPacketHeader = populatePacketHeader(reinterpret_cast(messageBuffer), command); - unsigned short int* sequenceAt = (unsigned short int*) &messageBuffer[numBytesPacketHeader]; - *sequenceAt = sequence; - - // pack in timestamp - quint64 now = usecTimestampNow(); - quint64* timeAt = (quint64*)&messageBuffer[numBytesPacketHeader + sizeof(sequence)]; - *timeAt = now; - - unsigned char* copyAt = &messageBuffer[numBytesPacketHeader + sizeof(sequence) + sizeof(now)]; - int actualMessageSize = numBytesPacketHeader + sizeof(sequence) + sizeof(now); - - for (int i = 0; i < voxelCount && success; i++) { - // get the coded voxel - unsigned char* voxelData = pointToVoxel(voxelDetails[i].x,voxelDetails[i].y,voxelDetails[i].z, - voxelDetails[i].s,voxelDetails[i].red,voxelDetails[i].green,voxelDetails[i].blue); - - int lengthOfVoxelData = bytesRequiredForCodeLength(*voxelData)+SIZE_OF_COLOR_DATA; - - // make sure we have room to copy this voxel - if (actualMessageSize + lengthOfVoxelData > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { - success = false; - } else { - // add it to our message - memcpy(copyAt, voxelData, lengthOfVoxelData); - copyAt += lengthOfVoxelData; - actualMessageSize += lengthOfVoxelData; - } - // cleanup - delete[] voxelData; - } - - if (success) { - // finally, copy the result to the output - bufferOut = new unsigned char[actualMessageSize]; - sizeOut = actualMessageSize; - memcpy(bufferOut, messageBuffer, actualMessageSize); - } - - delete[] messageBuffer; // clean up our temporary buffer - return success; -} - -/// encodes the voxel details portion of a voxel edit message -bool encodeVoxelEditMessageDetails(PacketType, int voxelCount, VoxelDetail* voxelDetails, - unsigned char* bufferOut, int sizeIn, int& sizeOut) { - - bool success = true; // assume the best - unsigned char* copyAt = bufferOut; - sizeOut = 0; - - for (int i = 0; i < voxelCount && success; i++) { - // get the coded voxel - unsigned char* voxelData = pointToVoxel(voxelDetails[i].x,voxelDetails[i].y,voxelDetails[i].z, - voxelDetails[i].s,voxelDetails[i].red,voxelDetails[i].green,voxelDetails[i].blue); - - int lengthOfVoxelData = bytesRequiredForCodeLength(*voxelData)+SIZE_OF_COLOR_DATA; - - // make sure we have room to copy this voxel - if (sizeOut + lengthOfVoxelData > sizeIn) { - success = false; - } else { - // add it to our message - memcpy(copyAt, voxelData, lengthOfVoxelData); - copyAt += lengthOfVoxelData; - sizeOut += lengthOfVoxelData; - } - // cleanup - delete[] voxelData; - } - - return success; -} - -void VoxelEditPacketSender::sendVoxelEditMessage(PacketType type, const VoxelDetail& detail) { - // allows app to disable sending if for example voxels have been disabled - if (!_shouldSend) { - return; // bail early - } - - unsigned char* bufferOut; - int sizeOut; - - // This encodes the voxel edit message into a buffer... - if (createVoxelEditMessage(type, 0, 1, &detail, bufferOut, 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 (!voxelServersExist()) { - queuePendingPacketToNodes(type, bufferOut, sizeOut, satoshiCostForMessage(detail)); - } else { - queuePacketToNodes(bufferOut, sizeOut, satoshiCostForMessage(detail)); - } - - // either way, clean up the created buffer - delete[] bufferOut; - } -} - -void VoxelEditPacketSender::queueVoxelEditMessages(PacketType type, int numberOfDetails, VoxelDetail* details) { - if (!_shouldSend) { - return; // bail early - } - - for (int i = 0; i < numberOfDetails; i++) { - // use MAX_PACKET_SIZE since it's static and guarenteed to be larger than _maxPacketSize - unsigned char bufferOut[MAX_PACKET_SIZE]; - int sizeOut = 0; - - if (encodeVoxelEditMessageDetails(type, 1, &details[i], &bufferOut[0], _maxPacketSize, sizeOut)) { - queueOctreeEditMessage(type, bufferOut, sizeOut, satoshiCostForMessage(details[i])); - } - } -} - -qint64 VoxelEditPacketSender::satoshiCostForMessage(const VoxelDetail& details) { - if (_satoshisPerVoxel == 0 && _satoshisPerMeterCubed == 0) { - return 0; - } else { - float meterScale = details.s * TREE_SCALE; - float totalVolume = meterScale * meterScale * meterScale; - - return _satoshisPerVoxel + (qint64) floorf(totalVolume * _satoshisPerMeterCubed); - } -} diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h deleted file mode 100644 index 3b85155036..0000000000 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ /dev/null @@ -1,63 +0,0 @@ -// -// VoxelEditPacketSender.h -// libraries/voxels/src -// -// Created by Brad Hefta-Gaub on 8/12/13. -// Copyright 2013 High Fidelity, Inc. -// -// Voxel Packet Sender -// -// 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_VoxelEditPacketSender_h -#define hifi_VoxelEditPacketSender_h - -#include - -#include "VoxelDetail.h" - -/// Utility for processing, packing, queueing and sending of outbound edit voxel messages. -class VoxelEditPacketSender : public OctreeEditPacketSender { - Q_OBJECT -public: - /// Send voxel edit message immediately - void sendVoxelEditMessage(PacketType type, const VoxelDetail& detail); - - /// Queues a single voxel edit message. 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. - void queueVoxelEditMessage(PacketType type, unsigned char* codeColorBuffer, size_t length) { - queueOctreeEditMessage(type, codeColorBuffer, length); - } - - /// 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. - void queueVoxelEditMessages(PacketType type, int numberOfDetails, VoxelDetail* details); - - /// call this to inform the VoxelEditPacketSender of the voxel server jurisdictions. This is required for normal operation. - /// The internal contents of the jurisdiction map may change throughout the lifetime of the VoxelEditPacketSender. This map - /// can be set prior to voxel servers being present, so long as the contents of the map accurately reflect the current - /// known jurisdictions. - void setVoxelServerJurisdictions(NodeToJurisdictionMap* voxelServerJurisdictions) { - setServerJurisdictions(voxelServerJurisdictions); - } - - // is there a voxel server available to send packets to - bool voxelServersExist() const { return serversExist(); } - - // My server type is the voxel server - virtual char getMyNodeType() const { return NodeType::VoxelServer; } - - void setSatoshisPerVoxel(qint64 satoshisPerVoxel) { _satoshisPerVoxel = satoshisPerVoxel; } - void setSatoshisPerMeterCubed(qint64 satoshisPerMeterCubed) { _satoshisPerMeterCubed = satoshisPerMeterCubed; } - - qint64 satoshiCostForMessage(const VoxelDetail& details); - -private: - qint64 _satoshisPerVoxel; - qint64 _satoshisPerMeterCubed; -}; -#endif // hifi_VoxelEditPacketSender_h diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp deleted file mode 100644 index 0809e922e1..0000000000 --- a/libraries/voxels/src/VoxelTree.cpp +++ /dev/null @@ -1,591 +0,0 @@ -// -// VoxelTree.cpp -// libraries/voxels/src -// -// Created by Stephen Birarda on 3/13/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 - -#include -#include -#include - -#include "VoxelTree.h" -#include "Tags.h" - -// Voxel Specific operations.... - -VoxelTree::VoxelTree(bool shouldReaverage) : Octree(shouldReaverage) -{ - _rootElement = createNewElement(); -} - -VoxelTreeElement* VoxelTree::createNewElement(unsigned char * octalCode) { - VoxelSystem* voxelSystem = NULL; - if (_rootElement) { - voxelSystem = (static_cast(_rootElement))->getVoxelSystem(); - } - VoxelTreeElement* newElement = new VoxelTreeElement(octalCode); - newElement->setVoxelSystem(voxelSystem); - return newElement; -} - - -void VoxelTree::deleteVoxelAt(float x, float y, float z, float s) { - deleteOctreeElementAt(x, y, z, s); -} - -VoxelTreeElement* VoxelTree::getVoxelAt(float x, float y, float z, float s) const { - return static_cast(getOctreeElementAt(x, y, z, s)); -} - -VoxelTreeElement* VoxelTree::getEnclosingVoxelAt(float x, float y, float z, float s) const { - return static_cast(getOctreeEnclosingElementAt(x, y, z, s)); -} - -void VoxelTree::createVoxel(float x, float y, float z, float s, - unsigned char red, unsigned char green, unsigned char blue, bool destructive) { - - unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue); - lockForWrite(); - readCodeColorBufferToTree(voxelData, destructive); - unlock(); - delete[] voxelData; -} - -class NodeChunkArgs { -public: - VoxelTree* thisVoxelTree; - glm::vec3 nudgeVec; - VoxelEditPacketSender* voxelEditSenderPtr; - int childOrder[NUMBER_OF_CHILDREN]; -}; - -float findNewLeafSize(const glm::vec3& nudgeAmount, float leafSize) { - // we want the smallest non-zero and non-negative new leafSize - float newLeafSizeX = fabs(fmod(nudgeAmount.x, leafSize)); - float newLeafSizeY = fabs(fmod(nudgeAmount.y, leafSize)); - float newLeafSizeZ = fabs(fmod(nudgeAmount.z, leafSize)); - - float newLeafSize = leafSize; - if (newLeafSizeX) { - newLeafSize = std::min(newLeafSize, newLeafSizeX); - } - if (newLeafSizeY) { - newLeafSize = std::min(newLeafSize, newLeafSizeY); - } - if (newLeafSizeZ) { - newLeafSize = std::min(newLeafSize, newLeafSizeZ); - } - return newLeafSize; -} - -void reorderChildrenForNudge(void* extraData) { - NodeChunkArgs* args = (NodeChunkArgs*)extraData; - glm::vec3 nudgeVec = args->nudgeVec; - int lastToNudgeVote[NUMBER_OF_CHILDREN] = { 0 }; - - const int POSITIVE_X_ORDERING[4] = {0, 1, 2, 3}; - const int NEGATIVE_X_ORDERING[4] = {4, 5, 6, 7}; - const int POSITIVE_Y_ORDERING[4] = {0, 1, 4, 5}; - const int NEGATIVE_Y_ORDERING[4] = {2, 3, 6, 7}; - const int POSITIVE_Z_ORDERING[4] = {0, 2, 4, 6}; - const int NEGATIVE_Z_ORDERING[4] = {1, 3, 5, 7}; - - if (nudgeVec.x > 0) { - for (int i = 0; i < NUMBER_OF_CHILDREN / 2; i++) { - lastToNudgeVote[POSITIVE_X_ORDERING[i]]++; - } - } else if (nudgeVec.x < 0) { - for (int i = 0; i < NUMBER_OF_CHILDREN / 2; i++) { - lastToNudgeVote[NEGATIVE_X_ORDERING[i]]++; - } - } - if (nudgeVec.y > 0) { - for (int i = 0; i < NUMBER_OF_CHILDREN / 2; i++) { - lastToNudgeVote[POSITIVE_Y_ORDERING[i]]++; - } - } else if (nudgeVec.y < 0) { - for (int i = 0; i < NUMBER_OF_CHILDREN / 2; i++) { - lastToNudgeVote[NEGATIVE_Y_ORDERING[i]]++; - } - } - if (nudgeVec.z > 0) { - for (int i = 0; i < NUMBER_OF_CHILDREN / 2; i++) { - lastToNudgeVote[POSITIVE_Z_ORDERING[i]]++; - } - } else if (nudgeVec.z < 0) { - for (int i = 0; i < NUMBER_OF_CHILDREN / 2; i++) { - lastToNudgeVote[NEGATIVE_Z_ORDERING[i]]++; - } - } - - int nUncountedVotes = NUMBER_OF_CHILDREN; - - while (nUncountedVotes > 0) { - int maxNumVotes = 0; - int maxVoteIndex = -1; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (lastToNudgeVote[i] > maxNumVotes) { - maxNumVotes = lastToNudgeVote[i]; - maxVoteIndex = i; - } else if (lastToNudgeVote[i] == maxNumVotes && maxVoteIndex == -1) { - maxVoteIndex = i; - } - } - lastToNudgeVote[maxVoteIndex] = -1; - args->childOrder[nUncountedVotes - 1] = maxVoteIndex; - nUncountedVotes--; - } -} - -bool VoxelTree::nudgeCheck(OctreeElement* element, void* extraData) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - if (voxel->isLeaf()) { - // we have reached the deepest level of elements/voxels - // now there are two scenarios - // 1) this element's size is <= the minNudgeAmount - // in which case we will simply call nudgeLeaf on this leaf - // 2) this element's size is still not <= the minNudgeAmount - // in which case we need to break this leaf down until the leaf sizes are <= minNudgeAmount - - NodeChunkArgs* args = (NodeChunkArgs*)extraData; - - // get octal code of this element - const unsigned char* octalCode = element->getOctalCode(); - - // get voxel position/size - VoxelPositionSize unNudgedDetails; - voxelDetailsForCode(octalCode, unNudgedDetails); - - // find necessary leaf size - float newLeafSize = findNewLeafSize(args->nudgeVec, unNudgedDetails.s); - - // check to see if this unNudged element can be nudged - if (unNudgedDetails.s <= newLeafSize) { - args->thisVoxelTree->nudgeLeaf(voxel, extraData); - return false; - } else { - // break the current leaf into smaller chunks - args->thisVoxelTree->chunkifyLeaf(voxel); - } - } - return true; -} - -void VoxelTree::chunkifyLeaf(VoxelTreeElement* element) { - // because this function will continue being called recursively - // we only need to worry about breaking this specific leaf down - if (!element->isColored()) { - return; - } - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - element->addChildAtIndex(i); - element->getChildAtIndex(i)->setColor(element->getColor()); - } -} - -// This function is called to nudge the leaves of a tree, given that the -// nudge amount is >= to the leaf scale. -void VoxelTree::nudgeLeaf(VoxelTreeElement* element, void* extraData) { - NodeChunkArgs* args = (NodeChunkArgs*)extraData; - - // get octal code of this element - const unsigned char* octalCode = element->getOctalCode(); - - // get voxel position/size - VoxelPositionSize unNudgedDetails; - voxelDetailsForCode(octalCode, unNudgedDetails); - - VoxelDetail voxelDetails; - voxelDetails.x = unNudgedDetails.x; - voxelDetails.y = unNudgedDetails.y; - voxelDetails.z = unNudgedDetails.z; - voxelDetails.s = unNudgedDetails.s; - voxelDetails.red = element->getColor()[RED_INDEX]; - voxelDetails.green = element->getColor()[GREEN_INDEX]; - voxelDetails.blue = element->getColor()[BLUE_INDEX]; - glm::vec3 nudge = args->nudgeVec; - - // delete the old element - args->voxelEditSenderPtr->sendVoxelEditMessage(PacketTypeVoxelErase, voxelDetails); - - // nudge the old element - voxelDetails.x += nudge.x; - voxelDetails.y += nudge.y; - voxelDetails.z += nudge.z; - - // create a new voxel in its stead - args->voxelEditSenderPtr->sendVoxelEditMessage(PacketTypeVoxelSetDestructive, voxelDetails); -} - -// Recurses voxel element with an operation function -void VoxelTree::recurseNodeForNudge(VoxelTreeElement* element, RecurseOctreeOperation operation, void* extraData) { - NodeChunkArgs* args = (NodeChunkArgs*)extraData; - if (operation(element, extraData)) { - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - // XXXBHG cleanup!! - VoxelTreeElement* child = (VoxelTreeElement*)element->getChildAtIndex(args->childOrder[i]); - if (child) { - recurseNodeForNudge(child, operation, extraData); - } - } - } -} - -void VoxelTree::nudgeSubTree(VoxelTreeElement* elementToNudge, const glm::vec3& nudgeAmount, VoxelEditPacketSender& voxelEditSender) { - if (nudgeAmount == glm::vec3(0, 0, 0)) { - return; - } - - NodeChunkArgs args; - args.thisVoxelTree = this; - args.nudgeVec = nudgeAmount; - args.voxelEditSenderPtr = &voxelEditSender; - reorderChildrenForNudge(&args); - - recurseNodeForNudge(elementToNudge, nudgeCheck, &args); -} - - - - - -bool VoxelTree::readFromSquareARGB32Pixels(const char* filename) { - emit importProgress(0); - int minAlpha = INT_MAX; - - QImage pngImage = QImage(filename); - - for (int i = 0; i < pngImage.width(); ++i) { - for (int j = 0; j < pngImage.height(); ++j) { - minAlpha = std::min(qAlpha(pngImage.pixel(i, j)) , minAlpha); - } - } - - int maxSize = std::max(pngImage.width(), pngImage.height()); - - int scale = 1; - while (maxSize > scale) {scale *= 2;} - float size = 1.0f / scale; - - emit importSize(size * pngImage.width(), 1.0f, size * pngImage.height()); - - QRgb pixel; - int minNeighborhoodAlpha; - - for (int i = 0; i < pngImage.width(); ++i) { - for (int j = 0; j < pngImage.height(); ++j) { - emit importProgress((100 * (i * pngImage.height() + j)) / - (pngImage.width() * pngImage.height())); - - pixel = pngImage.pixel(i, j); - minNeighborhoodAlpha = qAlpha(pixel) - 1; - - if (i != 0) { - minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i - 1, j))); - } - if (j != 0) { - minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i, j - 1))); - } - if (i < pngImage.width() - 1) { - minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i + 1, j))); - } - if (j < pngImage.height() - 1) { - minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i, j + 1))); - } - - while (qAlpha(pixel) > minNeighborhoodAlpha) { - ++minNeighborhoodAlpha; - createVoxel(i * size, - (minNeighborhoodAlpha - minAlpha) * size, - j * size, - size, - qRed(pixel), - qGreen(pixel), - qBlue(pixel), - true); - } - - } - } - - emit importProgress(100); - return true; -} - -bool VoxelTree::readFromSchematicFile(const char *fileName) { - _stopImport = false; - emit importProgress(0); - - std::stringstream ss; - int err = retrieveData(std::string(fileName), ss); - if (err && ss.get() != TAG_Compound) { - qDebug("[ERROR] Invalid schematic file."); - return false; - } - - ss.get(); - TagCompound schematics(ss); - if (!schematics.getBlocksId() || !schematics.getBlocksData()) { - qDebug("[ERROR] Invalid schematic data."); - return false; - } - - int max = (schematics.getWidth() > schematics.getLength()) ? schematics.getWidth() : schematics.getLength(); - max = (max > schematics.getHeight()) ? max : schematics.getHeight(); - - int scale = 1; - while (max > scale) {scale *= 2;} - float size = 1.0f / scale; - - emit importSize(size * schematics.getWidth(), - size * schematics.getHeight(), - size * schematics.getLength()); - - int create = 1; - int red = 128, green = 128, blue = 128; - int count = 0; - - for (int y = 0; y < schematics.getHeight(); ++y) { - for (int z = 0; z < schematics.getLength(); ++z) { - emit importProgress((int) 100 * (y * schematics.getLength() + z) / (schematics.getHeight() * schematics.getLength())); - - for (int x = 0; x < schematics.getWidth(); ++x) { - if (_stopImport) { - qDebug("Canceled import at %d voxels.", count); - _stopImport = false; - return true; - } - - int pos = ((y * schematics.getLength()) + z) * schematics.getWidth() + x; - int id = schematics.getBlocksId()[pos]; - int data = schematics.getBlocksData()[pos]; - - create = 1; - computeBlockColor(id, data, red, green, blue, create); - - switch (create) { - case 1: - createVoxel(size * x, size * y, size * z, size, red, green, blue, true); - ++count; - break; - case 2: - switch (data) { - case 0: - createVoxel(size * x + size / 2, size * y + size / 2, size * z , size / 2, red, green, blue, true); - createVoxel(size * x + size / 2, size * y + size / 2, size * z + size / 2, size / 2, red, green, blue, true); - break; - case 1: - createVoxel(size * x , size * y + size / 2, size * z , size / 2, red, green, blue, true); - createVoxel(size * x , size * y + size / 2, size * z + size / 2, size / 2, red, green, blue, true); - break; - case 2: - createVoxel(size * x , size * y + size / 2, size * z + size / 2, size / 2, red, green, blue, true); - createVoxel(size * x + size / 2, size * y + size / 2, size * z + size / 2, size / 2, red, green, blue, true); - break; - case 3: - createVoxel(size * x , size * y + size / 2, size * z , size / 2, red, green, blue, true); - createVoxel(size * x + size / 2, size * y + size / 2, size * z , size / 2, red, green, blue, true); - break; - } - count += 2; - // There's no break on purpose. - case 3: - createVoxel(size * x , size * y, size * z , size / 2, red, green, blue, true); - createVoxel(size * x + size / 2, size * y, size * z , size / 2, red, green, blue, true); - createVoxel(size * x , size * y, size * z + size / 2, size / 2, red, green, blue, true); - createVoxel(size * x + size / 2, size * y, size * z + size / 2, size / 2, red, green, blue, true); - count += 4; - break; - } - } - } - } - - emit importProgress(100); - qDebug("Created %d voxels from minecraft import.", count); - - return true; -} - -class ReadCodeColorBufferToTreeArgs { -public: - const unsigned char* codeColorBuffer; - int lengthOfCode; - bool destructive; - bool pathChanged; -}; - -void VoxelTree::readCodeColorBufferToTree(const unsigned char* codeColorBuffer, bool destructive) { - ReadCodeColorBufferToTreeArgs args; - args.codeColorBuffer = codeColorBuffer; - args.lengthOfCode = numberOfThreeBitSectionsInCode(codeColorBuffer); - args.destructive = destructive; - args.pathChanged = false; - VoxelTreeElement* node = getRoot(); - readCodeColorBufferToTreeRecursion(node, args); -} - -void VoxelTree::readCodeColorBufferToTreeRecursion(VoxelTreeElement* node, ReadCodeColorBufferToTreeArgs& args) { - int lengthOfNodeCode = numberOfThreeBitSectionsInCode(node->getOctalCode()); - - // Since we traverse the tree in code order, we know that if our code - // matches, then we've reached our target node. - if (lengthOfNodeCode == args.lengthOfCode) { - // we've reached our target -- we might have found our node, but that node might have children. - // in this case, we only allow you to set the color if you explicitly asked for a destructive - // write. - if (!node->isLeaf() && args.destructive) { - // if it does exist, make sure it has no children - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - node->deleteChildAtIndex(i); - } - } else { - if (!node->isLeaf()) { - qDebug("WARNING! operation would require deleting children, add Voxel ignored!"); - } - } - - // If we get here, then it means, we either had a true leaf to begin with, or we were in - // destructive mode and we deleted all the child trees. So we can color. - if (node->isLeaf()) { - // give this node its color - int octalCodeBytes = bytesRequiredForCodeLength(args.lengthOfCode); - - nodeColor newColor; - memcpy(newColor, args.codeColorBuffer + octalCodeBytes, SIZE_OF_COLOR_DATA); - newColor[SIZE_OF_COLOR_DATA] = 1; - node->setColor(newColor); - - // It's possible we just reset the node to it's exact same color, in - // which case we don't consider this to be dirty... - if (node->isDirty()) { - // track our tree dirtiness - _isDirty = true; - // track that path has changed - args.pathChanged = true; - } - } - return; - } - - // Ok, we know we haven't reached our target node yet, so keep looking - //printOctalCode(args.codeColorBuffer); - int childIndex = branchIndexWithDescendant(node->getOctalCode(), args.codeColorBuffer); - VoxelTreeElement* childNode = node->getChildAtIndex(childIndex); - - // If the branch we need to traverse does not exist, then create it on the way down... - if (!childNode) { - childNode = node->addChildAtIndex(childIndex); - } - - // recurse... - readCodeColorBufferToTreeRecursion(childNode, args); - - // Unwinding... - - // If the lower level did some work, then we need to let this node know, so it can - // do any bookkeeping it wants to, like color re-averaging, time stamp marking, etc - if (args.pathChanged) { - node->handleSubtreeChanged(this); - } -} - -bool VoxelTree::handlesEditPacketType(PacketType packetType) const { - // we handle these types of "edit" packets - switch (packetType) { - case PacketTypeVoxelSet: - case PacketTypeVoxelSetDestructive: - case PacketTypeVoxelErase: - return true; - default: - return false; - - } -} - -const unsigned int REPORT_OVERFLOW_WARNING_INTERVAL = 100; -unsigned int overflowWarnings = 0; -int VoxelTree::processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength, - const unsigned char* editData, int maxLength, const SharedNodePointer& node) { - - // we handle these types of "edit" packets - switch (packetType) { - case PacketTypeVoxelSet: - case PacketTypeVoxelSetDestructive: { - bool destructive = (packetType == PacketTypeVoxelSetDestructive); - int octets = numberOfThreeBitSectionsInCode(editData, maxLength); - - if (octets == OVERFLOWED_OCTCODE_BUFFER) { - overflowWarnings++; - if (overflowWarnings % REPORT_OVERFLOW_WARNING_INTERVAL == 1) { - qDebug() << "WARNING! Got voxel edit record that would overflow buffer in numberOfThreeBitSectionsInCode()" - " [NOTE: this is warning number" << overflowWarnings << ", the next" << - (REPORT_OVERFLOW_WARNING_INTERVAL-1) << "will be suppressed.]"; - - QDebug debug = qDebug(); - debug << "edit data contents:"; - outputBufferBits(editData, maxLength, &debug); - } - return maxLength; - } - - const int COLOR_SIZE_IN_BYTES = 3; - int voxelCodeSize = bytesRequiredForCodeLength(octets); - int voxelDataSize = voxelCodeSize + COLOR_SIZE_IN_BYTES; - - if (voxelDataSize > maxLength) { - overflowWarnings++; - if (overflowWarnings % REPORT_OVERFLOW_WARNING_INTERVAL == 1) { - qDebug() << "WARNING! Got voxel edit record that would overflow buffer." - " [NOTE: this is warning number" << overflowWarnings << ", the next" << - (REPORT_OVERFLOW_WARNING_INTERVAL-1) << "will be suppressed.]"; - - QDebug debug = qDebug(); - debug << "edit data contents:"; - outputBufferBits(editData, maxLength, &debug); - } - return maxLength; - } - - readCodeColorBufferToTree(editData, destructive); - - return voxelDataSize; - } break; - - case PacketTypeVoxelErase: - processRemoveOctreeElementsBitstream((unsigned char*)packetData, packetLength); - return maxLength; - default: - return 0; - } -} - -class VoxelTreeDebugOperator : public RecurseOctreeOperator { -public: - virtual bool preRecursion(OctreeElement* element); - virtual bool postRecursion(OctreeElement* element) { return true; } -}; - -bool VoxelTreeDebugOperator::preRecursion(OctreeElement* element) { - VoxelTreeElement* treeElement = static_cast(element); - qDebug() << "VoxelTreeElement [" << treeElement << ":" << treeElement->getAACube() << "]"; - qDebug() << " isLeaf:" << treeElement->isLeaf(); - qDebug() << " color:" << treeElement->getColor()[0] << ", " - << treeElement->getColor()[1] << ", " - << treeElement->getColor()[2]; - return true; -} - -void VoxelTree::dumpTree() { - // First, look for the existing entity in the tree.. - VoxelTreeDebugOperator theOperator; - recurseTreeWithOperator(&theOperator); -} - diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h deleted file mode 100644 index 547f590270..0000000000 --- a/libraries/voxels/src/VoxelTree.h +++ /dev/null @@ -1,87 +0,0 @@ -// -// VoxelTree.h -// libraries/voxels/src -// -// Created by Stephen Birarda on 3/13/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_VoxelTree_h -#define hifi_VoxelTree_h - -#include - -#include "VoxelTreeElement.h" -#include "VoxelEditPacketSender.h" - -class ReadCodeColorBufferToTreeArgs; - -class VoxelTree : public Octree { - Q_OBJECT -public: - - VoxelTree(bool shouldReaverage = false); - - virtual VoxelTreeElement* createNewElement(unsigned char * octalCode = NULL); - VoxelTreeElement* getRoot() { return static_cast(_rootElement); } - - void deleteVoxelAt(float x, float y, float z, float s); - - /// Find the voxel at position x,y,z,s - /// \return pointer to the VoxelTreeElement or NULL if none at x,y,z,s. - VoxelTreeElement* getVoxelAt(float x, float y, float z, float s) const; - - /// Find the voxel at position x,y,z,s - /// \return pointer to the VoxelTreeElement or to the smallest enclosing parent if none at x,y,z,s. - VoxelTreeElement* getEnclosingVoxelAt(float x, float y, float z, float s) const; - - void createVoxel(float x, float y, float z, float s, - unsigned char red, unsigned char green, unsigned char blue, bool destructive = false); - - void nudgeSubTree(VoxelTreeElement* elementToNudge, const glm::vec3& nudgeAmount, VoxelEditPacketSender& voxelEditSender); - - /// reads voxels from square image with alpha as a Y-axis - bool readFromSquareARGB32Pixels(const char *filename); - - /// reads from minecraft file - bool readFromSchematicFile(const char* filename); - - void readCodeColorBufferToTree(const unsigned char* codeColorBuffer, bool destructive = false); - - - virtual bool getWantSVOfileVersions() const { return true; } - virtual bool canProcessVersion(PacketVersion thisVersion) const { - return thisVersion == 0 || thisVersion == versionForPacketType(expectedDataPacketType()); } - virtual PacketVersion expectedVersion() const { return versionForPacketType(expectedDataPacketType()); } - - virtual PacketType expectedDataPacketType() const { return PacketTypeVoxelData; } - 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& node); - virtual bool recurseChildrenWithData() const { return false; } - - /// some versions of the SVO file will include breaks with buffer lengths between each buffer chunk in the SVO - /// file. If the Octree subclass expects this for this particular version of the file, it should override this - /// method and return true. - virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const { - if (thisVersion == 0) { - return false; // old versions didn't have buffer breaks - } - return true; - } - - virtual void dumpTree(); - -private: - // helper functions for nudgeSubTree - void recurseNodeForNudge(VoxelTreeElement* element, RecurseOctreeOperation operation, void* extraData); - static bool nudgeCheck(OctreeElement* element, void* extraData); - void nudgeLeaf(VoxelTreeElement* element, void* extraData); - void chunkifyLeaf(VoxelTreeElement* element); - void readCodeColorBufferToTreeRecursion(VoxelTreeElement* node, ReadCodeColorBufferToTreeArgs& args); -}; - -#endif // hifi_VoxelTree_h diff --git a/libraries/voxels/src/VoxelTreeCommands.cpp b/libraries/voxels/src/VoxelTreeCommands.cpp deleted file mode 100644 index 4ddc280749..0000000000 --- a/libraries/voxels/src/VoxelTreeCommands.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// -// VoxelTreeCommands.cpp -// libraries/voxels/src -// -// Created by Clement on 4/4/14. -// 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 "VoxelTree.h" - -#include "VoxelTreeCommands.h" - - - -struct SendVoxelsOperationArgs { - const unsigned char* newBaseOctCode; - VoxelEditPacketSender* packetSender; -}; - -bool sendVoxelsOperation(OctreeElement* element, void* extraData) { - VoxelTreeElement* voxel = static_cast(element); - SendVoxelsOperationArgs* args = static_cast(extraData); - if (voxel->isColored()) { - const unsigned char* nodeOctalCode = voxel->getOctalCode(); - unsigned char* codeColorBuffer = NULL; - int codeLength = 0; - int bytesInCode = 0; - int codeAndColorLength; - - // If the newBase is NULL, then don't rebase - if (args->newBaseOctCode) { - codeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true); - codeLength = numberOfThreeBitSectionsInCode(codeColorBuffer); - bytesInCode = bytesRequiredForCodeLength(codeLength); - codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA; - } else { - codeLength = numberOfThreeBitSectionsInCode(nodeOctalCode); - bytesInCode = bytesRequiredForCodeLength(codeLength); - codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA; - codeColorBuffer = new unsigned char[codeAndColorLength]; - memcpy(codeColorBuffer, nodeOctalCode, bytesInCode); - } - - // copy the colors over - codeColorBuffer[bytesInCode + RED_INDEX] = voxel->getColor()[RED_INDEX]; - codeColorBuffer[bytesInCode + GREEN_INDEX] = voxel->getColor()[GREEN_INDEX]; - codeColorBuffer[bytesInCode + BLUE_INDEX] = voxel->getColor()[BLUE_INDEX]; - args->packetSender->queueVoxelEditMessage(PacketTypeVoxelSetDestructive, - codeColorBuffer, codeAndColorLength); - - delete[] codeColorBuffer; - } - return true; // keep going -} - - -AddVoxelCommand::AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) : - QUndoCommand("Add Voxel", parent), - _tree(tree), - _packetSender(packetSender), - _voxel(voxel) -{ -} - -void AddVoxelCommand::redo() { - if (_tree) { - _tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue); - } - if (_packetSender) { - _packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel); - } -} - -void AddVoxelCommand::undo() { - if (_tree) { - _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - } - if (_packetSender) { - _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); - } -} - -DeleteVoxelCommand::DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) : - QUndoCommand("Delete Voxel", parent), - _tree(tree), - _packetSender(packetSender), - _voxel(voxel), - _oldTree(NULL) -{ - _tree->lockForRead(); - VoxelTreeElement* element = _tree->getEnclosingVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - if (element->getScale() == _voxel.s) { - if (!element->hasContent() && !element->isLeaf()) { - _oldTree = new VoxelTree(); - _tree->copySubTreeIntoNewTree(element, _oldTree, false); - } else { - _voxel.red = element->getColor()[0]; - _voxel.green = element->getColor()[1]; - _voxel.blue = element->getColor()[2]; - } - } else if (element->hasContent() && element->isLeaf()) { - _voxel.red = element->getColor()[0]; - _voxel.green = element->getColor()[1]; - _voxel.blue = element->getColor()[2]; - } else { - _voxel.s = 0.0f; - } - _tree->unlock(); -} - -DeleteVoxelCommand::~DeleteVoxelCommand() { - delete _oldTree; -} - -void DeleteVoxelCommand::redo() { - if (_voxel.s == 0.0f) { - return; - } - - if (_tree) { - _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - } - if (_packetSender) { - _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); - } -} - -void DeleteVoxelCommand::undo() { - if (_voxel.s == 0.0f) { - return; - } - - if (_oldTree) { - VoxelTreeElement* element = _oldTree->getVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - if (element) { - if (_tree) { - _tree->lockForWrite(); - _oldTree->copySubTreeIntoNewTree(element, _tree, false); - _tree->unlock(); - } - if (_packetSender) { - SendVoxelsOperationArgs args; - args.newBaseOctCode = NULL; - args.packetSender = _packetSender; - _oldTree->recurseTreeWithOperation(sendVoxelsOperation, &args); - _packetSender->releaseQueuedMessages(); - } - } - } else { - if (_tree) { - _tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue); - } - if (_packetSender) { - _packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel); - } - } -} diff --git a/libraries/voxels/src/VoxelTreeCommands.h b/libraries/voxels/src/VoxelTreeCommands.h deleted file mode 100644 index 8df1f0dc14..0000000000 --- a/libraries/voxels/src/VoxelTreeCommands.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// VoxelTreeCommands.h -// libraries/voxels/src -// -// Created by Clement on 4/4/14. -// 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_VoxelTreeCommands_h -#define hifi_VoxelTreeCommands_h - -#include -#include - -#include "VoxelDetail.h" -#include "VoxelEditPacketSender.h" - -class VoxelTree; - -class AddVoxelCommand : public QUndoCommand { -public: - AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL); - - virtual void redo(); - virtual void undo(); - -private: - VoxelTree* _tree; - VoxelEditPacketSender* _packetSender; - VoxelDetail _voxel; -}; - -class DeleteVoxelCommand : public QUndoCommand { -public: - DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL); - ~DeleteVoxelCommand(); - - virtual void redo(); - virtual void undo(); - -private: - VoxelTree* _tree; - VoxelEditPacketSender* _packetSender; - VoxelDetail _voxel; - VoxelTree* _oldTree; -}; - -#endif // hifi_VoxelTreeCommands_h diff --git a/libraries/voxels/src/VoxelTreeElement.cpp b/libraries/voxels/src/VoxelTreeElement.cpp deleted file mode 100644 index f81e8c073f..0000000000 --- a/libraries/voxels/src/VoxelTreeElement.cpp +++ /dev/null @@ -1,253 +0,0 @@ -// -// VoxelTreeElement.cpp -// libraries/voxels/src -// -// Created by Stephen Birarda on 3/13/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 -#include - -#include "VoxelConstants.h" -#include "VoxelTreeElement.h" -#include "VoxelTree.h" - -VoxelTreeElement::VoxelTreeElement(unsigned char* octalCode) : - OctreeElement(), - _exteriorOcclusions(OctreeElement::HalfSpace::All), - _interiorOcclusions(OctreeElement::HalfSpace::None) -{ - init(octalCode); -}; - -VoxelTreeElement::~VoxelTreeElement() { - _voxelMemoryUsage -= sizeof(VoxelTreeElement); -} - -// 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* VoxelTreeElement::createNewElement(unsigned char* octalCode) { - VoxelTreeElement* newChild = new VoxelTreeElement(octalCode); - newChild->setVoxelSystem(getVoxelSystem()); // our child is always part of our voxel system NULL ok - return newChild; -} - -void VoxelTreeElement::init(unsigned char* octalCode) { - setVoxelSystem(NULL); - setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - _falseColored = false; // assume true color - _color[0] = _color[1] = _color[2] = _color[3] = 0; - _density = 0.0f; - OctreeElement::init(octalCode); - _voxelMemoryUsage += sizeof(VoxelTreeElement); -} - -bool VoxelTreeElement::requiresSplit() const { - return isLeaf() && isColored(); -} - -void VoxelTreeElement::splitChildren() { - if (requiresSplit()) { - const nodeColor& ourColor = getColor(); - - // for colored leaves, we must add *all* the children - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - addChildAtIndex(i)->setColor(ourColor); - } - nodeColor noColor = { 0, 0, 0, 0}; - setColor(noColor); // set our own color to noColor so we are a pure non-leaf - } -} - -OctreeElement::AppendState VoxelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { - return packetData->appendColor(getColor()) ? OctreeElement::COMPLETED : OctreeElement::NONE; -} - - -int VoxelTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args) { - const int BYTES_PER_COLOR = 3; - - if (bytesLeftToRead < BYTES_PER_COLOR) { - qDebug() << "UNEXPECTED: readElementDataFromBuffer() only had " << bytesLeftToRead << " bytes. " - "Not enough for meaningful data."; - return bytesLeftToRead; - } - - - // pull the color for this child - nodeColor newColor = { 128, 128, 128, 1}; - if (args.includeColor) { - memcpy(newColor, data, BYTES_PER_COLOR); - } - setColor(newColor); - return BYTES_PER_COLOR; -} - - -const uint8_t INDEX_FOR_NULL = 0; -uint8_t VoxelTreeElement::_nextIndex = INDEX_FOR_NULL + 1; // start at 1, 0 is reserved for NULL -std::map VoxelTreeElement::_mapVoxelSystemPointersToIndex; -std::map VoxelTreeElement::_mapIndexToVoxelSystemPointers; - -VoxelSystem* VoxelTreeElement::getVoxelSystem() const { - if (_voxelSystemIndex > INDEX_FOR_NULL) { - if (_mapIndexToVoxelSystemPointers.end() != _mapIndexToVoxelSystemPointers.find(_voxelSystemIndex)) { - - VoxelSystem* voxelSystem = _mapIndexToVoxelSystemPointers[_voxelSystemIndex]; - return voxelSystem; - } - } - return NULL; -} - -void VoxelTreeElement::setVoxelSystem(VoxelSystem* voxelSystem) { - if (!voxelSystem) { - _voxelSystemIndex = INDEX_FOR_NULL; - } else { - uint8_t index; - if (_mapVoxelSystemPointersToIndex.end() != _mapVoxelSystemPointersToIndex.find(voxelSystem)) { - index = _mapVoxelSystemPointersToIndex[voxelSystem]; - } else { - index = _nextIndex; - _nextIndex++; - _mapVoxelSystemPointersToIndex[voxelSystem] = index; - _mapIndexToVoxelSystemPointers[index] = voxelSystem; - } - _voxelSystemIndex = index; - } -} - -void VoxelTreeElement::setColor(const nodeColor& color) { - if (_color[0] != color[0] || _color[1] != color[1] || _color[2] != color[2]) { - memcpy(&_color,&color,sizeof(nodeColor)); - _isDirty = true; - if (color[3]) { - _density = 1.0f; // If color set, assume leaf, re-averaging will update density if needed. - } else { - _density = 0.0f; - } - markWithChangedTime(); - } -} - - - -// will average the child colors... -void VoxelTreeElement::calculateAverageFromChildren() { - int colorArray[4] = {0,0,0,0}; - float density = 0.0f; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - VoxelTreeElement* childAt = getChildAtIndex(i); - if (childAt && childAt->isColored()) { - for (int j = 0; j < 3; j++) { - colorArray[j] += childAt->getColor()[j]; // color averaging should always be based on true colors - } - colorArray[3]++; - } - if (childAt) { - density += childAt->getDensity(); - } - } - density /= (float) NUMBER_OF_CHILDREN; - // - // The VISIBLE_ABOVE_DENSITY sets the density of matter above which an averaged color voxel will - // be set. It is an important physical constant in our universe. A number below 0.5 will cause - // things to get 'fatter' at a distance, because upward averaging will make larger voxels out of - // less data, which is (probably) going to be preferable because it gives a sense that there is - // something out there to go investigate. A number above 0.5 would cause the world to become - // more 'empty' at a distance. Exactly 0.5 would match the physical world, at least for materials - // that are not shiny and have equivalent ambient reflectance. - // - const float VISIBLE_ABOVE_DENSITY = 0.10f; - nodeColor newColor = { 0, 0, 0, 0}; - if (density > VISIBLE_ABOVE_DENSITY) { - // The density of material in the space of the voxel sets whether it is actually colored - for (int c = 0; c < 3; c++) { - // set the average color value - newColor[c] = colorArray[c] / colorArray[3]; - } - // set the alpha to 1 to indicate that this isn't transparent - newColor[3] = 1; - } - // Set the color from the average of the child colors, and update the density - setColor(newColor); - setDensity(density); -} - -// will detect if children are leaves AND the same color -// and in that case will delete the children and make this node -// a leaf, returns TRUE if all the leaves are collapsed into a -// single node -bool VoxelTreeElement::collapseChildren() { - // scan children, verify that they are ALL present and accounted for - bool allChildrenMatch = true; // assume the best (ottimista) - int red = 0; - int green = 0; - int blue = 0; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - VoxelTreeElement* childAt = getChildAtIndex(i); - // if no child, child isn't a leaf, or child doesn't have a color - if (!childAt || !childAt->isLeaf() || !childAt->isColored()) { - allChildrenMatch = false; - break; - } else { - if (i==0) { - red = childAt->getColor()[0]; - green = childAt->getColor()[1]; - blue = childAt->getColor()[2]; - } else if (red != childAt->getColor()[0] || - green != childAt->getColor()[1] || blue != childAt->getColor()[2]) { - allChildrenMatch=false; - break; - } - } - } - - - if (allChildrenMatch) { - //qDebug("allChildrenMatch: pruning tree\n"); - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* childAt = getChildAtIndex(i); - delete childAt; // delete all the child nodes - setChildAtIndex(i, NULL); // set it to NULL - } - nodeColor collapsedColor; - collapsedColor[0]=red; - collapsedColor[1]=green; - collapsedColor[2]=blue; - collapsedColor[3]=1; // color is set - setColor(collapsedColor); - } - return allChildrenMatch; -} - - -bool VoxelTreeElement::findSpherePenetration(const glm::vec3& center, float radius, - glm::vec3& penetration, void** penetratedObject) const { - if (_cube.findSpherePenetration(center, radius, penetration)) { - - // if the caller wants details about the voxel, then return them here... - if (penetratedObject) { - VoxelDetail* voxelDetails = new VoxelDetail; - voxelDetails->x = _cube.getCorner().x; - voxelDetails->y = _cube.getCorner().y; - voxelDetails->z = _cube.getCorner().z; - voxelDetails->s = _cube.getScale(); - voxelDetails->red = getColor()[RED_INDEX]; - voxelDetails->green = getColor()[GREEN_INDEX]; - voxelDetails->blue = getColor()[BLUE_INDEX]; - - *penetratedObject = (void*)voxelDetails; - } - return true; - } - return false; -} - diff --git a/libraries/voxels/src/VoxelTreeElement.h b/libraries/voxels/src/VoxelTreeElement.h deleted file mode 100644 index 0ea91d4657..0000000000 --- a/libraries/voxels/src/VoxelTreeElement.h +++ /dev/null @@ -1,123 +0,0 @@ -// -// VoxelTreeElement.h -// libraries/voxels/src -// -// Created by Stephen Birarda on 3/13/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_VoxelTreeElement_h -#define hifi_VoxelTreeElement_h - -//#define HAS_AUDIT_CHILDREN -//#define SIMPLE_CHILD_ARRAY -#define SIMPLE_EXTERNAL_CHILDREN - -#include - -#include -#include -#include - -#include "ViewFrustum.h" -#include "VoxelConstants.h" - -class VoxelTree; -class VoxelTreeElement; -class VoxelSystem; - -class VoxelTreeElement : public OctreeElement { - friend class VoxelTree; // to allow createElement to new us... - - VoxelTreeElement(unsigned char* octalCode = NULL); - - virtual OctreeElement* createNewElement(unsigned char* octalCode = NULL); - -public: - virtual ~VoxelTreeElement(); - virtual void init(unsigned char * octalCode); - - virtual bool hasContent() const { return isColored(); } - virtual void splitChildren(); - virtual bool requiresSplit() const; - virtual OctreeElement::AppendState appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const; - virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); - virtual void calculateAverageFromChildren(); - virtual bool collapseChildren(); - virtual bool findSpherePenetration(const glm::vec3& center, float radius, - glm::vec3& penetration, void** penetratedObject) const; - - - - glBufferIndex getBufferIndex() const { return _glBufferIndex; } - bool isKnownBufferIndex() const { return !_unknownBufferIndex; } - void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; _unknownBufferIndex =(index == GLBUFFER_INDEX_UNKNOWN);} - VoxelSystem* getVoxelSystem() const; - void setVoxelSystem(VoxelSystem* voxelSystem); - - virtual bool isRendered() const { return isKnownBufferIndex(); } - - bool isColored() const { return _color[3] == 1; } - - void setColor(const nodeColor& color); - const nodeColor& getColor() const { return _color; } - - void setDensity(float density) { _density = density; } - float getDensity() const { return _density; } - - void setInteriorOcclusions(unsigned char interiorExclusions); - void setExteriorOcclusions(unsigned char exteriorOcclusions); - unsigned char getExteriorOcclusions() const; - unsigned char getInteriorOcclusions() const; - - // type safe versions of OctreeElement methods - VoxelTreeElement* getChildAtIndex(int childIndex) { return (VoxelTreeElement*)OctreeElement::getChildAtIndex(childIndex); } - VoxelTreeElement* addChildAtIndex(int childIndex) { return (VoxelTreeElement*)OctreeElement::addChildAtIndex(childIndex); } - -protected: - - uint32_t _glBufferIndex : 24; /// Client only, vbo index for this voxel if being rendered, 3 bytes - uint32_t _voxelSystemIndex : 8; /// Client only, index to the VoxelSystem rendering this voxel, 1 bytes - - // Support for _voxelSystemIndex, we use these static member variables to track the VoxelSystems that are - // in use by various voxel nodes. We map the VoxelSystem pointers into an 1 byte key, this limits us to at - // most 255 voxel systems in use at a time within the client. Which is far more than we need. - static uint8_t _nextIndex; - static std::map _mapVoxelSystemPointersToIndex; - static std::map _mapIndexToVoxelSystemPointers; - - float _density; /// Client and server, If leaf: density = 1, if internal node: 0-1 density of voxels inside, 4 bytes - - nodeColor _color; /// Client and server, true color of this voxel, 4 bytes - -private: - unsigned char _exteriorOcclusions; ///< Exterior shared partition boundaries that are completely occupied - unsigned char _interiorOcclusions; ///< Interior shared partition boundaries with siblings -}; - -inline void VoxelTreeElement::setExteriorOcclusions(unsigned char exteriorOcclusions) { - if (_exteriorOcclusions != exteriorOcclusions) { - _exteriorOcclusions = exteriorOcclusions; - setDirtyBit(); - } -} - -inline void VoxelTreeElement::setInteriorOcclusions(unsigned char interiorOcclusions) { - if (_interiorOcclusions != interiorOcclusions) { - _interiorOcclusions = interiorOcclusions; - setDirtyBit(); - } -} - -inline unsigned char VoxelTreeElement::getInteriorOcclusions() const { - return _interiorOcclusions; -} - -inline unsigned char VoxelTreeElement::getExteriorOcclusions() const { - return _exteriorOcclusions; -} - -#endif // hifi_VoxelTreeElement_h diff --git a/libraries/voxels/src/VoxelTreeHeadlessViewer.cpp b/libraries/voxels/src/VoxelTreeHeadlessViewer.cpp deleted file mode 100644 index 5aaa8c8d97..0000000000 --- a/libraries/voxels/src/VoxelTreeHeadlessViewer.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// -// VoxelTreeHeadlessViewer.cpp -// libraries/voxels/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 "VoxelTreeHeadlessViewer.h" - -VoxelTreeHeadlessViewer::VoxelTreeHeadlessViewer() : - OctreeHeadlessViewer() { -} - -VoxelTreeHeadlessViewer::~VoxelTreeHeadlessViewer() { -} - -void VoxelTreeHeadlessViewer::init() { - OctreeHeadlessViewer::init(); -} - diff --git a/libraries/voxels/src/VoxelTreeHeadlessViewer.h b/libraries/voxels/src/VoxelTreeHeadlessViewer.h deleted file mode 100644 index 291ad7f813..0000000000 --- a/libraries/voxels/src/VoxelTreeHeadlessViewer.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// VoxelTreeHeadlessViewer.h -// libraries/voxels/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_VoxelTreeHeadlessViewer_h -#define hifi_VoxelTreeHeadlessViewer_h - -#include -#include -#include -#include -#include -#include "VoxelTree.h" -#include - -// Generic client side Octree renderer class. -class VoxelTreeHeadlessViewer : public OctreeHeadlessViewer { - Q_OBJECT -public: - VoxelTreeHeadlessViewer(); - virtual ~VoxelTreeHeadlessViewer(); - - virtual char getMyNodeType() const { return NodeType::VoxelServer; } - virtual PacketType getMyQueryMessageType() const { return PacketTypeVoxelQuery; } - virtual PacketType getExpectedPacketType() const { return PacketTypeVoxelData; } - - VoxelTree* getTree() { return (VoxelTree*)_tree; } - - virtual void init(); - -protected: - virtual Octree* createTree() { return new VoxelTree(true); } -}; - -#endif // hifi_VoxelTreeHeadlessViewer_h diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp deleted file mode 100644 index c11aca2872..0000000000 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// -// VoxelsScriptingInterface.cpp -// libraries/voxels/src -// -// Created by Stephen Birarda on 9/17/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 "VoxelTreeCommands.h" - -#include "VoxelsScriptingInterface.h" - -void VoxelsScriptingInterface::queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails) { - getVoxelPacketSender()->queueVoxelEditMessages(addPacketType, 1, &addVoxelDetails); -} - -VoxelDetail VoxelsScriptingInterface::getVoxelAt(float x, float y, float z, float scale) { - // setup a VoxelDetail struct with the data - VoxelDetail result = {0,0,0,0,0,0,0}; - - if (_tree) { - _tree->lockForRead(); - - VoxelTreeElement* voxel = static_cast(_tree->getOctreeElementAt(x / (float)TREE_SCALE, y / (float)TREE_SCALE, - z / (float)TREE_SCALE, scale / (float)TREE_SCALE)); - _tree->unlock(); - if (voxel) { - // Note: these need to be in voxel space because the VoxelDetail -> js converter will upscale - result.x = voxel->getCorner().x; - result.y = voxel->getCorner().y; - result.z = voxel->getCorner().z; - result.s = voxel->getScale(); - result.red = voxel->getColor()[RED_INDEX]; - result.green = voxel->getColor()[GREEN_INDEX]; - result.blue = voxel->getColor()[BLUE_INDEX]; - } - } - return result; -} - -void VoxelsScriptingInterface::setVoxelNonDestructive(float x, float y, float z, float scale, - uchar red, uchar green, uchar blue) { - // setup a VoxelDetail struct with the data - VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, - scale / (float)TREE_SCALE, red, green, blue}; - - - // handle the local tree also... - if (_tree) { - if (_undoStack) { - AddVoxelCommand* command = new AddVoxelCommand(_tree, - addVoxelDetail, - getVoxelPacketSender()); - - // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. - _undoStack->push(command); - } else { - // queue the add packet - queueVoxelAdd(PacketTypeVoxelSet, addVoxelDetail); - _tree->createVoxel(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s, red, green, blue, false); - } - } -} - -void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, - uchar red, uchar green, uchar blue) { - // setup a VoxelDetail struct with the data - VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, - scale / (float)TREE_SCALE, red, green, blue}; - - // handle the local tree also... - if (_tree) { - if (_undoStack) { - AddVoxelCommand* addCommand = new AddVoxelCommand(_tree, - addVoxelDetail, - getVoxelPacketSender()); - DeleteVoxelCommand* deleteCommand = new DeleteVoxelCommand(_tree, - addVoxelDetail, - getVoxelPacketSender()); - _undoStackMutex.lock(); - - _undoStack->beginMacro(addCommand->text()); - // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. - _undoStack->push(deleteCommand); - _undoStack->push(addCommand); - _undoStack->endMacro(); - - //Unlock the mutex - _undoStackMutex.unlock(); - } else { - // queue the destructive add - queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail); - _tree->createVoxel(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s, red, green, blue, true); - } - } -} - -void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale) { - // setup a VoxelDetail struct with data - VoxelDetail deleteVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, - scale / (float)TREE_SCALE}; - - - // handle the local tree also... - if (_tree) { - VoxelTreeElement* deleteVoxelElement = _tree->getVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s); - if (deleteVoxelElement) { - deleteVoxelDetail.red = deleteVoxelElement->getColor()[0]; - deleteVoxelDetail.green = deleteVoxelElement->getColor()[1]; - deleteVoxelDetail.blue = deleteVoxelElement->getColor()[2]; - } - - if (_undoStack) { - - DeleteVoxelCommand* command = new DeleteVoxelCommand(_tree, - deleteVoxelDetail, - getVoxelPacketSender()); - - _undoStackMutex.lock(); - // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. - _undoStack->push(command); - _undoStackMutex.unlock(); - } else { - getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail); - _tree->deleteVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s); - } - } -} - -RayToVoxelIntersectionResult VoxelsScriptingInterface::findRayIntersection(const PickRay& ray) { - return findRayIntersectionWorker(ray, Octree::TryLock); -} - -RayToVoxelIntersectionResult VoxelsScriptingInterface::findRayIntersectionBlocking(const PickRay& ray) { - return findRayIntersectionWorker(ray, Octree::Lock); -} - -RayToVoxelIntersectionResult VoxelsScriptingInterface::findRayIntersectionWorker(const PickRay& ray, - Octree::lockType lockType) { - RayToVoxelIntersectionResult result; - if (_tree) { - OctreeElement* element; - result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, NULL, - lockType, &result.accurate); - if (result.intersects) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - result.voxel.x = voxel->getCorner().x; - result.voxel.y = voxel->getCorner().y; - result.voxel.z = voxel->getCorner().z; - result.voxel.s = voxel->getScale(); - result.voxel.red = voxel->getColor()[0]; - result.voxel.green = voxel->getColor()[1]; - result.voxel.blue = voxel->getColor()[2]; - result.intersection = ray.origin + (ray.direction * result.distance); - } - } - return result; -} - -glm::vec3 VoxelsScriptingInterface::getFaceVector(const QString& face) { - if (face == "MIN_X_FACE") { - return glm::vec3(-1, 0, 0); - } else if (face == "MAX_X_FACE") { - return glm::vec3(1, 0, 0); - } else if (face == "MIN_Y_FACE") { - return glm::vec3(0, -1, 0); - } else if (face == "MAX_Y_FACE") { - return glm::vec3(0, 1, 0); - } else if (face == "MIN_Z_FACE") { - return glm::vec3(0, 0, -1); - } else if (face == "MAX_Z_FACE") { - return glm::vec3(0, 0, 1); - } - return glm::vec3(0, 0, 0); //error case -} - -VoxelDetail VoxelsScriptingInterface::getVoxelEnclosingPoint(const glm::vec3& point) { - VoxelDetail result = { 0.0f, 0.0f, 0.0f, 0.0f, 0, 0, 0 }; - if (_tree) { - OctreeElement* element = _tree->getElementEnclosingPoint(point / (float)TREE_SCALE); - if (element) { - VoxelTreeElement* voxel = static_cast(element); - result.x = voxel->getCorner().x; - result.y = voxel->getCorner().y; - result.z = voxel->getCorner().z; - result.s = voxel->getScale(); - result.red = voxel->getColor()[0]; - result.green = voxel->getColor()[1]; - result.blue = voxel->getColor()[2]; - } - } - return result; -} - -VoxelDetail VoxelsScriptingInterface::getVoxelEnclosingPointBlocking(const glm::vec3& point) { - VoxelDetail result = { 0.0f, 0.0f, 0.0f, 0.0f, 0, 0, 0 }; - if (_tree) { - OctreeElement* element = _tree->getElementEnclosingPoint(point / (float)TREE_SCALE, Octree::Lock); - if (element) { - VoxelTreeElement* voxel = static_cast(element); - result.x = voxel->getCorner().x; - result.y = voxel->getCorner().y; - result.z = voxel->getCorner().z; - result.s = voxel->getScale(); - result.red = voxel->getColor()[0]; - result.green = voxel->getColor()[1]; - result.blue = voxel->getColor()[2]; - } - } - return result; -} - diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h deleted file mode 100644 index 2e1fc2a8d5..0000000000 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ /dev/null @@ -1,108 +0,0 @@ -// -// VoxelsScriptingInterface.h -// libraries/voxels/src -// -// Created by Stephen Birarda on 9/17/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_VoxelsScriptingInterface_h -#define hifi_VoxelsScriptingInterface_h - -#include - -#include -#include - -#include "VoxelConstants.h" -#include "VoxelEditPacketSender.h" -#include "VoxelTree.h" - -class QUndoStack; - -/// handles scripting of voxel commands from JS passed to assigned clients -class VoxelsScriptingInterface : public OctreeScriptingInterface { - Q_OBJECT -public: - VoxelsScriptingInterface() : _tree(NULL), _undoStack(NULL) {}; - VoxelEditPacketSender* getVoxelPacketSender() { return (VoxelEditPacketSender*)getPacketSender(); } - - virtual NodeType_t getServerNodeType() const { return NodeType::VoxelServer; } - virtual OctreeEditPacketSender* createPacketSender() { return new VoxelEditPacketSender(); } - void setVoxelTree(VoxelTree* tree) { _tree = tree; } - void setUndoStack(QUndoStack* undoStack) { _undoStack = undoStack; } - -public: - /// provide the world scale - Q_INVOKABLE const int getTreeScale() const { return TREE_SCALE; } - - /// checks the local voxel tree for a voxel at the specified location and scale - /// \param x the x-coordinate of the voxel (in meter units) - /// \param y the y-coordinate of the voxel (in meter units) - /// \param z the z-coordinate of the voxel (in meter units) - /// \param scale the scale of the voxel (in meter units) - Q_INVOKABLE VoxelDetail getVoxelAt(float x, float y, float z, float scale); - - /// queues the creation of a voxel which will be sent by calling process on the PacketSender - /// \param x the x-coordinate of the voxel (in meter units) - /// \param y the y-coordinate of the voxel (in meter units) - /// \param z the z-coordinate of the voxel (in meter units) - /// \param scale the scale of the voxel (in meter units) - /// \param red the R value for RGB color of voxel - /// \param green the G value for RGB color of voxel - /// \param blue the B value for RGB color of voxel - Q_INVOKABLE void setVoxelNonDestructive(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); - - /// queues the destructive creation of a voxel which will be sent by calling process on the PacketSender - /// \param x the x-coordinate of the voxel (in meter units) - /// \param y the y-coordinate of the voxel (in meter units) - /// \param z the z-coordinate of the voxel (in meter units) - /// \param scale the scale of the voxel (in meter units) - /// \param red the R value for RGB color of voxel - /// \param green the G value for RGB color of voxel - /// \param blue the B value for RGB color of voxel - Q_INVOKABLE void setVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); - - /// queues the deletion of a voxel, sent by calling process on the PacketSender - /// \param x the x-coordinate of the voxel (in meter units) - /// \param y the y-coordinate of the voxel (in meter units) - /// \param z the z-coordinate of the voxel (in meter units) - /// \param scale the scale of the voxel (in meter units) - Q_INVOKABLE void eraseVoxel(float x, float y, float z, float scale); - - /// If the scripting context has visible voxels, this will determine a ray intersection, the results - /// may be inaccurate if the engine is unable to access the visible voxels, in which case result.accurate - /// will be false. - Q_INVOKABLE RayToVoxelIntersectionResult findRayIntersection(const PickRay& ray); - - /// If the scripting context has visible voxels, this will determine a ray intersection, and will block in - /// order to return an accurate result - Q_INVOKABLE RayToVoxelIntersectionResult findRayIntersectionBlocking(const PickRay& ray); - - /// returns a voxel space axis aligned vector for the face, useful in doing voxel math - Q_INVOKABLE glm::vec3 getFaceVector(const QString& face); - - /// checks the local voxel tree for the smallest voxel enclosing the point - /// \param point the x,y,z coordinates of the point (in meter units) - /// \return VoxelDetail - if no voxel encloses the point then VoxelDetail items will be 0 - Q_INVOKABLE VoxelDetail getVoxelEnclosingPoint(const glm::vec3& point); - - /// checks the local voxel tree for the smallest voxel enclosing the point and uses a blocking lock - /// \param point the x,y,z coordinates of the point (in meter units) - /// \return VoxelDetail - if no voxel encloses the point then VoxelDetail items will be 0 - Q_INVOKABLE VoxelDetail getVoxelEnclosingPointBlocking(const glm::vec3& point); - -private: - /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode - RayToVoxelIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType); - - void queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails); - VoxelTree* _tree; - QUndoStack* _undoStack; - QMutex _undoStackMutex; -}; - -#endif // hifi_VoxelsScriptingInterface_h