mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 16:14:01 +02:00
first major pass at voxelEctomy
This commit is contained in:
parent
2a129b6635
commit
4ea9bbc309
65 changed files with 43 additions and 5956 deletions
|
@ -24,8 +24,6 @@
|
|||
#include <EntityTreeHeadlessViewer.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <ThreadedAssignment.h>
|
||||
#include <VoxelEditPacketSender.h>
|
||||
#include <VoxelTreeHeadlessViewer.h>
|
||||
|
||||
#include "MixedAudioStream.h"
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 <PacketHeaders.h>
|
||||
|
||||
#include "../octree/OctreeQueryNode.h"
|
||||
|
||||
class VoxelNodeData : public OctreeQueryNode {
|
||||
public:
|
||||
VoxelNodeData() : OctreeQueryNode() { }
|
||||
virtual PacketType getMyPacketType() const { return PacketTypeVoxelData; }
|
||||
};
|
||||
|
||||
#endif // hifi_VoxelNodeData_h
|
|
@ -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 <VoxelTree.h>
|
||||
|
||||
#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<char*>(_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);
|
||||
}
|
|
@ -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 <QStringList>
|
||||
#include <QDateTime>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <ThreadedAssignment.h>
|
||||
#include <EnvironmentData.h>
|
||||
|
||||
#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
|
|
@ -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
|
|
@ -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<GeometryCache>()->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<Faceshift>()->reset();
|
||||
DependencyManager::get<Visage>()->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() {
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include <ScriptEngine.h>
|
||||
#include <TextureCache.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <VoxelEditPacketSender.h>
|
||||
|
||||
#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<GLCanvas>()->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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "ModelReferential.h"
|
||||
#include "Physics.h"
|
||||
#include "Recorder.h"
|
||||
#include "Util.h"
|
||||
#include "world.h"
|
||||
#include "devices/OculusManager.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Menu.h"
|
||||
#include "SkeletonModel.h"
|
||||
#include "SkeletonRagdoll.h"
|
||||
#include "Util.h"
|
||||
|
||||
enum StandingFootState {
|
||||
LEFT_FOOT,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#define hifi_ClipboardScriptingInterface_h
|
||||
|
||||
#include <QObject>
|
||||
#include <VoxelDetail.h>
|
||||
|
||||
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);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "ApplicationOverlay.h"
|
||||
#include "devices/OculusManager.h"
|
||||
|
||||
#include "Util.h"
|
||||
#include "ui/Stats.h"
|
||||
|
||||
// Used to fade the UI
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
#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<GLCanvas>();
|
||||
Application::getInstance()->resizeGL(glCanvas->width(), glCanvas->height());
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "ScriptEditorWidget.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QFrame>
|
||||
#include <QLayoutItem>
|
||||
#include <QMainWindow>
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "ui_scriptEditorWindow.h"
|
||||
#include "ScriptEditorWindow.h"
|
||||
#include "ScriptEditorWidget.h"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 <QStandardPaths>
|
||||
#include <QGridLayout>
|
||||
#include <QSplitter>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
#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("<b>Import</b> %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<QWidget*>("sidebar")->setEnabled(true);
|
||||
findChild<QWidget*>("treeView")->setEnabled(true);
|
||||
findChild<QWidget*>("backButton")->setEnabled(true);
|
||||
findChild<QWidget*>("forwardButton")->setEnabled(true);
|
||||
findChild<QWidget*>("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<QWidget*>("sidebar")->setEnabled(false);
|
||||
findChild<QWidget*>("treeView")->setEnabled(false);
|
||||
findChild<QWidget*>("backButton")->setEnabled(false);
|
||||
findChild<QWidget*>("forwardButton")->setEnabled(false);
|
||||
findChild<QWidget*>("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<QWidget*>("lookInLabel"), 0, 0, 1, 5);
|
||||
|
||||
QSize BUTTON_SIZE = QSize(43, 33);
|
||||
QPushButton* button = (QPushButton*) findChild<QWidget*>("backButton");
|
||||
button->setIcon(QIcon());
|
||||
button->setFixedSize(BUTTON_SIZE);
|
||||
subLayout->addWidget(button, 1, 0, 1, 1);
|
||||
|
||||
button = (QPushButton*) findChild<QWidget*>("forwardButton");
|
||||
button->setIcon(QIcon());
|
||||
button->setFixedSize(BUTTON_SIZE);
|
||||
subLayout->addWidget(button, 1, 1, 1, 1);
|
||||
|
||||
button = (QPushButton*) findChild<QWidget*>("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<QWidget*>("lookInCombo");
|
||||
widget->hide();
|
||||
|
||||
widget = findChild<QWidget*>("newFolderButton");
|
||||
widget->hide();
|
||||
|
||||
widget = findChild<QWidget*>("listModeButton");
|
||||
widget->hide();
|
||||
|
||||
widget = findChild<QWidget*>("detailModeButton");
|
||||
widget->hide();
|
||||
|
||||
widget = findChild<QWidget*>("fileNameEdit");
|
||||
widget->hide();
|
||||
|
||||
widget = findChild<QWidget*>("fileTypeCombo");
|
||||
widget->hide();
|
||||
|
||||
widget = findChild<QWidget*>("fileTypeLabel");
|
||||
widget->hide();
|
||||
|
||||
widget = findChild<QWidget*>("fileNameLabel");
|
||||
widget->hide();
|
||||
|
||||
widget = findChild<QWidget*>("buttonBox");
|
||||
widget->hide();
|
||||
|
||||
QSplitter* splitter = findChild<QSplitter*>("splitter");
|
||||
splitter->setHandleWidth(0);
|
||||
|
||||
// remove blue outline on Mac
|
||||
widget = findChild<QWidget*>("sidebar");
|
||||
widget->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
|
||||
widget = findChild<QWidget*>("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<QString, QString> 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));
|
||||
}
|
||||
}
|
|
@ -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 <QFileDialog>
|
||||
#include <QPushButton>
|
||||
#include <QProgressBar>
|
||||
#include <QLabel>
|
||||
#include <QFileIconProvider>
|
||||
#include <QHash>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "voxels/VoxelImporter.h"
|
||||
|
||||
class HiFiIconProvider : public QFileIconProvider {
|
||||
public:
|
||||
HiFiIconProvider(const QHash<QString, QString> map) { iconsMap = map; };
|
||||
virtual QIcon icon(IconType type) const;
|
||||
virtual QIcon icon(const QFileInfo &info) const;
|
||||
virtual QString type(const QFileInfo &info) const;
|
||||
QHash<QString, QString> 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
|
|
@ -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 <QGLWidget>
|
||||
#include <QScriptValue>
|
||||
|
||||
#include <GlowEffect.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "LocalVoxelsOverlay.h"
|
||||
#include "voxels/VoxelSystem.h"
|
||||
|
||||
QMap<QString, WeakVoxelSystemPointer> 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);
|
||||
}
|
||||
|
|
@ -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 <QGLWidget>
|
||||
#include <QScriptValue>
|
||||
#include <QMap>
|
||||
#include <QSharedPointer>
|
||||
#include <QWeakPointer>
|
||||
|
||||
#include <LocalVoxelsList.h>
|
||||
|
||||
#include "Volume3DOverlay.h"
|
||||
|
||||
typedef QSharedPointer<VoxelSystem> StrongVoxelSystemPointer;
|
||||
typedef QWeakPointer<VoxelSystem> 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<QString, WeakVoxelSystemPointer> _voxelSystemMap; // treeName/voxelSystem
|
||||
|
||||
QString _treeName;
|
||||
StrongVoxelTreePointer _tree; // so that the tree doesn't get freed
|
||||
unsigned long _voxelCount;
|
||||
StrongVoxelSystemPointer _voxelSystem;
|
||||
};
|
||||
|
||||
#endif // hifi_LocalVoxelsOverlay_h
|
|
@ -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") {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <QDebug>
|
||||
#include <NodeList.h>
|
||||
#include <PerfStat.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#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
|
||||
}
|
|
@ -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 <GenericThread.h>
|
||||
#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
|
|
@ -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 <QFileInfo>
|
||||
#include <QThreadPool>
|
||||
|
||||
#include <Application.h>
|
||||
#include <LocalVoxelsList.h>
|
||||
|
||||
#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();
|
||||
}
|
|
@ -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 <QThread>
|
||||
#include <QRunnable>
|
||||
#include <QStringList>
|
||||
|
||||
#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
|
File diff suppressed because it is too large
Load diff
|
@ -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 <glm/glm.hpp>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <NodeData.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <VoxelTree.h>
|
||||
#include <OctreePersistThread.h>
|
||||
|
||||
#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<glBufferIndex> _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
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <AbstractAudioInterface.h>
|
||||
#include <VoxelTree.h>
|
||||
#include <AvatarData.h>
|
||||
#include <CollisionInfo.h>
|
||||
#include <HeadData.h>
|
||||
|
@ -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()) {
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <CollisionInfo.h>
|
||||
#include <OctreePacketData.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <VoxelDetail.h>
|
||||
|
||||
#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;
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
#include <Octree.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <SharedUtil.h> // usecTimestampNow()
|
||||
#include <VoxelsScriptingInterface.h>
|
||||
#include <VoxelDetail.h>
|
||||
|
||||
#include "EntityScriptingInterface.h"
|
||||
#include "EntityItem.h"
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <Octree.h> // for EncodeBitstreamParams class
|
||||
#include <OctreeElement.h> // for OctreeElement::AppendState
|
||||
#include <OctreePacketData.h>
|
||||
#include <VoxelDetail.h>
|
||||
|
||||
#include "EntityItemID.h"
|
||||
#include "EntityItemProperties.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<EntityItemID> 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);
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
#include <GLMHelpers.h>
|
||||
#include <OctalCode.h>
|
||||
|
||||
#include <VoxelTree.h>
|
||||
|
||||
#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<FBXMesh*>(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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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<VoxelTreeElement*>(_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
|
||||
}
|
|
@ -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 <QObject>
|
||||
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <LocalVoxelsList.h>
|
||||
|
||||
|
||||
/// 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
|
|
@ -28,22 +28,19 @@
|
|||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <UUID.h>
|
||||
#include <VoxelConstants.h>
|
||||
#include <VoxelDetail.h>
|
||||
//#include <VoxelConstants.h>
|
||||
|
||||
#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<LocalVoxels>();
|
||||
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<AnimationCache>().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();
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <AudioScriptingInterface.h>
|
||||
#include <AvatarData.h>
|
||||
#include <AvatarHashMap.h>
|
||||
#include <VoxelsScriptingInterface.h>
|
||||
#include <LimitedNodeList.h>
|
||||
|
||||
#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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 <QHash>
|
||||
#include <QString>
|
||||
#include <QSharedPointer>
|
||||
#include <QWeakPointer>
|
||||
|
||||
#include "VoxelTree.h"
|
||||
|
||||
typedef QSharedPointer<VoxelTree> StrongVoxelTreePointer;
|
||||
typedef QWeakPointer<VoxelTree> 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<QString, WeakVoxelTreePointer> _trees;
|
||||
|
||||
QList<StrongVoxelTreePointer> _persistantTrees;
|
||||
};
|
||||
|
||||
#endif // hifi_LocalVoxelsList_h
|
|
@ -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 <assert.h>
|
||||
#include <PerfStat.h>
|
||||
#include <OctalCode.h>
|
||||
#include <PacketHeaders.h>
|
||||
#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<char*>(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);
|
||||
}
|
||||
}
|
|
@ -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 <OctreeEditPacketSender.h>
|
||||
|
||||
#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
|
|
@ -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 <algorithm>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QImage>
|
||||
#include <QRgb>
|
||||
|
||||
#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<VoxelTreeElement*>(_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<VoxelTreeElement*>(getOctreeElementAt(x, y, z, s));
|
||||
}
|
||||
|
||||
VoxelTreeElement* VoxelTree::getEnclosingVoxelAt(float x, float y, float z, float s) const {
|
||||
return static_cast<VoxelTreeElement*>(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<VoxelTreeElement*>(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);
|
||||
}
|
||||
|
|
@ -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 <Octree.h>
|
||||
|
||||
#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<VoxelTreeElement*>(_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
|
|
@ -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<VoxelTreeElement*>(element);
|
||||
SendVoxelsOperationArgs* args = static_cast<SendVoxelsOperationArgs*>(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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 <QRgb>
|
||||
#include <QUndoCommand>
|
||||
|
||||
#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
|
|
@ -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 <NodeList.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
#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<VoxelSystem*, uint8_t> VoxelTreeElement::_mapVoxelSystemPointersToIndex;
|
||||
std::map<uint8_t, VoxelSystem*> 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;
|
||||
}
|
||||
|
|
@ -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 <QReadWriteLock>
|
||||
|
||||
#include <AACube.h>
|
||||
#include <OctreeElement.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#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<VoxelSystem*, uint8_t> _mapVoxelSystemPointersToIndex;
|
||||
static std::map<uint8_t, VoxelSystem*> _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
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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 <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <Octree.h>
|
||||
#include <OctreePacketData.h>
|
||||
#include <OctreeHeadlessViewer.h>
|
||||
#include "VoxelTree.h"
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
// 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
|
|
@ -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<VoxelTreeElement*>(_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<VoxelTreeElement*>(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<VoxelTreeElement*>(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;
|
||||
}
|
||||
|
|
@ -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 <QtCore/QObject>
|
||||
|
||||
#include <OctreeScriptingInterface.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
#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
|
Loading…
Reference in a new issue