This commit is contained in:
Andrzej Kapolka 2014-02-27 18:14:18 -08:00
commit 5d4ed4c85e
34 changed files with 920 additions and 413 deletions

View file

@ -39,6 +39,7 @@ void Agent::readPendingDatagrams() {
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
PacketType datagramPacketType = packetTypeForPacket(receivedPacket);
if (datagramPacketType == PacketTypeJurisdiction) {
int headerBytes = numBytesForPacketHeader(receivedPacket);
@ -48,12 +49,12 @@ void Agent::readPendingDatagrams() {
// PacketType_JURISDICTION, first byte is the node type...
switch (receivedPacket[headerBytes]) {
case NodeType::VoxelServer:
_scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(matchedNode,
receivedPacket);
_scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener()->
queueReceivedPacket(matchedNode,receivedPacket);
break;
case NodeType::ParticleServer:
_scriptEngine.getParticlesScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(matchedNode,
receivedPacket);
_scriptEngine.getParticlesScriptingInterface()->getJurisdictionListener()->
queueReceivedPacket(matchedNode, receivedPacket);
break;
}
}
@ -63,7 +64,44 @@ void Agent::readPendingDatagrams() {
Particle::handleAddParticleResponse(receivedPacket);
// also give our local particle tree a chance to remap any internal locally created particles
_particleTree.handleAddParticleResponse(receivedPacket);
_particleViewer.getTree()->handleAddParticleResponse(receivedPacket);
} else if (datagramPacketType == PacketTypeParticleData
|| datagramPacketType == PacketTypeParticleErase
|| datagramPacketType == PacketTypeOctreeStats
|| datagramPacketType == PacketTypeVoxelData
) {
SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);
QByteArray mutablePacket = receivedPacket;
ssize_t messageLength = mutablePacket.size();
if (datagramPacketType == PacketTypeOctreeStats) {
int statsMessageLength = OctreeHeadlessViewer::parseOctreeStats(mutablePacket, sourceNode);
if (messageLength > statsMessageLength) {
mutablePacket = mutablePacket.mid(statsMessageLength);
// TODO: this needs to be fixed, the goal is to test the packet version for the piggyback, but
// this is testing the version and hash of the original packet
// need to use numBytesArithmeticCodingFromBuffer()...
if (!NodeList::getInstance()->packetVersionAndHashMatch(receivedPacket)) {
return; // bail since piggyback data doesn't match our versioning
}
} else {
return; // bail since no piggyback data
}
datagramPacketType = packetTypeForPacket(mutablePacket);
} // fall through to piggyback message
if (datagramPacketType == PacketTypeParticleData || datagramPacketType == PacketTypeParticleErase) {
_particleViewer.processDatagram(mutablePacket, sourceNode);
}
if (datagramPacketType == PacketTypeVoxelData) {
_voxelViewer.processDatagram(mutablePacket, sourceNode);
}
} else {
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
}
@ -110,9 +148,6 @@ void Agent::run() {
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
// tell our script engine about our local particle tree
_scriptEngine.getParticlesScriptingInterface()->setParticleTree(&_particleTree);
// setup an Avatar for the script to use
AvatarData scriptedAvatar;
@ -126,6 +161,21 @@ void Agent::run() {
// register ourselves to the script engine
_scriptEngine.registerGlobalObject("Agent", this);
_scriptEngine.init(); // must be done before we set up the viewers
_scriptEngine.registerGlobalObject("VoxelViewer", &_voxelViewer);
// connect the VoxelViewer and the VoxelScriptingInterface to each other
JurisdictionListener* voxelJL = _scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener();
_voxelViewer.setJurisdictionListener(voxelJL);
_voxelViewer.init();
_scriptEngine.getVoxelsScriptingInterface()->setVoxelTree(_voxelViewer.getTree());
_scriptEngine.registerGlobalObject("ParticleViewer", &_particleViewer);
JurisdictionListener* particleJL = _scriptEngine.getParticlesScriptingInterface()->getJurisdictionListener();
_particleViewer.setJurisdictionListener(particleJL);
_particleViewer.init();
_scriptEngine.getParticlesScriptingInterface()->setParticleTree(_particleViewer.getTree());
_scriptEngine.setScriptContents(scriptContents);
_scriptEngine.run();
_scriptEngine.run();
}

View file

@ -17,9 +17,11 @@
#include <ParticleEditPacketSender.h>
#include <ParticleTree.h>
#include <ParticleTreeHeadlessViewer.h>
#include <ScriptEngine.h>
#include <ThreadedAssignment.h>
#include <VoxelEditPacketSender.h>
#include <VoxelTreeHeadlessViewer.h>
class Agent : public ThreadedAssignment {
@ -41,9 +43,11 @@ signals:
void willSendVisualDataCallback();
private:
ScriptEngine _scriptEngine;
ParticleTree _particleTree;
VoxelEditPacketSender _voxelEditSender;
ParticleEditPacketSender _particleEditSender;
ParticleTreeHeadlessViewer _particleViewer;
VoxelTreeHeadlessViewer _voxelViewer;
};
#endif /* defined(__hifi__Agent__) */

View file

@ -161,7 +161,7 @@ void OctreeQueryNode::writeToPacket(const unsigned char* buffer, int bytes) {
OctreeQueryNode::~OctreeQueryNode() {
if (_octreeSendThread) {
_octreeSendThread->terminate();
_octreeSendThread->deleteLater();
delete _octreeSendThread;
}
delete[] _octreePacket;

View file

@ -22,8 +22,16 @@ OctreeSendThread::OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer
_myServer(myServer),
_packetData()
{
qDebug() << "client connected";
_myServer->clientConnected();
}
OctreeSendThread::~OctreeSendThread() {
qDebug() << "client disconnected";
_myServer->clientDisconnected();
}
bool OctreeSendThread::process() {
quint64 start = usecTimestampNow();
bool gotLock = false;

View file

@ -20,6 +20,7 @@
class OctreeSendThread : public GenericThread {
public:
OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer);
virtual ~OctreeSendThread();
static quint64 _totalBytes;
static quint64 _totalWastedBytes;

View file

@ -19,6 +19,8 @@
#include "OctreeServerConsts.h"
OctreeServer* OctreeServer::_instance = NULL;
int OctreeServer::_clientCount = 0;
void OctreeServer::attachQueryNodeToNode(Node* newNode) {
if (newNode->getLinkedData() == NULL) {
@ -35,6 +37,7 @@ OctreeServer::OctreeServer(const QByteArray& packet) :
_parsedArgV(NULL),
_httpManager(NULL),
_packetsPerClientPerInterval(10),
_packetsTotalPerInterval(DEFAULT_PACKETS_PER_INTERVAL),
_tree(NULL),
_wantPersist(true),
_debugSending(false),
@ -75,8 +78,7 @@ OctreeServer::~OctreeServer() {
delete _jurisdiction;
_jurisdiction = NULL;
qDebug() << "OctreeServer::run()... DONE";
qDebug() << "OctreeServer::~OctreeServer()... DONE";
}
void OctreeServer::initHTTPManager(int port) {
@ -155,12 +157,24 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
statsString += "Uptime: ";
if (hours > 0) {
statsString += QString("%1 hour%2").arg(hours).arg((hours > 1) ? "s" : "");
statsString += QString("%1 hour").arg(hours);
if (hours > 1) {
statsString += QString("s");
}
}
if (minutes > 0) {
statsString += QString("%1 minute%s").arg(minutes).arg((minutes > 1) ? "s" : "");
if (hours > 0) {
statsString += QString(" ");
}
statsString += QString("%1 minute").arg(minutes);
if (minutes > 1) {
statsString += QString("s");
}
}
if (seconds > 0) {
if (hours > 0 || minutes > 0) {
statsString += QString(" ");
}
statsString += QString().sprintf("%.3f seconds", seconds);
}
statsString += "\r\n\r\n";
@ -180,14 +194,26 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR;
int hours = (msecsElapsed/(MSECS_PER_MIN * MIN_PER_HOUR));
statsString += QString("%1 File Load Took").arg(getMyServerName());
statsString += QString("%1 File Load Took ").arg(getMyServerName());
if (hours > 0) {
statsString += QString("%1 hour%2").arg(hours).arg((hours > 1) ? "s" : "");
statsString += QString("%1 hour").arg(hours);
if (hours > 1) {
statsString += QString("s");
}
}
if (minutes > 0) {
statsString += QString("%1 minute%2").arg(minutes).arg((minutes > 1) ? "s" : "");
if (hours > 0) {
statsString += QString(" ");
}
statsString += QString("%1 minute").arg(minutes);
if (minutes > 1) {
statsString += QString("s");
}
}
if (seconds >= 0) {
if (hours > 0 || minutes > 0) {
statsString += QString(" ");
}
statsString += QString().sprintf("%.3f seconds", seconds);
}
statsString += "\r\n";
@ -234,6 +260,13 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString&
quint64 totalBytesOfColor = OctreePacketData::getTotalBytesOfColor();
const int COLUMN_WIDTH = 10;
statsString += QString(" Configured Max PPS/Client: %1 pps/client\r\n")
.arg(locale.toString((uint)getPacketsPerClientPerSecond()).rightJustified(COLUMN_WIDTH, ' '));
statsString += QString(" Configured Max PPS/Server: %1 pps/server\r\n\r\n")
.arg(locale.toString((uint)getPacketsTotalPerSecond()).rightJustified(COLUMN_WIDTH, ' '));
statsString += QString(" Total Clients Connected: %1 clients\r\n\r\n")
.arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' '));
statsString += QString(" Total Outbound Packets: %1 packets\r\n")
.arg(locale.toString((uint)totalOutboundPackets).rightJustified(COLUMN_WIDTH, ' '));
statsString += QString(" Total Outbound Bytes: %1 bytes\r\n")
@ -612,15 +645,28 @@ void OctreeServer::run() {
}
// Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND = "--packetsPerSecond";
const char* packetsPerSecond = getCmdOption(_argc, _argv, PACKETS_PER_SECOND);
if (packetsPerSecond) {
_packetsPerClientPerInterval = atoi(packetsPerSecond) / INTERVALS_PER_SECOND;
const char* PACKETS_PER_SECOND_PER_CLIENT_MAX = "--packetsPerSecondPerClientMax";
const char* packetsPerSecondPerClientMax = getCmdOption(_argc, _argv, PACKETS_PER_SECOND_PER_CLIENT_MAX);
if (packetsPerSecondPerClientMax) {
_packetsPerClientPerInterval = atoi(packetsPerSecondPerClientMax) / INTERVALS_PER_SECOND;
if (_packetsPerClientPerInterval < 1) {
_packetsPerClientPerInterval = 1;
}
qDebug("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d", packetsPerSecond, _packetsPerClientPerInterval);
}
qDebug("packetsPerSecondPerClientMax=%s _packetsPerClientPerInterval=%d",
packetsPerSecondPerClientMax, _packetsPerClientPerInterval);
// Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND_TOTAL_MAX = "--packetsPerSecondTotalMax";
const char* packetsPerSecondTotalMax = getCmdOption(_argc, _argv, PACKETS_PER_SECOND_TOTAL_MAX);
if (packetsPerSecondTotalMax) {
_packetsTotalPerInterval = atoi(packetsPerSecondTotalMax) / INTERVALS_PER_SECOND;
if (_packetsTotalPerInterval < 1) {
_packetsTotalPerInterval = 1;
}
}
qDebug("packetsPerSecondTotalMax=%s _packetsTotalPerInterval=%d",
packetsPerSecondTotalMax, _packetsTotalPerInterval);
HifiSockAddr senderSockAddr;
@ -656,3 +702,4 @@ void OctreeServer::run() {
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
}

View file

@ -24,6 +24,8 @@
#include "OctreeServerConsts.h"
#include "OctreeInboundPacketProcessor.h"
const int DEFAULT_PACKETS_PER_INTERVAL = 2000; // some 120,000 packets per second total
/// Handles assignments of type OctreeServer - sending octrees to various clients.
class OctreeServer : public ThreadedAssignment, public HTTPRequestHandler {
Q_OBJECT
@ -41,7 +43,16 @@ public:
Octree* getOctree() { return _tree; }
JurisdictionMap* getJurisdiction() { return _jurisdiction; }
int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; }
int getPacketsPerClientPerInterval() const { return std::min(_packetsPerClientPerInterval,
std::max(1, getPacketsTotalPerInterval() / std::max(1, getCurrentClientCount()))); }
int getPacketsPerClientPerSecond() const { return getPacketsPerClientPerInterval() * INTERVALS_PER_SECOND; }
int getPacketsTotalPerInterval() const { return _packetsTotalPerInterval; }
int getPacketsTotalPerSecond() const { return getPacketsTotalPerInterval() * INTERVALS_PER_SECOND; }
static int getCurrentClientCount() { return _clientCount; }
static void clientConnected() { _clientCount++; }
static void clientDisconnected() { _clientCount--; }
bool isInitialLoadComplete() const { return (_persistThread) ? _persistThread->isInitialLoadComplete() : true; }
bool isPersistEnabled() const { return (_persistThread) ? true : false; }
@ -81,6 +92,7 @@ protected:
char _persistFilename[MAX_FILENAME_LENGTH];
int _packetsPerClientPerInterval;
int _packetsTotalPerInterval;
Octree* _tree; // this IS a reaveraging tree
bool _wantPersist;
bool _debugSending;
@ -95,6 +107,8 @@ protected:
time_t _started;
quint64 _startedUSecs;
static int _clientCount;
};
#endif // __octree_server__OctreeServer__

View file

@ -68,7 +68,8 @@ colors[4] = { red: 236, green: 174, blue: 0 };
colors[5] = { red: 234, green: 133, blue: 0 };
colors[6] = { red: 211, green: 115, blue: 0 };
colors[7] = { red: 48, green: 116, blue: 119 };
var numColors = 8;
colors[8] = { red: 31, green: 64, blue: 64 };
var numColors = 9;
var whichColor = -1; // Starting color is 'Copy' mode
// Create sounds for adding, deleting, recoloring voxels
@ -138,34 +139,46 @@ var linePreviewRight = Overlays.addOverlay("line3d", {
// these will be used below
var sliderWidth = 158;
var sliderHeight = 35;
var sliderWidth = 154;
var sliderHeight = 37;
// These will be our "overlay IDs"
var swatches = new Array();
var swatchHeight = 54;
var swatchWidth = 31;
var swatchesWidth = swatchWidth * numColors;
var swatchExtraPadding = 5;
var swatchHeight = 37;
var swatchWidth = 27;
var swatchesWidth = swatchWidth * numColors + numColors + swatchExtraPadding * 2;
var swatchesX = (windowDimensions.x - (swatchesWidth + sliderWidth)) / 2;
var swatchesY = windowDimensions.y - swatchHeight;
var swatchesY = windowDimensions.y - swatchHeight + 1;
var toolIconUrl = "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/tools/";
// create the overlays, position them in a row, set their colors, and for the selected one, use a different source image
// location so that it displays the "selected" marker
for (s = 0; s < numColors; s++) {
var imageFromX = 12 + (s * 27);
var imageFromY = 0;
if (s == whichColor) {
imageFromY = 55;
var extraWidth = 0;
if (s == 0) {
extraWidth = swatchExtraPadding;
}
var imageFromX = swatchExtraPadding - extraWidth + s * swatchWidth;
var imageFromY = swatchHeight + 1;
var swatchX = swatchExtraPadding - extraWidth + swatchesX + ((swatchWidth - 1) * s);
if (s == (numColors - 1)) {
extraWidth = swatchExtraPadding;
}
var swatchX = swatchesX + (30 * s);
swatches[s] = Overlays.addOverlay("image", {
x: swatchX,
y: swatchesY,
width: swatchWidth,
width: swatchWidth + extraWidth,
height: swatchHeight,
subImage: { x: imageFromX, y: imageFromY, width: (swatchWidth - 1), height: swatchHeight },
imageURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/swatches.svg",
subImage: { x: imageFromX, y: imageFromY, width: swatchWidth + extraWidth, height: swatchHeight },
imageURL: toolIconUrl + "swatches.svg",
color: colors[s],
alpha: 1,
visible: editToolsOn
@ -174,66 +187,41 @@ for (s = 0; s < numColors; s++) {
// These will be our tool palette overlays
var numberOfTools = 5;
var toolHeight = 40;
var toolWidth = 62;
var toolsHeight = toolHeight * numberOfTools;
var toolsX = 0;
var numberOfTools = 3;
var toolHeight = 50;
var toolWidth = 50;
var toolVerticalSpacing = 4;
var toolsHeight = toolHeight * numberOfTools + toolVerticalSpacing * (numberOfTools - 1);
var toolsX = 8;
var toolsY = (windowDimensions.y - toolsHeight) / 2;
var addToolAt = 0;
var deleteToolAt = 1;
var recolorToolAt = 2;
var eyedropperToolAt = 3;
var selectToolAt = 4;
var toolSelectedColor = { red: 255, green: 255, blue: 255 };
var notSelectedColor = { red: 128, green: 128, blue: 128 };
var voxelToolAt = 0;
var recolorToolAt = 1;
var eyedropperToolAt = 2;
var addTool = Overlays.addOverlay("image", {
var voxelTool = Overlays.addOverlay("image", {
x: 0, y: 0, width: toolWidth, height: toolHeight,
subImage: { x: 0, y: toolHeight * addToolAt, width: toolWidth, height: toolHeight },
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg",
color: toolSelectedColor,
visible: false,
alpha: 0.9
});
var deleteTool = Overlays.addOverlay("image", {
x: 0, y: 0, width: toolWidth, height: toolHeight,
subImage: { x: 0, y: toolHeight * deleteToolAt, width: toolWidth, height: toolHeight },
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg",
color: toolSelectedColor,
subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight },
imageURL: toolIconUrl + "voxel-tool.svg",
visible: false,
alpha: 0.9
});
var recolorTool = Overlays.addOverlay("image", {
x: 0, y: 0, width: toolWidth, height: toolHeight,
subImage: { x: 0, y: toolHeight * recolorToolAt, width: toolWidth, height: toolHeight },
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg",
color: toolSelectedColor,
subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight },
imageURL: toolIconUrl + "paint-tool.svg",
visible: false,
alpha: 0.9
});
var eyedropperTool = Overlays.addOverlay("image", {
x: 0, y: 0, width: toolWidth, height: toolHeight,
subImage: { x: 0, y: toolHeight * eyedropperToolAt, width: toolWidth, height: toolHeight },
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg",
color: toolSelectedColor,
subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight },
imageURL: toolIconUrl + "eyedropper-tool.svg",
visible: false,
alpha: 0.9
});
var selectTool = Overlays.addOverlay("image", {
x: 0, y: 0, width: toolWidth, height: toolHeight,
subImage: { x: 0, y: toolHeight * selectToolAt, width: toolWidth, height: toolHeight },
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg",
color: toolSelectedColor,
visible: false,
alpha: 0.9
});
// This will create a couple of image overlays that make a "slider", we will demonstrate how to trap mouse messages to
// move the slider
@ -242,35 +230,34 @@ var selectTool = Overlays.addOverlay("image", {
//var sliderWidth = 158;
//var sliderHeight = 35;
var sliderX = swatchesX + swatchesWidth;
var sliderY = windowDimensions.y - sliderHeight;
var sliderOffsetX = 17;
var sliderX = swatchesX - swatchWidth - sliderOffsetX;
var sliderY = windowDimensions.y - sliderHeight + 1;
var slider = Overlays.addOverlay("image", {
// alternate form of expressing bounds
bounds: { x: sliderX, y: sliderY, width: sliderWidth, height: sliderHeight},
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/slider.png",
color: { red: 255, green: 255, blue: 255},
imageURL: toolIconUrl + "voxel-size-slider-bg.svg",
alpha: 1,
visible: false
});
// The slider is handled in the mouse event callbacks.
var isMovingSlider = false;
var thumbClickOffsetX = 0;
// This is the thumb of our slider
var minThumbX = 30; // relative to the x of the slider
var maxThumbX = minThumbX + 65;
var minThumbX = 20; // relative to the x of the slider
var maxThumbX = minThumbX + 90;
var thumbExtents = maxThumbX - minThumbX;
var thumbX = (minThumbX + maxThumbX) / 2;
var thumbY = sliderY + 9;
var thumbOffsetY = 11;
var thumbY = sliderY + thumbOffsetY;
var thumb = Overlays.addOverlay("image", {
x: sliderX + thumbX,
y: thumbY,
width: 18,
width: 17,
height: 17,
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/thumb.png",
color: { red: 255, green: 255, blue: 255},
imageURL: toolIconUrl + "voxel-size-slider-handle.svg",
alpha: 1,
visible: false
});
@ -347,11 +334,9 @@ var trackAsRecolor = false;
var trackAsEyedropper = false;
var trackAsOrbitOrPan = false;
var addToolSelected = true;
var deleteToolSelected = false;
var voxelToolSelected = true;
var recolorToolSelected = false;
var eyedropperToolSelected = false;
var selectToolSelected = false;
function playRandomAddSound(audioOptions) {
if (Math.random() < 0.33) {
@ -524,51 +509,12 @@ function showPreviewVoxel() {
}
var guidePosition;
if (trackAsDelete || deleteToolSelected) {
guidePosition = calculateVoxelFromIntersection(intersection,"delete");
Overlays.editOverlay(voxelPreview, {
position: guidePosition,
size: guidePosition.s + zFightingSizeAdjust,
visible: true,
color: { red: 255, green: 0, blue: 0 },
solid: false,
alpha: 1
});
} else if (selectToolSelected) {
guidePosition = calculateVoxelFromIntersection(intersection,"select");
Overlays.editOverlay(voxelPreview, {
position: guidePosition,
size: guidePosition.s + zFightingSizeAdjust,
visible: true,
color: { red: 255, green: 255, blue: 0 },
solid: false,
alpha: 1
});
} else if (trackAsRecolor || recolorToolSelected || trackAsEyedropper|| eyedropperToolSelected) {
guidePosition = calculateVoxelFromIntersection(intersection,"recolor");
Overlays.editOverlay(voxelPreview, {
position: guidePosition,
size: guidePosition.s + zFightingSizeAdjust,
visible: true,
color: voxelColor,
solid: true,
alpha: 0.8
});
if (trackAsRecolor || recolorToolSelected || trackAsEyedropper || eyedropperToolSelected) {
Overlays.editOverlay(voxelPreview, { visible: true });
} else if (trackAsOrbitOrPan) {
Overlays.editOverlay(voxelPreview, { visible: false });
} else if (addToolSelected && !isExtruding) {
guidePosition = calculateVoxelFromIntersection(intersection,"add");
Overlays.editOverlay(voxelPreview, {
position: guidePosition,
size: (guidePosition.s - zFightingSizeAdjust),
visible: true,
color: voxelColor,
solid: true,
alpha: 0.7
});
} else if (voxelToolSelected && !isExtruding) {
Overlays.editOverlay(voxelPreview, { visible: true });
} else if (isExtruding) {
Overlays.editOverlay(voxelPreview, { visible: false });
}
@ -587,23 +533,11 @@ function showPreviewLines() {
}
resultVoxel = calculateVoxelFromIntersection(intersection,"");
if (selectToolSelected) {
Overlays.editOverlay(voxelPreview, {
position: resultVoxel,
size: resultVoxel.s + zFightingSizeAdjust,
visible: true,
color: { red: 255, green: 255, blue: 0 },
lineWidth: previewLineWidth,
solid: false,
alpha: 1
});
} else {
Overlays.editOverlay(voxelPreview, { visible: false });
Overlays.editOverlay(linePreviewTop, { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true });
Overlays.editOverlay(linePreviewBottom, { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true });
Overlays.editOverlay(linePreviewLeft, { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true });
Overlays.editOverlay(linePreviewRight, { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true });
}
Overlays.editOverlay(voxelPreview, { visible: false });
Overlays.editOverlay(linePreviewTop, { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true });
Overlays.editOverlay(linePreviewBottom, { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true });
Overlays.editOverlay(linePreviewLeft, { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true });
Overlays.editOverlay(linePreviewRight, { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true });
} else {
Overlays.editOverlay(voxelPreview, { visible: false });
Overlays.editOverlay(linePreviewTop, { visible: false });
@ -829,44 +763,39 @@ function mousePressEvent(event) {
isMovingSlider = true;
thumbClickOffsetX = event.x - (sliderX + thumbX); // this should be the position of the mouse relative to the thumb
clickedOnSomething = true;
} else if (clickedOverlay == addTool) {
addToolSelected = true;
deleteToolSelected = false;
Overlays.editOverlay(thumb, { imageURL: toolIconUrl + "voxel-size-slider-handle.svg", });
} else if (clickedOverlay == voxelTool) {
voxelToolSelected = true;
recolorToolSelected = false;
eyedropperToolSelected = false;
selectToolSelected = false;
moveTools();
clickedOnSomething = true;
} else if (clickedOverlay == deleteTool) {
addToolSelected = false;
deleteToolSelected = true;
recolorToolSelected = false;
eyedropperToolSelected = false;
selectToolSelected = false;
moveTools();
clickedOnSomething = true;
} else if (clickedOverlay == recolorTool) {
addToolSelected = false;
deleteToolSelected = false;
voxelToolSelected = false;
recolorToolSelected = true;
eyedropperToolSelected = false;
selectToolSelected = false;
moveTools();
clickedOnSomething = true;
} else if (clickedOverlay == eyedropperTool) {
addToolSelected = false;
deleteToolSelected = false;
voxelToolSelected = false;
recolorToolSelected = false;
eyedropperToolSelected = true;
selectToolSelected = false;
moveTools();
clickedOnSomething = true;
} else if (clickedOverlay == selectTool) {
addToolSelected = false;
deleteToolSelected = false;
recolorToolSelected = false;
eyedropperToolSelected = false;
selectToolSelected = true;
} else if (clickedOverlay == slider) {
if (event.x < sliderX + minThumbX) {
thumbX -= thumbDeltaPerStep;
calcScaleFromThumb(thumbX);
}
if (event.x > sliderX + maxThumbX) {
thumbX += thumbDeltaPerStep;
calcScaleFromThumb(thumbX);
}
moveTools();
clickedOnSomething = true;
} else {
@ -908,7 +837,7 @@ function mousePressEvent(event) {
startPanMode(event);
isPanning = true;
}
} else if (deleteToolSelected || trackAsDelete || (event.isRightButton && !trackAsEyedropper)) {
} else if (trackAsDelete || event.isRightButton && !trackAsEyedropper) {
// Delete voxel
voxelDetails = calculateVoxelFromIntersection(intersection,"delete");
Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s);
@ -932,7 +861,7 @@ function mousePressEvent(event) {
colors[whichColor].red, colors[whichColor].green, colors[whichColor].blue);
Audio.playSound(changeColorSound, audioOptions);
Overlays.editOverlay(voxelPreview, { visible: false });
} else if (addToolSelected) {
} else if (voxelToolSelected) {
// Add voxel on face
if (whichColor == -1) {
// Copy mode - use clicked voxel color
@ -968,7 +897,7 @@ function keyPressEvent(event) {
// if our tools are off, then don't do anything
if (editToolsOn) {
var nVal = parseInt(event.text);
if (event.text == "0") {
if (event.text == "`") {
print("Color = Copy");
whichColor = -1;
Audio.playSound(clickSound, audioOptions);
@ -978,7 +907,7 @@ function keyPressEvent(event) {
print("Color = " + (whichColor + 1));
Audio.playSound(clickSound, audioOptions);
moveTools();
} else if (event.text == "9") {
} else if (event.text == "0") {
// Create a brand new 1 meter voxel in front of your avatar
var color = whichColor;
if (color == -1) color = 0;
@ -1010,18 +939,6 @@ function keyPressEvent(event) {
function keyReleaseEvent(event) {
trackKeyReleaseEvent(event); // used by preview support
// handle clipboard items
if (selectToolSelected) {
// menu tied to BACKSPACE, so we handle DELETE key here...
if (event.text == "DELETE") {
var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY);
var intersection = Voxels.findRayIntersection(pickRay);
selectedVoxel = calculateVoxelFromIntersection(intersection,"select");
print("the DELETE key was pressed... delete");
Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
}
}
}
function setupMenus() {
@ -1186,22 +1103,33 @@ function mouseReleaseEvent(event) {
function moveTools() {
// move the swatches
swatchesX = (windowDimensions.x - (swatchesWidth + sliderWidth)) / 2;
swatchesY = windowDimensions.y - swatchHeight;
swatchesY = windowDimensions.y - swatchHeight + 1;
// create the overlays, position them in a row, set their colors, and for the selected one, use a different source image
// location so that it displays the "selected" marker
for (s = 0; s < numColors; s++) {
var imageFromX = 12 + (s * 27);
var imageFromY = 0;
if (s == whichColor) {
imageFromY = 55;
}
var swatchX = swatchesX + ((swatchWidth - 1) * s);
var extraWidth = 0;
if (s == 0) {
extraWidth = swatchExtraPadding;
}
var imageFromX = swatchExtraPadding - extraWidth + s * swatchWidth;
var imageFromY = swatchHeight + 1;
if (s == whichColor) {
imageFromY = 0;
}
var swatchX = swatchExtraPadding - extraWidth + swatchesX + ((swatchWidth - 1) * s);
if (s == (numColors - 1)) {
extraWidth = swatchExtraPadding;
}
Overlays.editOverlay(swatches[s], {
x: swatchX,
y: swatchesY,
subImage: { x: imageFromX, y: imageFromY, width: (swatchWidth - 1), height: swatchHeight },
subImage: { x: imageFromX, y: imageFromY, width: swatchWidth + extraWidth, height: swatchHeight },
color: colors[s],
alpha: 1,
visible: editToolsOn
@ -1210,62 +1138,45 @@ function moveTools() {
// move the tools
toolsY = (windowDimensions.y - toolsHeight) / 2;
addToolColor = notSelectedColor;
deleteToolColor = notSelectedColor;
recolorToolColor = notSelectedColor;
eyedropperToolColor = notSelectedColor;
selectToolColor = notSelectedColor;
if (trackAsDelete || deleteToolSelected) {
deleteToolColor = toolSelectedColor;
} else if (trackAsRecolor || recolorToolSelected) {
recolorToolColor = toolSelectedColor;
var voxelToolOffset = 1,
recolorToolOffset = 1,
eyedropperToolOffset = 1;
if (trackAsRecolor || recolorToolSelected) {
recolorToolOffset = 2;
} else if (trackAsEyedropper || eyedropperToolSelected) {
eyedropperToolColor = toolSelectedColor;
} else if (selectToolSelected) {
selectToolColor = toolSelectedColor;
eyedropperToolOffset = 2;
} else if (trackAsOrbitOrPan) {
// nothing gets selected in this case...
} else {
addToolColor = toolSelectedColor;
voxelToolOffset = 2;
}
Overlays.editOverlay(addTool, {
x: 0, y: toolsY + (toolHeight * addToolAt), width: toolWidth, height: toolHeight,
color: addToolColor,
visible: editToolsOn
});
Overlays.editOverlay(deleteTool, {
x: 0, y: toolsY + (toolHeight * deleteToolAt), width: toolWidth, height: toolHeight,
color: deleteToolColor,
Overlays.editOverlay(voxelTool, {
subImage: { x: 0, y: toolHeight * voxelToolOffset, width: toolWidth, height: toolHeight },
x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * voxelToolAt), width: toolWidth, height: toolHeight,
visible: editToolsOn
});
Overlays.editOverlay(recolorTool, {
x: 0, y: toolsY + (toolHeight * recolorToolAt), width: toolWidth, height: toolHeight,
color: recolorToolColor,
subImage: { x: 0, y: toolHeight * recolorToolOffset, width: toolWidth, height: toolHeight },
x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * recolorToolAt), width: toolWidth, height: toolHeight,
visible: editToolsOn
});
Overlays.editOverlay(eyedropperTool, {
x: 0, y: toolsY + (toolHeight * eyedropperToolAt), width: toolWidth, height: toolHeight,
color: eyedropperToolColor,
subImage: { x: 0, y: toolHeight * eyedropperToolOffset, width: toolWidth, height: toolHeight },
x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * eyedropperToolAt), width: toolWidth, height: toolHeight,
visible: editToolsOn
});
Overlays.editOverlay(selectTool, {
x: 0, y: toolsY + (toolHeight * selectToolAt), width: toolWidth, height: toolHeight,
color: selectToolColor,
visible: editToolsOn
});
sliderX = swatchesX + swatchesWidth;
sliderY = windowDimensions.y - sliderHeight;
sliderX = swatchesX + swatchesWidth - sliderOffsetX;
sliderY = windowDimensions.y - sliderHeight + 1;
thumbY = sliderY + thumbOffsetY;
Overlays.editOverlay(slider, { x: sliderX, y: sliderY, visible: editToolsOn });
// This is the thumb of our slider
thumbY = sliderY + 9;
Overlays.editOverlay(thumb, { x: sliderX + thumbX, y: thumbY, visible: editToolsOn });
}
@ -1421,11 +1332,9 @@ function scriptEnding() {
for (s = 0; s < numColors; s++) {
Overlays.deleteOverlay(swatches[s]);
}
Overlays.deleteOverlay(addTool);
Overlays.deleteOverlay(deleteTool);
Overlays.deleteOverlay(voxelTool);
Overlays.deleteOverlay(recolorTool);
Overlays.deleteOverlay(eyedropperTool);
Overlays.deleteOverlay(selectTool);
Overlays.deleteOverlay(slider);
Overlays.deleteOverlay(thumb);
Controller.releaseKeyEvents({ text: "+" });

View file

@ -0,0 +1,74 @@
//
// seeingVoxelsExample.js
// hifi
//
// Created by Brad Hefta-Gaub on 2/26/14
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
// This is an example script
//
var count = 0;
var yawDirection = -1;
var yaw = 45;
var yawMax = 70;
var yawMin = 20;
var isLocal = false;
// set up our VoxelViewer with a position and orientation
var orientation = Quat.fromPitchYawRoll(0, yaw, 0);
function init() {
if (isLocal) {
MyAvatar.position = {x: 5000, y: 500, z: 5000};
MyAvatar.orientation = orientation;
} else {
VoxelViewer.setPosition({x: 5000, y: 500, z: 5000});
VoxelViewer.setOrientation(orientation);
VoxelViewer.queryOctree();
Agent.isAvatar = true;
}
}
function keepLooking() {
//print("count =" + count);
if (count == 0) {
init();
}
count++;
if (count % 10 == 0) {
yaw += yawDirection;
orientation = Quat.fromPitchYawRoll(0, yaw, 0);
if (yaw > yawMax || yaw < yawMin) {
yawDirection = yawDirection * -1;
}
print("calling VoxelViewer.queryOctree()... count=" + count + " yaw=" + yaw);
if (isLocal) {
MyAvatar.orientation = orientation;
} else {
VoxelViewer.setOrientation(orientation);
VoxelViewer.queryOctree();
print("VoxelViewer.getOctreeElementsCount()=" + VoxelViewer.getOctreeElementsCount());
}
}
}
function scriptEnding() {
print("SCRIPT ENDNG!!!\n");
}
// register the call back so it fires before each data send
Script.willSendVisualDataCallback.connect(keepLooking);
// register our scriptEnding callback
Script.scriptEnding.connect(scriptEnding);
// test for local...
Menu.isOptionChecked("Voxels");
isLocal = true; // will only get here on local client

View file

@ -1382,6 +1382,26 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) {
_window->activateWindow();
}
void Application::importVoxels() {
if (!_voxelImporter) {
_voxelImporter = new VoxelImporter(_window);
_voxelImporter->loadSettings(_settings);
}
if (!_voxelImporter->exec()) {
qDebug() << "[DEBUG] Import succeeded." << endl;
} else {
qDebug() << "[DEBUG] Import failed." << endl;
if (_sharedVoxelSystem.getTree() == _voxelImporter->getVoxelTree()) {
_sharedVoxelSystem.killLocalVoxels();
_sharedVoxelSystem.changeTree(&_clipboard);
}
}
// restore the main window's active state
_window->activateWindow();
}
void Application::cutVoxels(const VoxelDetail& sourceVoxel) {
copyVoxels(sourceVoxel);
deleteVoxelAt(sourceVoxel);
@ -1520,8 +1540,8 @@ void Application::init() {
// Set up VoxelSystem after loading preferences so we can get the desired max voxel count
_voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels());
_voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader));
_voxels.setVoxelsAsPoints(Menu::getInstance()->isOptionChecked(MenuOption::VoxelsAsPoints));
_voxels.setUseVoxelShader(false);
_voxels.setVoxelsAsPoints(false);
_voxels.setDisableFastVoxelPipeline(false);
_voxels.init();
@ -1917,7 +1937,7 @@ void Application::updateMyAvatar(float deltaTime) {
// actually need to calculate the view frustum planes to send these details
// to the server.
loadViewFrustum(_myCamera, _viewFrustum);
// Update my voxel servers with my current voxel query...
queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions);
queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions);
@ -1930,26 +1950,28 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
return;
}
//qDebug() << ">>> inside... queryOctree()... _viewFrustum.getFieldOfView()=" << _viewFrustum.getFieldOfView();
bool wantExtraDebugging = getLogger()->extraDebugging();
// These will be the same for all servers, so we can set them up once and then reuse for each server we send to.
_voxelQuery.setWantLowResMoving(!Menu::getInstance()->isOptionChecked(MenuOption::DisableLowRes));
_voxelQuery.setWantColor(!Menu::getInstance()->isOptionChecked(MenuOption::DisableColorVoxels));
_voxelQuery.setWantDelta(!Menu::getInstance()->isOptionChecked(MenuOption::DisableDeltaSending));
_voxelQuery.setWantOcclusionCulling(Menu::getInstance()->isOptionChecked(MenuOption::EnableOcclusionCulling));
_voxelQuery.setWantCompression(Menu::getInstance()->isOptionChecked(MenuOption::EnableVoxelPacketCompression));
_octreeQuery.setWantLowResMoving(true);
_octreeQuery.setWantColor(true);
_octreeQuery.setWantDelta(true);
_octreeQuery.setWantOcclusionCulling(false);
_octreeQuery.setWantCompression(true);
_voxelQuery.setCameraPosition(_viewFrustum.getPosition());
_voxelQuery.setCameraOrientation(_viewFrustum.getOrientation());
_voxelQuery.setCameraFov(_viewFrustum.getFieldOfView());
_voxelQuery.setCameraAspectRatio(_viewFrustum.getAspectRatio());
_voxelQuery.setCameraNearClip(_viewFrustum.getNearClip());
_voxelQuery.setCameraFarClip(_viewFrustum.getFarClip());
_voxelQuery.setCameraEyeOffsetPosition(_viewFrustum.getEyeOffsetPosition());
_voxelQuery.setOctreeSizeScale(Menu::getInstance()->getVoxelSizeScale());
_voxelQuery.setBoundaryLevelAdjust(Menu::getInstance()->getBoundaryLevelAdjust());
_octreeQuery.setCameraPosition(_viewFrustum.getPosition());
_octreeQuery.setCameraOrientation(_viewFrustum.getOrientation());
_octreeQuery.setCameraFov(_viewFrustum.getFieldOfView());
_octreeQuery.setCameraAspectRatio(_viewFrustum.getAspectRatio());
_octreeQuery.setCameraNearClip(_viewFrustum.getNearClip());
_octreeQuery.setCameraFarClip(_viewFrustum.getFarClip());
_octreeQuery.setCameraEyeOffsetPosition(_viewFrustum.getEyeOffsetPosition());
_octreeQuery.setOctreeSizeScale(Menu::getInstance()->getVoxelSizeScale());
_octreeQuery.setBoundaryLevelAdjust(Menu::getInstance()->getBoundaryLevelAdjust());
unsigned char voxelQueryPacket[MAX_PACKET_SIZE];
unsigned char queryPacket[MAX_PACKET_SIZE];
// Iterate all of the nodes, and get a count of how many voxel servers we have...
int totalServers = 0;
@ -1989,7 +2011,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
}
}
if (wantExtraDebugging && unknownJurisdictionServers > 0) {
if (wantExtraDebugging) {
qDebug("Servers: total %d, in view %d, unknown jurisdiction %d",
totalServers, inViewServers, unknownJurisdictionServers);
}
@ -2010,7 +2032,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
}
}
if (wantExtraDebugging && unknownJurisdictionServers > 0) {
if (wantExtraDebugging) {
qDebug("perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer);
}
@ -2059,7 +2081,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
}
if (inView) {
_voxelQuery.setMaxOctreePacketsPerSecond(perServerPPS);
_octreeQuery.setMaxOctreePacketsPerSecond(perServerPPS);
} else if (unknownView) {
if (wantExtraDebugging) {
qDebug() << "no known jurisdiction for node " << *node << ", give it budget of "
@ -2070,11 +2092,11 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
// If there's only one server, then don't do this, and just let the normal voxel query pass through
// as expected... this way, we will actually get a valid scene if there is one to be seen
if (totalServers > 1) {
_voxelQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1));
_octreeQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1));
const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0);
_voxelQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE);
_voxelQuery.setCameraNearClip(0.1f);
_voxelQuery.setCameraFarClip(0.1f);
_octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE);
_octreeQuery.setCameraNearClip(0.1f);
_octreeQuery.setCameraFarClip(0.1f);
if (wantExtraDebugging) {
qDebug() << "Using 'minimal' camera position for node" << *node;
}
@ -2083,23 +2105,23 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
qDebug() << "Using regular camera position for node" << *node;
}
}
_voxelQuery.setMaxOctreePacketsPerSecond(perUnknownServer);
_octreeQuery.setMaxOctreePacketsPerSecond(perUnknownServer);
} else {
_voxelQuery.setMaxOctreePacketsPerSecond(0);
_octreeQuery.setMaxOctreePacketsPerSecond(0);
}
// set up the packet for sending...
unsigned char* endOfVoxelQueryPacket = voxelQueryPacket;
unsigned char* endOfQueryPacket = queryPacket;
// insert packet type/version and node UUID
endOfVoxelQueryPacket += populatePacketHeader(reinterpret_cast<char*>(endOfVoxelQueryPacket), packetType);
endOfQueryPacket += populatePacketHeader(reinterpret_cast<char*>(endOfQueryPacket), packetType);
// encode the query data...
endOfVoxelQueryPacket += _voxelQuery.getBroadcastData(endOfVoxelQueryPacket);
endOfQueryPacket += _octreeQuery.getBroadcastData(endOfQueryPacket);
int packetLength = endOfVoxelQueryPacket - voxelQueryPacket;
int packetLength = endOfQueryPacket - queryPacket;
// make sure we still have an active socket
nodeList->writeDatagram(reinterpret_cast<const char*>(voxelQueryPacket), packetLength, node);
nodeList->writeDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
// Feed number of bytes to corresponding channel of the bandwidth meter
_bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength);
@ -2341,14 +2363,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... voxels...");
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontRenderVoxels)) {
_voxels.render();
// double check that our LOD doesn't need to be auto-adjusted
// only adjust if our option is set
if (Menu::getInstance()->isOptionChecked(MenuOption::AutoAdjustLOD)) {
Menu::getInstance()->autoAdjustLOD(_fps);
}
_voxels.render();
// double check that our LOD doesn't need to be auto-adjusted
// adjust it unless we were asked to disable this feature
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD)) {
Menu::getInstance()->autoAdjustLOD(_fps);
}
}
@ -3406,7 +3427,7 @@ void Application::nodeKilled(SharedNodePointer node) {
}
// If the voxel server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server
_voxelServerJurisdictions.erase(nodeUUID);
_voxelServerJurisdictions.erase(_voxelServerJurisdictions.find(nodeUUID));
}
// also clean up scene stats for that server
@ -3437,7 +3458,7 @@ void Application::nodeKilled(SharedNodePointer node) {
}
// If the voxel server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server
_particleServerJurisdictions.erase(nodeUUID);
_particleServerJurisdictions.erase(_particleServerJurisdictions.find(nodeUUID));
}
// also clean up scene stats for that server

View file

@ -27,7 +27,7 @@
#include <ParticleCollisionSystem.h>
#include <ParticleEditPacketSender.h>
#include <ScriptEngine.h>
#include <VoxelQuery.h>
#include <OctreeQuery.h>
#include "Audio.h"
@ -235,6 +235,7 @@ public slots:
void nodeKilled(SharedNodePointer node);
void packetSent(quint64 length);
void importVoxels(); // doesn't include source voxel because it goes to clipboard
void cutVoxels(const VoxelDetail& sourceVoxel);
void copyVoxels(const VoxelDetail& sourceVoxel);
void pasteVoxels(const VoxelDetail& sourceVoxel);
@ -387,7 +388,7 @@ private:
Oscilloscope _audioScope;
VoxelQuery _voxelQuery; // NodeData derived class for querying voxels from voxel server
OctreeQuery _octreeQuery; // NodeData derived class for querying voxels from voxel server
AvatarManager _avatarManager;
MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)

View file

@ -14,8 +14,6 @@
#include <RegisteredMetaTypes.h>
#include <ViewFrustum.h>
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 90.0f;
enum CameraMode
{
CAMERA_MODE_NULL = -1,

View file

@ -238,29 +238,12 @@ Menu::Menu() :
true,
appInstance,
SLOT(setRenderVoxels(bool)));
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontRenderVoxels);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontCallOpenGLForVoxels);
_useVoxelShader = addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0,
false, appInstance->getVoxels(), SLOT(setUseVoxelShader(bool)));
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelsAsPoints, 0,
false, appInstance->getVoxels(), SLOT(setVoxelsAsPoints(bool)));
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AutoAdjustLOD);
addActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools()));
QMenu* voxelProtoOptionsMenu = voxelOptionsMenu->addMenu("Voxel Server Protocol Options");
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DisableColorVoxels);
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DisableLowRes);
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DisableDeltaSending);
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::EnableVoxelPacketCompression);
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::EnableOcclusionCulling);
addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DestructiveAddVoxel);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DisableAutoAdjustLOD);
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");

View file

@ -201,7 +201,7 @@ namespace MenuOption {
const QString AmbientOcclusion = "Ambient Occlusion";
const QString Avatars = "Avatars";
const QString Atmosphere = "Atmosphere";
const QString AutoAdjustLOD = "Automatically Adjust LOD";
const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD";
const QString AutomaticallyAuditTree = "Automatically Audit Tree Stats";
const QString Bandwidth = "Bandwidth Display";
const QString BandwidthDetails = "Bandwidth Details";
@ -217,19 +217,11 @@ namespace MenuOption {
const QString CullSharedFaces = "Cull Shared Voxel Faces";
const QString DecreaseAvatarSize = "Decrease Avatar Size";
const QString DecreaseVoxelSize = "Decrease Voxel Size";
const QString DestructiveAddVoxel = "Create Voxel is Destructive";
const QString DisableColorVoxels = "Disable Colored Voxels";
const QString DisableDeltaSending = "Disable Delta Sending";
const QString DisableLowRes = "Disable Lower Resolution While Moving";
const QString DisplayFrustum = "Display Frustum";
const QString DisplayHands = "Display Hands";
const QString DisplayHandTargets = "Display Hand Targets";
const QString FilterSixense = "Smooth Sixense Movement";
const QString DontRenderVoxels = "Don't call _voxels.render()";
const QString DontCallOpenGLForVoxels = "Don't call glDrawRangeElementsEXT() for Voxels";
const QString Enable3DTVMode = "Enable 3DTV Mode";
const QString EnableOcclusionCulling = "Enable Occlusion Culling";
const QString EnableVoxelPacketCompression = "Enable Voxel Packet Compression";
const QString AudioNoiseReduction = "Audio Noise Reduction";
const QString EchoServerAudio = "Echo Server Audio";
const QString EchoLocalAudio = "Echo Local Audio";
@ -301,8 +293,6 @@ namespace MenuOption {
const QString TreeStats = "Calculate Tree Stats";
const QString TransmitterDrive = "Transmitter Drive";
const QString Quit = "Quit";
const QString UseVoxelShader = "Use Voxel Shader";
const QString VoxelsAsPoints = "Draw Voxels as Points";
const QString Voxels = "Voxels";
const QString VoxelDrumming = "Voxel Drumming";
const QString VoxelMode = "Cycle Voxel Mode";

View file

@ -48,6 +48,9 @@ void VoxelPacketProcessor::processPacket(const SharedNodePointer& sendingNode, c
wasStatsPacket = true;
if (messageLength > statsMessageLength) {
mutablePacket = mutablePacket.mid(statsMessageLength);
// TODO: this does not look correct, the goal is to test the packet version for the piggyback, but
// this is testing the version and hash of the original packet
if (!NodeList::getInstance()->packetVersionAndHashMatch(packet)) {
return; // bail since piggyback data doesn't match our versioning
}

View file

@ -867,7 +867,6 @@ void VoxelSystem::checkForCulling() {
bool fullRedraw = (_lastKnownVoxelSizeScale != Menu::getInstance()->getVoxelSizeScale() ||
_lastKnownBoundaryLevelAdjust != Menu::getInstance()->getBoundaryLevelAdjust());
// track that these values
_lastKnownVoxelSizeScale = Menu::getInstance()->getVoxelSizeScale();
_lastKnownBoundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust();
@ -1386,7 +1385,6 @@ void VoxelSystem::render() {
updateVBOs();
bool dontCallOpenGLDraw = Menu::getInstance()->isOptionChecked(MenuOption::DontCallOpenGLForVoxels);
// if not don't... then do...
if (_useVoxelShader) {
PerformanceWarning warn(showWarnings,"render().. _useVoxelShader openGL..");
@ -1432,9 +1430,7 @@ void VoxelSystem::render() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID);
if (!dontCallOpenGLDraw) {
glDrawElements(GL_POINTS, _voxelsInReadArrays, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); //The starting point of the IBO
}
glDrawElements(GL_POINTS, _voxelsInReadArrays, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); //The starting point of the IBO
// deactivate vertex and color arrays after drawing
glDisableClientState(GL_VERTEX_ARRAY);
@ -1477,7 +1473,7 @@ void VoxelSystem::render() {
// draw voxels in 6 passes
if (!dontCallOpenGLDraw) {
{
PerformanceWarning warn(showWarnings, "render().. glDrawRangeElementsEXT()...");
glNormal3f(0,1.0f,0);
@ -1510,7 +1506,6 @@ void VoxelSystem::render() {
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
}
{
PerformanceWarning warn(showWarnings, "render().. cleanup after glDrawRangeElementsEXT()...");

View file

@ -62,8 +62,7 @@ bool JurisdictionListener::queueJurisdictionRequest() {
}
void JurisdictionListener::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
//qDebug() << "JurisdictionListener::processPacket()";
if (packetTypeForPacket(packet) == PacketTypeJurisdictionRequest && sendingNode) {
if (packetTypeForPacket(packet) == PacketTypeJurisdiction && sendingNode) {
QUuid nodeUUID = sendingNode->getUUID();
JurisdictionMap map;
map.unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()), packet.size());

View file

@ -79,7 +79,8 @@ private:
/// Map between node IDs and their reported JurisdictionMap. Typically used by classes that need to know which nodes are
/// managing which jurisdictions.
typedef std::map<QUuid, JurisdictionMap> NodeToJurisdictionMap;
typedef QMap<QUuid, JurisdictionMap> NodeToJurisdictionMap;
typedef QMap<QUuid, JurisdictionMap>::iterator NodeToJurisdictionMapIterator;
#endif /* defined(__hifi__JurisdictionMap__) */

View file

@ -0,0 +1,241 @@
//
// OctreeHeadlessViewer.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 2/26/14
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
//
#include <NodeList.h>
#include "OctreeHeadlessViewer.h"
OctreeHeadlessViewer::OctreeHeadlessViewer() :
OctreeRenderer(),
_voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
_boundaryLevelAdjust(0),
_maxPacketsPerSecond(DEFAULT_MAX_OCTREE_PPS)
{
_viewFrustum.setFieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES);
_viewFrustum.setAspectRatio(DEFAULT_ASPECT_RATIO);
_viewFrustum.setNearClip(DEFAULT_NEAR_CLIP);
_viewFrustum.setFarClip(TREE_SCALE);
}
OctreeHeadlessViewer::~OctreeHeadlessViewer() {
}
void OctreeHeadlessViewer::init() {
OctreeRenderer::init();
setViewFrustum(&_viewFrustum);
}
void OctreeHeadlessViewer::queryOctree() {
NodeType_t serverType = getMyNodeType();
PacketType packetType = getMyQueryMessageType();
NodeToJurisdictionMap& jurisdictions = *_jurisdictionListener->getJurisdictions();
bool wantExtraDebugging = false;
if (wantExtraDebugging) {
qDebug() << "OctreeHeadlessViewer::queryOctree() _jurisdictionListener=" << _jurisdictionListener;
qDebug() << "---------------";
qDebug() << "_jurisdictionListener=" << _jurisdictionListener;
qDebug() << "Jurisdictions...";
for (NodeToJurisdictionMapIterator i = jurisdictions.begin(); i != jurisdictions.end(); ++i) {
qDebug() << i.key() << ": " << &i.value();
}
qDebug() << "---------------";
}
// These will be the same for all servers, so we can set them up once and then reuse for each server we send to.
_octreeQuery.setWantLowResMoving(true);
_octreeQuery.setWantColor(true);
_octreeQuery.setWantDelta(true);
_octreeQuery.setWantOcclusionCulling(false);
_octreeQuery.setWantCompression(true); // TODO: should be on by default
_octreeQuery.setCameraPosition(_viewFrustum.getPosition());
_octreeQuery.setCameraOrientation(_viewFrustum.getOrientation());
_octreeQuery.setCameraFov(_viewFrustum.getFieldOfView());
_octreeQuery.setCameraAspectRatio(_viewFrustum.getAspectRatio());
_octreeQuery.setCameraNearClip(_viewFrustum.getNearClip());
_octreeQuery.setCameraFarClip(_viewFrustum.getFarClip());
_octreeQuery.setCameraEyeOffsetPosition(_viewFrustum.getEyeOffsetPosition());
_octreeQuery.setOctreeSizeScale(getVoxelSizeScale());
_octreeQuery.setBoundaryLevelAdjust(getBoundaryLevelAdjust());
unsigned char queryPacket[MAX_PACKET_SIZE];
// Iterate all of the nodes, and get a count of how many voxel servers we have...
int totalServers = 0;
int inViewServers = 0;
int unknownJurisdictionServers = 0;
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
// only send to the NodeTypes that are serverType
if (node->getActiveSocket() != NULL && node->getType() == serverType) {
totalServers++;
// get the server bounds for this server
QUuid nodeUUID = node->getUUID();
// if we haven't heard from this voxel server, go ahead and send it a query, so we
// can get the jurisdiction...
if (jurisdictions.find(nodeUUID) == jurisdictions.end()) {
unknownJurisdictionServers++;
} else {
const JurisdictionMap& map = (jurisdictions)[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
serverBounds.scale(TREE_SCALE);
ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds);
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
inViewServers++;
}
}
}
}
}
if (wantExtraDebugging) {
qDebug("Servers: total %d, in view %d, unknown jurisdiction %d",
totalServers, inViewServers, unknownJurisdictionServers);
}
int perServerPPS = 0;
const int SMALL_BUDGET = 10;
int perUnknownServer = SMALL_BUDGET;
int totalPPS = getMaxPacketsPerSecond();
// determine PPS based on number of servers
if (inViewServers >= 1) {
// set our preferred PPS to be exactly evenly divided among all of the voxel servers... and allocate 1 PPS
// for each unknown jurisdiction server
perServerPPS = (totalPPS / inViewServers) - (unknownJurisdictionServers * perUnknownServer);
} else {
if (unknownJurisdictionServers > 0) {
perUnknownServer = (totalPPS / unknownJurisdictionServers);
}
}
if (wantExtraDebugging) {
qDebug("perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer);
}
NodeList* nodeList = NodeList::getInstance();
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
// only send to the NodeTypes that are serverType
if (node->getActiveSocket() != NULL && node->getType() == serverType) {
// get the server bounds for this server
QUuid nodeUUID = node->getUUID();
bool inView = false;
bool unknownView = false;
// if we haven't heard from this voxel server, go ahead and send it a query, so we
// can get the jurisdiction...
if (jurisdictions.find(nodeUUID) == jurisdictions.end()) {
unknownView = true; // assume it's in view
if (wantExtraDebugging) {
qDebug() << "no known jurisdiction for node " << *node << ", assume it's visible.";
}
} else {
const JurisdictionMap& map = (jurisdictions)[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
serverBounds.scale(TREE_SCALE);
ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds);
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
inView = true;
} else {
inView = false;
}
} else {
if (wantExtraDebugging) {
qDebug() << "Jurisdiction without RootCode for node " << *node << ". That's unusual!";
}
}
}
if (inView) {
_octreeQuery.setMaxOctreePacketsPerSecond(perServerPPS);
if (wantExtraDebugging) {
qDebug() << "inView for node " << *node << ", give it budget of " << perServerPPS;
}
} else if (unknownView) {
if (wantExtraDebugging) {
qDebug() << "no known jurisdiction for node " << *node << ", give it budget of "
<< perUnknownServer << " to send us jurisdiction.";
}
// set the query's position/orientation to be degenerate in a manner that will get the scene quickly
// If there's only one server, then don't do this, and just let the normal voxel query pass through
// as expected... this way, we will actually get a valid scene if there is one to be seen
if (totalServers > 1) {
_octreeQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1));
const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0);
_octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE);
_octreeQuery.setCameraNearClip(0.1f);
_octreeQuery.setCameraFarClip(0.1f);
if (wantExtraDebugging) {
qDebug() << "Using 'minimal' camera position for node" << *node;
}
} else {
if (wantExtraDebugging) {
qDebug() << "Using regular camera position for node" << *node;
}
}
_octreeQuery.setMaxOctreePacketsPerSecond(perUnknownServer);
} else {
_octreeQuery.setMaxOctreePacketsPerSecond(0);
}
// set up the packet for sending...
unsigned char* endOfQueryPacket = queryPacket;
// insert packet type/version and node UUID
endOfQueryPacket += populatePacketHeader(reinterpret_cast<char*>(endOfQueryPacket), packetType);
// encode the query data...
endOfQueryPacket += _octreeQuery.getBroadcastData(endOfQueryPacket);
int packetLength = endOfQueryPacket - queryPacket;
// make sure we still have an active socket
nodeList->writeDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
}
}
}
int OctreeHeadlessViewer::parseOctreeStats(const QByteArray& packet, const SharedNodePointer& sourceNode) {
OctreeSceneStats temp;
int statsMessageLength = temp.unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()), packet.size());
// TODO: actually do something with these stats, like expose them to JS...
return statsMessageLength;
}
void OctreeHeadlessViewer::trackIncomingOctreePacket(const QByteArray& packet,
const SharedNodePointer& sendingNode, bool wasStatsPacket) {
}

View file

@ -0,0 +1,73 @@
//
// OctreeHeadlessViewer.h
// hifi
//
// Created by Brad Hefta-Gaub on 2/26/14
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
//
#ifndef __hifi__OctreeHeadlessViewer__
#define __hifi__OctreeHeadlessViewer__
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include "JurisdictionListener.h"
#include "Octree.h"
#include "OctreeConstants.h"
#include "OctreeQuery.h"
#include "OctreeRenderer.h"
#include "OctreeSceneStats.h"
#include "Octree.h"
#include "ViewFrustum.h"
// Generic client side Octree renderer class.
class OctreeHeadlessViewer : public OctreeRenderer {
Q_OBJECT
public:
OctreeHeadlessViewer();
virtual ~OctreeHeadlessViewer();
virtual void renderElement(OctreeElement* element, RenderArgs* args) { /* swallow these */ };
virtual void init();
virtual void render() { /* swallow these */ };
void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; }
static int parseOctreeStats(const QByteArray& packet, const SharedNodePointer& sourceNode);
static void trackIncomingOctreePacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket);
public slots:
void queryOctree();
// setters for camera attributes
void setPosition(const glm::vec3& position) { _viewFrustum.setPosition(position); }
void setOrientation(const glm::quat& orientation) { _viewFrustum.setOrientation(orientation); }
// setters for LOD and PPS
void setVoxelSizeScale(float sizeScale) { _voxelSizeScale = sizeScale; }
void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; }
void setMaxPacketsPerSecond(int maxPacketsPerSecond) { _maxPacketsPerSecond = maxPacketsPerSecond; }
// getters for camera attributes
const glm::vec3& getPosition() const { return _viewFrustum.getPosition(); }
const glm::quat& getOrientation() const { return _viewFrustum.getOrientation(); }
// getters for LOD and PPS
float getVoxelSizeScale() const { return _voxelSizeScale; }
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
int getMaxPacketsPerSecond() const { return _maxPacketsPerSecond; }
unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); }
private:
ViewFrustum _viewFrustum;
JurisdictionListener* _jurisdictionListener;
OctreeQuery _octreeQuery;
float _voxelSizeScale;
int _boundaryLevelAdjust;
int _maxPacketsPerSecond;
};
#endif /* defined(__hifi__OctreeHeadlessViewer__) */

View file

@ -6,22 +6,11 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <cstdio>
#include <cstring>
#include <stdint.h>
#include <NodeList.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <UUID.h>
#include "OctreeConstants.h"
#include "OctreeQuery.h"
using namespace std;
static const float fingerVectorRadix = 4; // bits of precision when converting from float<->fixed
OctreeQuery::OctreeQuery() :
NodeData(),
_cameraPosition(0,0,0),

View file

@ -9,8 +9,6 @@
#ifndef __hifi__OctreeQuery__
#define __hifi__OctreeQuery__
#include <string>
/* VS2010 defines stdint.h, but not inttypes.h */
#if defined(_MSC_VER)
typedef signed char int8_t;
@ -27,17 +25,9 @@ typedef unsigned long long quint64;
#endif
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <QtCore/QObject>
#include <QtCore/QUuid>
#include <QtCore/QVariantMap>
#include <RegisteredMetaTypes.h>
#include <NodeData.h>
// First bitset

View file

@ -27,42 +27,48 @@ OctreeRenderer::~OctreeRenderer() {
}
void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
bool extraDebugging = false;
if (extraDebugging) {
qDebug() << "OctreeRenderer::processDatagram()";
}
if (!_tree) {
qDebug() << "OctreeRenderer::processDatagram() called before init, calling init()...";
this->init();
}
bool showTimingDetails = false; // Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
bool extraDebugging = false; // Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)
PerformanceWarning warn(showTimingDetails, "OctreeRenderer::processDatagram()",showTimingDetails);
const unsigned char* packetData = (const unsigned char*)dataByteArray.constData();
int packetLength = dataByteArray.size();
unsigned char command = *packetData;
PacketType command = packetTypeForPacket(dataByteArray);
int numBytesPacketHeader = numBytesForPacketHeader(dataByteArray);
QUuid sourceUUID = uuidFromPacketHeader(dataByteArray);
PacketType expectedType = getExpectedPacketType();
if(command == expectedType) {
PerformanceWarning warn(showTimingDetails, "OctreeRenderer::processDatagram expected PacketType", showTimingDetails);
// if we are getting inbound packets, then our tree is also viewing, and we should remember that fact.
_tree->setIsViewing(true);
const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(dataByteArray.data()) + numBytesPacketHeader;
OCTREE_PACKET_FLAGS flags = (*(OCTREE_PACKET_FLAGS*)(dataAt));
dataAt += sizeof(OCTREE_PACKET_FLAGS);
OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt);
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
OCTREE_PACKET_SENT_TIME sentAt = (*(OCTREE_PACKET_SENT_TIME*)dataAt);
dataAt += sizeof(OCTREE_PACKET_SENT_TIME);
bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT);
bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT);
OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
int clockSkew = sourceNode ? sourceNode->getClockSkewUsec() : 0;
int flightTime = arrivedAt - sentAt + clockSkew;
OCTREE_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0;
int dataBytes = packetLength - (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_SIZE);
@ -91,7 +97,7 @@ void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const Shar
if (sectionLength) {
// ask the VoxelTree to read the bitstream into the tree
ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL,
getDataSourceUUID(), sourceNode);
sourceUUID, sourceNode);
_tree->lockForWrite();
OctreePacketData packetData(packetIsCompressed);
packetData.loadFinalizedContent(dataAt, sectionLength);

View file

@ -13,6 +13,8 @@
#include <glm/glm.hpp>
#include <stdint.h>
#include <QObject>
#include <PacketHeaders.h>
#include <SharedUtil.h>
@ -31,7 +33,8 @@ public:
// Generic client side Octree renderer class.
class OctreeRenderer {
class OctreeRenderer : public QObject {
Q_OBJECT
public:
OctreeRenderer();
virtual ~OctreeRenderer();
@ -51,8 +54,6 @@ public:
/// render the content of the octree
virtual void render();
void setDataSourceUUID(const QUuid& dataSourceUUID) { _dataSourceUUID = dataSourceUUID; }
const QUuid& getDataSourceUUID() const { return _dataSourceUUID; }
ViewFrustum* getViewFrustum() const { return _viewFrustum; }
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }
@ -62,7 +63,6 @@ public:
void clear();
protected:
Octree* _tree;
QUuid _dataSourceUUID;
ViewFrustum* _viewFrustum;
};

View file

@ -32,6 +32,9 @@ public:
virtual NodeType_t getServerNodeType() const = 0;
virtual OctreeEditPacketSender* createPacketSender() = 0;
private slots:
void cleanupManagedObjects();
public slots:
/// Set the desired max packet size in bytes that should be created
void setMaxPacketSize(int maxPacketSize) { return _packetSender->setMaxPacketSize(maxPacketSize); }
@ -84,9 +87,6 @@ public slots:
/// returns the total bytes queued by this object over its lifetime
long long unsigned int getLifetimeBytesQueued() const { return _packetSender->getLifetimeBytesQueued(); }
// TODO: hmmm... we don't want this called from JS, how to handle that?
void cleanupManagedObjects();
protected:
/// attached OctreeEditPacketSender that handles queuing and sending of packets to VS
OctreeEditPacketSender* _packetSender;

View file

@ -54,11 +54,9 @@ void ViewFrustum::setOrientation(const glm::quat& orientationAsQuaternion) {
_direction = glm::vec3(orientationAsQuaternion * glm::vec4(IDENTITY_FRONT, 0.0f));
}
/////////////////////////////////////////////////////////////////////////////////////
// ViewFrustum::calculateViewFrustum()
//
// Description: this will calculate the view frustum bounds for a given position
// and direction
// Description: this will calculate the view frustum bounds for a given position and direction
//
// Notes on how/why this works:
// http://www.lighthouse3d.com/tutorials/view-frustum-culling/view-frustums-shape/

View file

@ -17,9 +17,14 @@
#include "AABox.h"
#include "Plane.h"
#include "OctreeConstants.h"
#include "OctreeProjectedPolygon.h"
const float DEFAULT_KEYHOLE_RADIUS = 3.0f;
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 90.0f;
const float DEFAULT_ASPECT_RATIO = 16.f/9.f;
const float DEFAULT_NEAR_CLIP = 0.08f;
const float DEFAULT_FAR_CLIP = 50.0f * TREE_SCALE;
class ViewFrustum {
public:

View file

@ -0,0 +1,36 @@
//
// ParticleTreeHeadlessViewer.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 2/26/14
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
//
#include "ParticleTreeHeadlessViewer.h"
ParticleTreeHeadlessViewer::ParticleTreeHeadlessViewer() :
OctreeHeadlessViewer() {
}
ParticleTreeHeadlessViewer::~ParticleTreeHeadlessViewer() {
}
void ParticleTreeHeadlessViewer::init() {
OctreeHeadlessViewer::init();
}
void ParticleTreeHeadlessViewer::update() {
if (_tree) {
ParticleTree* tree = static_cast<ParticleTree*>(_tree);
if (tree->tryLockForWrite()) {
tree->update();
tree->unlock();
}
}
}
void ParticleTreeHeadlessViewer::processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
static_cast<ParticleTree*>(_tree)->processEraseMessage(dataByteArray, sourceNode);
}

View file

@ -0,0 +1,42 @@
//
// ParticleTreeHeadlessViewer.h
// hifi
//
// Created by Brad Hefta-Gaub on 2/26/14
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
//
#ifndef __hifi__ParticleTreeHeadlessViewer__
#define __hifi__ParticleTreeHeadlessViewer__
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <Octree.h>
#include <OctreePacketData.h>
#include <OctreeHeadlessViewer.h>
#include "ParticleTree.h"
#include <ViewFrustum.h>
// Generic client side Octree renderer class.
class ParticleTreeHeadlessViewer : public OctreeHeadlessViewer {
Q_OBJECT
public:
ParticleTreeHeadlessViewer();
virtual ~ParticleTreeHeadlessViewer();
virtual Octree* createTree() { return new ParticleTree(true); }
virtual NodeType_t getMyNodeType() const { return NodeType::ParticleServer; }
virtual PacketType getMyQueryMessageType() const { return PacketTypeParticleQuery; }
virtual PacketType getExpectedPacketType() const { return PacketTypeParticleData; }
void update();
ParticleTree* getTree() { return (ParticleTree*)_tree; }
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
virtual void init();
};
#endif /* defined(__hifi__ParticleTreeHeadlessViewer__) */

View file

@ -26,7 +26,19 @@ public:
void setParticleTree(ParticleTree* particleTree) { _particleTree = particleTree; }
ParticleTree* getParticleTree(ParticleTree*) { return _particleTree; }
private slots:
/// inbound slots for external collision systems
void forwardParticleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel) {
qDebug() << "forwardParticleCollisionWithVoxel()";
emit particleCollisionWithVoxel(particleID, voxel);
}
void forwardParticleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB) {
qDebug() << "forwardParticleCollisionWithParticle()";
emit particleCollisionWithParticle(idA, idB);
}
public slots:
/// adds a particle with the specific properties
ParticleID addParticle(const ParticleProperties& properties);
@ -54,15 +66,6 @@ public slots:
/// this function will not find any particles in script engine contexts which don't have access to particles
QVector<ParticleID> findParticles(const glm::vec3& center, float radius) const;
/// inbound slots for external collision systems
void forwardParticleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel) {
emit particleCollisionWithVoxel(particleID, voxel);
}
void forwardParticleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB) {
emit particleCollisionWithParticle(idA, idB);
}
signals:
void particleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel);
void particleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB);

View file

@ -1,9 +0,0 @@
//
// VoxelQuery.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 10/24/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "VoxelQuery.h"

View file

@ -1,25 +0,0 @@
//
// VoxelQuery.h
// hifi
//
// Created by Stephen Birarda on 4/9/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __hifi__VoxelQuery__
#define __hifi__VoxelQuery__
#include <OctreeQuery.h>
class VoxelQuery : public OctreeQuery {
public:
// currently just an alias
VoxelQuery() : OctreeQuery() {};
private:
// privatize the copy constructor and assignment operator so they cannot be called
VoxelQuery(const VoxelQuery&);
VoxelQuery& operator= (const VoxelQuery&);
};
#endif /* defined(__hifi__VoxelQuery__) */

View file

@ -0,0 +1,22 @@
//
// VoxelTreeHeadlessViewer.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 2/26/14
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
//
#include "VoxelTreeHeadlessViewer.h"
VoxelTreeHeadlessViewer::VoxelTreeHeadlessViewer() :
OctreeHeadlessViewer() {
}
VoxelTreeHeadlessViewer::~VoxelTreeHeadlessViewer() {
}
void VoxelTreeHeadlessViewer::init() {
OctreeHeadlessViewer::init();
}

View file

@ -0,0 +1,38 @@
//
// VoxelTreeHeadlessViewer.h
// hifi
//
// Created by Brad Hefta-Gaub on 2/26/14
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
//
#ifndef __hifi__VoxelTreeHeadlessViewer__
#define __hifi__VoxelTreeHeadlessViewer__
#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 Octree* createTree() { return new VoxelTree(true); }
virtual NodeType_t 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();
};
#endif /* defined(__hifi__VoxelTreeHeadlessViewer__) */