mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-24 01:24:00 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into ssao
This commit is contained in:
commit
cceeb1c6ff
32 changed files with 1101 additions and 420 deletions
28
interface/resources/shaders/diffuse.frag
Normal file
28
interface/resources/shaders/diffuse.frag
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// diffuse.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 8/14/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
// the texture containing the original color
|
||||||
|
uniform sampler2D originalTexture;
|
||||||
|
|
||||||
|
// the texture containing the diffused color
|
||||||
|
uniform sampler2D diffusedTexture;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
float ds = dFdx(gl_TexCoord[0].s);
|
||||||
|
float dt = dFdy(gl_TexCoord[0].t);
|
||||||
|
gl_FragColor = (texture2D(diffusedTexture, gl_TexCoord[0].st + vec2(-ds, -dt)) +
|
||||||
|
texture2D(diffusedTexture, gl_TexCoord[0].st + vec2(0.0, -dt)) +
|
||||||
|
texture2D(diffusedTexture, gl_TexCoord[0].st + vec2(ds, -dt)) +
|
||||||
|
texture2D(diffusedTexture, gl_TexCoord[0].st + vec2(ds, 0.0)) +
|
||||||
|
texture2D(diffusedTexture, gl_TexCoord[0].st + vec2(ds, dt)) +
|
||||||
|
texture2D(diffusedTexture, gl_TexCoord[0].st + vec2(0.0, dt)) +
|
||||||
|
texture2D(diffusedTexture, gl_TexCoord[0].st + vec2(-ds, dt)) +
|
||||||
|
texture2D(diffusedTexture, gl_TexCoord[0].st + vec2(-ds, 0.0))) / 8.5 + texture2D(originalTexture, gl_TexCoord[0].st) * 0.1;
|
||||||
|
}
|
17
interface/resources/shaders/glow_add.frag
Normal file
17
interface/resources/shaders/glow_add.frag
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// glow_add.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 8/14/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
// the texture containing the original color
|
||||||
|
uniform sampler2D originalTexture;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
vec4 color = texture2D(originalTexture, gl_TexCoord[0].st);
|
||||||
|
gl_FragColor = color * (1.0 + color.a);
|
||||||
|
}
|
20
interface/resources/shaders/glow_add_separate.frag
Normal file
20
interface/resources/shaders/glow_add_separate.frag
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// glow_add_separate.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 8/14/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
// the texture containing the original color
|
||||||
|
uniform sampler2D originalTexture;
|
||||||
|
|
||||||
|
// the texture containing the blurred color
|
||||||
|
uniform sampler2D blurredTexture;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
vec4 blurred = texture2D(blurredTexture, gl_TexCoord[0].st);
|
||||||
|
gl_FragColor = blurred * blurred.a + texture2D(originalTexture, gl_TexCoord[0].st) * (1.0 + blurred.a * 0.5);
|
||||||
|
}
|
|
@ -4,25 +4,21 @@
|
||||||
// vertical_blur.frag
|
// vertical_blur.frag
|
||||||
// fragment shader
|
// fragment shader
|
||||||
//
|
//
|
||||||
// Created by Andrzej Kapolka on 8/8/13.
|
// Created by Andrzej Kapolka on 8/14/13.
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
// the texture containing the original color
|
|
||||||
uniform sampler2D originalTexture;
|
|
||||||
|
|
||||||
// the texture containing the horizontally blurred color
|
// the texture containing the horizontally blurred color
|
||||||
uniform sampler2D horizontallyBlurredTexture;
|
uniform sampler2D originalTexture;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
float dt = dFdy(gl_TexCoord[0].t);
|
float dt = dFdy(gl_TexCoord[0].t);
|
||||||
vec4 blurred = (texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -7.5)) +
|
gl_FragColor = (texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * -7.5)) +
|
||||||
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -5.5)) +
|
texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * -5.5)) +
|
||||||
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -3.5)) +
|
texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * -3.5)) +
|
||||||
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -1.5)) +
|
texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * -1.5)) +
|
||||||
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 1.5)) +
|
texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * 1.5)) +
|
||||||
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 3.5)) +
|
texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * 3.5)) +
|
||||||
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 5.5)) +
|
texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * 5.5)) +
|
||||||
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 7.5))) / 8.0;
|
texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * 7.5))) / 8.0;
|
||||||
gl_FragColor = blurred * blurred.a + texture2D(originalTexture, gl_TexCoord[0].st) * (1.0 + blurred.a * 0.5);
|
|
||||||
}
|
}
|
||||||
|
|
28
interface/resources/shaders/vertical_blur_add.frag
Normal file
28
interface/resources/shaders/vertical_blur_add.frag
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// vertical_blur_add.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 8/8/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
// the texture containing the original color
|
||||||
|
uniform sampler2D originalTexture;
|
||||||
|
|
||||||
|
// the texture containing the horizontally blurred color
|
||||||
|
uniform sampler2D horizontallyBlurredTexture;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
float dt = dFdy(gl_TexCoord[0].t);
|
||||||
|
vec4 blurred = (texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -7.5)) +
|
||||||
|
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -5.5)) +
|
||||||
|
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -3.5)) +
|
||||||
|
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -1.5)) +
|
||||||
|
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 1.5)) +
|
||||||
|
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 3.5)) +
|
||||||
|
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 5.5)) +
|
||||||
|
texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 7.5))) / 8.0;
|
||||||
|
gl_FragColor = blurred * blurred.a + texture2D(originalTexture, gl_TexCoord[0].st) * (1.0 + blurred.a * 0.5);
|
||||||
|
}
|
|
@ -95,9 +95,7 @@ const int STARTUP_JITTER_SAMPLES = PACKET_LENGTH_SAMPLES_PER_CHANNEL / 2;
|
||||||
// customized canvas that simply forwards requests/events to the singleton application
|
// customized canvas that simply forwards requests/events to the singleton application
|
||||||
class GLCanvas : public QGLWidget {
|
class GLCanvas : public QGLWidget {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GLCanvas();
|
GLCanvas();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void initializeGL();
|
virtual void initializeGL();
|
||||||
|
@ -214,8 +212,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_justEditedVoxel(false),
|
_justEditedVoxel(false),
|
||||||
_isLookingAtOtherAvatar(false),
|
_isLookingAtOtherAvatar(false),
|
||||||
_lookatIndicatorScale(1.0f),
|
_lookatIndicatorScale(1.0f),
|
||||||
_paintOn(false),
|
|
||||||
_dominantColor(0),
|
|
||||||
_perfStatsOn(false),
|
_perfStatsOn(false),
|
||||||
_chatEntryOn(false),
|
_chatEntryOn(false),
|
||||||
_oculusTextureID(0),
|
_oculusTextureID(0),
|
||||||
|
@ -225,7 +221,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_audio(&_audioScope, STARTUP_JITTER_SAMPLES),
|
_audio(&_audioScope, STARTUP_JITTER_SAMPLES),
|
||||||
#endif
|
#endif
|
||||||
_stopNetworkReceiveThread(false),
|
_stopNetworkReceiveThread(false),
|
||||||
_stopProcessVoxelsThread(false),
|
_voxelProcessor(this),
|
||||||
|
_voxelEditSender(this),
|
||||||
_packetCount(0),
|
_packetCount(0),
|
||||||
_packetsPerSecond(0),
|
_packetsPerSecond(0),
|
||||||
_bytesPerSecond(0),
|
_bytesPerSecond(0),
|
||||||
|
@ -377,8 +374,9 @@ void Application::initializeGL() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create thread for parsing of voxel data independent of the main network and rendering threads
|
// create thread for parsing of voxel data independent of the main network and rendering threads
|
||||||
|
_voxelProcessor.initialize(_enableProcessVoxelsThread);
|
||||||
|
_voxelEditSender.initialize(_enableProcessVoxelsThread);
|
||||||
if (_enableProcessVoxelsThread) {
|
if (_enableProcessVoxelsThread) {
|
||||||
pthread_create(&_processVoxelsThread, NULL, processVoxels, NULL);
|
|
||||||
qDebug("Voxel parsing thread created.\n");
|
qDebug("Voxel parsing thread created.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,13 +560,6 @@ void Application::controlledBroadcastToNodes(unsigned char* broadcastData, size_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::sendVoxelServerAddScene() {
|
|
||||||
char message[100];
|
|
||||||
sprintf(message,"%c%s",'Z',"add scene");
|
|
||||||
int messageSize = strlen(message) + 1;
|
|
||||||
controlledBroadcastToNodes((unsigned char*)message, messageSize, & NODE_TYPE_VOXEL_SERVER, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::keyPressEvent(QKeyEvent* event) {
|
void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
if (activeWindow() == _window) {
|
if (activeWindow() == _window) {
|
||||||
if (_chatEntryOn) {
|
if (_chatEntryOn) {
|
||||||
|
@ -634,19 +625,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
_viewFrustumOffsetUp += 0.05;
|
_viewFrustumOffsetUp += 0.05;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Qt::Key_Ampersand:
|
|
||||||
_paintOn = !_paintOn;
|
|
||||||
setupPaintingVoxel();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Qt::Key_AsciiCircum:
|
|
||||||
shiftPaintingColor();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Qt::Key_Percent:
|
|
||||||
sendVoxelServerAddScene();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Qt::Key_Semicolon:
|
case Qt::Key_Semicolon:
|
||||||
_audio.ping();
|
_audio.ping();
|
||||||
break;
|
break;
|
||||||
|
@ -1186,10 +1164,8 @@ void Application::terminate() {
|
||||||
pthread_join(_networkReceiveThread, NULL);
|
pthread_join(_networkReceiveThread, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_enableProcessVoxelsThread) {
|
_voxelProcessor.terminate();
|
||||||
_stopProcessVoxelsThread = true;
|
_voxelEditSender.terminate();
|
||||||
pthread_join(_processVoxelsThread, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
|
void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
|
||||||
|
@ -1539,16 +1515,6 @@ void Application::updateVoxelModeActions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail& detail) {
|
|
||||||
unsigned char* bufferOut;
|
|
||||||
int sizeOut;
|
|
||||||
|
|
||||||
if (createVoxelEditMessage(type, 0, 1, &detail, bufferOut, sizeOut)){
|
|
||||||
Application::controlledBroadcastToNodes(bufferOut, sizeOut, & NODE_TYPE_VOXEL_SERVER, 1);
|
|
||||||
delete[] bufferOut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel) {
|
const glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel) {
|
||||||
return glm::vec3((_mouseVoxel.x + _mouseVoxel.s / 2.f) * TREE_SCALE,
|
return glm::vec3((_mouseVoxel.x + _mouseVoxel.s / 2.f) * TREE_SCALE,
|
||||||
(_mouseVoxel.y + _mouseVoxel.s / 2.f) * TREE_SCALE,
|
(_mouseVoxel.y + _mouseVoxel.s / 2.f) * TREE_SCALE,
|
||||||
|
@ -1587,11 +1553,6 @@ void Application::chooseVoxelPaintColor() {
|
||||||
const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500;
|
const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500;
|
||||||
struct SendVoxelsOperationArgs {
|
struct SendVoxelsOperationArgs {
|
||||||
unsigned char* newBaseOctCode;
|
unsigned char* newBaseOctCode;
|
||||||
unsigned char messageBuffer[MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE];
|
|
||||||
int bufferInUse;
|
|
||||||
uint64_t lastSendTime;
|
|
||||||
int packetsSent;
|
|
||||||
uint64_t bytesSent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
|
bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||||
|
@ -1623,37 +1584,10 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||||
codeColorBuffer[bytesInCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX];
|
codeColorBuffer[bytesInCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX];
|
||||||
codeColorBuffer[bytesInCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ];
|
codeColorBuffer[bytesInCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ];
|
||||||
|
|
||||||
// if we have room don't have room in the buffer, then send the previously generated message first
|
getInstance()->_voxelEditSender.queueVoxelEditMessage(PACKET_TYPE_SET_VOXEL_DESTRUCTIVE,
|
||||||
if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) {
|
codeColorBuffer, codeAndColorLength);
|
||||||
|
|
||||||
args->packetsSent++;
|
delete[] codeColorBuffer;
|
||||||
args->bytesSent += args->bufferInUse;
|
|
||||||
|
|
||||||
controlledBroadcastToNodes(args->messageBuffer, args->bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1);
|
|
||||||
args->bufferInUse = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_SET_VOXEL_DESTRUCTIVE)
|
|
||||||
+ sizeof(unsigned short int); // reset
|
|
||||||
|
|
||||||
uint64_t now = usecTimestampNow();
|
|
||||||
// dynamically sleep until we need to fire off the next set of voxels
|
|
||||||
uint64_t elapsed = now - args->lastSendTime;
|
|
||||||
int usecToSleep = CLIENT_TO_SERVER_VOXEL_SEND_INTERVAL_USECS - elapsed;
|
|
||||||
if (usecToSleep > 0) {
|
|
||||||
//qDebug("sendVoxelsOperation: packet: %d bytes:%lld elapsed %lld usecs, sleeping for %d usecs!\n",
|
|
||||||
// args->packetsSent, (long long int)args->bytesSent, (long long int)elapsed, usecToSleep);
|
|
||||||
|
|
||||||
Application::getInstance()->timer();
|
|
||||||
|
|
||||||
usleep(usecToSleep);
|
|
||||||
} else {
|
|
||||||
//qDebug("sendVoxelsOperation: packet: %d bytes:%lld elapsed %lld usecs, no need to sleep!\n",
|
|
||||||
// args->packetsSent, (long long int)args->bytesSent, (long long int)elapsed);
|
|
||||||
}
|
|
||||||
args->lastSendTime = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy this node's code color details into our buffer.
|
|
||||||
memcpy(&args->messageBuffer[args->bufferInUse], codeColorBuffer, codeAndColorLength);
|
|
||||||
args->bufferInUse += codeAndColorLength;
|
|
||||||
}
|
}
|
||||||
return true; // keep going
|
return true; // keep going
|
||||||
}
|
}
|
||||||
|
@ -1835,15 +1769,6 @@ void Application::importVoxels() {
|
||||||
// the server as an set voxel message, this will also rebase the voxels to the new location
|
// the server as an set voxel message, this will also rebase the voxels to the new location
|
||||||
unsigned char* calculatedOctCode = NULL;
|
unsigned char* calculatedOctCode = NULL;
|
||||||
SendVoxelsOperationArgs args;
|
SendVoxelsOperationArgs args;
|
||||||
args.lastSendTime = usecTimestampNow();
|
|
||||||
args.packetsSent = 0;
|
|
||||||
args.bytesSent = 0;
|
|
||||||
|
|
||||||
int numBytesPacketHeader = populateTypeAndVersion(args.messageBuffer, PACKET_TYPE_SET_VOXEL_DESTRUCTIVE);
|
|
||||||
|
|
||||||
unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[numBytesPacketHeader];
|
|
||||||
*sequenceAt = 0;
|
|
||||||
args.bufferInUse = numBytesPacketHeader + sizeof(unsigned short int); // set to command + sequence
|
|
||||||
|
|
||||||
// we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the
|
// we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the
|
||||||
// voxel size/position details.
|
// voxel size/position details.
|
||||||
|
@ -1857,30 +1782,7 @@ void Application::importVoxels() {
|
||||||
|
|
||||||
// send the insert/paste of these voxels
|
// send the insert/paste of these voxels
|
||||||
importVoxels.recurseTreeWithOperation(sendVoxelsOperation, &args);
|
importVoxels.recurseTreeWithOperation(sendVoxelsOperation, &args);
|
||||||
|
_voxelEditSender.flushQueue();
|
||||||
// If we have voxels left in the packet, then send the packet
|
|
||||||
if (args.bufferInUse > (numBytesPacketHeader + sizeof(unsigned short int))) {
|
|
||||||
controlledBroadcastToNodes(args.messageBuffer, args.bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1);
|
|
||||||
|
|
||||||
|
|
||||||
args.packetsSent++;
|
|
||||||
args.bytesSent += args.bufferInUse;
|
|
||||||
|
|
||||||
uint64_t now = usecTimestampNow();
|
|
||||||
// dynamically sleep until we need to fire off the next set of voxels
|
|
||||||
uint64_t elapsed = now - args.lastSendTime;
|
|
||||||
int usecToSleep = CLIENT_TO_SERVER_VOXEL_SEND_INTERVAL_USECS - elapsed;
|
|
||||||
|
|
||||||
if (usecToSleep > 0) {
|
|
||||||
//qDebug("after sendVoxelsOperation: packet: %d bytes:%lld elapsed %lld usecs, sleeping for %d usecs!\n",
|
|
||||||
// args.packetsSent, (long long int)args.bytesSent, (long long int)elapsed, usecToSleep);
|
|
||||||
usleep(usecToSleep);
|
|
||||||
} else {
|
|
||||||
//qDebug("after sendVoxelsOperation: packet: %d bytes:%lld elapsed %lld usecs, no need to sleep!\n",
|
|
||||||
// args.packetsSent, (long long int)args.bytesSent, (long long int)elapsed);
|
|
||||||
}
|
|
||||||
args.lastSendTime = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (calculatedOctCode) {
|
if (calculatedOctCode) {
|
||||||
delete[] calculatedOctCode;
|
delete[] calculatedOctCode;
|
||||||
|
@ -1915,15 +1817,6 @@ void Application::pasteVoxels() {
|
||||||
// Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to
|
// Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to
|
||||||
// the server as an set voxel message, this will also rebase the voxels to the new location
|
// the server as an set voxel message, this will also rebase the voxels to the new location
|
||||||
SendVoxelsOperationArgs args;
|
SendVoxelsOperationArgs args;
|
||||||
args.lastSendTime = usecTimestampNow();
|
|
||||||
args.packetsSent = 0;
|
|
||||||
args.bytesSent = 0;
|
|
||||||
|
|
||||||
int numBytesPacketHeader = populateTypeAndVersion(args.messageBuffer, PACKET_TYPE_SET_VOXEL_DESTRUCTIVE);
|
|
||||||
|
|
||||||
unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[numBytesPacketHeader];
|
|
||||||
*sequenceAt = 0;
|
|
||||||
args.bufferInUse = numBytesPacketHeader + sizeof(unsigned short int); // set to command + sequence
|
|
||||||
|
|
||||||
// we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the
|
// we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the
|
||||||
// voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a
|
// voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a
|
||||||
|
@ -1935,14 +1828,7 @@ void Application::pasteVoxels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_clipboardTree.recurseTreeWithOperation(sendVoxelsOperation, &args);
|
_clipboardTree.recurseTreeWithOperation(sendVoxelsOperation, &args);
|
||||||
|
_voxelEditSender.flushQueue();
|
||||||
// If we have voxels left in the packet, then send the packet
|
|
||||||
if (args.bufferInUse > (numBytesPacketHeader + sizeof(unsigned short int))) {
|
|
||||||
controlledBroadcastToNodes(args.messageBuffer, args.bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1);
|
|
||||||
qDebug("sending packet: %d\n", ++args.packetsSent);
|
|
||||||
args.bytesSent += args.bufferInUse;
|
|
||||||
qDebug("total bytes sent: %lld\n", (long long int)args.bytesSent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (calculatedOctCode) {
|
if (calculatedOctCode) {
|
||||||
delete[] calculatedOctCode;
|
delete[] calculatedOctCode;
|
||||||
|
@ -2011,6 +1897,7 @@ void Application::initMenu() {
|
||||||
_renderAvatarBalls->setChecked(false);
|
_renderAvatarBalls->setChecked(false);
|
||||||
renderMenu->addAction("Cycle Voxel Mode", _myAvatar.getVoxels(), SLOT(cycleMode()));
|
renderMenu->addAction("Cycle Voxel Mode", _myAvatar.getVoxels(), SLOT(cycleMode()));
|
||||||
renderMenu->addAction("Cycle Face Mode", &_myAvatar.getHead().getFace(), SLOT(cycleRenderMode()));
|
renderMenu->addAction("Cycle Face Mode", &_myAvatar.getHead().getFace(), SLOT(cycleRenderMode()));
|
||||||
|
renderMenu->addAction("Cycle Glow Mode", &_glowEffect, SLOT(cycleRenderMode()));
|
||||||
(_renderFrameTimerOn = renderMenu->addAction("Show Timer"))->setCheckable(true);
|
(_renderFrameTimerOn = renderMenu->addAction("Show Timer"))->setCheckable(true);
|
||||||
_renderFrameTimerOn->setChecked(false);
|
_renderFrameTimerOn->setChecked(false);
|
||||||
(_renderLookatOn = renderMenu->addAction("Lookat Vectors"))->setCheckable(true);
|
(_renderLookatOn = renderMenu->addAction("Lookat Vectors"))->setCheckable(true);
|
||||||
|
@ -2605,7 +2492,8 @@ void Application::update(float deltaTime) {
|
||||||
|
|
||||||
// parse voxel packets
|
// parse voxel packets
|
||||||
if (!_enableProcessVoxelsThread) {
|
if (!_enableProcessVoxelsThread) {
|
||||||
processVoxels(0);
|
_voxelProcessor.threadRoutine();
|
||||||
|
_voxelEditSender.threadRoutine();
|
||||||
}
|
}
|
||||||
|
|
||||||
//loop through all the other avatars and simulate them...
|
//loop through all the other avatars and simulate them...
|
||||||
|
@ -2789,26 +2677,6 @@ void Application::updateAvatar(float deltaTime) {
|
||||||
sendAvatarVoxelURLMessage(_myAvatar.getVoxels()->getVoxelURL());
|
sendAvatarVoxelURLMessage(_myAvatar.getVoxels()->getVoxelURL());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If I'm in paint mode, send a voxel out to VOXEL server nodes.
|
|
||||||
if (_paintOn) {
|
|
||||||
|
|
||||||
glm::vec3 avatarPos = _myAvatar.getPosition();
|
|
||||||
|
|
||||||
// For some reason, we don't want to flip X and Z here.
|
|
||||||
_paintingVoxel.x = avatarPos.x / 10.0;
|
|
||||||
_paintingVoxel.y = avatarPos.y / 10.0;
|
|
||||||
_paintingVoxel.z = avatarPos.z / 10.0;
|
|
||||||
|
|
||||||
if (_paintingVoxel.x >= 0.0 && _paintingVoxel.x <= 1.0 &&
|
|
||||||
_paintingVoxel.y >= 0.0 && _paintingVoxel.y <= 1.0 &&
|
|
||||||
_paintingVoxel.z >= 0.0 && _paintingVoxel.z <= 1.0) {
|
|
||||||
|
|
||||||
PACKET_TYPE message = (_destructiveAddVoxel->isChecked() ?
|
|
||||||
PACKET_TYPE_SET_VOXEL_DESTRUCTIVE : PACKET_TYPE_SET_VOXEL);
|
|
||||||
sendVoxelEditMessage(message, _paintingVoxel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -3305,15 +3173,6 @@ void Application::displayOverlay() {
|
||||||
sprintf(nodes, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars);
|
sprintf(nodes, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars);
|
||||||
drawtext(_glWidget->width() - 150, 20, 0.10, 0, 1.0, 0, nodes, 1, 0, 0);
|
drawtext(_glWidget->width() - 150, 20, 0.10, 0, 1.0, 0, nodes, 1, 0, 0);
|
||||||
|
|
||||||
if (_paintOn) {
|
|
||||||
|
|
||||||
char paintMessage[100];
|
|
||||||
sprintf(paintMessage,"Painting (%.3f,%.3f,%.3f/%.3f/%d,%d,%d)",
|
|
||||||
_paintingVoxel.x, _paintingVoxel.y, _paintingVoxel.z, _paintingVoxel.s,
|
|
||||||
(unsigned int)_paintingVoxel.red, (unsigned int)_paintingVoxel.green, (unsigned int)_paintingVoxel.blue);
|
|
||||||
drawtext(_glWidget->width() - 350, 50, 0.10, 0, 1.0, 0, paintMessage, 1, 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render the webcam input frame
|
// render the webcam input frame
|
||||||
_webcam.renderPreview(_glWidget->width(), _glWidget->height());
|
_webcam.renderPreview(_glWidget->width(), _glWidget->height());
|
||||||
|
|
||||||
|
@ -3771,26 +3630,6 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setupPaintingVoxel() {
|
|
||||||
glm::vec3 avatarPos = _myAvatar.getPosition();
|
|
||||||
|
|
||||||
_paintingVoxel.x = avatarPos.z/-10.0; // voxel space x is negative z head space
|
|
||||||
_paintingVoxel.y = avatarPos.y/-10.0; // voxel space y is negative y head space
|
|
||||||
_paintingVoxel.z = avatarPos.x/-10.0; // voxel space z is negative x head space
|
|
||||||
_paintingVoxel.s = 1.0/256;
|
|
||||||
|
|
||||||
shiftPaintingColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::shiftPaintingColor() {
|
|
||||||
// About the color of the paintbrush... first determine the dominant color
|
|
||||||
_dominantColor = (_dominantColor + 1) % 3; // 0=red,1=green,2=blue
|
|
||||||
_paintingVoxel.red = (_dominantColor == 0) ? randIntInRange(200, 255) : randIntInRange(40, 100);
|
|
||||||
_paintingVoxel.green = (_dominantColor == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100);
|
|
||||||
_paintingVoxel.blue = (_dominantColor == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Application::injectVoxelAddedSoundEffect() {
|
void Application::injectVoxelAddedSoundEffect() {
|
||||||
AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(11025);
|
AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(11025);
|
||||||
|
|
||||||
|
@ -3852,7 +3691,7 @@ bool Application::maybeEditVoxelUnderCursor() {
|
||||||
if (_mouseVoxel.s != 0) {
|
if (_mouseVoxel.s != 0) {
|
||||||
PACKET_TYPE message = (_destructiveAddVoxel->isChecked() ?
|
PACKET_TYPE message = (_destructiveAddVoxel->isChecked() ?
|
||||||
PACKET_TYPE_SET_VOXEL_DESTRUCTIVE : PACKET_TYPE_SET_VOXEL);
|
PACKET_TYPE_SET_VOXEL_DESTRUCTIVE : PACKET_TYPE_SET_VOXEL);
|
||||||
sendVoxelEditMessage(message, _mouseVoxel);
|
_voxelEditSender.sendVoxelEditMessage(message, _mouseVoxel);
|
||||||
|
|
||||||
// create the voxel locally so it appears immediately
|
// create the voxel locally so it appears immediately
|
||||||
_voxels.createVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s,
|
_voxels.createVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s,
|
||||||
|
@ -3898,7 +3737,7 @@ bool Application::maybeEditVoxelUnderCursor() {
|
||||||
void Application::deleteVoxelUnderCursor() {
|
void Application::deleteVoxelUnderCursor() {
|
||||||
if (_mouseVoxel.s != 0) {
|
if (_mouseVoxel.s != 0) {
|
||||||
// sending delete to the server is sufficient, server will send new version so we see updates soon enough
|
// sending delete to the server is sufficient, server will send new version so we see updates soon enough
|
||||||
sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, _mouseVoxel);
|
_voxelEditSender.sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, _mouseVoxel);
|
||||||
AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(5000);
|
AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(5000);
|
||||||
|
|
||||||
if (voxelInjector) {
|
if (voxelInjector) {
|
||||||
|
@ -4018,15 +3857,16 @@ void Application::nodeKilled(Node* node) {
|
||||||
uint16_t nodeID = node->getNodeID();
|
uint16_t nodeID = node->getNodeID();
|
||||||
// see if this is the first we've heard of this node...
|
// see if this is the first we've heard of this node...
|
||||||
if (_voxelServerJurisdictions.find(nodeID) != _voxelServerJurisdictions.end()) {
|
if (_voxelServerJurisdictions.find(nodeID) != _voxelServerJurisdictions.end()) {
|
||||||
VoxelPositionSize jurisditionDetails;
|
unsigned char* rootCode = _voxelServerJurisdictions[nodeID].getRootOctalCode();
|
||||||
jurisditionDetails = _voxelServerJurisdictions[nodeID];
|
VoxelPositionSize rootDetails;
|
||||||
|
voxelDetailsForCode(rootCode, rootDetails);
|
||||||
|
|
||||||
printf("voxel server going away...... v[%f, %f, %f, %f]\n",
|
printf("voxel server going away...... v[%f, %f, %f, %f]\n",
|
||||||
jurisditionDetails.x, jurisditionDetails.y, jurisditionDetails.z, jurisditionDetails.s);
|
rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
|
||||||
|
|
||||||
// Add the jurisditionDetails object to the list of "fade outs"
|
// Add the jurisditionDetails object to the list of "fade outs"
|
||||||
VoxelFade fade(VoxelFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE);
|
VoxelFade fade(VoxelFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE);
|
||||||
fade.voxelDetails = jurisditionDetails;
|
fade.voxelDetails = rootDetails;
|
||||||
const float slightly_smaller = 0.99;
|
const float slightly_smaller = 0.99;
|
||||||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||||
_voxelFades.push_back(fade);
|
_voxelFades.push_back(fade);
|
||||||
|
@ -4047,100 +3887,32 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng
|
||||||
if (voxelServer) {
|
if (voxelServer) {
|
||||||
uint16_t nodeID = voxelServer->getNodeID();
|
uint16_t nodeID = voxelServer->getNodeID();
|
||||||
|
|
||||||
VoxelPositionSize jurisditionDetails;
|
VoxelPositionSize rootDetails;
|
||||||
voxelDetailsForCode(_voxelSceneStats.getJurisdictionRoot(), jurisditionDetails);
|
voxelDetailsForCode(_voxelSceneStats.getJurisdictionRoot(), rootDetails);
|
||||||
|
|
||||||
// see if this is the first we've heard of this node...
|
// see if this is the first we've heard of this node...
|
||||||
if (_voxelServerJurisdictions.find(nodeID) == _voxelServerJurisdictions.end()) {
|
if (_voxelServerJurisdictions.find(nodeID) == _voxelServerJurisdictions.end()) {
|
||||||
printf("stats from new voxel server... v[%f, %f, %f, %f]\n",
|
printf("stats from new voxel server... v[%f, %f, %f, %f]\n",
|
||||||
jurisditionDetails.x, jurisditionDetails.y, jurisditionDetails.z, jurisditionDetails.s);
|
rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
|
||||||
|
|
||||||
// Add the jurisditionDetails object to the list of "fade outs"
|
// Add the jurisditionDetails object to the list of "fade outs"
|
||||||
VoxelFade fade(VoxelFade::FADE_OUT, NODE_ADDED_RED, NODE_ADDED_GREEN, NODE_ADDED_BLUE);
|
VoxelFade fade(VoxelFade::FADE_OUT, NODE_ADDED_RED, NODE_ADDED_GREEN, NODE_ADDED_BLUE);
|
||||||
fade.voxelDetails = jurisditionDetails;
|
fade.voxelDetails = rootDetails;
|
||||||
const float slightly_smaller = 0.99;
|
const float slightly_smaller = 0.99;
|
||||||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||||
_voxelFades.push_back(fade);
|
_voxelFades.push_back(fade);
|
||||||
}
|
}
|
||||||
// store jurisdiction details for later use
|
// store jurisdiction details for later use
|
||||||
_voxelServerJurisdictions[nodeID] = jurisditionDetails;
|
// This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it
|
||||||
|
// but VoxelSceneStats thinks it's just returning a reference to it's contents. So we need to make a copy of the
|
||||||
|
// details from the VoxelSceneStats to construct the JurisdictionMap
|
||||||
|
JurisdictionMap jurisdictionMap;
|
||||||
|
jurisdictionMap.copyContents(_voxelSceneStats.getJurisdictionRoot(), _voxelSceneStats.getJurisdictionEndNodes());
|
||||||
|
_voxelServerJurisdictions[nodeID] = jurisdictionMap;
|
||||||
}
|
}
|
||||||
return statsMessageLength;
|
return statsMessageLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive packets from other nodes/servers and decide what to do with them!
|
|
||||||
void* Application::processVoxels(void* args) {
|
|
||||||
Application* app = Application::getInstance();
|
|
||||||
while (!app->_stopProcessVoxelsThread) {
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
app->_voxelPacketMutex.lock();
|
|
||||||
while (app->_voxelPackets.size() > 0) {
|
|
||||||
NetworkPacket& packet = app->_voxelPackets.front();
|
|
||||||
app->processVoxelPacket(packet.getSenderAddress(), packet.getData(), packet.getLength());
|
|
||||||
app->_voxelPackets.erase(app->_voxelPackets.begin());
|
|
||||||
}
|
|
||||||
app->_voxelPacketMutex.unlock();
|
|
||||||
|
|
||||||
if (!app->_enableProcessVoxelsThread) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app->_enableProcessVoxelsThread) {
|
|
||||||
pthread_exit(0);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::queueVoxelPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
|
||||||
_voxelPacketMutex.lock();
|
|
||||||
_voxelPackets.push_back(NetworkPacket(senderAddress, packetData, packetLength));
|
|
||||||
_voxelPacketMutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::processVoxelPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
|
||||||
PerformanceWarning warn(_renderPipelineWarnings->isChecked(),"processVoxelPacket()");
|
|
||||||
ssize_t messageLength = packetLength;
|
|
||||||
|
|
||||||
// note: PACKET_TYPE_VOXEL_STATS can have PACKET_TYPE_VOXEL_DATA or PACKET_TYPE_VOXEL_DATA_MONOCHROME
|
|
||||||
// immediately following them inside the same packet. So, we process the PACKET_TYPE_VOXEL_STATS first
|
|
||||||
// then process any remaining bytes as if it was another packet
|
|
||||||
if (packetData[0] == PACKET_TYPE_VOXEL_STATS) {
|
|
||||||
|
|
||||||
int statsMessageLength = parseVoxelStats(packetData, messageLength, senderAddress);
|
|
||||||
if (messageLength > statsMessageLength) {
|
|
||||||
packetData += statsMessageLength;
|
|
||||||
messageLength -= statsMessageLength;
|
|
||||||
if (!packetVersionMatch(packetData)) {
|
|
||||||
return; // bail since piggyback data doesn't match our versioning
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return; // bail since no piggyback data
|
|
||||||
}
|
|
||||||
} // fall through to piggyback message
|
|
||||||
|
|
||||||
if (_renderVoxels->isChecked()) {
|
|
||||||
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
|
||||||
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
|
|
||||||
voxelServer->lock();
|
|
||||||
if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
|
|
||||||
_environment.parseData(&senderAddress, packetData, messageLength);
|
|
||||||
} else {
|
|
||||||
_voxels.setDataSourceID(voxelServer->getNodeID());
|
|
||||||
_voxels.parseData(packetData, messageLength);
|
|
||||||
_voxels.setDataSourceID(UNKNOWN_NODE_ID);
|
|
||||||
}
|
|
||||||
voxelServer->unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive packets from other nodes/servers and decide what to do with them!
|
// Receive packets from other nodes/servers and decide what to do with them!
|
||||||
void* Application::networkReceive(void* args) {
|
void* Application::networkReceive(void* args) {
|
||||||
sockaddr senderAddress;
|
sockaddr senderAddress;
|
||||||
|
@ -4148,12 +3920,6 @@ void* Application::networkReceive(void* args) {
|
||||||
|
|
||||||
Application* app = Application::getInstance();
|
Application* app = Application::getInstance();
|
||||||
while (!app->_stopNetworkReceiveThread) {
|
while (!app->_stopNetworkReceiveThread) {
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NodeList::getInstance()->getNodeSocket()->receive(&senderAddress, app->_incomingPacket, &bytesReceived)) {
|
if (NodeList::getInstance()->getNodeSocket()->receive(&senderAddress, app->_incomingPacket, &bytesReceived)) {
|
||||||
|
|
||||||
app->_packetCount++;
|
app->_packetCount++;
|
||||||
|
@ -4177,7 +3943,7 @@ void* Application::networkReceive(void* args) {
|
||||||
case PACKET_TYPE_VOXEL_STATS:
|
case PACKET_TYPE_VOXEL_STATS:
|
||||||
case PACKET_TYPE_ENVIRONMENT_DATA: {
|
case PACKET_TYPE_ENVIRONMENT_DATA: {
|
||||||
// add this packet to our list of voxel packets and process them on the voxel processing
|
// add this packet to our list of voxel packets and process them on the voxel processing
|
||||||
app->queueVoxelPacket(senderAddress, app->_incomingPacket, bytesReceived);
|
app->_voxelProcessor.queuePacket(senderAddress, app->_incomingPacket, bytesReceived);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PACKET_TYPE_BULK_AVATAR_DATA:
|
case PACKET_TYPE_BULK_AVATAR_DATA:
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#include "ToolsPalette.h"
|
#include "ToolsPalette.h"
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
#include "VoxelFade.h"
|
#include "VoxelFade.h"
|
||||||
|
#include "VoxelEditPacketSender.h"
|
||||||
|
#include "VoxelPacketProcessor.h"
|
||||||
#include "VoxelSystem.h"
|
#include "VoxelSystem.h"
|
||||||
#include "Webcam.h"
|
#include "Webcam.h"
|
||||||
#include "avatar/Avatar.h"
|
#include "avatar/Avatar.h"
|
||||||
|
@ -74,6 +76,9 @@ static const float NODE_KILLED_BLUE = 0.0f;
|
||||||
class Application : public QApplication, public NodeListHook {
|
class Application : public QApplication, public NodeListHook {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
friend class VoxelPacketProcessor;
|
||||||
|
friend class VoxelEditPacketSender;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Application* getInstance() { return static_cast<Application*>(QCoreApplication::instance()); }
|
static Application* getInstance() { return static_cast<Application*>(QCoreApplication::instance()); }
|
||||||
|
|
||||||
|
@ -219,9 +224,7 @@ private:
|
||||||
static void controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes,
|
static void controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes,
|
||||||
const char* nodeTypes, int numNodeTypes);
|
const char* nodeTypes, int numNodeTypes);
|
||||||
|
|
||||||
static void sendVoxelServerAddScene();
|
|
||||||
static bool sendVoxelsOperation(VoxelNode* node, void* extraData);
|
static bool sendVoxelsOperation(VoxelNode* node, void* extraData);
|
||||||
static void sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail& detail);
|
|
||||||
static void sendAvatarVoxelURLMessage(const QUrl& url);
|
static void sendAvatarVoxelURLMessage(const QUrl& url);
|
||||||
static void processAvatarVoxelURLMessage(unsigned char* packetData, size_t dataBytes);
|
static void processAvatarVoxelURLMessage(unsigned char* packetData, size_t dataBytes);
|
||||||
static void processAvatarFaceVideoMessage(unsigned char* packetData, size_t dataBytes);
|
static void processAvatarFaceVideoMessage(unsigned char* packetData, size_t dataBytes);
|
||||||
|
@ -250,8 +253,6 @@ private:
|
||||||
|
|
||||||
void checkBandwidthMeterClick();
|
void checkBandwidthMeterClick();
|
||||||
|
|
||||||
void setupPaintingVoxel();
|
|
||||||
void shiftPaintingColor();
|
|
||||||
bool maybeEditVoxelUnderCursor();
|
bool maybeEditVoxelUnderCursor();
|
||||||
void deleteVoxelUnderCursor();
|
void deleteVoxelUnderCursor();
|
||||||
void eyedropperVoxelUnderCursor();
|
void eyedropperVoxelUnderCursor();
|
||||||
|
@ -267,10 +268,6 @@ private:
|
||||||
static void attachNewHeadToNode(Node *newNode);
|
static void attachNewHeadToNode(Node *newNode);
|
||||||
static void* networkReceive(void* args); // network receive thread
|
static void* networkReceive(void* args); // network receive thread
|
||||||
|
|
||||||
static void* processVoxels(void* args); // voxel parsing thread
|
|
||||||
void processVoxelPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
|
|
||||||
void queueVoxelPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
|
|
||||||
|
|
||||||
// methodes handling menu settings
|
// methodes handling menu settings
|
||||||
typedef void(*settingsAction)(QSettings*, QAction*);
|
typedef void(*settingsAction)(QSettings*, QAction*);
|
||||||
static void loadAction(QSettings* set, QAction* action);
|
static void loadAction(QSettings* set, QAction* action);
|
||||||
|
@ -428,10 +425,6 @@ private:
|
||||||
glm::vec3 _lookatOtherPosition;
|
glm::vec3 _lookatOtherPosition;
|
||||||
float _lookatIndicatorScale;
|
float _lookatIndicatorScale;
|
||||||
|
|
||||||
bool _paintOn; // Whether to paint voxels as you fly around
|
|
||||||
unsigned char _dominantColor; // The dominant color of the voxel we're painting
|
|
||||||
VoxelDetail _paintingVoxel; // The voxel we're painting if we're painting
|
|
||||||
|
|
||||||
bool _perfStatsOn; // Do we want to display perfStats?
|
bool _perfStatsOn; // Do we want to display perfStats?
|
||||||
|
|
||||||
ChatEntry _chatEntry; // chat entry field
|
ChatEntry _chatEntry; // chat entry field
|
||||||
|
@ -463,10 +456,8 @@ private:
|
||||||
bool _stopNetworkReceiveThread;
|
bool _stopNetworkReceiveThread;
|
||||||
|
|
||||||
bool _enableProcessVoxelsThread;
|
bool _enableProcessVoxelsThread;
|
||||||
pthread_t _processVoxelsThread;
|
VoxelPacketProcessor _voxelProcessor;
|
||||||
bool _stopProcessVoxelsThread;
|
VoxelEditPacketSender _voxelEditSender;
|
||||||
std::vector<NetworkPacket> _voxelPackets;
|
|
||||||
QMutex _voxelPacketMutex;
|
|
||||||
|
|
||||||
unsigned char _incomingPacket[MAX_PACKET_SIZE];
|
unsigned char _incomingPacket[MAX_PACKET_SIZE];
|
||||||
int _packetCount;
|
int _packetCount;
|
||||||
|
@ -485,7 +476,7 @@ private:
|
||||||
VoxelSceneStats _voxelSceneStats;
|
VoxelSceneStats _voxelSceneStats;
|
||||||
int parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress);
|
int parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress);
|
||||||
|
|
||||||
std::map<uint16_t,VoxelPositionSize> _voxelServerJurisdictions;
|
std::map<uint16_t, JurisdictionMap> _voxelServerJurisdictions;
|
||||||
|
|
||||||
std::vector<VoxelFade> _voxelFades;
|
std::vector<VoxelFade> _voxelFades;
|
||||||
};
|
};
|
||||||
|
|
108
interface/src/VoxelEditPacketSender.cpp
Normal file
108
interface/src/VoxelEditPacketSender.cpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
//
|
||||||
|
// VoxelEditPacketSender.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Threaded or non-threaded voxel packet Sender for the Application
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <PerfStat.h>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "VoxelEditPacketSender.h"
|
||||||
|
|
||||||
|
VoxelEditPacketSender::VoxelEditPacketSender(Application* app) :
|
||||||
|
_app(app)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelEditPacketSender::sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail& detail) {
|
||||||
|
|
||||||
|
// if the app has Voxels disabled, we don't do any of this...
|
||||||
|
if (!_app->_renderVoxels->isChecked()) {
|
||||||
|
return; // bail early
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* bufferOut;
|
||||||
|
int sizeOut;
|
||||||
|
int totalBytesSent = 0;
|
||||||
|
|
||||||
|
if (createVoxelEditMessage(type, 0, 1, &detail, bufferOut, sizeOut)){
|
||||||
|
actuallySendMessage(UNKNOWN_NODE_ID, bufferOut, sizeOut); // sends to all servers... not ideal!
|
||||||
|
delete[] bufferOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the application's bandwidth meters about what we've sent
|
||||||
|
_app->_bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(totalBytesSent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelEditPacketSender::actuallySendMessage(uint16_t nodeID, unsigned char* bufferOut, ssize_t sizeOut) {
|
||||||
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
|
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
||||||
|
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER &&
|
||||||
|
((node->getNodeID() == nodeID) || (nodeID == (uint16_t)UNKNOWN_NODE_ID)) ) {
|
||||||
|
sockaddr* nodeAddress = node->getActiveSocket();
|
||||||
|
queuePacket(*nodeAddress, bufferOut, sizeOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelEditPacketSender::queueVoxelEditMessage(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length) {
|
||||||
|
// We want to filter out edit messages for voxel servers based on the server's Jurisdiction
|
||||||
|
// But we can't really do that with a packed message, since each edit message could be destined
|
||||||
|
// for a different voxel server... So we need to actually manage multiple queued packets... one
|
||||||
|
// for each voxel server
|
||||||
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
|
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
||||||
|
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
|
|
||||||
|
// we need to get the jurisdiction for this
|
||||||
|
// here we need to get the "pending packet" for this server
|
||||||
|
uint16_t nodeID = node->getNodeID();
|
||||||
|
const JurisdictionMap& map = _app->_voxelServerJurisdictions[nodeID];
|
||||||
|
if (map.isMyJurisdiction(codeColorBuffer, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN) {
|
||||||
|
EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeID];
|
||||||
|
packetBuffer._nodeID = nodeID;
|
||||||
|
|
||||||
|
// If we're switching type, then we send the last one and start over
|
||||||
|
if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) ||
|
||||||
|
(packetBuffer._currentSize + length >= MAX_PACKET_SIZE)) {
|
||||||
|
flushQueue(packetBuffer);
|
||||||
|
initializePacket(packetBuffer, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the buffer is empty and not correctly initialized for our type...
|
||||||
|
if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) {
|
||||||
|
initializePacket(packetBuffer, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], codeColorBuffer, length);
|
||||||
|
packetBuffer._currentSize += length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelEditPacketSender::flushQueue() {
|
||||||
|
for (std::map<uint16_t,EditPacketBuffer>::iterator i = _pendingEditPackets.begin(); i != _pendingEditPackets.end(); i++) {
|
||||||
|
flushQueue(i->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelEditPacketSender::flushQueue(EditPacketBuffer& packetBuffer) {
|
||||||
|
actuallySendMessage(packetBuffer._nodeID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize);
|
||||||
|
packetBuffer._currentSize = 0;
|
||||||
|
packetBuffer._currentType = PACKET_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelEditPacketSender::initializePacket(EditPacketBuffer& packetBuffer, PACKET_TYPE type) {
|
||||||
|
packetBuffer._currentSize = populateTypeAndVersion(&packetBuffer._currentBuffer[0], type);
|
||||||
|
unsigned short int* sequenceAt = (unsigned short int*)&packetBuffer._currentBuffer[packetBuffer._currentSize];
|
||||||
|
*sequenceAt = 0;
|
||||||
|
packetBuffer._currentSize += sizeof(unsigned short int); // set to command + sequence
|
||||||
|
packetBuffer._currentType = type;
|
||||||
|
}
|
52
interface/src/VoxelEditPacketSender.h
Normal file
52
interface/src/VoxelEditPacketSender.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
//
|
||||||
|
// VoxelEditPacketSender.h
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Voxel Packet Sender
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __shared__VoxelEditPacketSender__
|
||||||
|
#define __shared__VoxelEditPacketSender__
|
||||||
|
|
||||||
|
#include <PacketSender.h>
|
||||||
|
#include <SharedUtil.h> // for VoxelDetail
|
||||||
|
|
||||||
|
class Application;
|
||||||
|
|
||||||
|
/// Used for construction of edit voxel packets
|
||||||
|
class EditPacketBuffer {
|
||||||
|
public:
|
||||||
|
EditPacketBuffer() { _currentSize = 0; _currentType = PACKET_TYPE_UNKNOWN; _nodeID = UNKNOWN_NODE_ID; }
|
||||||
|
uint16_t _nodeID;
|
||||||
|
PACKET_TYPE _currentType;
|
||||||
|
unsigned char _currentBuffer[MAX_PACKET_SIZE];
|
||||||
|
ssize_t _currentSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Threaded processor for queueing and sending of outbound edit voxel packets.
|
||||||
|
class VoxelEditPacketSender : public PacketSender {
|
||||||
|
public:
|
||||||
|
VoxelEditPacketSender(Application* app);
|
||||||
|
|
||||||
|
/// Send voxel edit message immediately
|
||||||
|
void sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail& detail);
|
||||||
|
|
||||||
|
/// Queues a voxel edit message. Will potentially sends a pending multi-command packet. Determines which voxel-server
|
||||||
|
/// node or nodes the packet should be sent to.
|
||||||
|
void queueVoxelEditMessage(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length);
|
||||||
|
|
||||||
|
/// flushes all queued packets for all nodes
|
||||||
|
void flushQueue();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void actuallySendMessage(uint16_t nodeID, unsigned char* bufferOut, ssize_t sizeOut);
|
||||||
|
void initializePacket(EditPacketBuffer& packetBuffer, PACKET_TYPE type);
|
||||||
|
void flushQueue(EditPacketBuffer& packetBuffer); // flushes specific queued packet
|
||||||
|
|
||||||
|
Application* _app;
|
||||||
|
std::map<uint16_t,EditPacketBuffer> _pendingEditPackets;
|
||||||
|
};
|
||||||
|
#endif // __shared__VoxelEditPacketSender__
|
62
interface/src/VoxelPacketProcessor.cpp
Normal file
62
interface/src/VoxelPacketProcessor.cpp
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
//
|
||||||
|
// VoxelPacketProcessor.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Threaded or non-threaded voxel packet receiver for the Application
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <PerfStat.h>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "VoxelPacketProcessor.h"
|
||||||
|
|
||||||
|
VoxelPacketProcessor::VoxelPacketProcessor(Application* app) :
|
||||||
|
_app(app) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
||||||
|
PerformanceWarning warn(_app->_renderPipelineWarnings->isChecked(),"VoxelPacketProcessor::processPacket()");
|
||||||
|
ssize_t messageLength = packetLength;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: PACKET_TYPE_VOXEL_STATS can have PACKET_TYPE_VOXEL_DATA or PACKET_TYPE_VOXEL_DATA_MONOCHROME
|
||||||
|
// immediately following them inside the same packet. So, we process the PACKET_TYPE_VOXEL_STATS first
|
||||||
|
// then process any remaining bytes as if it was another packet
|
||||||
|
if (packetData[0] == PACKET_TYPE_VOXEL_STATS) {
|
||||||
|
|
||||||
|
int statsMessageLength = _app->parseVoxelStats(packetData, messageLength, senderAddress);
|
||||||
|
if (messageLength > statsMessageLength) {
|
||||||
|
packetData += statsMessageLength;
|
||||||
|
messageLength -= statsMessageLength;
|
||||||
|
if (!packetVersionMatch(packetData)) {
|
||||||
|
return; // bail since piggyback data doesn't match our versioning
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return; // bail since no piggyback data
|
||||||
|
}
|
||||||
|
} // fall through to piggyback message
|
||||||
|
|
||||||
|
if (_app->_renderVoxels->isChecked()) {
|
||||||
|
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
||||||
|
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
|
||||||
|
voxelServer->lock();
|
||||||
|
if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
|
||||||
|
_app->_environment.parseData(&senderAddress, packetData, messageLength);
|
||||||
|
} else {
|
||||||
|
_app->_voxels.setDataSourceID(voxelServer->getNodeID());
|
||||||
|
_app->_voxels.parseData(packetData, messageLength);
|
||||||
|
_app->_voxels.setDataSourceID(UNKNOWN_NODE_ID);
|
||||||
|
}
|
||||||
|
voxelServer->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
29
interface/src/VoxelPacketProcessor.h
Normal file
29
interface/src/VoxelPacketProcessor.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// VoxelPacketProcessor.h
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Voxel Packet Receiver
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __shared__VoxelPacketProcessor__
|
||||||
|
#define __shared__VoxelPacketProcessor__
|
||||||
|
|
||||||
|
#include <ReceivedPacketProcessor.h>
|
||||||
|
|
||||||
|
class Application;
|
||||||
|
|
||||||
|
/// Handles processing of incoming voxel packets for the interface application.
|
||||||
|
class VoxelPacketProcessor : public ReceivedPacketProcessor {
|
||||||
|
public:
|
||||||
|
VoxelPacketProcessor(Application* app);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Application* _app;
|
||||||
|
};
|
||||||
|
#endif // __shared__VoxelPacketProcessor__
|
|
@ -14,9 +14,12 @@
|
||||||
#include "GlowEffect.h"
|
#include "GlowEffect.h"
|
||||||
#include "ProgramObject.h"
|
#include "ProgramObject.h"
|
||||||
|
|
||||||
static ProgramObject* createBlurProgram(const QString& direction) {
|
GlowEffect::GlowEffect() : _renderMode(BLUR_ADD_MODE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static ProgramObject* createProgram(const QString& name) {
|
||||||
ProgramObject* program = new ProgramObject();
|
ProgramObject* program = new ProgramObject();
|
||||||
program->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/" + direction + "_blur.frag");
|
program->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/" + name + ".frag");
|
||||||
program->link();
|
program->link();
|
||||||
|
|
||||||
program->bind();
|
program->bind();
|
||||||
|
@ -28,12 +31,25 @@ static ProgramObject* createBlurProgram(const QString& direction) {
|
||||||
|
|
||||||
void GlowEffect::init() {
|
void GlowEffect::init() {
|
||||||
switchToResourcesParentIfRequired();
|
switchToResourcesParentIfRequired();
|
||||||
_horizontalBlurProgram = createBlurProgram("horizontal");
|
|
||||||
_verticalBlurProgram = createBlurProgram("vertical");
|
|
||||||
|
|
||||||
_verticalBlurProgram->bind();
|
_addProgram = createProgram("glow_add");
|
||||||
_verticalBlurProgram->setUniformValue("horizontallyBlurredTexture", 1);
|
_horizontalBlurProgram = createProgram("horizontal_blur");
|
||||||
_verticalBlurProgram->release();
|
_verticalBlurAddProgram = createProgram("vertical_blur_add");
|
||||||
|
_verticalBlurProgram = createProgram("vertical_blur");
|
||||||
|
_addSeparateProgram = createProgram("glow_add_separate");
|
||||||
|
_diffuseProgram = createProgram("diffuse");
|
||||||
|
|
||||||
|
_verticalBlurAddProgram->bind();
|
||||||
|
_verticalBlurAddProgram->setUniformValue("horizontallyBlurredTexture", 1);
|
||||||
|
_verticalBlurAddProgram->release();
|
||||||
|
|
||||||
|
_addSeparateProgram->bind();
|
||||||
|
_addSeparateProgram->setUniformValue("blurredTexture", 1);
|
||||||
|
_addSeparateProgram->release();
|
||||||
|
|
||||||
|
_diffuseProgram->bind();
|
||||||
|
_diffuseProgram->setUniformValue("diffusedTexture", 1);
|
||||||
|
_diffuseProgram->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlowEffect::prepare() {
|
void GlowEffect::prepare() {
|
||||||
|
@ -43,8 +59,8 @@ void GlowEffect::prepare() {
|
||||||
_isEmpty = true;
|
_isEmpty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlowEffect::begin(float amount) {
|
void GlowEffect::begin(float intensity) {
|
||||||
glBlendColor(0.0f, 0.0f, 0.0f, amount);
|
glBlendColor(0.0f, 0.0f, 0.0f, intensity);
|
||||||
_isEmpty = false;
|
_isEmpty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +109,42 @@ void GlowEffect::render() {
|
||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
glEnable(GL_LIGHTING);
|
glEnable(GL_LIGHTING);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (_renderMode == ADD_MODE) {
|
||||||
|
_addProgram->bind();
|
||||||
|
renderFullscreenQuad();
|
||||||
|
_addProgram->release();
|
||||||
|
|
||||||
|
} else if (_renderMode == DIFFUSE_ADD_MODE) {
|
||||||
|
// diffuse into the secondary/tertiary (alternating between frames)
|
||||||
|
QOpenGLFramebufferObject* oldDiffusedFBO =
|
||||||
|
Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject();
|
||||||
|
QOpenGLFramebufferObject* newDiffusedFBO =
|
||||||
|
Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject();
|
||||||
|
if ((_isOddFrame = !_isOddFrame)) {
|
||||||
|
qSwap(oldDiffusedFBO, newDiffusedFBO);
|
||||||
|
}
|
||||||
|
newDiffusedFBO->bind();
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, oldDiffusedFBO->texture());
|
||||||
|
|
||||||
|
_diffuseProgram->bind();
|
||||||
|
renderFullscreenQuad();
|
||||||
|
_diffuseProgram->release();
|
||||||
|
|
||||||
|
newDiffusedFBO->release();
|
||||||
|
|
||||||
|
// add diffused texture to the primary
|
||||||
|
glBindTexture(GL_TEXTURE_2D, newDiffusedFBO->texture());
|
||||||
|
|
||||||
|
_addSeparateProgram->bind();
|
||||||
|
renderFullscreenQuad();
|
||||||
|
_addSeparateProgram->release();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
} else { // _renderMode == BLUR_ADD_MODE || _renderMode == BLUR_PERSIST_ADD_MODE
|
||||||
// render the primary to the secondary with the horizontal blur
|
// render the primary to the secondary with the horizontal blur
|
||||||
QOpenGLFramebufferObject* secondaryFBO =
|
QOpenGLFramebufferObject* secondaryFBO =
|
||||||
Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject();
|
Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject();
|
||||||
|
@ -105,14 +156,49 @@ void GlowEffect::render() {
|
||||||
|
|
||||||
secondaryFBO->release();
|
secondaryFBO->release();
|
||||||
|
|
||||||
|
if (_renderMode == BLUR_ADD_MODE) {
|
||||||
// render the secondary to the screen with the vertical blur
|
// render the secondary to the screen with the vertical blur
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture());
|
glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture());
|
||||||
|
|
||||||
|
_verticalBlurAddProgram->bind();
|
||||||
|
renderFullscreenQuad();
|
||||||
|
_verticalBlurAddProgram->release();
|
||||||
|
|
||||||
|
} else { // _renderMode == BLUR_PERSIST_ADD_MODE
|
||||||
|
// render the secondary to the tertiary with horizontal blur and persistence
|
||||||
|
QOpenGLFramebufferObject* tertiaryFBO =
|
||||||
|
Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject();
|
||||||
|
tertiaryFBO->bind();
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA);
|
||||||
|
const float PERSISTENCE_SMOOTHING = 0.9f;
|
||||||
|
glBlendColor(0.0f, 0.0f, 0.0f, PERSISTENCE_SMOOTHING);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture());
|
||||||
|
|
||||||
_verticalBlurProgram->bind();
|
_verticalBlurProgram->bind();
|
||||||
renderFullscreenQuad();
|
renderFullscreenQuad();
|
||||||
_verticalBlurProgram->release();
|
_verticalBlurProgram->release();
|
||||||
|
|
||||||
|
glBlendColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
// now add the tertiary to the primary buffer
|
||||||
|
tertiaryFBO->release();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, tertiaryFBO->texture());
|
||||||
|
|
||||||
|
_addSeparateProgram->bind();
|
||||||
|
renderFullscreenQuad();
|
||||||
|
_addSeparateProgram->release();
|
||||||
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
@ -126,3 +212,7 @@ void GlowEffect::render() {
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GlowEffect::cycleRenderMode() {
|
||||||
|
_renderMode = (RenderMode)((_renderMode + 1) % RENDER_MODE_COUNT);
|
||||||
|
}
|
||||||
|
|
|
@ -9,26 +9,51 @@
|
||||||
#ifndef __interface__GlowEffect__
|
#ifndef __interface__GlowEffect__
|
||||||
#define __interface__GlowEffect__
|
#define __interface__GlowEffect__
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
class ProgramObject;
|
class ProgramObject;
|
||||||
|
|
||||||
class GlowEffect {
|
/// A generic full screen glow effect.
|
||||||
|
class GlowEffect : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
GlowEffect();
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
/// Prepares the glow effect for rendering the current frame. To be called before rendering the scene.
|
||||||
void prepare();
|
void prepare();
|
||||||
|
|
||||||
void begin(float amount = 1.0f);
|
/// Starts using the glow effect.
|
||||||
|
/// \param intensity the desired glow intensity, from zero to one
|
||||||
|
void begin(float intensity = 1.0f);
|
||||||
|
|
||||||
|
/// Stops using the glow effect.
|
||||||
void end();
|
void end();
|
||||||
|
|
||||||
|
/// Renders the glow effect. To be called after rendering the scene.
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void cycleRenderMode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ProgramObject* _horizontalBlurProgram;
|
enum RenderMode { ADD_MODE, BLUR_ADD_MODE, BLUR_PERSIST_ADD_MODE, DIFFUSE_ADD_MODE, RENDER_MODE_COUNT };
|
||||||
ProgramObject* _verticalBlurProgram;
|
|
||||||
|
|
||||||
bool _isEmpty;
|
RenderMode _renderMode;
|
||||||
|
ProgramObject* _addProgram;
|
||||||
|
ProgramObject* _horizontalBlurProgram;
|
||||||
|
ProgramObject* _verticalBlurAddProgram;
|
||||||
|
ProgramObject* _verticalBlurProgram;
|
||||||
|
ProgramObject* _addSeparateProgram;
|
||||||
|
ProgramObject* _diffuseProgram;
|
||||||
|
|
||||||
|
bool _isEmpty; ///< set when nothing in the scene is currently glowing
|
||||||
|
bool _isOddFrame; ///< controls the alternation between texture targets in diffuse add mode
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__GlowEffect__) */
|
#endif /* defined(__interface__GlowEffect__) */
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
|
|
||||||
TextureCache::TextureCache() : _permutationNormalTextureID(0),
|
TextureCache::TextureCache() : _permutationNormalTextureID(0),
|
||||||
_primaryFramebufferObject(NULL), _secondaryFramebufferObject(NULL) {
|
_primaryFramebufferObject(NULL), _secondaryFramebufferObject(NULL), _tertiaryFramebufferObject(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCache::~TextureCache() {
|
TextureCache::~TextureCache() {
|
||||||
|
@ -27,6 +27,9 @@ TextureCache::~TextureCache() {
|
||||||
if (_secondaryFramebufferObject != NULL) {
|
if (_secondaryFramebufferObject != NULL) {
|
||||||
delete _secondaryFramebufferObject;
|
delete _secondaryFramebufferObject;
|
||||||
}
|
}
|
||||||
|
if (_tertiaryFramebufferObject != NULL) {
|
||||||
|
delete _tertiaryFramebufferObject;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint TextureCache::getPermutationNormalTextureID() {
|
GLuint TextureCache::getPermutationNormalTextureID() {
|
||||||
|
@ -72,6 +75,14 @@ QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() {
|
||||||
return _secondaryFramebufferObject;
|
return _secondaryFramebufferObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QOpenGLFramebufferObject* TextureCache::getTertiaryFramebufferObject() {
|
||||||
|
if (_tertiaryFramebufferObject == NULL) {
|
||||||
|
_tertiaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size());
|
||||||
|
Application::getInstance()->getGLWidget()->installEventFilter(this);
|
||||||
|
}
|
||||||
|
return _tertiaryFramebufferObject;
|
||||||
|
}
|
||||||
|
|
||||||
bool TextureCache::eventFilter(QObject* watched, QEvent* event) {
|
bool TextureCache::eventFilter(QObject* watched, QEvent* event) {
|
||||||
if (event->type() == QEvent::Resize) {
|
if (event->type() == QEvent::Resize) {
|
||||||
QSize size = static_cast<QResizeEvent*>(event)->size();
|
QSize size = static_cast<QResizeEvent*>(event)->size();
|
||||||
|
@ -83,6 +94,10 @@ bool TextureCache::eventFilter(QObject* watched, QEvent* event) {
|
||||||
delete _secondaryFramebufferObject;
|
delete _secondaryFramebufferObject;
|
||||||
_secondaryFramebufferObject = NULL;
|
_secondaryFramebufferObject = NULL;
|
||||||
}
|
}
|
||||||
|
if (_tertiaryFramebufferObject != NULL && _tertiaryFramebufferObject->size() != size) {
|
||||||
|
delete _tertiaryFramebufferObject;
|
||||||
|
_tertiaryFramebufferObject = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ public:
|
||||||
|
|
||||||
QOpenGLFramebufferObject* getPrimaryFramebufferObject();
|
QOpenGLFramebufferObject* getPrimaryFramebufferObject();
|
||||||
QOpenGLFramebufferObject* getSecondaryFramebufferObject();
|
QOpenGLFramebufferObject* getSecondaryFramebufferObject();
|
||||||
|
QOpenGLFramebufferObject* getTertiaryFramebufferObject();
|
||||||
|
|
||||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ private:
|
||||||
|
|
||||||
QOpenGLFramebufferObject* _primaryFramebufferObject;
|
QOpenGLFramebufferObject* _primaryFramebufferObject;
|
||||||
QOpenGLFramebufferObject* _secondaryFramebufferObject;
|
QOpenGLFramebufferObject* _secondaryFramebufferObject;
|
||||||
|
QOpenGLFramebufferObject* _tertiaryFramebufferObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__TextureCache__) */
|
#endif /* defined(__interface__TextureCache__) */
|
||||||
|
|
64
libraries/shared/src/GenericThread.cpp
Normal file
64
libraries/shared/src/GenericThread.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
//
|
||||||
|
// GenericThread.cpp
|
||||||
|
// shared
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Generic Threaded or non-threaded processing class
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "GenericThread.h"
|
||||||
|
|
||||||
|
GenericThread::GenericThread() :
|
||||||
|
_stopThread(false),
|
||||||
|
_isThreaded(false) // assume non-threaded, must call initialize()
|
||||||
|
{
|
||||||
|
pthread_mutex_init(&_mutex, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericThread::~GenericThread() {
|
||||||
|
terminate();
|
||||||
|
pthread_mutex_destroy(&_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenericThread::initialize(bool isThreaded) {
|
||||||
|
_isThreaded = isThreaded;
|
||||||
|
if (_isThreaded) {
|
||||||
|
pthread_create(&_thread, NULL, GenericThreadEntry, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenericThread::terminate() {
|
||||||
|
if (_isThreaded) {
|
||||||
|
_stopThread = true;
|
||||||
|
pthread_join(_thread, NULL);
|
||||||
|
_isThreaded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GenericThread::threadRoutine() {
|
||||||
|
while (!_stopThread) {
|
||||||
|
|
||||||
|
// override this function to do whatever your class actually does, return false to exit thread early
|
||||||
|
if (!process()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In non-threaded mode, this will break each time you call it so it's the
|
||||||
|
// callers responsibility to continuously call this method
|
||||||
|
if (!_isThreaded) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isThreaded) {
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void* GenericThreadEntry(void* arg) {
|
||||||
|
GenericThread* genericThread = (GenericThread*)arg;
|
||||||
|
return genericThread->threadRoutine();
|
||||||
|
}
|
53
libraries/shared/src/GenericThread.h
Normal file
53
libraries/shared/src/GenericThread.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//
|
||||||
|
// GenericThread.h
|
||||||
|
// shared
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Generic Threaded or non-threaded processing class.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __shared__GenericThread__
|
||||||
|
#define __shared__GenericThread__
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
/// A basic generic "thread" class. Handles a single thread of control within the application. Can operate in non-threaded
|
||||||
|
/// mode but caller must regularly call threadRoutine() method.
|
||||||
|
class GenericThread {
|
||||||
|
public:
|
||||||
|
GenericThread();
|
||||||
|
virtual ~GenericThread();
|
||||||
|
|
||||||
|
/// Call to start the thread.
|
||||||
|
/// \param bool isThreaded true by default. false for non-threaded mode and caller must call threadRoutine() regularly.
|
||||||
|
void initialize(bool isThreaded = true);
|
||||||
|
|
||||||
|
/// Call to stop the thread
|
||||||
|
void terminate();
|
||||||
|
|
||||||
|
/// If you're running in non-threaded mode, you must call this regularly
|
||||||
|
void* threadRoutine();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Override this function to do whatever your class actually does, return false to exit thread early.
|
||||||
|
virtual bool process() = 0;
|
||||||
|
|
||||||
|
/// Locks all the resources of the thread.
|
||||||
|
void lock() { pthread_mutex_lock(&_mutex); }
|
||||||
|
|
||||||
|
/// Unlocks all the resources of the thread.
|
||||||
|
void unlock() { pthread_mutex_unlock(&_mutex); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
pthread_mutex_t _mutex;
|
||||||
|
|
||||||
|
bool _stopThread;
|
||||||
|
bool _isThreaded;
|
||||||
|
pthread_t _thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" void* GenericThreadEntry(void* arg);
|
||||||
|
|
||||||
|
#endif // __shared__GenericThread__
|
|
@ -10,20 +10,53 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include "NetworkPacket.h"
|
#include "NetworkPacket.h"
|
||||||
|
|
||||||
NetworkPacket::NetworkPacket() : _packetLength(0) {
|
NetworkPacket::NetworkPacket() {
|
||||||
|
_packetLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkPacket::~NetworkPacket() {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkPacket::copyContents(const sockaddr& address, const unsigned char* packetData, ssize_t packetLength) {
|
||||||
|
_packetLength = 0;
|
||||||
|
if (packetLength >=0 && packetLength <= MAX_PACKET_SIZE) {
|
||||||
|
memcpy(&_address, &address, sizeof(_address));
|
||||||
|
_packetLength = packetLength;
|
||||||
|
memcpy(&_packetData[0], packetData, packetLength);
|
||||||
|
} else {
|
||||||
|
qDebug(">>> NetworkPacket::copyContents() unexpected length=%lu\n",packetLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkPacket::NetworkPacket(const NetworkPacket& packet) {
|
NetworkPacket::NetworkPacket(const NetworkPacket& packet) {
|
||||||
memcpy(&_senderAddress, &packet.getSenderAddress(), sizeof(_senderAddress));
|
copyContents(packet.getAddress(), packet.getData(), packet.getLength());
|
||||||
_packetLength = packet.getLength();
|
|
||||||
memcpy(&_packetData[0], packet.getData(), _packetLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkPacket::NetworkPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
NetworkPacket::NetworkPacket(sockaddr& address, unsigned char* packetData, ssize_t packetLength) {
|
||||||
memcpy(&_senderAddress, &senderAddress, sizeof(_senderAddress));
|
copyContents(address, packetData, packetLength);
|
||||||
_packetLength = packetLength;
|
|
||||||
memcpy(&_packetData[0], packetData, packetLength);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// copy assignment
|
||||||
|
NetworkPacket& NetworkPacket::operator=(NetworkPacket const& other) {
|
||||||
|
copyContents(other.getAddress(), other.getData(), other.getLength());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_MOVE_SEMANTICS
|
||||||
|
// move, same as copy, but other packet won't be used further
|
||||||
|
NetworkPacket::NetworkPacket(NetworkPacket && packet) {
|
||||||
|
copyContents(packet.getAddress(), packet.getData(), packet.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
// move assignment
|
||||||
|
NetworkPacket& NetworkPacket::operator=(NetworkPacket&& other) {
|
||||||
|
_packetLength = 0;
|
||||||
|
copyContents(other.getAddress(), other.getData(), other.getLength());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -17,22 +17,32 @@
|
||||||
|
|
||||||
#include "NodeList.h" // for MAX_PACKET_SIZE
|
#include "NodeList.h" // for MAX_PACKET_SIZE
|
||||||
|
|
||||||
|
/// Storage of not-yet processed inbound, or not yet sent outbound generic UDP network packet
|
||||||
class NetworkPacket {
|
class NetworkPacket {
|
||||||
public:
|
public:
|
||||||
NetworkPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
|
|
||||||
NetworkPacket(const NetworkPacket& packet);
|
|
||||||
NetworkPacket();
|
NetworkPacket();
|
||||||
//~NetworkPacket();
|
NetworkPacket(const NetworkPacket& packet); // copy constructor
|
||||||
|
~NetworkPacket(); // destructor
|
||||||
|
NetworkPacket& operator= (const NetworkPacket& other); // copy assignment
|
||||||
|
|
||||||
sockaddr& getSenderAddress() { return _senderAddress; };
|
#ifdef HAS_MOVE_SEMANTICS
|
||||||
|
NetworkPacket(NetworkPacket&& packet); // move?? // same as copy, but other packet won't be used further
|
||||||
|
NetworkPacket& operator= (NetworkPacket&& other); // move assignment
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NetworkPacket(sockaddr& address, unsigned char* packetData, ssize_t packetLength);
|
||||||
|
|
||||||
|
sockaddr& getAddress() { return _address; };
|
||||||
ssize_t getLength() const { return _packetLength; };
|
ssize_t getLength() const { return _packetLength; };
|
||||||
unsigned char* getData() { return &_packetData[0]; };
|
unsigned char* getData() { return &_packetData[0]; };
|
||||||
|
|
||||||
const sockaddr& getSenderAddress() const { return _senderAddress; };
|
const sockaddr& getAddress() const { return _address; };
|
||||||
const unsigned char* getData() const { return &_packetData[0]; };
|
const unsigned char* getData() const { return &_packetData[0]; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sockaddr _senderAddress;
|
void copyContents(const sockaddr& address, const unsigned char* packetData, ssize_t packetLength);
|
||||||
|
|
||||||
|
sockaddr _address;
|
||||||
ssize_t _packetLength;
|
ssize_t _packetLength;
|
||||||
unsigned char _packetData[MAX_PACKET_SIZE];
|
unsigned char _packetData[MAX_PACKET_SIZE];
|
||||||
};
|
};
|
||||||
|
|
|
@ -439,7 +439,7 @@ void NodeList::addNodeToList(Node* newNode) {
|
||||||
notifyHooksOfAddedNode(newNode);
|
notifyHooksOfAddedNode(newNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned NodeList::broadcastToNodes(unsigned char *broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) {
|
unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) {
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||||
// only send to the NodeTypes we are asked to send to.
|
// only send to the NodeTypes we are asked to send to.
|
||||||
|
|
|
@ -319,3 +319,48 @@ bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescen
|
||||||
// they all match, so we are an ancestor
|
// they all match, so we are an ancestor
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char* hexStringToOctalCode(const QString& input) {
|
||||||
|
const int HEX_NUMBER_BASE = 16;
|
||||||
|
const int HEX_BYTE_SIZE = 2;
|
||||||
|
int stringIndex = 0;
|
||||||
|
int byteArrayIndex = 0;
|
||||||
|
|
||||||
|
// allocate byte array based on half of string length
|
||||||
|
unsigned char* bytes = new unsigned char[(input.length()) / HEX_BYTE_SIZE];
|
||||||
|
|
||||||
|
// loop through the string - 2 bytes at a time converting
|
||||||
|
// it to decimal equivalent and store in byte array
|
||||||
|
bool ok;
|
||||||
|
while (stringIndex < input.length()) {
|
||||||
|
uint value = input.mid(stringIndex, HEX_BYTE_SIZE).toUInt(&ok, HEX_NUMBER_BASE);
|
||||||
|
if (!ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytes[byteArrayIndex] = (unsigned char)value;
|
||||||
|
stringIndex += HEX_BYTE_SIZE;
|
||||||
|
byteArrayIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// something went wrong
|
||||||
|
if (!ok) {
|
||||||
|
delete[] bytes;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString octalCodeToHexString(unsigned char* octalCode) {
|
||||||
|
const int HEX_NUMBER_BASE = 16;
|
||||||
|
const int HEX_BYTE_SIZE = 2;
|
||||||
|
QString output;
|
||||||
|
if (!octalCode) {
|
||||||
|
output = "00";
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) {
|
||||||
|
output.append(QString("%1").arg(octalCode[i], HEX_BYTE_SIZE, HEX_NUMBER_BASE, QChar('0')).toUpper());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#define __hifi__OctalCode__
|
#define __hifi__OctalCode__
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
const int BITS_IN_BYTE = 8;
|
const int BITS_IN_BYTE = 8;
|
||||||
const int BITS_IN_OCTAL = 3;
|
const int BITS_IN_OCTAL = 3;
|
||||||
|
@ -39,7 +40,7 @@ void copyFirstVertexForCode(unsigned char * octalCode, float* output);
|
||||||
struct VoxelPositionSize {
|
struct VoxelPositionSize {
|
||||||
float x, y, z, s;
|
float x, y, z, s;
|
||||||
};
|
};
|
||||||
void voxelDetailsForCode(unsigned char * octalCode, VoxelPositionSize& voxelPositionSize);
|
void voxelDetailsForCode(unsigned char* octalCode, VoxelPositionSize& voxelPositionSize);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ILLEGAL_CODE = -2,
|
ILLEGAL_CODE = -2,
|
||||||
|
@ -49,4 +50,8 @@ typedef enum {
|
||||||
} OctalCodeComparison;
|
} OctalCodeComparison;
|
||||||
|
|
||||||
OctalCodeComparison compareOctalCodes(unsigned char* code1, unsigned char* code2);
|
OctalCodeComparison compareOctalCodes(unsigned char* code1, unsigned char* code2);
|
||||||
|
|
||||||
|
QString octalCodeToHexString(unsigned char* octalCode);
|
||||||
|
unsigned char* hexStringToOctalCode(const QString& input);
|
||||||
|
|
||||||
#endif /* defined(__hifi__OctalCode__) */
|
#endif /* defined(__hifi__OctalCode__) */
|
||||||
|
|
|
@ -26,7 +26,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case PACKET_TYPE_VOXEL_STATS:
|
case PACKET_TYPE_VOXEL_STATS:
|
||||||
return 1;
|
return 2;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define hifi_PacketHeaders_h
|
#define hifi_PacketHeaders_h
|
||||||
|
|
||||||
typedef char PACKET_TYPE;
|
typedef char PACKET_TYPE;
|
||||||
|
const PACKET_TYPE PACKET_TYPE_UNKNOWN = 0;
|
||||||
const PACKET_TYPE PACKET_TYPE_DOMAIN = 'D';
|
const PACKET_TYPE PACKET_TYPE_DOMAIN = 'D';
|
||||||
const PACKET_TYPE PACKET_TYPE_PING = 'P';
|
const PACKET_TYPE PACKET_TYPE_PING = 'P';
|
||||||
const PACKET_TYPE PACKET_TYPE_PING_REPLY = 'R';
|
const PACKET_TYPE PACKET_TYPE_PING_REPLY = 'R';
|
||||||
|
|
59
libraries/shared/src/PacketSender.cpp
Normal file
59
libraries/shared/src/PacketSender.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
//
|
||||||
|
// PacketSender.cpp
|
||||||
|
// shared
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Threaded or non-threaded packet sender.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
const uint64_t SEND_INTERVAL_USECS = 1000 * 5; // no more than 200pps... should be settable
|
||||||
|
|
||||||
|
#include "NodeList.h"
|
||||||
|
#include "PacketSender.h"
|
||||||
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
|
PacketSender::PacketSender() {
|
||||||
|
_lastSendTime = usecTimestampNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PacketSender::queuePacket(sockaddr& address, unsigned char* packetData, ssize_t packetLength) {
|
||||||
|
NetworkPacket packet(address, packetData, packetLength);
|
||||||
|
lock();
|
||||||
|
_packets.push_back(packet);
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PacketSender::process() {
|
||||||
|
if (_packets.size() == 0) {
|
||||||
|
const uint64_t SEND_THREAD_SLEEP_INTERVAL = (1000 * 1000)/60; // check at 60fps
|
||||||
|
usleep(SEND_THREAD_SLEEP_INTERVAL);
|
||||||
|
}
|
||||||
|
while (_packets.size() > 0) {
|
||||||
|
NetworkPacket& packet = _packets.front();
|
||||||
|
|
||||||
|
// send the packet through the NodeList...
|
||||||
|
UDPSocket* nodeSocket = NodeList::getInstance()->getNodeSocket();
|
||||||
|
|
||||||
|
nodeSocket->send(&packet.getAddress(), packet.getData(), packet.getLength());
|
||||||
|
|
||||||
|
lock();
|
||||||
|
_packets.erase(_packets.begin());
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
uint64_t now = usecTimestampNow();
|
||||||
|
// dynamically sleep until we need to fire off the next set of voxels
|
||||||
|
uint64_t elapsed = now - _lastSendTime;
|
||||||
|
int usecToSleep = SEND_INTERVAL_USECS - elapsed;
|
||||||
|
_lastSendTime = now;
|
||||||
|
if (usecToSleep > 0) {
|
||||||
|
usleep(usecToSleep);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return true; // keep running till they terminate us
|
||||||
|
}
|
38
libraries/shared/src/PacketSender.h
Normal file
38
libraries/shared/src/PacketSender.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// PacketSender.h
|
||||||
|
// shared
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Threaded or non-threaded packet sender.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __shared__PacketSender__
|
||||||
|
#define __shared__PacketSender__
|
||||||
|
|
||||||
|
#include "GenericThread.h"
|
||||||
|
#include "NetworkPacket.h"
|
||||||
|
|
||||||
|
/// Generalized threaded processor for queueing and sending of outbound packets.
|
||||||
|
class PacketSender : public GenericThread {
|
||||||
|
public:
|
||||||
|
|
||||||
|
PacketSender();
|
||||||
|
|
||||||
|
/// Add packet to outbound queue.
|
||||||
|
/// \param sockaddr& address the destination address
|
||||||
|
/// \param packetData pointer to data
|
||||||
|
/// \param ssize_t packetLength size of data
|
||||||
|
/// \thread any thread, typically the application thread
|
||||||
|
void queuePacket(sockaddr& address, unsigned char* packetData, ssize_t packetLength);
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual bool process();
|
||||||
|
|
||||||
|
std::vector<NetworkPacket> _packets;
|
||||||
|
uint64_t _lastSendTime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __shared__PacketSender__
|
34
libraries/shared/src/ReceivedPacketProcessor.cpp
Normal file
34
libraries/shared/src/ReceivedPacketProcessor.cpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
//
|
||||||
|
// ReceivedPacketProcessor.cpp
|
||||||
|
// shared
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Threaded or non-threaded packet receiver.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "ReceivedPacketProcessor.h"
|
||||||
|
|
||||||
|
void ReceivedPacketProcessor::queuePacket(sockaddr& address, unsigned char* packetData, ssize_t packetLength) {
|
||||||
|
NetworkPacket packet(address, packetData, packetLength);
|
||||||
|
lock();
|
||||||
|
_packets.push_back(packet);
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReceivedPacketProcessor::process() {
|
||||||
|
if (_packets.size() == 0) {
|
||||||
|
const uint64_t RECEIVED_THREAD_SLEEP_INTERVAL = (1000 * 1000)/60; // check at 60fps
|
||||||
|
usleep(RECEIVED_THREAD_SLEEP_INTERVAL);
|
||||||
|
}
|
||||||
|
while (_packets.size() > 0) {
|
||||||
|
NetworkPacket& packet = _packets.front();
|
||||||
|
processPacket(packet.getAddress(), packet.getData(), packet.getLength());
|
||||||
|
|
||||||
|
lock();
|
||||||
|
_packets.erase(_packets.begin());
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
return true; // keep running till they terminate us
|
||||||
|
}
|
43
libraries/shared/src/ReceivedPacketProcessor.h
Normal file
43
libraries/shared/src/ReceivedPacketProcessor.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
//
|
||||||
|
// ReceivedPacketProcessor.h
|
||||||
|
// shared
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/12/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Threaded or non-threaded received packet processor.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __shared__ReceivedPacketProcessor__
|
||||||
|
#define __shared__ReceivedPacketProcessor__
|
||||||
|
|
||||||
|
#include "GenericThread.h"
|
||||||
|
#include "NetworkPacket.h"
|
||||||
|
|
||||||
|
/// Generalized threaded processor for handling received inbound packets.
|
||||||
|
class ReceivedPacketProcessor : public GenericThread {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Add packet from network receive thread to the processing queue.
|
||||||
|
/// \param sockaddr& senderAddress the address of the sender
|
||||||
|
/// \param packetData pointer to received data
|
||||||
|
/// \param ssize_t packetLength size of received data
|
||||||
|
/// \thread network receive thread
|
||||||
|
void queuePacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Callback for processing of recieved packets. Implement this to process the incoming packets.
|
||||||
|
/// \param sockaddr& senderAddress the address of the sender
|
||||||
|
/// \param packetData pointer to received data
|
||||||
|
/// \param ssize_t packetLength size of received data
|
||||||
|
/// \thread "this" individual processing thread
|
||||||
|
virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) = 0;
|
||||||
|
|
||||||
|
/// Implements generic processing behavior for this thread.
|
||||||
|
virtual bool process();
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<NetworkPacket> _packets;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __shared__PacketReceiver__
|
|
@ -13,6 +13,63 @@
|
||||||
#include "JurisdictionMap.h"
|
#include "JurisdictionMap.h"
|
||||||
#include "VoxelNode.h"
|
#include "VoxelNode.h"
|
||||||
|
|
||||||
|
|
||||||
|
// standard assignment
|
||||||
|
// copy assignment
|
||||||
|
JurisdictionMap& JurisdictionMap::operator=(const JurisdictionMap& other) {
|
||||||
|
copyContents(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_MOVE_SEMANTICS
|
||||||
|
// Move constructor
|
||||||
|
JurisdictionMap::JurisdictionMap(JurisdictionMap&& other) : _rootOctalCode(NULL) {
|
||||||
|
init(other._rootOctalCode, other._endNodes);
|
||||||
|
other._rootOctalCode = NULL;
|
||||||
|
other._endNodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// move assignment
|
||||||
|
JurisdictionMap& JurisdictionMap::operator=(JurisdictionMap&& other) {
|
||||||
|
init(other._rootOctalCode, other._endNodes);
|
||||||
|
other._rootOctalCode = NULL;
|
||||||
|
other._endNodes.clear();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Copy constructor
|
||||||
|
JurisdictionMap::JurisdictionMap(const JurisdictionMap& other) : _rootOctalCode(NULL) {
|
||||||
|
copyContents(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JurisdictionMap::copyContents(unsigned char* rootCodeIn, const std::vector<unsigned char*>& endNodesIn) {
|
||||||
|
unsigned char* rootCode;
|
||||||
|
std::vector<unsigned char*> endNodes;
|
||||||
|
if (rootCodeIn) {
|
||||||
|
int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(rootCodeIn));
|
||||||
|
rootCode = new unsigned char[bytes];
|
||||||
|
memcpy(rootCode, rootCodeIn, bytes);
|
||||||
|
} else {
|
||||||
|
rootCode = new unsigned char[1];
|
||||||
|
*rootCode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < endNodesIn.size(); i++) {
|
||||||
|
if (endNodesIn[i]) {
|
||||||
|
int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodesIn[i]));
|
||||||
|
unsigned char* endNodeCode = new unsigned char[bytes];
|
||||||
|
memcpy(endNodeCode, endNodesIn[i], bytes);
|
||||||
|
endNodes.push_back(endNodeCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
init(rootCode, endNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JurisdictionMap::copyContents(const JurisdictionMap& other) {
|
||||||
|
copyContents(other._rootOctalCode, other._endNodes);
|
||||||
|
}
|
||||||
|
|
||||||
JurisdictionMap::~JurisdictionMap() {
|
JurisdictionMap::~JurisdictionMap() {
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
@ -82,12 +139,6 @@ JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(unsigned char* nodeOctal
|
||||||
|
|
||||||
// otherwise...
|
// otherwise...
|
||||||
bool isInJurisdiction = isAncestorOf(_rootOctalCode, nodeOctalCode, childIndex);
|
bool isInJurisdiction = isAncestorOf(_rootOctalCode, nodeOctalCode, childIndex);
|
||||||
|
|
||||||
//printf("isInJurisdiction=%s rootOctalCode=",debug::valueOf(isInJurisdiction));
|
|
||||||
//printOctalCode(_rootOctalCode);
|
|
||||||
//printf("nodeOctalCode=");
|
|
||||||
//printOctalCode(nodeOctalCode);
|
|
||||||
|
|
||||||
// if we're under the root, then we can't be under any of the endpoints
|
// if we're under the root, then we can't be under any of the endpoints
|
||||||
if (isInJurisdiction) {
|
if (isInJurisdiction) {
|
||||||
for (int i = 0; i < _endNodes.size(); i++) {
|
for (int i = 0; i < _endNodes.size(); i++) {
|
||||||
|
@ -98,7 +149,6 @@ JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(unsigned char* nodeOctal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return isInJurisdiction ? WITHIN : BELOW;
|
return isInJurisdiction ? WITHIN : BELOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,48 +197,3 @@ bool JurisdictionMap::writeToFile(const char* filename) {
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned char* JurisdictionMap::hexStringToOctalCode(const QString& input) const {
|
|
||||||
const int HEX_NUMBER_BASE = 16;
|
|
||||||
const int HEX_BYTE_SIZE = 2;
|
|
||||||
int stringIndex = 0;
|
|
||||||
int byteArrayIndex = 0;
|
|
||||||
|
|
||||||
// allocate byte array based on half of string length
|
|
||||||
unsigned char* bytes = new unsigned char[(input.length()) / HEX_BYTE_SIZE];
|
|
||||||
|
|
||||||
// loop through the string - 2 bytes at a time converting
|
|
||||||
// it to decimal equivalent and store in byte array
|
|
||||||
bool ok;
|
|
||||||
while (stringIndex < input.length()) {
|
|
||||||
uint value = input.mid(stringIndex, HEX_BYTE_SIZE).toUInt(&ok, HEX_NUMBER_BASE);
|
|
||||||
if (!ok) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bytes[byteArrayIndex] = (unsigned char)value;
|
|
||||||
stringIndex += HEX_BYTE_SIZE;
|
|
||||||
byteArrayIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// something went wrong
|
|
||||||
if (!ok) {
|
|
||||||
delete[] bytes;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString JurisdictionMap::octalCodeToHexString(unsigned char* octalCode) const {
|
|
||||||
const int HEX_NUMBER_BASE = 16;
|
|
||||||
const int HEX_BYTE_SIZE = 2;
|
|
||||||
QString output;
|
|
||||||
if (!octalCode) {
|
|
||||||
output = "00";
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) {
|
|
||||||
output.append(QString("%1").arg(octalCode[i], HEX_BYTE_SIZE, HEX_NUMBER_BASE, QChar('0')).toUpper());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,7 +20,20 @@ public:
|
||||||
BELOW
|
BELOW
|
||||||
};
|
};
|
||||||
|
|
||||||
JurisdictionMap();
|
// standard constructors
|
||||||
|
JurisdictionMap(); // default constructor
|
||||||
|
JurisdictionMap(const JurisdictionMap& other); // copy constructor
|
||||||
|
|
||||||
|
// standard assignment
|
||||||
|
JurisdictionMap& operator=(const JurisdictionMap& other); // copy assignment
|
||||||
|
|
||||||
|
#ifdef HAS_MOVE_SEMANTICS
|
||||||
|
// move constructor and assignment
|
||||||
|
JurisdictionMap(JurisdictionMap&& other); // move constructor
|
||||||
|
JurisdictionMap& operator= (JurisdictionMap&& other); // move assignment
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// application constructors
|
||||||
JurisdictionMap(const char* filename);
|
JurisdictionMap(const char* filename);
|
||||||
JurisdictionMap(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes);
|
JurisdictionMap(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes);
|
||||||
JurisdictionMap(const char* rootHextString, const char* endNodesHextString);
|
JurisdictionMap(const char* rootHextString, const char* endNodesHextString);
|
||||||
|
@ -35,13 +48,13 @@ public:
|
||||||
unsigned char* getEndNodeOctalCode(int index) const { return _endNodes[index]; }
|
unsigned char* getEndNodeOctalCode(int index) const { return _endNodes[index]; }
|
||||||
int getEndNodeCount() const { return _endNodes.size(); }
|
int getEndNodeCount() const { return _endNodes.size(); }
|
||||||
|
|
||||||
|
void copyContents(unsigned char* rootCodeIn, const std::vector<unsigned char*>& endNodesIn);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void copyContents(const JurisdictionMap& other); // use assignment instead
|
||||||
void clear();
|
void clear();
|
||||||
void init(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes);
|
void init(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes);
|
||||||
|
|
||||||
unsigned char* hexStringToOctalCode(const QString& input) const;
|
|
||||||
QString octalCodeToHexString(unsigned char* octalCode) const;
|
|
||||||
|
|
||||||
unsigned char* _rootOctalCode;
|
unsigned char* _rootOctalCode;
|
||||||
std::vector<unsigned char*> _endNodes;
|
std::vector<unsigned char*> _endNodes;
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,21 +17,18 @@
|
||||||
const int samples = 100;
|
const int samples = 100;
|
||||||
VoxelSceneStats::VoxelSceneStats() :
|
VoxelSceneStats::VoxelSceneStats() :
|
||||||
_elapsedAverage(samples),
|
_elapsedAverage(samples),
|
||||||
_bitsPerVoxelAverage(samples)
|
_bitsPerVoxelAverage(samples),
|
||||||
|
_jurisdictionRoot(NULL)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
_isReadyToSend = false;
|
_isReadyToSend = false;
|
||||||
_isStarted = false;
|
_isStarted = false;
|
||||||
_jurisdictionRoot = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelSceneStats::~VoxelSceneStats() {
|
VoxelSceneStats::~VoxelSceneStats() {
|
||||||
if (_jurisdictionRoot) {
|
reset();
|
||||||
delete[] _jurisdictionRoot;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void VoxelSceneStats::sceneStarted(bool isFullScene, bool isMoving, VoxelNode* root, JurisdictionMap* jurisdictionMap) {
|
void VoxelSceneStats::sceneStarted(bool isFullScene, bool isMoving, VoxelNode* root, JurisdictionMap* jurisdictionMap) {
|
||||||
reset(); // resets packet and voxel stats
|
reset(); // resets packet and voxel stats
|
||||||
_isStarted = true;
|
_isStarted = true;
|
||||||
|
@ -54,6 +51,16 @@ void VoxelSceneStats::sceneStarted(bool isFullScene, bool isMoving, VoxelNode* r
|
||||||
_jurisdictionRoot = new unsigned char[bytes];
|
_jurisdictionRoot = new unsigned char[bytes];
|
||||||
memcpy(_jurisdictionRoot, jurisdictionRoot, bytes);
|
memcpy(_jurisdictionRoot, jurisdictionRoot, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i=0; i < jurisdictionMap->getEndNodeCount(); i++) {
|
||||||
|
unsigned char* endNodeCode = jurisdictionMap->getEndNodeOctalCode(i);
|
||||||
|
if (endNodeCode) {
|
||||||
|
int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode));
|
||||||
|
unsigned char* endNodeCodeCopy = new unsigned char[bytes];
|
||||||
|
memcpy(endNodeCodeCopy, endNodeCode, bytes);
|
||||||
|
_jurisdictionEndNodes.push_back(endNodeCodeCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +132,17 @@ void VoxelSceneStats::reset() {
|
||||||
_existsBitsWritten = 0;
|
_existsBitsWritten = 0;
|
||||||
_existsInPacketBitsWritten = 0;
|
_existsInPacketBitsWritten = 0;
|
||||||
_treesRemoved = 0;
|
_treesRemoved = 0;
|
||||||
|
|
||||||
|
if (_jurisdictionRoot) {
|
||||||
|
delete[] _jurisdictionRoot;
|
||||||
|
_jurisdictionRoot = NULL;
|
||||||
|
}
|
||||||
|
for (int i=0; i < _jurisdictionEndNodes.size(); i++) {
|
||||||
|
if (_jurisdictionEndNodes[i]) {
|
||||||
|
delete[] _jurisdictionEndNodes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_jurisdictionEndNodes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelSceneStats::packetSent(int bytes) {
|
void VoxelSceneStats::packetSent(int bytes) {
|
||||||
|
@ -303,6 +321,21 @@ int VoxelSceneStats::packIntoMessage(unsigned char* destinationBuffer, int avail
|
||||||
destinationBuffer += sizeof(bytes);
|
destinationBuffer += sizeof(bytes);
|
||||||
memcpy(destinationBuffer, _jurisdictionRoot, bytes);
|
memcpy(destinationBuffer, _jurisdictionRoot, bytes);
|
||||||
destinationBuffer += bytes;
|
destinationBuffer += bytes;
|
||||||
|
|
||||||
|
// if and only if there's a root jurisdiction, also include the end nodes
|
||||||
|
int endNodeCount = _jurisdictionEndNodes.size();
|
||||||
|
|
||||||
|
memcpy(destinationBuffer, &endNodeCount, sizeof(endNodeCount));
|
||||||
|
destinationBuffer += sizeof(endNodeCount);
|
||||||
|
|
||||||
|
for (int i=0; i < endNodeCount; i++) {
|
||||||
|
unsigned char* endNodeCode = _jurisdictionEndNodes[i];
|
||||||
|
int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode));
|
||||||
|
memcpy(destinationBuffer, &bytes, sizeof(bytes));
|
||||||
|
destinationBuffer += sizeof(bytes);
|
||||||
|
memcpy(destinationBuffer, endNodeCode, bytes);
|
||||||
|
destinationBuffer += bytes;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
int bytes = 0;
|
int bytes = 0;
|
||||||
memcpy(destinationBuffer, &bytes, sizeof(bytes));
|
memcpy(destinationBuffer, &bytes, sizeof(bytes));
|
||||||
|
@ -406,10 +439,25 @@ int VoxelSceneStats::unpackFromMessage(unsigned char* sourceBuffer, int availabl
|
||||||
|
|
||||||
if (bytes == 0) {
|
if (bytes == 0) {
|
||||||
_jurisdictionRoot = NULL;
|
_jurisdictionRoot = NULL;
|
||||||
|
_jurisdictionEndNodes.clear();
|
||||||
} else {
|
} else {
|
||||||
_jurisdictionRoot = new unsigned char[bytes];
|
_jurisdictionRoot = new unsigned char[bytes];
|
||||||
memcpy(_jurisdictionRoot, sourceBuffer, bytes);
|
memcpy(_jurisdictionRoot, sourceBuffer, bytes);
|
||||||
sourceBuffer += bytes;
|
sourceBuffer += bytes;
|
||||||
|
// if and only if there's a root jurisdiction, also include the end nodes
|
||||||
|
_jurisdictionEndNodes.clear();
|
||||||
|
int endNodeCount = 0;
|
||||||
|
memcpy(&endNodeCount, sourceBuffer, sizeof(endNodeCount));
|
||||||
|
sourceBuffer += sizeof(endNodeCount);
|
||||||
|
for (int i=0; i < endNodeCount; i++) {
|
||||||
|
int bytes = 0;
|
||||||
|
memcpy(&bytes, sourceBuffer, sizeof(bytes));
|
||||||
|
sourceBuffer += sizeof(bytes);
|
||||||
|
unsigned char* endNodeCode = new unsigned char[bytes];
|
||||||
|
memcpy(endNodeCode, sourceBuffer, bytes);
|
||||||
|
sourceBuffer += bytes;
|
||||||
|
_jurisdictionEndNodes.push_back(endNodeCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// running averages
|
// running averages
|
||||||
|
|
|
@ -81,7 +81,7 @@ public:
|
||||||
char* getItemValue(int item);
|
char* getItemValue(int item);
|
||||||
|
|
||||||
unsigned char* getJurisdictionRoot() const { return _jurisdictionRoot; }
|
unsigned char* getJurisdictionRoot() const { return _jurisdictionRoot; }
|
||||||
|
const std::vector<unsigned char*>& getJurisdictionEndNodes() const { return _jurisdictionEndNodes; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _isReadyToSend;
|
bool _isReadyToSend;
|
||||||
|
@ -172,6 +172,7 @@ private:
|
||||||
char _itemValueBuffer[MAX_ITEM_VALUE_LENGTH];
|
char _itemValueBuffer[MAX_ITEM_VALUE_LENGTH];
|
||||||
|
|
||||||
unsigned char* _jurisdictionRoot;
|
unsigned char* _jurisdictionRoot;
|
||||||
|
std::vector<unsigned char*> _jurisdictionEndNodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__VoxelSceneStats__) */
|
#endif /* defined(__hifi__VoxelSceneStats__) */
|
||||||
|
|
Loading…
Reference in a new issue