mirror of
https://github.com/overte-org/overte.git
synced 2025-04-23 06:53:46 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into Remove-body
This commit is contained in:
commit
639b6be01a
31 changed files with 1164 additions and 198 deletions
22
interface/resources/images/hifi-interface-tools-v2-pie.svg
Normal file
22
interface/resources/images/hifi-interface-tools-v2-pie.svg
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="152px" height="152px" viewBox="0 0 152 152" enable-background="new 0 0 152 152" xml:space="preserve">
|
||||
<path fill="#333333" d="M76,13.441C41.45,13.441,13.442,41.45,13.442,76S41.45,138.558,76,138.558S138.558,110.55,138.558,76
|
||||
S110.55,13.441,76,13.441z M76,107.279c-17.275,0-31.279-14.004-31.279-31.279S58.725,44.721,76,44.721S107.279,58.725,107.279,76
|
||||
S93.275,107.279,76,107.279z"/>
|
||||
<g id="XMLID_46_">
|
||||
<g>
|
||||
<path fill="#EAEAEA" d="M41.465,38.653c0.483-0.558-1.506-5.81-0.071-6.338c1.041-0.38,0.971,1.524,1.041,2.08
|
||||
c0.102,1.143,0.346,2.528,0.727,3.567c0.346-1.663,0.312-3.36,0.381-5.056c0.034-0.521,0.173-1.697,0.865-1.629
|
||||
c1.628,0.105-0.242,5.576,0.832,6.269c0.727-0.832,0.935-2.979,1.212-4.052c0.104-0.45,0.245-1.873,1.246-1.281
|
||||
c0.763,0.451,0.138,3.291-0.103,4.19c-0.244,0.935-0.244,1.592-0.521,2.667c-0.067,0.728-0.206,1.524,0.277,2.078
|
||||
c0.867,0,2.859-2.46,3.829-1.699c0.658,0.485,0.331,1.109-0.12,1.403c-3.326,2.149-2.808,4.815-4.402,5.126
|
||||
c0,2.73-0.165,2.833,0.11,5.551c-1.731,0.287-3.542,0.216-5.199,0.106c0-0.001,0-0.001,0-0.001
|
||||
c0.113-1.432,0.067-0.342,0.173-1.931c0.079-1.235,0.103-2.339,0.139-3.551l-0.036-0.138c-1.038-0.278-1.349-2.095-1.696-3.307
|
||||
c-0.38-1.318,0.069-2.495-0.416-3.775c-0.308-0.97-1.62-3.381-0.795-4.086c0.487-0.417,0.761-0.07,1.142,0.83
|
||||
C40.392,36.408,40.549,38.549,41.465,38.653z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -852,6 +852,8 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
|||
deleteVoxelUnderCursor();
|
||||
}
|
||||
}
|
||||
|
||||
_pieMenu.mouseMoveEvent(_mouseX, _mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -869,7 +871,12 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
|||
_mouseDragStartedY = _mouseY;
|
||||
_mouseVoxelDragging = _mouseVoxel;
|
||||
_mousePressed = true;
|
||||
maybeEditVoxelUnderCursor();
|
||||
|
||||
|
||||
if (!maybeEditVoxelUnderCursor()) {
|
||||
_pieMenu.mousePressEvent(_mouseX, _mouseY);
|
||||
}
|
||||
|
||||
if (MAKE_SOUND_ON_VOXEL_CLICK && _isHoverVoxel && !_isHoverVoxelSounding) {
|
||||
_hoverVoxelOriginalColor[0] = _hoverVoxel.red;
|
||||
_hoverVoxelOriginalColor[1] = _hoverVoxel.green;
|
||||
|
@ -892,6 +899,8 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
|
|||
_mouseY = event->y();
|
||||
_mousePressed = false;
|
||||
checkBandwidthMeterClick();
|
||||
|
||||
_pieMenu.mouseReleaseEvent(_mouseX, _mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1383,6 +1392,10 @@ void Application::doFalseColorizeOccludedV2() {
|
|||
_voxels.falseColorizeOccludedV2();
|
||||
}
|
||||
|
||||
void Application::doFalseColorizeBySource() {
|
||||
_voxels.falseColorizeBySource();
|
||||
}
|
||||
|
||||
void Application::doTrueVoxelColors() {
|
||||
_voxels.trueColorize();
|
||||
}
|
||||
|
@ -1804,6 +1817,7 @@ void Application::initMenu() {
|
|||
_testPing->setChecked(true);
|
||||
(_fullScreenMode = optionsMenu->addAction("Fullscreen", this, SLOT(setFullscreen(bool)), Qt::Key_F))->setCheckable(true);
|
||||
optionsMenu->addAction("Webcam", &_webcam, SLOT(setEnabled(bool)))->setCheckable(true);
|
||||
optionsMenu->addAction("Toggle Skeleton Tracking", &_webcam, SLOT(setSkeletonTrackingOn(bool)))->setCheckable(true);
|
||||
optionsMenu->addAction("Cycle Webcam Send Mode", _webcam.getGrabber(), SLOT(cycleVideoSendMode()));
|
||||
optionsMenu->addAction("Go Home", this, SLOT(goHome()));
|
||||
|
||||
|
@ -1832,7 +1846,6 @@ void Application::initMenu() {
|
|||
(_renderLookatIndicatorOn = renderMenu->addAction("Lookat Indicator"))->setCheckable(true);
|
||||
_renderLookatIndicatorOn->setChecked(true);
|
||||
(_renderParticleSystemOn = renderMenu->addAction("Particle System"))->setCheckable(true);
|
||||
_renderParticleSystemOn->setChecked(true);
|
||||
(_manualFirstPerson = renderMenu->addAction(
|
||||
"First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P))->setCheckable(true);
|
||||
(_manualThirdPerson = renderMenu->addAction(
|
||||
|
@ -1919,6 +1932,7 @@ void Application::initMenu() {
|
|||
renderDebugMenu->addAction("FALSE Color Voxel Out of View", this, SLOT(doFalseColorizeInView()));
|
||||
renderDebugMenu->addAction("FALSE Color Occluded Voxels", this, SLOT(doFalseColorizeOccluded()), Qt::CTRL | Qt::Key_O);
|
||||
renderDebugMenu->addAction("FALSE Color Occluded V2 Voxels", this, SLOT(doFalseColorizeOccludedV2()), Qt::CTRL | Qt::Key_P);
|
||||
renderDebugMenu->addAction("FALSE Color By Source", this, SLOT(doFalseColorizeBySource()), Qt::CTRL | Qt::SHIFT | Qt::Key_S);
|
||||
renderDebugMenu->addAction("Show TRUE Colors", this, SLOT(doTrueVoxelColors()), Qt::CTRL | Qt::Key_T);
|
||||
|
||||
(_shouldLowPassFilter = debugMenu->addAction("Test: LowPass filter"))->setCheckable(true);
|
||||
|
@ -2057,7 +2071,15 @@ void Application::init() {
|
|||
_palette.addTool(&_swatch);
|
||||
_palette.addAction(_colorVoxelMode, 0, 2);
|
||||
_palette.addAction(_eyedropperMode, 0, 3);
|
||||
_palette.addAction(_selectVoxelMode, 0, 4);
|
||||
_palette.addAction(_selectVoxelMode, 0, 4);
|
||||
|
||||
_pieMenu.init("./resources/images/hifi-interface-tools-v2-pie.svg",
|
||||
_glWidget->width(),
|
||||
_glWidget->height());
|
||||
|
||||
_followMode = new QAction(this);
|
||||
connect(_followMode, SIGNAL(triggered()), this, SLOT(toggleFollowMode()));
|
||||
_pieMenu.addAction(_followMode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2069,7 +2091,7 @@ const float HEAD_SPHERE_RADIUS = 0.07;
|
|||
static uint16_t DEFAULT_NODE_ID_REF = 1;
|
||||
|
||||
|
||||
bool Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||
Avatar* Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||
glm::vec3& eyePosition, uint16_t& nodeID = DEFAULT_NODE_ID_REF) {
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
@ -2082,11 +2104,11 @@ bool Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& m
|
|||
_lookatIndicatorScale = avatar->getScale();
|
||||
_lookatOtherPosition = headPosition;
|
||||
nodeID = avatar->getOwningNode()->getNodeID();
|
||||
return true;
|
||||
return avatar;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Application::renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera) {
|
||||
|
@ -2101,6 +2123,7 @@ void Application::renderLookatIndicator(glm::vec3 pointOfInterest, Camera& which
|
|||
}
|
||||
|
||||
void Application::update(float deltaTime) {
|
||||
|
||||
// Use Transmitter Hand to move hand if connected, else use mouse
|
||||
if (_myTransmitter.isConnected()) {
|
||||
const float HAND_FORCE_SCALING = 0.01f;
|
||||
|
@ -2997,6 +3020,10 @@ void Application::displayOverlay() {
|
|||
_swatch.checkColor();
|
||||
}
|
||||
|
||||
if (_pieMenu.isDisplayed()) {
|
||||
_pieMenu.render();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
@ -3009,19 +3036,35 @@ void Application::displayStats() {
|
|||
drawtext(10, statsVerticalOffset + 15, 0.10f, 0, 1.0, 0, stats);
|
||||
|
||||
if (_testPing->isChecked()) {
|
||||
int pingAudio = 0, pingAvatar = 0, pingVoxel = 0;
|
||||
int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0;
|
||||
|
||||
NodeList *nodeList = NodeList::getInstance();
|
||||
Node *audioMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||
Node *avatarMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
||||
Node *voxelServerNode = nodeList->soloNodeOfType(NODE_TYPE_VOXEL_SERVER);
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
Node* audioMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||
Node* avatarMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
||||
|
||||
pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : 0;
|
||||
pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : 0;
|
||||
pingVoxel = voxelServerNode ? voxelServerNode->getPingMs() : 0;
|
||||
|
||||
|
||||
// Now handle voxel servers, since there could be more than one, we average their ping times
|
||||
unsigned long totalPingVoxel = 0;
|
||||
int voxelServerCount = 0;
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||
totalPingVoxel += node->getPingMs();
|
||||
voxelServerCount++;
|
||||
if (pingVoxelMax < node->getPingMs()) {
|
||||
pingVoxelMax = node->getPingMs();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (voxelServerCount) {
|
||||
pingVoxel = totalPingVoxel/voxelServerCount;
|
||||
}
|
||||
|
||||
|
||||
char pingStats[200];
|
||||
sprintf(pingStats, "Ping audio/avatar/voxel: %d / %d / %d ", pingAudio, pingAvatar, pingVoxel);
|
||||
sprintf(pingStats, "Ping audio/avatar/voxel: %d / %d / %d avg %d max ", pingAudio, pingAvatar, pingVoxel, pingVoxelMax);
|
||||
drawtext(10, statsVerticalOffset + 35, 0.10f, 0, 1.0, 0, pingStats);
|
||||
}
|
||||
|
||||
|
@ -3396,7 +3439,7 @@ void Application::shiftPaintingColor() {
|
|||
}
|
||||
|
||||
|
||||
void Application::maybeEditVoxelUnderCursor() {
|
||||
bool Application::maybeEditVoxelUnderCursor() {
|
||||
if (_addVoxelMode->isChecked() || _colorVoxelMode->isChecked()) {
|
||||
if (_mouseVoxel.s != 0) {
|
||||
PACKET_TYPE message = (_destructiveAddVoxel->isChecked() ?
|
||||
|
@ -3467,7 +3510,11 @@ void Application::maybeEditVoxelUnderCursor() {
|
|||
deleteVoxelUnderCursor();
|
||||
} else if (_eyedropperMode->isChecked()) {
|
||||
eyedropperVoxelUnderCursor();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::deleteVoxelUnderCursor() {
|
||||
|
@ -3510,6 +3557,22 @@ void Application::goHome() {
|
|||
_myAvatar.setPosition(START_LOCATION);
|
||||
}
|
||||
|
||||
|
||||
void Application::toggleFollowMode() {
|
||||
glm::vec3 mouseRayOrigin, mouseRayDirection;
|
||||
_viewFrustum.computePickRay(_pieMenu.getX() / (float)_glWidget->width(),
|
||||
_pieMenu.getY() / (float)_glWidget->height(),
|
||||
mouseRayOrigin, mouseRayDirection);
|
||||
glm::vec3 eyePositionIgnored;
|
||||
uint16_t nodeIDIgnored;
|
||||
Avatar* leadingAvatar = isLookingAtOtherAvatar(mouseRayOrigin,
|
||||
mouseRayDirection,
|
||||
eyePositionIgnored,
|
||||
nodeIDIgnored);
|
||||
|
||||
_myAvatar.follow(leadingAvatar);
|
||||
}
|
||||
|
||||
void Application::resetSensors() {
|
||||
_headMouseX = _mouseX = _glWidget->width() / 2;
|
||||
_headMouseY = _mouseY = _glWidget->height() / 2;
|
||||
|
@ -3622,13 +3685,15 @@ void* Application::networkReceive(void* args) {
|
|||
} // fall through to piggyback message
|
||||
|
||||
if (app->_renderVoxels->isChecked()) {
|
||||
Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER);
|
||||
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
||||
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
|
||||
voxelServer->lock();
|
||||
if (messageData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
|
||||
app->_environment.parseData(&senderAddress, messageData, messageLength);
|
||||
} else {
|
||||
app->_voxels.setDataSourceID(voxelServer->getNodeID());
|
||||
app->_voxels.parseData(messageData, messageLength);
|
||||
app->_voxels.setDataSourceID(UNKNOWN_NODE_ID);
|
||||
}
|
||||
voxelServer->unlock();
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "ViewFrustum.h"
|
||||
#include "VoxelSystem.h"
|
||||
#include "Webcam.h"
|
||||
#include "PieMenu.h"
|
||||
#include "avatar/Avatar.h"
|
||||
#include "avatar/HandControl.h"
|
||||
#include "ui/BandwidthDialog.h"
|
||||
|
@ -149,6 +150,7 @@ private slots:
|
|||
void doFalseColorizeByDistance();
|
||||
void doFalseColorizeOccluded();
|
||||
void doFalseColorizeOccludedV2();
|
||||
void doFalseColorizeBySource();
|
||||
void doFalseColorizeInView();
|
||||
void doTrueVoxelColors();
|
||||
void doTreeStats();
|
||||
|
@ -186,6 +188,8 @@ private slots:
|
|||
glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);
|
||||
void goHome();
|
||||
|
||||
void toggleFollowMode();
|
||||
|
||||
private:
|
||||
|
||||
static void controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes,
|
||||
|
@ -205,7 +209,7 @@ private:
|
|||
void init();
|
||||
|
||||
void update(float deltaTime);
|
||||
bool isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||
Avatar* isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||
glm::vec3& eyePosition, uint16_t& nodeID);
|
||||
|
||||
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);
|
||||
|
@ -222,7 +226,7 @@ private:
|
|||
|
||||
void setupPaintingVoxel();
|
||||
void shiftPaintingColor();
|
||||
void maybeEditVoxelUnderCursor();
|
||||
bool maybeEditVoxelUnderCursor();
|
||||
void deleteVoxelUnderCursor();
|
||||
void eyedropperVoxelUnderCursor();
|
||||
void resetSensors();
|
||||
|
@ -290,6 +294,8 @@ private:
|
|||
|
||||
QAction* _simulateLeapHand; // When there's no Leap, use this to pretend there is one and feed fake hand data
|
||||
QAction* _testRaveGlove; // Test fancy sparkle-rave-glove mode
|
||||
|
||||
QAction* _followMode;
|
||||
|
||||
BandwidthMeter _bandwidthMeter;
|
||||
BandwidthDialog* _bandwidthDialog;
|
||||
|
@ -429,6 +435,8 @@ private:
|
|||
|
||||
ToolsPalette _palette;
|
||||
Swatch _swatch;
|
||||
|
||||
PieMenu _pieMenu;
|
||||
|
||||
VoxelSceneStats _voxelSceneStats;
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@ ParticleSystem::ParticleSystem() {
|
|||
for (unsigned int emitterIndex = 0; emitterIndex < MAX_EMITTERS; emitterIndex++) {
|
||||
|
||||
Emitter * e = &_emitter[emitterIndex];
|
||||
e->active = false;
|
||||
e->position = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
e->previousPosition = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
e->direction = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
|
@ -72,25 +73,16 @@ void ParticleSystem::simulate(float deltaTime) {
|
|||
|
||||
_timer += deltaTime;
|
||||
|
||||
// emit particles
|
||||
for (int e = 0; e < _numEmitters; e++) {
|
||||
// update emitters
|
||||
for (int emitterIndex = 0; emitterIndex < _numEmitters; emitterIndex++) {
|
||||
assert(emitterIndex <= MAX_EMITTERS);
|
||||
|
||||
assert(e >= 0);
|
||||
assert(e <= MAX_EMITTERS);
|
||||
assert(_emitter[e].rate >= 0);
|
||||
|
||||
_emitter[e].emitReserve += _emitter[e].rate * deltaTime;
|
||||
_emitter[e].numParticlesEmittedThisTime = (int)_emitter[e].emitReserve;
|
||||
_emitter[e].emitReserve -= _emitter[e].numParticlesEmittedThisTime;
|
||||
|
||||
for (int p = 0; p < _emitter[e].numParticlesEmittedThisTime; p++) {
|
||||
float timeFraction = (float)p / (float)_emitter[e].numParticlesEmittedThisTime;
|
||||
createParticle(e, timeFraction);
|
||||
if (_emitter[emitterIndex].active) {
|
||||
updateEmitter(emitterIndex, deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
// update particles
|
||||
|
||||
// update particles
|
||||
for (int p = 0; p < MAX_PARTICLES; p++) {
|
||||
if (_particle[p].alive) {
|
||||
if (_particle[p].age > _emitter[_particle[p].emitterIndex].particleLifespan) {
|
||||
|
@ -102,6 +94,20 @@ void ParticleSystem::simulate(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void ParticleSystem::updateEmitter(int emitterIndex, float deltaTime) {
|
||||
|
||||
_emitter[emitterIndex].emitReserve += _emitter[emitterIndex].rate * deltaTime;
|
||||
_emitter[emitterIndex].numParticlesEmittedThisTime = (int)_emitter[emitterIndex].emitReserve;
|
||||
_emitter[emitterIndex].emitReserve -= _emitter[emitterIndex].numParticlesEmittedThisTime;
|
||||
|
||||
for (int p = 0; p < _emitter[emitterIndex].numParticlesEmittedThisTime; p++) {
|
||||
float timeFraction = (float)p / (float)_emitter[emitterIndex].numParticlesEmittedThisTime;
|
||||
createParticle(emitterIndex, timeFraction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ParticleSystem::createParticle(int e, float timeFraction) {
|
||||
|
||||
for (unsigned int p = 0; p < MAX_PARTICLES; p++) {
|
||||
|
@ -212,7 +218,6 @@ void ParticleSystem::setParticleAttributes(int emitterIndex, ParticleLifeStage l
|
|||
}
|
||||
|
||||
|
||||
|
||||
void ParticleSystem::updateParticle(int p, float deltaTime) {
|
||||
|
||||
Emitter myEmitter = _emitter[_particle[p].emitterIndex];
|
||||
|
@ -363,14 +368,16 @@ void ParticleSystem::killAllParticles() {
|
|||
void ParticleSystem::render() {
|
||||
|
||||
// render the emitters
|
||||
for (int e = 0; e < _numEmitters; e++) {
|
||||
for (int e = 0; e < MAX_EMITTERS; e++) {
|
||||
|
||||
if (_emitter[e].showingBaseParticle) {
|
||||
glColor4f(_particle[0].color.r, _particle[0].color.g, _particle[0].color.b, _particle[0].color.a);
|
||||
glPushMatrix();
|
||||
glTranslatef(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z);
|
||||
glutSolidSphere(_particle[0].radius, _emitter[e].particleResolution, _emitter[e].particleResolution);
|
||||
glPopMatrix();
|
||||
if (_emitter[e].active) {
|
||||
if (_emitter[e].showingBaseParticle) {
|
||||
glColor4f(_particle[0].color.r, _particle[0].color.g, _particle[0].color.b, _particle[0].color.a);
|
||||
glPushMatrix();
|
||||
glTranslatef(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z);
|
||||
glutSolidSphere(_particle[0].radius, _emitter[e].particleResolution, _emitter[e].particleResolution);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
if (_emitter[e].visible) {
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
const int MAX_PARTICLES = 5000;
|
||||
const int NULL_EMITTER = -1;
|
||||
const int NULL_PARTICLE = -1;
|
||||
const int MAX_EMITTERS = 100;
|
||||
const int MAX_PARTICLES = 5000;
|
||||
|
||||
enum ParticleRenderStyle
|
||||
{
|
||||
|
@ -78,6 +78,7 @@ public:
|
|||
void setParticleAttributes (int emitterIndex, ParticleAttributes attributes); // set attributes for whole life of particles
|
||||
void setParticleAttributes (int emitterIndex, ParticleLifeStage lifeStage, ParticleAttributes attributes); // set attributes for this life stage
|
||||
void setEmitterPosition (int emitterIndex, glm::vec3 position );
|
||||
void setEmitterActive (int emitterIndex, bool active ) {_emitter[emitterIndex].active = active; }
|
||||
void setEmitterParticleResolution (int emitterIndex, int resolution ) {_emitter[emitterIndex].particleResolution = resolution; }
|
||||
void setEmitterDirection (int emitterIndex, glm::vec3 direction ) {_emitter[emitterIndex].direction = direction; }
|
||||
void setShowingEmitter (int emitterIndex, bool showing ) {_emitter[emitterIndex].visible = showing; }
|
||||
|
@ -101,6 +102,7 @@ private:
|
|||
};
|
||||
|
||||
struct Emitter {
|
||||
bool active; // if false, the emitter is disabled - allows for easy switching on and off
|
||||
glm::vec3 position; // the position of the emitter in world coordinates
|
||||
glm::vec3 previousPosition; // the position of the emitter in the previous time step
|
||||
glm::vec3 direction; // a normalized vector used as an axis for particle emission and other effects
|
||||
|
@ -124,6 +126,7 @@ private:
|
|||
float _timer;
|
||||
|
||||
// private methods
|
||||
void updateEmitter(int emitterIndex, float deltaTime);
|
||||
void updateParticle(int index, float deltaTime);
|
||||
void createParticle(int e, float timeFraction);
|
||||
void killParticle(int p);
|
||||
|
|
138
interface/src/PieMenu.cpp
Normal file
138
interface/src/PieMenu.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
//
|
||||
// PieMenu.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Clement Brisset on 7/18/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "PieMenu.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QAction>
|
||||
#include <QSvgRenderer>
|
||||
#include <QPainter>
|
||||
#include <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
PieMenu::PieMenu() :
|
||||
_radiusIntern(30),
|
||||
_radiusExtern(70),
|
||||
_magnification(1.2f),
|
||||
_isDisplayed(false) {
|
||||
}
|
||||
|
||||
void PieMenu::init(const char *fileName, int screenWidth, int screenHeight) {
|
||||
// Load SVG
|
||||
switchToResourcesParentIfRequired();
|
||||
QSvgRenderer renderer((QString) QString(fileName));
|
||||
|
||||
// Prepare a QImage with desired characteritisc
|
||||
QImage image(2 * _radiusExtern, 2 * _radiusExtern, QImage::Format_ARGB32);
|
||||
image.fill(0x0);
|
||||
|
||||
// Get QPainter that paints to the image
|
||||
QPainter painter(&image);
|
||||
renderer.render(&painter);
|
||||
|
||||
//get the OpenGL-friendly image
|
||||
_textureImage = QGLWidget::convertToGLFormat(image);
|
||||
|
||||
glGenTextures(1, &_textureID);
|
||||
glBindTexture(GL_TEXTURE_2D, _textureID);
|
||||
|
||||
//generate the texture
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
|
||||
_textureImage.width(),
|
||||
_textureImage.height(),
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
_textureImage.bits());
|
||||
|
||||
//texture parameters
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
|
||||
void PieMenu::addAction(QAction* action){
|
||||
_actions.push_back(action);
|
||||
}
|
||||
|
||||
void PieMenu::render() {
|
||||
if (_actions.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
float start = M_PI / 2.0f;
|
||||
float end = start + 2.0f * M_PI;
|
||||
float step = 2.0f * M_PI / 100.0f;
|
||||
float distance = sqrt((_mouseX - _x) * (_mouseX - _x) +
|
||||
(_mouseY - _y) * (_mouseY - _y));
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, _textureID);
|
||||
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
|
||||
if (_radiusIntern < distance) {
|
||||
float angle = atan2((_mouseY - _y), (_mouseX - _x)) - start;
|
||||
angle = (0.0f < angle) ? angle : angle + 2.0f * M_PI;
|
||||
|
||||
_selectedAction = floor(angle / (2.0f * M_PI / _actions.size()));
|
||||
|
||||
start = start + _selectedAction * 2.0f * M_PI / _actions.size();
|
||||
end = start + 2.0f * M_PI / _actions.size();
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glTexCoord2f(0.5f, 0.5f);
|
||||
glVertex2f(_x, _y);
|
||||
for (float i = start; i < end; i += step) {
|
||||
glTexCoord2f(0.5f + 0.5f * cos(i), 0.5f - 0.5f * sin(i));
|
||||
glVertex2f(_x + _magnification * _radiusExtern * cos(i),
|
||||
_y + _magnification * _radiusExtern * sin(i));
|
||||
}
|
||||
glTexCoord2f(0.5f + 0.5f * cos(end), 0.5f + - 0.5f * sin(end));
|
||||
glVertex2f(_x + _magnification * _radiusExtern * cos(end),
|
||||
_y + _magnification * _radiusExtern * sin(end));
|
||||
glEnd();
|
||||
} else {
|
||||
_selectedAction = -1;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(_x + _radiusExtern, _y - _radiusExtern);
|
||||
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex2f(_x + _radiusExtern, _y + _radiusExtern);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(_x - _radiusExtern, _y + _radiusExtern);
|
||||
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex2f(_x - _radiusExtern, _y - _radiusExtern);
|
||||
glEnd();
|
||||
}
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void PieMenu::resize(int screenWidth, int screenHeight) {
|
||||
}
|
||||
|
||||
void PieMenu::mouseMoveEvent(int x, int y) {
|
||||
_mouseX = x;
|
||||
_mouseY = y;
|
||||
}
|
||||
|
||||
void PieMenu::mousePressEvent(int x, int y) {
|
||||
_x = _mouseX = x;
|
||||
_y = _mouseY = y;
|
||||
_selectedAction = -1;
|
||||
_isDisplayed = true;
|
||||
}
|
||||
|
||||
void PieMenu::mouseReleaseEvent(int x, int y) {
|
||||
if (0 <= _selectedAction && _selectedAction < _actions.size() && _actions[_selectedAction]) {
|
||||
_actions[_selectedAction]->trigger();
|
||||
}
|
||||
|
||||
_isDisplayed = false;
|
||||
}
|
59
interface/src/PieMenu.h
Normal file
59
interface/src/PieMenu.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// PieMenu.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Clement Brisset on 7/18/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__PieMenu__
|
||||
#define __hifi__PieMenu__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <QImage>
|
||||
|
||||
class QAction;
|
||||
|
||||
class PieMenu {
|
||||
public:
|
||||
PieMenu();
|
||||
|
||||
void init(const char* fileName, int screenWidth, int screenHeight);
|
||||
void addAction(QAction* action);
|
||||
void render();
|
||||
void resize(int screenWidth, int screenHeight);
|
||||
|
||||
bool isDisplayed() const {return _isDisplayed;}
|
||||
int getX () const {return _x;}
|
||||
int getY () const {return _y;}
|
||||
|
||||
void mouseMoveEvent (int x, int y);
|
||||
void mousePressEvent (int x, int y);
|
||||
void mouseReleaseEvent(int x, int y);
|
||||
|
||||
private:
|
||||
QImage _textureImage;
|
||||
GLuint _textureID;
|
||||
|
||||
// position of the menu
|
||||
int _x;
|
||||
int _y;
|
||||
int _radiusIntern;
|
||||
int _radiusExtern;
|
||||
float _magnification;
|
||||
|
||||
int _mouseX;
|
||||
int _mouseY;
|
||||
|
||||
int _selectedAction;
|
||||
|
||||
bool _isDisplayed;
|
||||
|
||||
std::vector<QAction*> _actions;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__PieMenu__) */
|
|
@ -23,6 +23,8 @@
|
|||
#include <PacketHeaders.h>
|
||||
#include <PerfStat.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <NodeList.h>
|
||||
#include <NodeTypes.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "CoverageMap.h"
|
||||
|
@ -61,6 +63,8 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) :
|
|||
|
||||
VoxelNode::addDeleteHook(this);
|
||||
_abandonedVBOSlots = 0;
|
||||
_falseColorizeBySource = false;
|
||||
_dataSourceID = UNKNOWN_NODE_ID;
|
||||
}
|
||||
|
||||
void VoxelSystem::nodeDeleted(VoxelNode* node) {
|
||||
|
@ -153,13 +157,15 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
case PACKET_TYPE_VOXEL_DATA: {
|
||||
PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()");
|
||||
// ask the VoxelTree to read the bitstream into the tree
|
||||
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, WANT_COLOR, WANT_EXISTS_BITS);
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID());
|
||||
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
|
||||
}
|
||||
break;
|
||||
case PACKET_TYPE_VOXEL_DATA_MONOCHROME: {
|
||||
PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()");
|
||||
// ask the VoxelTree to read the MONOCHROME bitstream into the tree
|
||||
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, NO_COLOR, WANT_EXISTS_BITS);
|
||||
ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID());
|
||||
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
|
||||
}
|
||||
break;
|
||||
case PACKET_TYPE_Z_COMMAND:
|
||||
|
@ -747,6 +753,7 @@ void VoxelSystem::randomizeVoxelColors() {
|
|||
_nodeCount = 0;
|
||||
_tree->recurseTreeWithOperation(randomColorOperation);
|
||||
qDebug("setting randomized true color for %d nodes\n", _nodeCount);
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
@ -761,6 +768,7 @@ void VoxelSystem::falseColorizeRandom() {
|
|||
_nodeCount = 0;
|
||||
_tree->recurseTreeWithOperation(falseColorizeRandomOperation);
|
||||
qDebug("setting randomized false color for %d nodes\n", _nodeCount);
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
@ -775,6 +783,7 @@ void VoxelSystem::trueColorize() {
|
|||
_nodeCount = 0;
|
||||
_tree->recurseTreeWithOperation(trueColorizeOperation);
|
||||
qDebug("setting true color for %d nodes\n", _nodeCount);
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
@ -795,6 +804,80 @@ void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) {
|
|||
_nodeCount = 0;
|
||||
_tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);
|
||||
qDebug("setting in view false color for %d nodes\n", _nodeCount);
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
// helper classes and args for falseColorizeBySource
|
||||
class groupColor {
|
||||
public:
|
||||
unsigned char red, green, blue;
|
||||
groupColor(unsigned char red, unsigned char green, unsigned char blue) :
|
||||
red(red), green(green), blue(blue) { };
|
||||
|
||||
groupColor() :
|
||||
red(0), green(0), blue(0) { };
|
||||
};
|
||||
|
||||
class colorizeBySourceArgs {
|
||||
public:
|
||||
std::map<uint16_t, groupColor> colors;
|
||||
};
|
||||
|
||||
// Will false colorize voxels that are not in view
|
||||
bool VoxelSystem::falseColorizeBySourceOperation(VoxelNode* node, void* extraData) {
|
||||
colorizeBySourceArgs* args = (colorizeBySourceArgs*)extraData;
|
||||
_nodeCount++;
|
||||
if (node->isColored()) {
|
||||
// pick a color based on the source - we want each source to be obviously different
|
||||
uint16_t nodeID = node->getSourceID();
|
||||
|
||||
//printf("false colorizing from source %d, color: %d, %d, %d\n", nodeID,
|
||||
// args->colors[nodeID].red, args->colors[nodeID].green, args->colors[nodeID].blue);
|
||||
|
||||
node->setFalseColor(args->colors[nodeID].red, args->colors[nodeID].green, args->colors[nodeID].blue);
|
||||
}
|
||||
return true; // keep going!
|
||||
}
|
||||
|
||||
void VoxelSystem::falseColorizeBySource() {
|
||||
_nodeCount = 0;
|
||||
colorizeBySourceArgs args;
|
||||
const int NUMBER_OF_COLOR_GROUPS = 3;
|
||||
const unsigned char MIN_COLOR = 128;
|
||||
int voxelServerCount = 0;
|
||||
groupColor groupColors[NUMBER_OF_COLOR_GROUPS] = { groupColor(255, 0, 0),
|
||||
groupColor(0, 255, 0),
|
||||
groupColor(0, 0, 255)};
|
||||
|
||||
// create a bunch of colors we'll use during colorization
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||
uint16_t nodeID = node->getNodeID();
|
||||
int groupColor = voxelServerCount % NUMBER_OF_COLOR_GROUPS;
|
||||
args.colors[nodeID] = groupColors[groupColor];
|
||||
|
||||
//printf("assigning color for source %d, color: %d, %d, %d\n", nodeID,
|
||||
// args.colors[nodeID].red, args.colors[nodeID].green, args.colors[nodeID].blue);
|
||||
|
||||
if (groupColors[groupColor].red > 0) {
|
||||
groupColors[groupColor].red = ((groupColors[groupColor].red - MIN_COLOR)/2) + MIN_COLOR;
|
||||
}
|
||||
if (groupColors[groupColor].green > 0) {
|
||||
groupColors[groupColor].green = ((groupColors[groupColor].green - MIN_COLOR)/2) + MIN_COLOR;
|
||||
}
|
||||
if (groupColors[groupColor].blue > 0) {
|
||||
groupColors[groupColor].blue = ((groupColors[groupColor].blue - MIN_COLOR)/2) + MIN_COLOR;
|
||||
}
|
||||
|
||||
voxelServerCount++;
|
||||
}
|
||||
}
|
||||
|
||||
_tree->recurseTreeWithOperation(falseColorizeBySourceOperation, &args);
|
||||
qDebug("setting false color by source for %d nodes\n", _nodeCount);
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
@ -848,6 +931,7 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) {
|
|||
_nodeCount = 0;
|
||||
_tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);
|
||||
qDebug("setting in distance false color for %d nodes\n", _nodeCount);
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
@ -1027,6 +1111,7 @@ void VoxelSystem::falseColorizeRandomEveryOther() {
|
|||
_tree->recurseTreeWithOperation(falseColorizeRandomEveryOtherOperation,&args);
|
||||
qDebug("randomized false color for every other node: total %ld, colorable %ld, colored %ld\n",
|
||||
args.totalNodes, args.colorableNodes, args.coloredNodes);
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
@ -1331,6 +1416,7 @@ void VoxelSystem::falseColorizeOccluded() {
|
|||
|
||||
//myCoverageMap.erase();
|
||||
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
@ -1447,6 +1533,7 @@ void VoxelSystem::falseColorizeOccludedV2() {
|
|||
//myCoverageMapV2.erase();
|
||||
|
||||
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@ public:
|
|||
VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = MAX_VOXELS_PER_SYSTEM);
|
||||
~VoxelSystem();
|
||||
|
||||
void setDataSourceID(int dataSourceID) { _dataSourceID = dataSourceID; };
|
||||
int getDataSourceID() const { return _dataSourceID; };
|
||||
|
||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||
|
||||
virtual void init();
|
||||
|
@ -62,6 +65,8 @@ public:
|
|||
void falseColorizeRandomEveryOther();
|
||||
void falseColorizeOccluded();
|
||||
void falseColorizeOccludedV2();
|
||||
void falseColorizeBySource();
|
||||
|
||||
|
||||
void killLocalVoxels();
|
||||
void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; };
|
||||
|
@ -94,7 +99,7 @@ public:
|
|||
CoverageMap myCoverageMap;
|
||||
|
||||
virtual void nodeDeleted(VoxelNode* node);
|
||||
|
||||
|
||||
protected:
|
||||
float _treeScale;
|
||||
int _maxVoxels;
|
||||
|
@ -134,7 +139,7 @@ private:
|
|||
static bool falseColorizeOccludedOperation(VoxelNode* node, void* extraData);
|
||||
static bool falseColorizeSubTreeOperation(VoxelNode* node, void* extraData);
|
||||
static bool falseColorizeOccludedV2Operation(VoxelNode* node, void* extraData);
|
||||
|
||||
static bool falseColorizeBySourceOperation(VoxelNode* node, void* extraData);
|
||||
|
||||
int updateNodeInArraysAsFullVBO(VoxelNode* node);
|
||||
int updateNodeInArraysAsPartialVBO(VoxelNode* node);
|
||||
|
@ -195,6 +200,9 @@ private:
|
|||
|
||||
void freeBufferIndex(glBufferIndex index);
|
||||
void clearFreeBufferIndexes();
|
||||
|
||||
bool _falseColorizeBySource;
|
||||
int _dataSourceID;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,7 +33,7 @@ int jointVectorMetaType = qRegisterMetaType<JointVector>("JointVector");
|
|||
int matMetaType = qRegisterMetaType<Mat>("cv::Mat");
|
||||
int rotatedRectMetaType = qRegisterMetaType<RotatedRect>("cv::RotatedRect");
|
||||
|
||||
Webcam::Webcam() : _enabled(false), _active(false), _colorTextureID(0), _depthTextureID(0) {
|
||||
Webcam::Webcam() : _enabled(false), _active(false), _colorTextureID(0), _depthTextureID(0), _skeletonTrackingOn(false) {
|
||||
// the grabber simply runs as fast as possible
|
||||
_grabber = new FrameGrabber();
|
||||
_grabber->moveToThread(&_grabberThread);
|
||||
|
@ -197,7 +197,7 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF
|
|||
_aspectRatio = aspectRatio;
|
||||
_faceRect = faceRect;
|
||||
_sending = sending;
|
||||
_joints = joints;
|
||||
_joints = _skeletonTrackingOn ? joints : JointVector();
|
||||
_frameCount++;
|
||||
|
||||
const int MAX_FPS = 60;
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
FrameGrabber* getGrabber() { return _grabber; }
|
||||
|
||||
bool isActive() const { return _active; }
|
||||
|
||||
bool isSending() const { return _sending; }
|
||||
|
||||
GLuint getColorTextureID() const { return _colorTextureID; }
|
||||
|
@ -62,13 +63,14 @@ public:
|
|||
const JointVector& getEstimatedJoints() const { return _estimatedJoints; }
|
||||
|
||||
void reset();
|
||||
void renderPreview(int screenWidth, int screenHeight);
|
||||
void renderPreview(int screenWidth, int screenHeight);
|
||||
|
||||
public slots:
|
||||
|
||||
void setEnabled(bool enabled);
|
||||
void setFrame(const cv::Mat& color, int format, const cv::Mat& depth, float midFaceDepth,
|
||||
float aspectRatio, const cv::RotatedRect& faceRect, bool sending, const JointVector& joints);
|
||||
void setSkeletonTrackingOn(bool toggle) { _skeletonTrackingOn = toggle; };
|
||||
|
||||
private:
|
||||
|
||||
|
@ -95,6 +97,8 @@ private:
|
|||
glm::vec3 _estimatedPosition;
|
||||
glm::vec3 _estimatedRotation;
|
||||
JointVector _estimatedJoints;
|
||||
|
||||
bool _skeletonTrackingOn;
|
||||
};
|
||||
|
||||
class FrameGrabber : public QObject {
|
||||
|
|
|
@ -101,7 +101,8 @@ Avatar::Avatar(Node* owningNode) :
|
|||
_lastCollisionPosition(0, 0, 0),
|
||||
_speedBrakes(false),
|
||||
_isThrustOn(false),
|
||||
_voxels(this)
|
||||
_voxels(this),
|
||||
_leadingAvatar(NULL)
|
||||
{
|
||||
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||
_headData = &_head;
|
||||
|
@ -404,6 +405,33 @@ void Avatar::updateThrust(float deltaTime, Transmitter * transmitter) {
|
|||
_thrust += _scale * THRUST_JUMP * up;
|
||||
_shouldJump = false;
|
||||
}
|
||||
|
||||
// Add thrusts from leading avatar
|
||||
if (_leadingAvatar != NULL) {
|
||||
glm::vec3 toTarget = _leadingAvatar->getPosition() - _position;
|
||||
|
||||
if (.5f < up.x * toTarget.x + up.y * toTarget.y + up.z * toTarget.z) {
|
||||
_thrust += _scale * THRUST_MAG_UP * deltaTime * up;
|
||||
} else if (up.x * toTarget.x + up.y * toTarget.y + up.z * toTarget.z < -.5f) {
|
||||
_thrust -= _scale * THRUST_MAG_UP * deltaTime * up;
|
||||
}
|
||||
|
||||
if (glm::length(_position - _leadingAvatar->getPosition()) > _scale * _stringLength) {
|
||||
_thrust += _scale * THRUST_MAG_FWD * deltaTime * front;
|
||||
} else {
|
||||
toTarget = _leadingAvatar->getHead().getLookAtPosition() - _position;
|
||||
getHead().setLookAtPosition(_leadingAvatar->getHead().getLookAtPosition());
|
||||
}
|
||||
|
||||
float yawAngle = angleBetween(front, glm::vec3(toTarget.x, 0.f, toTarget.z));
|
||||
if (yawAngle < -10.f || 10.f < yawAngle){
|
||||
if (right.x * toTarget.x + right.y * toTarget.y + right.z * toTarget.z > 0) {
|
||||
_bodyYawDelta -= YAW_MAG * deltaTime;
|
||||
} else {
|
||||
_bodyYawDelta += YAW_MAG * deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add thrusts from Transmitter
|
||||
if (transmitter) {
|
||||
|
@ -447,6 +475,18 @@ void Avatar::updateThrust(float deltaTime, Transmitter * transmitter) {
|
|||
_isThrustOn = (glm::length(_thrust) > EPSILON);
|
||||
}
|
||||
|
||||
void Avatar::follow(Avatar* leadingAvatar) {
|
||||
const float MAX_STRING_LENGTH = 2;
|
||||
|
||||
_leadingAvatar = leadingAvatar;
|
||||
if (_leadingAvatar != NULL) {
|
||||
_stringLength = glm::length(_position - _leadingAvatar->getPosition()) / _scale;
|
||||
if (_stringLength > MAX_STRING_LENGTH) {
|
||||
_stringLength = MAX_STRING_LENGTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||
|
||||
glm::quat orientation = getOrientation();
|
||||
|
@ -475,6 +515,13 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
|||
if (isMyAvatar()) {
|
||||
updateThrust(deltaTime, transmitter);
|
||||
}
|
||||
|
||||
// Ajust, scale, thrust and lookAt position when following an other avatar
|
||||
if (isMyAvatar() && _leadingAvatar && _scale != _leadingAvatar->getScale()) {
|
||||
float scale = 0.95f * _scale + 0.05f * _leadingAvatar->getScale();
|
||||
setScale(scale);
|
||||
Application::getInstance()->getCamera()->setScale(scale);
|
||||
}
|
||||
|
||||
// copy velocity so we can use it later for acceleration
|
||||
glm::vec3 oldVelocity = getVelocity();
|
||||
|
@ -681,7 +728,9 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
|||
_head.setScale(_scale);
|
||||
_head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]));
|
||||
_head.simulate(deltaTime, isMyAvatar());
|
||||
|
||||
|
||||
|
||||
|
||||
// use speed and angular velocity to determine walking vs. standing
|
||||
if (_speed + fabs(_bodyYawDelta) > 0.2) {
|
||||
_mode = AVATAR_MODE_WALKING;
|
||||
|
|
|
@ -114,6 +114,7 @@ public:
|
|||
void reset();
|
||||
void simulate(float deltaTime, Transmitter* transmitter);
|
||||
void updateThrust(float deltaTime, Transmitter * transmitter);
|
||||
void follow(Avatar* leadingAvatar);
|
||||
void updateFromGyrosAndOrWebcam(bool gyroLook,
|
||||
const glm::vec3& amplifyAngle,
|
||||
float yawFromTouch,
|
||||
|
@ -157,18 +158,16 @@ public:
|
|||
float getElapsedTimeMoving () const { return _elapsedTimeMoving;}
|
||||
float getElapsedTimeSinceCollision() const { return _elapsedTimeSinceCollision;}
|
||||
const glm::vec3& getLastCollisionPosition () const { return _lastCollisionPosition;}
|
||||
float getAbsoluteHeadYaw () const;
|
||||
float getAbsoluteHeadPitch () const;
|
||||
Head& getHead () {return _head; }
|
||||
Hand& getHand () {return _hand; }
|
||||
glm::quat getOrientation () const;
|
||||
glm::quat getWorldAlignedOrientation() const;
|
||||
|
||||
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
||||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||
|
||||
|
||||
glm::vec3 getGravity () const { return _gravity; }
|
||||
float getAbsoluteHeadYaw () const;
|
||||
float getAbsoluteHeadPitch () const;
|
||||
Head& getHead () {return _head; }
|
||||
Hand& getHand () {return _hand; }
|
||||
glm::quat getOrientation () const;
|
||||
glm::quat getWorldAlignedOrientation() const;
|
||||
const glm::vec3& getMouseRayOrigin () const { return _mouseRayOrigin; }
|
||||
const glm::vec3& getMouseRayDirection () const { return _mouseRayDirection; }
|
||||
Avatar* getLeadingAvatar () const { return _leadingAvatar; }
|
||||
glm::vec3 getGravity () const { return _gravity; }
|
||||
|
||||
glm::vec3 getUprightHeadPosition() const;
|
||||
glm::vec3 getUprightEyeLevelPosition() const;
|
||||
|
@ -255,7 +254,10 @@ private:
|
|||
glm::vec3 _lastCollisionPosition;
|
||||
bool _speedBrakes;
|
||||
bool _isThrustOn;
|
||||
|
||||
|
||||
Avatar* _leadingAvatar;
|
||||
float _stringLength;
|
||||
|
||||
AvatarVoxelSystem _voxels;
|
||||
|
||||
// private methods...
|
||||
|
|
|
@ -250,7 +250,8 @@ void AvatarVoxelSystem::handleVoxelDownloadProgress(qint64 bytesReceived, qint64
|
|||
_voxelReply->deleteLater();
|
||||
_voxelReply = 0;
|
||||
|
||||
_tree->readBitstreamToTree((unsigned char*)entirety.data(), entirety.size(), WANT_COLOR, NO_EXISTS_BITS);
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS);
|
||||
_tree->readBitstreamToTree((unsigned char*)entirety.data(), entirety.size(), args);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "Util.h"
|
||||
#include "renderer/ProgramObject.h"
|
||||
|
||||
const bool SHOW_LEAP_HAND = true;
|
||||
const bool SHOW_LEAP_HAND = false;
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -51,6 +51,7 @@ void Hand::reset() {
|
|||
|
||||
|
||||
void Hand::simulate(float deltaTime, bool isMine) {
|
||||
|
||||
if (_isRaveGloveActive) {
|
||||
updateRaveGloveParticles(deltaTime);
|
||||
}
|
||||
|
@ -63,7 +64,8 @@ void Hand::calculateGeometry() {
|
|||
_basePosition = head.getPosition() + head.getOrientation() * offset;
|
||||
_baseOrientation = head.getOrientation();
|
||||
|
||||
_leapBalls.clear();
|
||||
// generate finger tip balls....
|
||||
_leapFingerTipBalls.clear();
|
||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||
PalmData& palm = getPalms()[i];
|
||||
if (palm.isActive()) {
|
||||
|
@ -71,8 +73,8 @@ void Hand::calculateGeometry() {
|
|||
FingerData& finger = palm.getFingers()[f];
|
||||
if (finger.isActive()) {
|
||||
const float standardBallRadius = 0.01f;
|
||||
_leapBalls.resize(_leapBalls.size() + 1);
|
||||
HandBall& ball = _leapBalls.back();
|
||||
_leapFingerTipBalls.resize(_leapFingerTipBalls.size() + 1);
|
||||
HandBall& ball = _leapFingerTipBalls.back();
|
||||
ball.rotation = _baseOrientation;
|
||||
ball.position = finger.getTipPosition();
|
||||
ball.radius = standardBallRadius;
|
||||
|
@ -82,6 +84,27 @@ void Hand::calculateGeometry() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generate finger rot balls....
|
||||
_leapFingerRootBalls.clear();
|
||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||
PalmData& palm = getPalms()[i];
|
||||
if (palm.isActive()) {
|
||||
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
||||
FingerData& finger = palm.getFingers()[f];
|
||||
if (finger.isActive()) {
|
||||
const float standardBallRadius = 0.01f;
|
||||
_leapFingerRootBalls.resize(_leapFingerRootBalls.size() + 1);
|
||||
HandBall& ball = _leapFingerRootBalls.back();
|
||||
ball.rotation = _baseOrientation;
|
||||
ball.position = finger.getRootPosition();
|
||||
ball.radius = standardBallRadius;
|
||||
ball.touchForce = 0.0;
|
||||
ball.isCollidable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hand::setRaveGloveEffectsMode(QKeyEvent* event) {
|
||||
|
@ -120,8 +143,9 @@ void Hand::render(bool lookingInMirror) {
|
|||
glEnable(GL_RESCALE_NORMAL);
|
||||
|
||||
if ( SHOW_LEAP_HAND ) {
|
||||
renderFingerTrails();
|
||||
renderHandSpheres();
|
||||
//renderLeapHands();
|
||||
renderLeapFingerTrails();
|
||||
renderLeapHandSpheres();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,18 +177,64 @@ void Hand::renderRaveGloveStage() {
|
|||
}
|
||||
}
|
||||
|
||||
void Hand::renderHandSpheres() {
|
||||
|
||||
void Hand::renderLeapHands() {
|
||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||
PalmData& hand = getPalms()[i];
|
||||
if (hand.isActive()) {
|
||||
renderLeapHand(hand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hand::renderLeapHand(PalmData& hand) {
|
||||
|
||||
glPushMatrix();
|
||||
const float palmThickness = 0.002f;
|
||||
glColor4f(0.5f, 0.5f, 0.5f, 1.0);
|
||||
glm::vec3 tip = hand.getPosition();
|
||||
glm::vec3 root = hand.getPosition() + hand.getNormal() * palmThickness;
|
||||
Avatar::renderJointConnectingCone(root, tip, 0.05, 0.03);
|
||||
|
||||
for (size_t f = 0; f < hand.getNumFingers(); ++f) {
|
||||
FingerData& finger = hand.getFingers()[f];
|
||||
if (finger.isActive()) {
|
||||
glColor4f(_ballColor.r, _ballColor.g, _ballColor.b, 0.5);
|
||||
glm::vec3 tip = finger.getTipPosition();
|
||||
glm::vec3 root = finger.getRootPosition();
|
||||
Avatar::renderJointConnectingCone(root, tip, 0.001, 0.003);
|
||||
}
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void Hand::renderLeapHandSpheres() {
|
||||
glPushMatrix();
|
||||
// Draw the leap balls
|
||||
for (size_t i = 0; i < _leapBalls.size(); i++) {
|
||||
for (size_t i = 0; i < _leapFingerTipBalls.size(); i++) {
|
||||
float alpha = 1.0f;
|
||||
|
||||
if (alpha > 0.0f) {
|
||||
glColor4f(_ballColor.r, _ballColor.g, _ballColor.b, alpha);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(_leapBalls[i].position.x, _leapBalls[i].position.y, _leapBalls[i].position.z);
|
||||
glutSolidSphere(_leapBalls[i].radius, 20.0f, 20.0f);
|
||||
glTranslatef(_leapFingerTipBalls[i].position.x, _leapFingerTipBalls[i].position.y, _leapFingerTipBalls[i].position.z);
|
||||
glutSolidSphere(_leapFingerTipBalls[i].radius, 20.0f, 20.0f);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _leapFingerRootBalls.size(); i++) {
|
||||
float alpha = 1.0f;
|
||||
|
||||
if (alpha > 0.0f) {
|
||||
glColor4f(0.3f, 0.4f, 0.6f, alpha);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(_leapFingerRootBalls[i].position.x, _leapFingerRootBalls[i].position.y, _leapFingerRootBalls[i].position.z);
|
||||
glutSolidSphere(_leapFingerRootBalls[i].radius, 20.0f, 20.0f);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +270,7 @@ void Hand::renderHandSpheres() {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
void Hand::renderFingerTrails() {
|
||||
void Hand::renderLeapFingerTrails() {
|
||||
// Draw the finger root cones
|
||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||
PalmData& palm = getPalms()[i];
|
||||
|
@ -229,6 +299,7 @@ void Hand::renderFingerTrails() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void Hand::setLeapHands(const std::vector<glm::vec3>& handPositions,
|
||||
const std::vector<glm::vec3>& handNormals) {
|
||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||
|
@ -244,69 +315,28 @@ void Hand::setLeapHands(const std::vector<glm::vec3>& handPositions,
|
|||
}
|
||||
}
|
||||
|
||||
// call this right after the geometry of the leap hands are set
|
||||
|
||||
// call this soon after the geometry of the leap hands are set
|
||||
void Hand::updateRaveGloveEmitters() {
|
||||
|
||||
bool debug = false;
|
||||
for (size_t i = 0; i < NUM_FINGERS; i++) {
|
||||
_raveGloveParticleSystem.setEmitterActive(_raveGloveEmitter[i], false);
|
||||
}
|
||||
|
||||
if (_raveGloveInitialized) {
|
||||
|
||||
if(debug) printf( "\n" );
|
||||
if(debug) printf( "------------------------------------\n" );
|
||||
if(debug) printf( "updating rave glove emitters:\n" );
|
||||
if(debug) printf( "------------------------------------\n" );
|
||||
|
||||
int emitterIndex = 0;
|
||||
|
||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||
PalmData& palm = getPalms()[i];
|
||||
for (size_t i = 0; i < _leapFingerTipBalls.size(); i++) {
|
||||
if (i < NUM_FINGERS) {
|
||||
glm::vec3 fingerDirection = _leapFingerTipBalls[i].position - _leapFingerRootBalls[i].position;
|
||||
float fingerLength = glm::length(fingerDirection);
|
||||
|
||||
if(debug) printf( "\n" );
|
||||
if(debug) printf( "palm %d ", (int)i );
|
||||
|
||||
if (palm.isActive()) {
|
||||
|
||||
if(debug) printf( "is active\n" );
|
||||
|
||||
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
||||
FingerData& finger = palm.getFingers()[f];
|
||||
|
||||
if(debug) printf( "emitterIndex %d: ", emitterIndex );
|
||||
|
||||
if (finger.isActive()) {
|
||||
|
||||
if ((emitterIndex >=0)
|
||||
&& (emitterIndex < NUM_FINGERS)) {
|
||||
|
||||
assert(emitterIndex >=0 );
|
||||
assert(emitterIndex < NUM_FINGERS );
|
||||
|
||||
if(debug) printf( "_raveGloveEmitter[%d] = %d\n", emitterIndex, _raveGloveEmitter[emitterIndex] );
|
||||
|
||||
glm::vec3 fingerDirection = finger.getTipPosition() - finger.getRootPosition();
|
||||
float fingerLength = glm::length(fingerDirection);
|
||||
|
||||
if (fingerLength > 0.0f) {
|
||||
fingerDirection /= fingerLength;
|
||||
} else {
|
||||
fingerDirection = IDENTITY_UP;
|
||||
}
|
||||
|
||||
assert(_raveGloveEmitter[emitterIndex] >=0 );
|
||||
assert(_raveGloveEmitter[emitterIndex] < NUM_FINGERS );
|
||||
|
||||
_raveGloveParticleSystem.setEmitterPosition (_raveGloveEmitter[emitterIndex], finger.getTipPosition());
|
||||
_raveGloveParticleSystem.setEmitterDirection(_raveGloveEmitter[emitterIndex], fingerDirection);
|
||||
}
|
||||
} else {
|
||||
if(debug) printf( "BOGUS finger\n" );
|
||||
}
|
||||
|
||||
emitterIndex ++;
|
||||
}
|
||||
if (fingerLength > 0.0f) {
|
||||
fingerDirection /= fingerLength;
|
||||
} else {
|
||||
if(debug) printf( "is NOT active\n" );
|
||||
fingerDirection = IDENTITY_UP;
|
||||
}
|
||||
|
||||
_raveGloveParticleSystem.setEmitterActive (_raveGloveEmitter[i], true);
|
||||
_raveGloveParticleSystem.setEmitterPosition (_raveGloveEmitter[i], _leapFingerTipBalls[i].position);
|
||||
_raveGloveParticleSystem.setEmitterDirection(_raveGloveEmitter[i], fingerDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -317,16 +347,11 @@ void Hand::updateRaveGloveParticles(float deltaTime) {
|
|||
|
||||
if (!_raveGloveInitialized) {
|
||||
|
||||
//printf( "Initializing rave glove emitters:\n" );
|
||||
//printf( "The indices of the emitters are:\n" );
|
||||
|
||||
// start up the rave glove finger particles...
|
||||
for ( int f = 0; f< NUM_FINGERS; f ++ ) {
|
||||
_raveGloveEmitter[f] = _raveGloveParticleSystem.addEmitter();
|
||||
_raveGloveEmitter[f] = _raveGloveParticleSystem.addEmitter();
|
||||
assert( _raveGloveEmitter[f] >= 0 );
|
||||
assert( _raveGloveEmitter[f] != NULL_EMITTER );
|
||||
|
||||
//printf( "%d\n", _raveGloveEmitter[f] );
|
||||
}
|
||||
|
||||
setRaveGloveMode(RAVE_GLOVE_EFFECTS_MODE_FIRE);
|
||||
|
@ -339,13 +364,13 @@ void Hand::updateRaveGloveParticles(float deltaTime) {
|
|||
// this rave glove effect oscillates though various colors and radii that are meant to show off some effects
|
||||
if (_raveGloveMode == RAVE_GLOVE_EFFECTS_MODE_THROBBING_COLOR) {
|
||||
ParticleSystem::ParticleAttributes attributes;
|
||||
float red = 0.5f + 0.5f * sinf(_raveGloveClock * 1.4f);
|
||||
float green = 0.5f + 0.5f * cosf(_raveGloveClock * 1.7f);
|
||||
float blue = 0.5f + 0.5f * sinf(_raveGloveClock * 2.0f);
|
||||
float red = 0.5f + 0.5f * sinf(_raveGloveClock * 2.4f);
|
||||
float green = 0.5f + 0.5f * cosf(_raveGloveClock * 2.7f);
|
||||
float blue = 0.5f + 0.5f * sinf(_raveGloveClock * 3.0f);
|
||||
float alpha = 1.0f;
|
||||
|
||||
attributes.color = glm::vec4(red, green, blue, alpha);
|
||||
attributes.radius = 0.01f + 0.005f * sinf(_raveGloveClock * 2.2f);
|
||||
attributes.radius = 0.01f + 0.003f * sinf(_raveGloveClock * 50.0f);
|
||||
attributes.modulationAmplitude = 0.0f;
|
||||
|
||||
for ( int f = 0; f< NUM_FINGERS; f ++ ) {
|
||||
|
@ -360,6 +385,8 @@ void Hand::updateRaveGloveParticles(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Hand::setRaveGloveMode(int mode) {
|
||||
|
||||
_raveGloveMode = mode;
|
||||
|
@ -376,7 +403,7 @@ void Hand::setRaveGloveMode(int mode) {
|
|||
if (mode == RAVE_GLOVE_EFFECTS_MODE_THROBBING_COLOR) {
|
||||
_raveGloveParticleSystem.setParticleRenderStyle (_raveGloveEmitter[f], PARTICLE_RENDER_STYLE_SPHERE );
|
||||
_raveGloveParticleSystem.setShowingEmitterBaseParticle(_raveGloveEmitter[f], true );
|
||||
_raveGloveParticleSystem.setEmitterParticleLifespan (_raveGloveEmitter[f], 0.0f );
|
||||
_raveGloveParticleSystem.setEmitterParticleLifespan (_raveGloveEmitter[f], 0.03f );
|
||||
_raveGloveParticleSystem.setEmitterThrust (_raveGloveEmitter[f], 0.0f );
|
||||
_raveGloveParticleSystem.setEmitterRate (_raveGloveEmitter[f], 30.0f );
|
||||
_raveGloveParticleSystem.setEmitterParticleResolution (_raveGloveEmitter[f], 20 );
|
||||
|
@ -650,7 +677,7 @@ void Hand::setRaveGloveMode(int mode) {
|
|||
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_3, attributes);
|
||||
|
||||
//-----------------------------------------
|
||||
// throb
|
||||
// long sparkler
|
||||
//-----------------------------------------
|
||||
} else if (mode == RAVE_GLOVE_EFFECTS_MODE_LONG_SPARKLER) {
|
||||
|
||||
|
@ -672,6 +699,30 @@ void Hand::setRaveGloveMode(int mode) {
|
|||
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_1, attributes);
|
||||
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_2, attributes);
|
||||
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_3, attributes);
|
||||
|
||||
//-----------------------------------------
|
||||
// throb
|
||||
//-----------------------------------------
|
||||
} else if (mode == RAVE_GLOVE_EFFECTS_MODE_THROB) {
|
||||
|
||||
_raveGloveParticleSystem.setParticleRenderStyle (_raveGloveEmitter[f], PARTICLE_RENDER_STYLE_SPHERE );
|
||||
_raveGloveParticleSystem.setShowingEmitterBaseParticle(_raveGloveEmitter[f], true );
|
||||
_raveGloveParticleSystem.setEmitterParticleLifespan (_raveGloveEmitter[f], 0.03 );
|
||||
_raveGloveParticleSystem.setEmitterThrust (_raveGloveEmitter[f], 0.0f );
|
||||
_raveGloveParticleSystem.setEmitterRate (_raveGloveEmitter[f], 30.0 );
|
||||
_raveGloveParticleSystem.setEmitterParticleResolution (_raveGloveEmitter[f], 20 );
|
||||
|
||||
_raveGloveParticleSystem.setParticleAttributesToDefault(&attributes);
|
||||
|
||||
attributes.radius = 0.01f;
|
||||
attributes.color = glm::vec4( 0.1f, 0.2f, 0.4f, 0.5f);
|
||||
attributes.modulationAmplitude = 0.5;
|
||||
attributes.modulationRate = 3.0;
|
||||
attributes.modulationStyle = COLOR_MODULATION_STYLE_LIGHTNESS_WAVE;
|
||||
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_0, attributes);
|
||||
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_1, attributes);
|
||||
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_2, attributes);
|
||||
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_3, attributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,8 +65,9 @@ public:
|
|||
void setRaveGloveEffectsMode(QKeyEvent* event);
|
||||
|
||||
// getters
|
||||
const glm::vec3& getLeapBallPosition (int ball) const { return _leapBalls[ball].position;}
|
||||
bool isRaveGloveActive () const { return _isRaveGloveActive; }
|
||||
const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;}
|
||||
const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;}
|
||||
bool isRaveGloveActive() const { return _isRaveGloveActive; }
|
||||
|
||||
private:
|
||||
// disallow copies of the Hand, copy of owning Avatar is disallowed too
|
||||
|
@ -84,7 +85,8 @@ private:
|
|||
float _renderAlpha;
|
||||
bool _lookingInMirror;
|
||||
glm::vec3 _ballColor;
|
||||
std::vector<HandBall> _leapBalls;
|
||||
std::vector<HandBall> _leapFingerTipBalls;
|
||||
std::vector<HandBall> _leapFingerRootBalls;
|
||||
|
||||
// private methods
|
||||
void setLeapHands(const std::vector<glm::vec3>& handPositions,
|
||||
|
@ -92,8 +94,10 @@ private:
|
|||
|
||||
void renderRaveGloveStage();
|
||||
void setRaveGloveMode(int mode);
|
||||
void renderHandSpheres();
|
||||
void renderFingerTrails();
|
||||
void renderLeapHandSpheres();
|
||||
void renderLeapHands();
|
||||
void renderLeapHand(PalmData& hand);
|
||||
void renderLeapFingerTrails();
|
||||
void calculateGeometry();
|
||||
};
|
||||
|
||||
|
|
17
libraries/avatars/src/AvatarData.cpp
Executable file → Normal file
17
libraries/avatars/src/AvatarData.cpp
Executable file → Normal file
|
@ -130,6 +130,8 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
|||
|
||||
// leap hand data
|
||||
std::vector<glm::vec3> fingerVectors;
|
||||
|
||||
//printf("about to call _handData->encodeRemoteData(fingerVectors);\n");
|
||||
_handData->encodeRemoteData(fingerVectors);
|
||||
|
||||
if (fingerVectors.size() > 255)
|
||||
|
@ -244,17 +246,32 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
// hand state, stored as a semi-nibble in the bitItems
|
||||
_handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT);
|
||||
|
||||
//printf("about to call leap hand data code in AvatarData::parseData...\n");
|
||||
|
||||
// leap hand data
|
||||
if (sourceBuffer - startPosition < numBytes) {
|
||||
|
||||
//printf("got inside of 'if (sourceBuffer - startPosition < numBytes)'\n");
|
||||
|
||||
|
||||
// check passed, bytes match
|
||||
unsigned int numFingerVectors = *sourceBuffer++;
|
||||
|
||||
//printf("numFingerVectors = %d\n", numFingerVectors);
|
||||
|
||||
|
||||
if (numFingerVectors > 0) {
|
||||
|
||||
//printf("ok, we got fingers in AvatarData::parseData\n");
|
||||
|
||||
std::vector<glm::vec3> fingerVectors(numFingerVectors);
|
||||
for (size_t i = 0; i < numFingerVectors; ++i) {
|
||||
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].x), fingerVectorRadix);
|
||||
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].y), fingerVectorRadix);
|
||||
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].z), fingerVectorRadix);
|
||||
}
|
||||
|
||||
//printf("about to call _handData->decodeRemoteData(fingerVectors);\n");
|
||||
_handData->decodeRemoteData(fingerVectors);
|
||||
}
|
||||
}
|
||||
|
|
3
libraries/avatars/src/HandData.cpp
Executable file → Normal file
3
libraries/avatars/src/HandData.cpp
Executable file → Normal file
|
@ -51,7 +51,9 @@ _owningHandData(owningHandData)
|
|||
|
||||
void HandData::encodeRemoteData(std::vector<glm::vec3>& fingerVectors) {
|
||||
fingerVectors.clear();
|
||||
|
||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||
|
||||
PalmData& palm = getPalms()[i];
|
||||
if (!palm.isActive()) {
|
||||
continue;
|
||||
|
@ -60,6 +62,7 @@ void HandData::encodeRemoteData(std::vector<glm::vec3>& fingerVectors) {
|
|||
fingerVectors.push_back(palm.getRawNormal());
|
||||
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
||||
FingerData& finger = palm.getFingers()[f];
|
||||
|
||||
if (finger.isActive()) {
|
||||
fingerVectors.push_back(finger.getTipRawPosition());
|
||||
fingerVectors.push_back(finger.getRootRawPosition());
|
||||
|
|
|
@ -24,10 +24,9 @@
|
|||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
const char SOLO_NODE_TYPES[3] = {
|
||||
const char SOLO_NODE_TYPES[2] = {
|
||||
NODE_TYPE_AVATAR_MIXER,
|
||||
NODE_TYPE_AUDIO_MIXER,
|
||||
NODE_TYPE_VOXEL_SERVER
|
||||
NODE_TYPE_AUDIO_MIXER
|
||||
};
|
||||
|
||||
const char DEFAULT_DOMAIN_HOSTNAME[MAX_HOSTNAME_BYTES] = "root.highfidelity.io";
|
||||
|
|
|
@ -32,7 +32,7 @@ const unsigned int NODE_SOCKET_LISTEN_PORT = 40103;
|
|||
const int NODE_SILENCE_THRESHOLD_USECS = 2 * 1000000;
|
||||
const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000;
|
||||
|
||||
extern const char SOLO_NODE_TYPES[3];
|
||||
extern const char SOLO_NODE_TYPES[2];
|
||||
|
||||
const int MAX_HOSTNAME_BYTES = 256;
|
||||
|
||||
|
|
|
@ -257,3 +257,42 @@ unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char*
|
|||
return newCode;
|
||||
}
|
||||
|
||||
bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescendent, int descendentsChild) {
|
||||
if (!possibleAncestor || !possibleDescendent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ancestorCodeLength = numberOfThreeBitSectionsInCode(possibleAncestor);
|
||||
if (ancestorCodeLength == 0) {
|
||||
return true; // this is the root, it's the anscestor of all
|
||||
}
|
||||
|
||||
int descendentCodeLength = numberOfThreeBitSectionsInCode(possibleDescendent);
|
||||
|
||||
// if the caller also include a child, then our descendent length is actually one extra!
|
||||
if (descendentsChild != CHECK_NODE_ONLY) {
|
||||
descendentCodeLength++;
|
||||
}
|
||||
|
||||
if (ancestorCodeLength > descendentCodeLength) {
|
||||
return false; // if the descendent is shorter, it can't be a descendent
|
||||
}
|
||||
|
||||
// compare the sections for the ancestor to the descendent
|
||||
for (int section = 0; section < ancestorCodeLength; section++) {
|
||||
char sectionValueAncestor = getOctalCodeSectionValue(possibleAncestor, section);
|
||||
char sectionValueDescendent;
|
||||
if (ancestorCodeLength <= descendentCodeLength) {
|
||||
sectionValueDescendent = getOctalCodeSectionValue(possibleDescendent, section);
|
||||
} else {
|
||||
assert(descendentsChild != CHECK_NODE_ONLY);
|
||||
sectionValueDescendent = descendentsChild;
|
||||
}
|
||||
if (sectionValueAncestor != sectionValueDescendent) {
|
||||
return false; // first non-match, means they don't match
|
||||
}
|
||||
}
|
||||
|
||||
// they all match, so we are an ancestor
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ const int BLUE_INDEX = 2;
|
|||
|
||||
void printOctalCode(unsigned char * octalCode);
|
||||
int bytesRequiredForCodeLength(unsigned char threeBitCodes);
|
||||
bool isDirectParentOfChild(unsigned char *parentOctalCode, unsigned char * childOctalCode);
|
||||
int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode);
|
||||
unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber);
|
||||
int numberOfThreeBitSectionsInCode(unsigned char * octalCode);
|
||||
|
@ -29,6 +28,9 @@ unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels);
|
|||
unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode,
|
||||
bool includeColorSpace = false);
|
||||
|
||||
const int CHECK_NODE_ONLY = -1;
|
||||
bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescendent, int descendentsChild = CHECK_NODE_ONLY);
|
||||
|
||||
// Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return
|
||||
// but other than that these do the same thing.
|
||||
float * firstVertexForCode(unsigned char * octalCode);
|
||||
|
|
178
libraries/voxels/src/JurisdictionMap.cpp
Normal file
178
libraries/voxels/src/JurisdictionMap.cpp
Normal file
|
@ -0,0 +1,178 @@
|
|||
//
|
||||
// JurisdictionMap.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 8/1/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "JurisdictionMap.h"
|
||||
#include "VoxelNode.h"
|
||||
|
||||
JurisdictionMap::~JurisdictionMap() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void JurisdictionMap::clear() {
|
||||
if (_rootOctalCode) {
|
||||
delete[] _rootOctalCode;
|
||||
_rootOctalCode = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _endNodes.size(); i++) {
|
||||
if (_endNodes[i]) {
|
||||
delete[] _endNodes[i];
|
||||
}
|
||||
}
|
||||
_endNodes.clear();
|
||||
}
|
||||
|
||||
JurisdictionMap::JurisdictionMap() : _rootOctalCode(NULL) {
|
||||
unsigned char* rootCode = new unsigned char[1];
|
||||
*rootCode = 0;
|
||||
|
||||
std::vector<unsigned char*> emptyEndNodes;
|
||||
init(rootCode, emptyEndNodes);
|
||||
}
|
||||
|
||||
JurisdictionMap::JurisdictionMap(const char* filename) : _rootOctalCode(NULL) {
|
||||
clear(); // clean up our own memory
|
||||
readFromFile(filename);
|
||||
}
|
||||
|
||||
|
||||
JurisdictionMap::JurisdictionMap(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes)
|
||||
: _rootOctalCode(NULL) {
|
||||
init(rootOctalCode, endNodes);
|
||||
}
|
||||
|
||||
void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes) {
|
||||
clear(); // clean up our own memory
|
||||
_rootOctalCode = rootOctalCode;
|
||||
_endNodes = endNodes;
|
||||
}
|
||||
|
||||
JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(unsigned char* nodeOctalCode, int childIndex) const {
|
||||
// to be in our jurisdiction, we must be under the root...
|
||||
|
||||
// if the node is an ancestor of my root, then we return ABOVE
|
||||
if (isAncestorOf(nodeOctalCode, _rootOctalCode)) {
|
||||
return ABOVE;
|
||||
}
|
||||
|
||||
// otherwise...
|
||||
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 (isInJurisdiction) {
|
||||
for (int i = 0; i < _endNodes.size(); i++) {
|
||||
bool isUnderEndNode = isAncestorOf(_endNodes[i], nodeOctalCode);
|
||||
if (isUnderEndNode) {
|
||||
isInJurisdiction = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isInJurisdiction ? WITHIN : BELOW;
|
||||
}
|
||||
|
||||
|
||||
bool JurisdictionMap::readFromFile(const char* filename) {
|
||||
QString settingsFile(filename);
|
||||
QSettings settings(settingsFile, QSettings::IniFormat);
|
||||
QString rootCode = settings.value("root","00").toString();
|
||||
qDebug() << "rootCode=" << rootCode << "\n";
|
||||
|
||||
_rootOctalCode = hexStringToOctalCode(rootCode);
|
||||
printOctalCode(_rootOctalCode);
|
||||
|
||||
settings.beginGroup("endNodes");
|
||||
const QStringList childKeys = settings.childKeys();
|
||||
QHash<QString, QString> values;
|
||||
foreach (const QString &childKey, childKeys) {
|
||||
QString childValue = settings.value(childKey).toString();
|
||||
values.insert(childKey, childValue);
|
||||
qDebug() << childKey << "=" << childValue << "\n";
|
||||
|
||||
unsigned char* octcode = hexStringToOctalCode(childValue);
|
||||
printOctalCode(octcode);
|
||||
|
||||
_endNodes.push_back(octcode);
|
||||
}
|
||||
settings.endGroup();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JurisdictionMap::writeToFile(const char* filename) {
|
||||
QString settingsFile(filename);
|
||||
QSettings settings(settingsFile, QSettings::IniFormat);
|
||||
|
||||
|
||||
QString rootNodeValue = octalCodeToHexString(_rootOctalCode);
|
||||
|
||||
settings.setValue("root", rootNodeValue);
|
||||
|
||||
settings.beginGroup("endNodes");
|
||||
for (int i = 0; i < _endNodes.size(); i++) {
|
||||
QString key = QString("endnode%1").arg(i);
|
||||
QString value = octalCodeToHexString(_endNodes[i]);
|
||||
settings.setValue(key, value);
|
||||
}
|
||||
settings.endGroup();
|
||||
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;
|
||||
}
|
46
libraries/voxels/src/JurisdictionMap.h
Normal file
46
libraries/voxels/src/JurisdictionMap.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// JurisdictionMap.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 8/1/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__JurisdictionMap__
|
||||
#define __hifi__JurisdictionMap__
|
||||
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
|
||||
class JurisdictionMap {
|
||||
public:
|
||||
enum Area {
|
||||
ABOVE,
|
||||
WITHIN,
|
||||
BELOW
|
||||
};
|
||||
|
||||
JurisdictionMap();
|
||||
JurisdictionMap(const char* filename);
|
||||
JurisdictionMap(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes);
|
||||
~JurisdictionMap();
|
||||
|
||||
Area isMyJurisdiction(unsigned char* nodeOctalCode, int childIndex) const;
|
||||
|
||||
bool writeToFile(const char* filename);
|
||||
bool readFromFile(const char* filename);
|
||||
|
||||
private:
|
||||
void clear();
|
||||
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;
|
||||
std::vector<unsigned char*> _endNodes;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__JurisdictionMap__) */
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Tags.h
|
||||
// Tags.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Clement Brisset on 7/3/13.
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include <QDebug>
|
||||
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "AABox.h"
|
||||
#include "OctalCode.h"
|
||||
#include "SharedUtil.h"
|
||||
|
@ -51,6 +53,7 @@ void VoxelNode::init(unsigned char * octalCode) {
|
|||
_voxelSystem = NULL;
|
||||
_isDirty = true;
|
||||
_shouldRender = false;
|
||||
_sourceID = UNKNOWN_NODE_ID;
|
||||
markWithChangedTime();
|
||||
calculateAABox();
|
||||
}
|
||||
|
|
|
@ -93,8 +93,6 @@ public:
|
|||
void setColor(const nodeColor& color);
|
||||
const nodeColor& getTrueColor() const { return _trueColor; };
|
||||
const nodeColor& getColor() const { return _currentColor; };
|
||||
void setDensity(float density) { _density = density; };
|
||||
float getDensity() const { return _density; };
|
||||
#else
|
||||
void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ };
|
||||
void setFalseColored(bool isFalseColored) { /* no op */ };
|
||||
|
@ -105,6 +103,11 @@ public:
|
|||
const nodeColor& getColor() const { return _trueColor; };
|
||||
#endif
|
||||
|
||||
void setDensity(float density) { _density = density; };
|
||||
float getDensity() const { return _density; };
|
||||
void setSourceID(uint16_t sourceID) { _sourceID = sourceID; };
|
||||
uint16_t getSourceID() const { return _sourceID; };
|
||||
|
||||
static void addDeleteHook(VoxelNodeDeleteHook* hook);
|
||||
static void removeDeleteHook(VoxelNodeDeleteHook* hook);
|
||||
|
||||
|
@ -135,6 +138,7 @@ private:
|
|||
unsigned long _subtreeNodeCount;
|
||||
unsigned long _subtreeLeafNodeCount;
|
||||
float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside
|
||||
uint16_t _sourceID;
|
||||
|
||||
static std::vector<VoxelNodeDeleteHook*> _hooks;
|
||||
};
|
||||
|
|
|
@ -231,7 +231,7 @@ VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char
|
|||
}
|
||||
|
||||
int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, int bytesLeftToRead,
|
||||
bool includeColor, bool includeExistsBits) {
|
||||
ReadBitstreamToTreeParams& args) {
|
||||
// give this destination node the child mask from the packet
|
||||
const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF;
|
||||
unsigned char colorInPacketMask = *nodeData;
|
||||
|
@ -254,12 +254,13 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData,
|
|||
|
||||
// pull the color for this child
|
||||
nodeColor newColor = { 128, 128, 128, 1};
|
||||
if (includeColor) {
|
||||
if (args.includeColor) {
|
||||
memcpy(newColor, nodeData + bytesRead, 3);
|
||||
bytesRead += 3;
|
||||
}
|
||||
bool nodeWasDirty = destinationNode->getChildAtIndex(i)->isDirty();
|
||||
destinationNode->getChildAtIndex(i)->setColor(newColor);
|
||||
destinationNode->getChildAtIndex(i)->setSourceID(args.sourceID);
|
||||
bool nodeIsDirty = destinationNode->getChildAtIndex(i)->isDirty();
|
||||
if (nodeIsDirty) {
|
||||
_isDirty = true;
|
||||
|
@ -273,11 +274,11 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData,
|
|||
}
|
||||
|
||||
// give this destination node the child mask from the packet
|
||||
unsigned char childrenInTreeMask = includeExistsBits ? *(nodeData + bytesRead) : ALL_CHILDREN_ASSUMED_TO_EXIST;
|
||||
unsigned char childMask = *(nodeData + bytesRead + (includeExistsBits ? sizeof(childrenInTreeMask) : 0));
|
||||
unsigned char childrenInTreeMask = args.includeExistsBits ? *(nodeData + bytesRead) : ALL_CHILDREN_ASSUMED_TO_EXIST;
|
||||
unsigned char childMask = *(nodeData + bytesRead + (args.includeExistsBits ? sizeof(childrenInTreeMask) : 0));
|
||||
|
||||
int childIndex = 0;
|
||||
bytesRead += includeExistsBits ? sizeof(childrenInTreeMask) + sizeof(childMask) : sizeof(childMask);
|
||||
bytesRead += args.includeExistsBits ? sizeof(childrenInTreeMask) + sizeof(childMask) : sizeof(childMask);
|
||||
|
||||
while (bytesLeftToRead - bytesRead > 0 && childIndex < NUMBER_OF_CHILDREN) {
|
||||
// check the exists mask to see if we have a child to traverse into
|
||||
|
@ -300,13 +301,12 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData,
|
|||
|
||||
// tell the child to read the subsequent data
|
||||
bytesRead += readNodeData(destinationNode->getChildAtIndex(childIndex),
|
||||
nodeData + bytesRead, bytesLeftToRead - bytesRead, includeColor, includeExistsBits);
|
||||
nodeData + bytesRead, bytesLeftToRead - bytesRead, args);
|
||||
}
|
||||
childIndex++;
|
||||
}
|
||||
|
||||
|
||||
if (includeExistsBits) {
|
||||
if (args.includeExistsBits) {
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
// now also check the childrenInTreeMask, if the mask is missing the bit, then it means we need to delete this child
|
||||
// subtree/node, because it shouldn't actually exist in the tree.
|
||||
|
@ -319,14 +319,14 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData,
|
|||
return bytesRead;
|
||||
}
|
||||
|
||||
void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes,
|
||||
bool includeColor, bool includeExistsBits, VoxelNode* destinationNode) {
|
||||
void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes,
|
||||
ReadBitstreamToTreeParams& args) {
|
||||
int bytesRead = 0;
|
||||
unsigned char* bitstreamAt = bitstream;
|
||||
|
||||
// If destination node is not included, set it to root
|
||||
if (!destinationNode) {
|
||||
destinationNode = rootNode;
|
||||
if (!args.destinationNode) {
|
||||
args.destinationNode = rootNode;
|
||||
}
|
||||
|
||||
_nodesChangedFromBitstream = 0;
|
||||
|
@ -336,14 +336,14 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int
|
|||
// if there are more bytes after that, it's assumed to be another root relative tree
|
||||
|
||||
while (bitstreamAt < bitstream + bufferSizeBytes) {
|
||||
VoxelNode* bitstreamRootNode = nodeForOctalCode(destinationNode, (unsigned char *)bitstreamAt, NULL);
|
||||
VoxelNode* bitstreamRootNode = nodeForOctalCode(args.destinationNode, (unsigned char *)bitstreamAt, NULL);
|
||||
if (*bitstreamAt != *bitstreamRootNode->getOctalCode()) {
|
||||
// if the octal code returned is not on the same level as
|
||||
// the code being searched for, we have VoxelNodes to create
|
||||
|
||||
// Note: we need to create this node relative to root, because we're assuming that the bitstream for the initial
|
||||
// octal code is always relative to root!
|
||||
bitstreamRootNode = createMissingNode(destinationNode, (unsigned char*) bitstreamAt);
|
||||
bitstreamRootNode = createMissingNode(args.destinationNode, (unsigned char*) bitstreamAt);
|
||||
if (bitstreamRootNode->isDirty()) {
|
||||
_isDirty = true;
|
||||
_nodesChangedFromBitstream++;
|
||||
|
@ -353,8 +353,8 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int
|
|||
int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt);
|
||||
int theseBytesRead = 0;
|
||||
theseBytesRead += octalCodeBytes;
|
||||
theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes,
|
||||
bufferSizeBytes - (bytesRead + octalCodeBytes), includeColor, includeExistsBits);
|
||||
theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes,
|
||||
bufferSizeBytes - (bytesRead + octalCodeBytes), args);
|
||||
|
||||
// skip bitstream to new startPoint
|
||||
bitstreamAt += theseBytesRead;
|
||||
|
@ -1078,6 +1078,15 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
|
|||
if (currentEncodeLevel >= params.maxEncodeLevel) {
|
||||
return bytesAtThisLevel;
|
||||
}
|
||||
|
||||
// If we've been provided a jurisdiction map, then we need to honor it.
|
||||
if (params.jurisdictionMap) {
|
||||
// here's how it works... if we're currently above our root jurisdiction, then we proceed normally.
|
||||
// but once we're in our own jurisdiction, then we need to make sure we're not below it.
|
||||
if (JurisdictionMap::BELOW == params.jurisdictionMap->isMyJurisdiction(node->getOctalCode(), CHECK_NODE_ONLY)) {
|
||||
return bytesAtThisLevel;
|
||||
}
|
||||
}
|
||||
|
||||
// caller can pass NULL as viewFrustum if they want everything
|
||||
if (params.viewFrustum) {
|
||||
|
@ -1197,9 +1206,18 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
|
|||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
VoxelNode* childNode = node->getChildAtIndex(i);
|
||||
|
||||
// if the caller wants to include childExistsBits, then include them even if not in view
|
||||
if (params.includeExistsBits && childNode) {
|
||||
childrenExistInTreeBits += (1 << (7 - i));
|
||||
// if the caller wants to include childExistsBits, then include them even if not in view, if however,
|
||||
// we're in a portion of the tree that's not our responsibility, then we assume the child nodes exist
|
||||
// even if they don't in our local tree
|
||||
bool notMyJurisdiction = false;
|
||||
if (params.jurisdictionMap) {
|
||||
notMyJurisdiction = (JurisdictionMap::BELOW == params.jurisdictionMap->isMyJurisdiction(node->getOctalCode(), i));
|
||||
}
|
||||
if (params.includeExistsBits) {
|
||||
// If the child is known to exist, OR, it's not my jurisdiction, then we mark the bit as existing
|
||||
if (childNode || notMyJurisdiction) {
|
||||
childrenExistInTreeBits += (1 << (7 - i));
|
||||
}
|
||||
}
|
||||
|
||||
if (params.wantOcclusionCulling) {
|
||||
|
@ -1548,7 +1566,8 @@ bool VoxelTree::readFromSVOFile(const char* fileName) {
|
|||
// read the entire file into a buffer, WHAT!? Why not.
|
||||
unsigned char* entireFile = new unsigned char[fileLength];
|
||||
file.read((char*)entireFile, fileLength);
|
||||
readBitstreamToTree(entireFile, fileLength, WANT_COLOR, NO_EXISTS_BITS);
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS);
|
||||
readBitstreamToTree(entireFile, fileLength, args);
|
||||
delete[] entireFile;
|
||||
|
||||
file.close();
|
||||
|
@ -1702,7 +1721,8 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat
|
|||
bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params);
|
||||
|
||||
// ask destination tree to read the bitstream
|
||||
destinationTree->readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS);
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS);
|
||||
destinationTree->readBitstreamToTree(&outputBuffer[0], bytesWritten, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1722,7 +1742,8 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin
|
|||
bytesWritten = sourceTree->encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params);
|
||||
|
||||
// ask destination tree to read the bitstream
|
||||
readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS, destinationNode);
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode);
|
||||
readBitstreamToTree(&outputBuffer[0], bytesWritten, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1877,4 +1898,4 @@ void VoxelTree::computeBlockColor(int id, int data, int& red, int& green, int& b
|
|||
create = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
#include <SimpleMovingAverage.h>
|
||||
|
||||
#include "CoverageMap.h"
|
||||
#include "JurisdictionMap.h"
|
||||
#include "ViewFrustum.h"
|
||||
#include "VoxelNode.h"
|
||||
#include "VoxelNodeBag.h"
|
||||
|
@ -36,9 +37,10 @@ const int NO_BOUNDARY_ADJUST = 0;
|
|||
const int LOW_RES_MOVING_ADJUST = 1;
|
||||
const uint64_t IGNORE_LAST_SENT = 0;
|
||||
|
||||
#define IGNORE_SCENE_STATS NULL
|
||||
#define IGNORE_VIEW_FRUSTUM NULL
|
||||
#define IGNORE_COVERAGE_MAP NULL
|
||||
#define IGNORE_SCENE_STATS NULL
|
||||
#define IGNORE_VIEW_FRUSTUM NULL
|
||||
#define IGNORE_COVERAGE_MAP NULL
|
||||
#define IGNORE_JURISDICTION_MAP NULL
|
||||
|
||||
class EncodeBitstreamParams {
|
||||
public:
|
||||
|
@ -56,6 +58,7 @@ public:
|
|||
bool forceSendScene;
|
||||
VoxelSceneStats* stats;
|
||||
CoverageMap* map;
|
||||
JurisdictionMap* jurisdictionMap;
|
||||
|
||||
EncodeBitstreamParams(
|
||||
int maxEncodeLevel = INT_MAX,
|
||||
|
@ -70,7 +73,8 @@ public:
|
|||
int boundaryLevelAdjust = NO_BOUNDARY_ADJUST,
|
||||
uint64_t lastViewFrustumSent = IGNORE_LAST_SENT,
|
||||
bool forceSendScene = true,
|
||||
VoxelSceneStats* stats = IGNORE_SCENE_STATS) :
|
||||
VoxelSceneStats* stats = IGNORE_SCENE_STATS,
|
||||
JurisdictionMap* jurisdictionMap = IGNORE_JURISDICTION_MAP) :
|
||||
maxEncodeLevel (maxEncodeLevel),
|
||||
maxLevelReached (0),
|
||||
viewFrustum (viewFrustum),
|
||||
|
@ -84,7 +88,27 @@ public:
|
|||
lastViewFrustumSent (lastViewFrustumSent),
|
||||
forceSendScene (forceSendScene),
|
||||
stats (stats),
|
||||
map (map)
|
||||
map (map),
|
||||
jurisdictionMap (jurisdictionMap)
|
||||
{}
|
||||
};
|
||||
|
||||
class ReadBitstreamToTreeParams {
|
||||
public:
|
||||
bool includeColor;
|
||||
bool includeExistsBits;
|
||||
VoxelNode* destinationNode;
|
||||
uint16_t sourceID;
|
||||
|
||||
ReadBitstreamToTreeParams(
|
||||
bool includeColor = WANT_COLOR,
|
||||
bool includeExistsBits = WANT_EXISTS_BITS,
|
||||
VoxelNode* destinationNode = NULL,
|
||||
uint16_t sourceID = UNKNOWN_NODE_ID) :
|
||||
includeColor (includeColor),
|
||||
includeExistsBits (includeExistsBits),
|
||||
destinationNode (destinationNode),
|
||||
sourceID (sourceID)
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -109,9 +133,7 @@ public:
|
|||
void eraseAllVoxels();
|
||||
|
||||
void processRemoveVoxelBitstream(unsigned char* bitstream, int bufferSizeBytes);
|
||||
void readBitstreamToTree(unsigned char* bitstream, unsigned long int bufferSizeBytes,
|
||||
bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS,
|
||||
VoxelNode* destinationNode = NULL);
|
||||
void readBitstreamToTree(unsigned char* bitstream, unsigned long int bufferSizeBytes, ReadBitstreamToTreeParams& args);
|
||||
void readCodeColorBufferToTree(unsigned char* codeColorBuffer, bool destructive = false);
|
||||
void deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool collapseEmptyTrees = DONT_COLLAPSE);
|
||||
void printTreeForDebugging(VoxelNode* startNode);
|
||||
|
@ -169,7 +191,8 @@ public:
|
|||
void recurseTreeWithOperationDistanceSortedTimed(PointerStack* stackOfNodes, long allowedTime,
|
||||
RecurseVoxelTreeOperation operation,
|
||||
const glm::vec3& point, void* extraData);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
void deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraData);
|
||||
void readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraData);
|
||||
|
@ -181,8 +204,7 @@ private:
|
|||
|
||||
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const;
|
||||
VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate);
|
||||
int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes,
|
||||
bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS);
|
||||
int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, ReadBitstreamToTreeParams& args);
|
||||
|
||||
bool _isDirty;
|
||||
unsigned long int _nodesChangedFromBitstream;
|
||||
|
|
80
voxel-server/src/README
Normal file
80
voxel-server/src/README
Normal file
|
@ -0,0 +1,80 @@
|
|||
NAME
|
||||
voxel-server - the High Fidelity Voxel Server
|
||||
|
||||
SYNOPSIS
|
||||
voxel-server [--local] [--jurisdictionFile <filename>] [--port <port>] [--voxelsPersistFilename <filename>]
|
||||
[--displayVoxelStats] [--debugVoxelSending] [--debugVoxelReceiving] [--shouldShowAnimationDebug]
|
||||
[--wantColorRandomizer] [--NoVoxelPersist] [--packetsPerSecond <value>]
|
||||
[--AddRandomVoxels] [--AddScene] [--NoAddScene]
|
||||
|
||||
DESCRIPTION
|
||||
voxel-server is a compact, portable, scalable, distributed sparse voxel octree server
|
||||
|
||||
OPTIONS
|
||||
|
||||
--local
|
||||
This will run the voxel server in "local domain mode" and will look for a domain-server running on the same IP
|
||||
address as the voxel server
|
||||
|
||||
--jurisdictionFile [filename]
|
||||
Tells the server to load it's jurisdiction from the specified file. When a voxel server is running with a limited
|
||||
"jurisdiction" it will only server voxels from that portion of the voxel tree. The jurisdiction file is a ".ini" style
|
||||
file with the following options: [General/root] specifies the octal code for the node in the tree that this server will
|
||||
use as it's "root". It will only server voxels under this root. [endNodes/...] a list or group of additional octalcodes
|
||||
under the root, which will not be served.
|
||||
|
||||
The following example jurisdiction file will server all voxels from the root and below, and exclude voxels from the
|
||||
voxel of scale 0.25 and 0,0,0.
|
||||
|
||||
****** example jurisdiction.ini **********************************************************************
|
||||
[General]
|
||||
root=00
|
||||
|
||||
[endNodes]
|
||||
endnode0=0200
|
||||
|
||||
******************************************************************************************************
|
||||
|
||||
|
||||
--port [port]
|
||||
Specify the port the voxel-server will listen on. You must specify different ports to enable multiple voxel servers
|
||||
running on a single machine.
|
||||
|
||||
--voxelsPersistFilename [filename]
|
||||
Specify and alternate file that the voxel server will read and write persistant voxels to. By default the voxel server
|
||||
will use one of the following files:
|
||||
|
||||
default: /etc/highfidelity/voxel-server/resources/voxels.svo
|
||||
in local mode: ./resources/voxels.svo
|
||||
|
||||
--displayVoxelStats
|
||||
Displays additional voxel stats debugging
|
||||
|
||||
--debugVoxelSending
|
||||
Displays additional voxel sending debugging
|
||||
|
||||
--debugVoxelReceiving
|
||||
Displays additional voxel receiving debugging
|
||||
|
||||
--shouldShowAnimationDebug
|
||||
Displays additional verbose animation debugging
|
||||
|
||||
--wantColorRandomizer
|
||||
Adds color randomization to inserts into the local voxel tree
|
||||
|
||||
--NoVoxelPersist
|
||||
Disables voxel persisting
|
||||
|
||||
--packetsPerSecond [value]
|
||||
Specifies the packets per second that this voxel server will send to attached clients
|
||||
|
||||
--AddRandomVoxels
|
||||
Add random voxels to the surface on startup
|
||||
|
||||
--AddScene
|
||||
OBSOLETE: Adds an arbitrary scene with several "planet" spheres
|
||||
|
||||
--NoAddScene
|
||||
OBSOLETE: disables adding of scene
|
||||
|
||||
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo";
|
||||
const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.svo";
|
||||
const int MAX_FILENAME_LENGTH = 1024;
|
||||
char voxelPersistFilename[MAX_FILENAME_LENGTH];
|
||||
const int VOXEL_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds
|
||||
|
||||
const int VOXEL_LISTEN_PORT = 40106;
|
||||
|
@ -65,6 +67,8 @@ bool debugVoxelReceiving = false;
|
|||
|
||||
EnvironmentData environmentData[3];
|
||||
|
||||
int receivedPacketCount = 0;
|
||||
JurisdictionMap* jurisdiction = NULL;
|
||||
|
||||
void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) {
|
||||
// randomly generate children for this node
|
||||
|
@ -292,7 +296,7 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
|
|||
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
|
||||
wantOcclusionCulling, coverageMap, boundaryLevelAdjust,
|
||||
nodeData->getLastTimeBagEmpty(),
|
||||
isFullScene, &nodeData->stats);
|
||||
isFullScene, &nodeData->stats, ::jurisdiction);
|
||||
|
||||
nodeData->stats.encodeStarted();
|
||||
bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
|
||||
|
@ -376,7 +380,7 @@ void persistVoxelsWhenDirty() {
|
|||
"persistVoxelsWhenDirty() - writeToSVOFile()", ::shouldShowAnimationDebug);
|
||||
|
||||
printf("saving voxels to file...\n");
|
||||
serverTree.writeToSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE);
|
||||
serverTree.writeToSVOFile(::voxelPersistFilename);
|
||||
serverTree.clearDirtyBit(); // tree is clean after saving
|
||||
printf("DONE saving voxels to file...\n");
|
||||
}
|
||||
|
@ -427,14 +431,39 @@ void attachVoxelNodeDataToNode(Node* newNode) {
|
|||
}
|
||||
}
|
||||
|
||||
int receivedPacketCount = 0;
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
pthread_mutex_init(&::treeLock, NULL);
|
||||
|
||||
qInstallMessageHandler(sharedMessageHandler);
|
||||
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, VOXEL_LISTEN_PORT);
|
||||
int listenPort = VOXEL_LISTEN_PORT;
|
||||
// Check to see if the user passed in a command line option for setting listen port
|
||||
const char* PORT_PARAMETER = "--port";
|
||||
const char* portParameter = getCmdOption(argc, argv, PORT_PARAMETER);
|
||||
if (portParameter) {
|
||||
listenPort = atoi(portParameter);
|
||||
if (listenPort < 1) {
|
||||
listenPort = VOXEL_LISTEN_PORT;
|
||||
}
|
||||
printf("portParameter=%s listenPort=%d\n", portParameter, listenPort);
|
||||
}
|
||||
|
||||
const char* JURISDICTION_FILE = "--jurisdictionFile";
|
||||
const char* jurisdictionFile = getCmdOption(argc, argv, JURISDICTION_FILE);
|
||||
if (jurisdictionFile) {
|
||||
printf("jurisdictionFile=%s\n", jurisdictionFile);
|
||||
|
||||
printf("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
||||
jurisdiction = new JurisdictionMap(jurisdictionFile);
|
||||
printf("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
||||
|
||||
// test writing the file...
|
||||
printf("about to writeToFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
||||
jurisdiction->writeToFile(jurisdictionFile);
|
||||
printf("after writeToFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
||||
}
|
||||
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, listenPort);
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
// Handle Local Domain testing with the --local command line
|
||||
|
@ -480,8 +509,19 @@ int main(int argc, const char * argv[]) {
|
|||
// if we want Voxel Persistance, load the local file now...
|
||||
bool persistantFileRead = false;
|
||||
if (::wantVoxelPersist) {
|
||||
printf("loading voxels from file...\n");
|
||||
persistantFileRead = ::serverTree.readFromSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE);
|
||||
|
||||
// Check to see if the user passed in a command line option for setting packet send rate
|
||||
const char* VOXELS_PERSIST_FILENAME = "--voxelsPersistFilename";
|
||||
const char* voxelsPersistFilenameParameter = getCmdOption(argc, argv, VOXELS_PERSIST_FILENAME);
|
||||
if (voxelsPersistFilenameParameter) {
|
||||
strcpy(voxelPersistFilename, voxelsPersistFilenameParameter);
|
||||
} else {
|
||||
strcpy(voxelPersistFilename, ::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE);
|
||||
}
|
||||
|
||||
printf("loading voxels from file: %s...\n", voxelPersistFilename);
|
||||
|
||||
persistantFileRead = ::serverTree.readFromSVOFile(::voxelPersistFilename);
|
||||
if (persistantFileRead) {
|
||||
PerformanceWarning warn(::shouldShowAnimationDebug,
|
||||
"persistVoxelsWhenDirty() - reaverageVoxelColors()", ::shouldShowAnimationDebug);
|
||||
|
@ -707,6 +747,10 @@ int main(int argc, const char * argv[]) {
|
|||
|
||||
pthread_join(sendVoxelThread, NULL);
|
||||
pthread_mutex_destroy(&::treeLock);
|
||||
|
||||
if (jurisdiction) {
|
||||
delete jurisdiction;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue