first major pass at voxelEctomy

This commit is contained in:
ZappoMan 2014-12-30 18:08:58 -08:00
parent 2a129b6635
commit 4ea9bbc309
65 changed files with 43 additions and 5956 deletions

View file

@ -24,8 +24,6 @@
#include <EntityTreeHeadlessViewer.h>
#include <ScriptEngine.h>
#include <ThreadedAssignment.h>
#include <VoxelEditPacketSender.h>
#include <VoxelTreeHeadlessViewer.h>
#include "MixedAudioStream.h"

View file

@ -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:

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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() {

View file

@ -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;

View file

@ -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);

View file

@ -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();

View file

@ -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";

View file

@ -41,6 +41,7 @@
#include "ModelReferential.h"
#include "Physics.h"
#include "Recorder.h"
#include "Util.h"
#include "world.h"
#include "devices/OculusManager.h"

View file

@ -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;

View file

@ -21,6 +21,7 @@
#include "Menu.h"
#include "SkeletonModel.h"
#include "SkeletonRagdoll.h"
#include "Util.h"
enum StandingFootState {
LEFT_FOOT,

View file

@ -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);
}

View file

@ -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);

View file

@ -20,6 +20,7 @@
#include "ApplicationOverlay.h"
#include "devices/OculusManager.h"
#include "Util.h"
#include "ui/Stats.h"
// Used to fade the UI

View file

@ -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;
}

View file

@ -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];

View file

@ -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());

View file

@ -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];

View file

@ -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());

View file

@ -13,6 +13,7 @@
#include "ScriptEditorWidget.h"
#include <QGridLayout>
#include <QFileDialog>
#include <QFrame>
#include <QLayoutItem>
#include <QMainWindow>

View file

@ -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"

View file

@ -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);

View file

@ -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));
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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") {

View file

@ -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;
}
}

View file

@ -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
}

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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()) {

View file

@ -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;

View file

@ -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"

View file

@ -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"

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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...

View file

@ -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
}

View file

@ -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

View file

@ -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();

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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;
}

View file

@ -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