Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels

This commit is contained in:
Andrzej Kapolka 2014-02-06 15:42:37 -08:00
commit 0a6288bda4
56 changed files with 550 additions and 508 deletions

View file

@ -18,9 +18,18 @@ send your resume to hiring@highfidelity.io
Building Interface & other High Fidelity Components
=========
Interface is our OS X and Linux build-able client for accessing our virtual
Interface is our Windows, OS X, and Linux build-able client for accessing our virtual
world.
For detailed notes on building for Windows, please refer to the following wiki page:
https://github.com/highfidelity/hifi/wiki/Building-on-Windows
For detailed notes on building for Ubuntu, please refer to the following wiki page:
https://github.com/highfidelity/hifi/wiki/Building-on-Ubuntu-13.04
Building on Mac OS X and Linux:
--------------------------------
CMake
-----
Hifi uses CMake to generate build files and project files
@ -45,9 +54,9 @@ If Cmake throws you an error related to Qt5 it likely cannot find your Qt5 cmake
You can solve this by setting an environment variable, QT_CMAKE_PREFIX_PATH, to the location of the folder distributed
with Qt5 that contains them.
For example, a Qt5 5.1.1 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
For example, a Qt5 5.2.0 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.1.1/clang_64/lib/cmake/
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.2.0/clang_64/lib/cmake/
The path it needs to be set to will depend on where and how Qt5 was installed.
@ -64,7 +73,7 @@ components located in the build/target_name/Debug directories.
Other dependencies & information
----
In addition to CMake, Qt 5.1 is required to build all components.
In addition to CMake, Qt 5.2 is required to build all components.
What can I build on?
We have successfully built on OS X 10.8, Ubuntu and a few other modern Linux

View file

@ -30,9 +30,6 @@ link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(metavoxels ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(octree-server ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(particle-server ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(voxel-server ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(script-engine ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(embedded-webserver ${TARGET_NAME} ${ROOT_DIR})

View file

@ -23,8 +23,12 @@
#include "Agent.h"
Agent::Agent(const QByteArray& packet) :
ThreadedAssignment(packet)
ThreadedAssignment(packet),
_voxelEditSender(),
_particleEditSender()
{
_scriptEngine.getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender);
_scriptEngine.getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
}
void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {

View file

@ -15,9 +15,12 @@
#include <QtCore/QObject>
#include <QtCore/QUrl>
#include <ParticleEditPacketSender.h>
#include <ParticleTree.h>
#include <ScriptEngine.h>
#include <ThreadedAssignment.h>
#include <VoxelEditPacketSender.h>
class Agent : public ThreadedAssignment {
Q_OBJECT
@ -39,6 +42,8 @@ signals:
private:
ScriptEngine _scriptEngine;
ParticleTree _particleTree;
VoxelEditPacketSender _voxelEditSender;
ParticleEditPacketSender _particleEditSender;
};
#endif /* defined(__hifi__Agent__) */

View file

@ -8,15 +8,13 @@
#include <PacketHeaders.h>
#include <ParticleServer.h>
#include <VoxelServer.h>
#include "Agent.h"
#include "AssignmentFactory.h"
#include "audio/AudioMixer.h"
#include "avatars/AvatarMixer.h"
#include "metavoxels/MetavoxelServer.h"
#include "particles/ParticleServer.h"
#include "voxels/VoxelServer.h"
ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet) {
QDataStream packetStream(packet);

View file

@ -46,9 +46,12 @@ void OctreeQueryNode::initializeOctreeSendThread(OctreeServer* octreeServer, con
bool OctreeQueryNode::packetIsDuplicate() const {
// since our packets now include header information, like sequence number, and createTime, we can't just do a memcmp
// of the entire packet, we need to compare only the packet content...
int numBytesPacketHeader = numBytesForPacketHeaderGivenPacketType(getMyPacketType());
if (_lastOctreePacketLength == getPacketLength()) {
if (memcmp(_lastOctreePacket + OCTREE_PACKET_HEADER_SIZE,
_octreePacket + OCTREE_PACKET_HEADER_SIZE , getPacketLength() - OCTREE_PACKET_HEADER_SIZE) == 0) {
if (memcmp(_lastOctreePacket + (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_SIZE),
_octreePacket + (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_SIZE),
getPacketLength() - (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_SIZE)) == 0) {
return true;
}
}
@ -125,7 +128,7 @@ void OctreeQueryNode::resetOctreePacket(bool lastWasSurpressed) {
*sequenceAt = _sequenceNumber;
_octreePacketAt += sizeof(OCTREE_PACKET_SEQUENCE);
_octreePacketAvailableBytes -= sizeof(OCTREE_PACKET_SEQUENCE);
if (!(lastWasSurpressed || _lastOctreePacketLength == OCTREE_PACKET_HEADER_SIZE)) {
if (!(lastWasSurpressed || _lastOctreePacketLength == (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_SIZE))) {
_sequenceNumber++;
}

View file

@ -92,6 +92,13 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
bool packetSent = false; // did we send a packet?
int packetsSent = 0;
// double check that the node has an active socket, otherwise, don't send...
const HifiSockAddr* nodeAddress = node->getActiveSocket();
if (!nodeAddress) {
return packetsSent; // without sending...
}
// Here's where we check to see if this packet is a duplicate of the last packet. If it is, we will silently
// obscure the packet and not send it. This allows the callers and upper level logic to not need to know about
// this rate control savings.
@ -136,14 +143,14 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
// actually send it
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength,
node->getActiveSocket()->getAddress(),
node->getActiveSocket()->getPort());
nodeAddress->getAddress(),
nodeAddress->getPort());
packetSent = true;
} else {
// not enough room in the packet, send two packets
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength,
node->getActiveSocket()->getAddress(),
node->getActiveSocket()->getPort());
nodeAddress->getAddress(),
nodeAddress->getPort());
// since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since
// there was nothing else to send.
@ -162,8 +169,8 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
packetsSent++;
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(),
node->getActiveSocket()->getAddress(),
node->getActiveSocket()->getPort());
nodeAddress->getAddress(),
nodeAddress->getPort());
packetSent = true;
@ -183,8 +190,8 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
if (nodeData->isPacketWaiting()) {
// just send the voxel packet
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(),
node->getActiveSocket()->getAddress(),
node->getActiveSocket()->getPort());
nodeAddress->getAddress(),
nodeAddress->getPort());
packetSent = true;
int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength();

View file

@ -10,9 +10,10 @@
#ifndef __hifi__ParticleNodeData__
#define __hifi__ParticleNodeData__
#include <OctreeQueryNode.h>
#include <PacketHeaders.h>
#include "../octree/OctreeQueryNode.h"
class ParticleNodeData : public OctreeQueryNode {
public:
ParticleNodeData() :

View file

@ -10,7 +10,7 @@
#ifndef __particle_server__ParticleServer__
#define __particle_server__ParticleServer__
#include <OctreeServer.h>
#include "../octree/OctreeServer.h"
#include "Particle.h"
#include "ParticleServerConsts.h"

View file

@ -3,15 +3,16 @@
// hifi
//
// Created by Stephen Birarda on 3/21/13.
//
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__VoxelNodeData__
#define __hifi__VoxelNodeData__
#include <OctreeQueryNode.h>
#include <PacketHeaders.h>
#include "../octree/OctreeQueryNode.h"
class VoxelNodeData : public OctreeQueryNode {
public:
VoxelNodeData() : OctreeQueryNode() { };

View file

@ -17,8 +17,7 @@
#include <ThreadedAssignment.h>
#include <EnvironmentData.h>
#include <OctreeServer.h>
#include "../octree/OctreeServer.h"
#include "VoxelServerConsts.h"

View file

@ -8,11 +8,9 @@ var NUMBER_OF_CELLS = NUMBER_OF_CELLS_EACH_DIMENSION * NUMBER_OF_CELLS_EACH_DIME
var currentCells = [];
var nextCells = [];
var METER_LENGTH = 1 / TREE_SCALE;
var METER_LENGTH = 1;
var cellScale = (NUMBER_OF_CELLS_EACH_DIMENSION * METER_LENGTH) / NUMBER_OF_CELLS_EACH_DIMENSION;
print("TREE_SCALE = " + TREE_SCALE + "\n");
// randomly populate the cell start values
for (var i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) {
// create the array to hold this row
@ -108,7 +106,7 @@ function sendNextCells() {
// queue a packet to add a voxel for the new cell
var color = (nextCells[i][j] == 1) ? 255 : 1;
Voxels.queueDestructiveVoxelAdd(x, y, 0, cellScale, color, color, color);
Voxels.setVoxel(x, y, 0, cellScale, color, color, color);
}
}
}
@ -128,4 +126,6 @@ function step() {
sendNextCells();
}
Agent.willSendVisualDataCallback.connect(step);
Script.willSendVisualDataCallback.connect(step);
Voxels.setPacketsPerSecond(200);

View file

@ -11,7 +11,7 @@
var count = 0;
var stopAfter = 100;
var modelProperties = {
var modelPropertiesA = {
position: { x: 1, y: 1, z: 1 },
velocity: { x: 0.5, y: 0, z: 0.5 },
gravity: { x: 0, y: 0, z: 0 },
@ -21,6 +21,18 @@ var modelProperties = {
lifetime: 20
};
var modelPropertiesB = {
position: { x: 1, y: 1.5, z: 1 },
velocity: { x: 0.5, y: 0, z: 0.5 },
gravity: { x: 0, y: 0, z: 0 },
damping: 0,
radius : 0.25,
modelURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/newInvader16x16.svo",
modelScale: 450,
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
lifetime: 20
};
var ballProperties = {
position: { x: 1, y: 0.5, z: 1 },
velocity: { x: 0.5, y: 0, z: 0.5 },
@ -31,7 +43,8 @@ var ballProperties = {
lifetime: 20
};
var modelParticleID = Particles.addParticle(modelProperties);
var modelAParticleID = Particles.addParticle(modelPropertiesA);
var modelBParticleID = Particles.addParticle(modelPropertiesB);
var ballParticleID = Particles.addParticle(ballProperties);
function endAfterAWhile() {

View file

@ -10,17 +10,50 @@
var iteration = 0;
var invaderStepsPerCycle = 30; // the number of update steps it takes then invaders to move one column to the right
var gameOver = false;
// horizontal movement of invaders
var invaderStepsPerCycle = 120; // the number of update steps it takes then invaders to move one column to the right
var invaderStepOfCycle = 0; // current iteration in the cycle
var invaderMoveDirection = 1; // 1 for moving to right, -1 for moving to left
var itemLifetimes = 60;
var gameAt = { x: 10, y: 0, z: 10 };
// game length...
var itemLifetimes = 60; // 1 minute
// position the game to be basically near the avatar running the game...
var gameSize = { x: 10, y: 20, z: 1 };
var positionFromAvatarZ = 10;
var avatarX = MyAvatar.position.x;
var avatarY = MyAvatar.position.y;
var avatarZ = MyAvatar.position.z;
var gameAtX = avatarX;
var gameAtY = avatarY;
var gameAtZ = avatarZ;
// move the game to be "centered" on our X
if (gameAtX > (gameSize.x/2)) {
gameAtX -= (gameSize.x/2);
}
// move the game to be "offset slightly" on our Y
if (gameAtY > (gameSize.y/4)) {
gameAtY -= (gameSize.y/4);
}
// move the game to be positioned away on our Z
if (gameAtZ > positionFromAvatarZ) {
gameAtZ -= positionFromAvatarZ;
}
var gameAt = { x: gameAtX, y: gameAtY, z: gameAtZ };
var middleX = gameAt.x + (gameSize.x/2);
var middleY = gameAt.y + (gameSize.y/2);
var shipSize = 0.2;
var invaderSize = 0.4;
var shipSize = 0.25;
var missileSize = 0.1;
var myShip;
var myShipProperties;
@ -34,34 +67,97 @@ var invadersBottomCorner = { x: gameAt.x, y: middleY , z: gameAt.z };
var rowHeight = ((gameAt.y + gameSize.y) - invadersBottomCorner.y) / numberOfRows;
var columnWidth = gameSize.x / (invadersPerRow + emptyColumns);
// vertical movement of invaders
var invaderRowOffset = 0;
var stepsPerRow = 20; // number of steps before invaders really move a whole row down.
var yPerStep = rowHeight/stepsPerRow;
var stepsToGround = (middleY - gameAt.y) / yPerStep;
var maxInvaderRowOffset=stepsToGround;
// missile related items
var missileFired = false;
var myMissile;
// sounds
var hitSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/hit.raw");
var shootSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/shoot.raw");
var moveSounds = new Array();
moveSounds[0] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/Lo1.raw");
moveSounds[1] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/Lo2.raw");
moveSounds[2] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/Lo3.raw");
moveSounds[3] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/Lo4.raw");
var currentMoveSound = 0;
var numberOfSounds = 4;
var stepsPerSound = invaderStepsPerCycle / numberOfSounds;
// if you set this to false, sounds will come from the location of particles instead of the player's head
var soundInMyHead = true;
// models...
var invaderModels = new Array();
invaderModels[0] = {
modelURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/newInvader16x16-large-purple.svo",
modelScale: 450,
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
};
invaderModels[1] = {
modelURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/newInvader16x16-large-cyan.svo",
modelScale: 450,
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
};
invaderModels[2] = {
modelURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/newInvader16x16-medium-cyan.svo",
modelScale: 450,
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
};
invaderModels[3] = {
modelURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/newInvader16x16-medium-green.svo",
modelScale: 450,
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
};
invaderModels[4] = {
modelURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/newInvader16x16-small-green.svo",
modelScale: 450,
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
};
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Feisar_Ship.FBX",
//modelURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/invader.svo",
// "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/spaceInvader3.fbx"
function initializeMyShip() {
myShipProperties = {
position: { x: middleX , y: gameAt.y, z: gameAt.z },
velocity: { x: 0, y: 0, z: 0 },
gravity: { x: 0, y: 0, z: 0 },
damping: 0,
radius: shipSize,
color: { red: 0, green: 255, blue: 0 },
lifetime: itemLifetimes
};
position: { x: middleX , y: gameAt.y, z: gameAt.z },
velocity: { x: 0, y: 0, z: 0 },
gravity: { x: 0, y: 0, z: 0 },
damping: 0,
radius: shipSize,
color: { red: 0, green: 255, blue: 0 },
modelURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/myCannon16x16.svo",
modelScale: 450,
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
lifetime: itemLifetimes
};
myShip = Particles.addParticle(myShipProperties);
}
// calculate the correct invaderPosition for an column row
function getInvaderPosition(row, column) {
var xMovePart = 0;
var xBasePart = invadersBottomCorner.x + (column * columnWidth);
var xMovePart = 0;
if (invaderMoveDirection > 0) {
xMovePart = (invaderMoveDirection * columnWidth * (invaderStepOfCycle/invaderStepsPerCycle));
} else {
xMovePart = columnWidth + (invaderMoveDirection * columnWidth * (invaderStepOfCycle/invaderStepsPerCycle));
}
var y = invadersBottomCorner.y + (row * rowHeight) - (invaderRowOffset * rowHeight/stepsPerRow);
var invaderPosition = {
x: xBasePart + xMovePart,
y: invadersBottomCorner.y + (row * rowHeight),
y: y,
z: invadersBottomCorner.z };
return invaderPosition;
@ -77,8 +173,11 @@ function initializeInvaders() {
velocity: { x: 0, y: 0, z: 0 },
gravity: { x: 0, y: 0, z: 0 },
damping: 0,
radius: shipSize,
radius: invaderSize,
color: { red: 255, green: 0, blue: 0 },
modelURL: invaderModels[row].modelURL,
modelScale: invaderModels[row].modelScale,
modelTranslation: invaderModels[row].modelTranslation,
lifetime: itemLifetimes
});
@ -88,31 +187,73 @@ function initializeInvaders() {
}
function moveInvaders() {
print("moveInvaders()...");
for (var row = 0; row < numberOfRows; row++) {
for (var column = 0; column < invadersPerRow; column++) {
props = Particles.getParticleProperties(invaders[row][column]);
if (props.isKnownID) {
invaderPosition = getInvaderPosition(row, column);
Particles.editParticle(invaders[row][column], { position: invaderPosition });
Particles.editParticle(invaders[row][column],
{
position: invaderPosition,
velocity: { x: 0, y: 0, z: 0 } // always reset this, incase they got collided with
});
}
}
}
}
function displayGameOver() {
gameOver = true;
print("Game over...");
}
function update() {
print("updating space invaders... iteration="+iteration);
iteration++;
invaderStepOfCycle++;
if (invaderStepOfCycle > invaderStepsPerCycle) {
invaderStepOfCycle = 0;
if (invaderMoveDirection > 0) {
invaderMoveDirection = -1;
} else {
invaderMoveDirection = 1;
if (!gameOver) {
//print("updating space invaders... iteration="+iteration);
iteration++;
if (invaderStepOfCycle % stepsPerSound == 0) {
// play the move sound
var options = new AudioInjectionOptions();
if (soundInMyHead) {
options.position = { x: MyAvatar.position.x + 0.0,
y: MyAvatar.position.y + 0.1,
z: MyAvatar.position.z + 0.0 };
} else {
options.position = getInvaderPosition(invadersPerRow / 2, numberOfRows / 2);
}
options.volume = 1.0;
Audio.playSound(moveSounds[currentMoveSound], options);
// get ready for next move sound
currentMoveSound = (currentMoveSound+1) % numberOfSounds;
}
invaderStepOfCycle++;
if (invaderStepOfCycle > invaderStepsPerCycle) {
// handle left/right movement
invaderStepOfCycle = 0;
if (invaderMoveDirection > 0) {
invaderMoveDirection = -1;
} else {
invaderMoveDirection = 1;
}
// handle downward movement
invaderRowOffset++; // move down one row
//print("invaderRowOffset="+invaderRowOffset);
// check to see if invaders have reached "ground"...
if (invaderRowOffset > maxInvaderRowOffset) {
displayGameOver();
return;
}
}
moveInvaders();
}
moveInvaders();
}
// register the call back so it fires before each data send
@ -134,6 +275,9 @@ function cleanupGame() {
if (missileFired) {
Particles.deleteParticle(myMissile);
}
Controller.releaseKeyEvents({text: " "});
Script.stop();
}
Script.scriptEnding.connect(cleanupGame);
@ -182,6 +326,17 @@ function fireMissile() {
lifetime: 5
});
var options = new AudioInjectionOptions();
if (soundInMyHead) {
options.position = { x: MyAvatar.position.x + 0.0,
y: MyAvatar.position.y + 0.1,
z: MyAvatar.position.z + 0.0 };
} else {
options.position = missilePosition;
}
options.volume = 1.0;
Audio.playSound(shootSound, options);
missileFired = true;
}
}
@ -219,6 +374,18 @@ function deleteIfInvader(possibleInvaderParticle) {
if (invaders[row][column].id == possibleInvaderParticle.id) {
Particles.deleteParticle(possibleInvaderParticle);
Particles.deleteParticle(myMissile);
// play the hit sound
var options = new AudioInjectionOptions();
if (soundInMyHead) {
options.position = { x: MyAvatar.position.x + 0.0,
y: MyAvatar.position.y + 0.1,
z: MyAvatar.position.z + 0.0 };
} else {
options.position = getInvaderPosition(row, column);
}
options.volume = 1.0;
Audio.playSound(hitSound, options);
}
}
}
@ -243,4 +410,6 @@ Particles.particleCollisionWithParticle.connect(particleCollisionWithParticle);
initializeMyShip();
initializeInvaders();
// shut down the game after 1 minute
var gameTimer = Script.setTimeout(endGame, itemLifetimes * 1000);

View file

@ -101,10 +101,12 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D
const int STATS_PELS_PER_LINE = 20;
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) {
QString messageWithNewLine = message + "\n";
fprintf(stdout, "%s", messageWithNewLine.toLocal8Bit().constData());
Application::getInstance()->getLogger()->addMessage(messageWithNewLine.toLocal8Bit().constData());
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
if (message.size() > 0) {
QString messageWithNewLine = message + "\n";
fprintf(stdout, "%s", messageWithNewLine.toLocal8Bit().constData());
Application::getInstance()->getLogger()->addMessage(messageWithNewLine.toLocal8Bit().constData());
}
}
Application::Application(int& argc, char** argv, timeval &startup_time) :
@ -152,8 +154,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_resetRecentMaxPacketsSoon(true),
_swatch(NULL),
_pasteMode(false),
_logger(new FileLogger(this)),
_persistThread(NULL)
_logger(new FileLogger(this))
{
_myAvatar = _avatarManager.getMyAvatar();
@ -314,12 +315,7 @@ Application::~Application() {
_voxelHideShowThread.terminate();
_voxelEditSender.terminate();
_particleEditSender.terminate();
if (_persistThread) {
_persistThread->terminate();
_persistThread->deleteLater();
_persistThread = NULL;
}
storeSizeAndPosition();
saveScripts();
_sharedVoxelSystem.changeTree(new VoxelTree);
@ -1260,7 +1256,8 @@ void Application::mousePressEvent(QMouseEvent* event) {
pasteVoxels();
}
if (MAKE_SOUND_ON_VOXEL_CLICK && _isHoverVoxel && !_isHoverVoxelSounding) {
if (!Menu::getInstance()->isOptionChecked(MenuOption::VoxelDeleteMode) &&
MAKE_SOUND_ON_VOXEL_CLICK && _isHoverVoxel && !_isHoverVoxelSounding) {
_hoverVoxelOriginalColor[0] = _hoverVoxel.red;
_hoverVoxelOriginalColor[1] = _hoverVoxel.green;
_hoverVoxelOriginalColor[2] = _hoverVoxel.blue;
@ -1905,9 +1902,6 @@ void Application::init() {
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
updateLocalOctreeCache(true);
}
void Application::closeMirrorView() {
@ -2060,7 +2054,7 @@ void Application::updateHoverVoxels(float deltaTime, float& distance, BoxFace& f
glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
// only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled,
// and make sure the tree is not already busy... because otherwise you'll have to wait.
if (!(_voxels.treeIsBusy() || _mousePressed)) {
if (!_mousePressed) {
{
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
_isHoverVoxel = _voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _hoverVoxel, distance, face);
@ -2205,9 +2199,6 @@ void Application::updateThreads(float deltaTime) {
_voxelHideShowThread.threadRoutine();
_voxelEditSender.threadRoutine();
_particleEditSender.threadRoutine();
if (_persistThread) {
_persistThread->threadRoutine();
}
}
}
@ -2882,7 +2873,8 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
}
}
_avatarManager.renderAvatars(whichCamera.getMode() == CAMERA_MODE_MIRROR, selfAvatarOnly);
bool renderMyHead = (whichCamera.getInterpolatedMode() != CAMERA_MODE_FIRST_PERSON);
_avatarManager.renderAvatars(renderMyHead, selfAvatarOnly);
if (!selfAvatarOnly) {
// Render the world box
@ -3880,10 +3872,6 @@ void Application::domainChanged(const QString& domainHostname) {
// reset the particle renderer
_particles.clear();
// reset our persist thread
qDebug() << "Domain changed to" << domainHostname << ". Swapping persist cache.";
updateLocalOctreeCache();
}
void Application::nodeKilled(SharedNodePointer node) {
@ -4153,49 +4141,6 @@ void Application::initAvatarAndViewFrustum() {
updateMyAvatar(0.f);
}
QString Application::getLocalVoxelCacheFileName() {
QString fileName = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
QDir logDir(fileName);
if (!logDir.exists(fileName)) {
logDir.mkdir(fileName);
}
fileName.append(QString("/hifi.voxelscache."));
fileName.append(_profile.getLastDomain());
fileName.append(QString(".svo"));
return fileName;
}
void Application::updateLocalOctreeCache(bool firstTime) {
// only do this if we've already got a persistThread or we're told this is the first time
if (firstTime || _persistThread) {
if (_persistThread) {
_persistThread->terminate();
_persistThread->deleteLater();
_persistThread = NULL;
}
QString localVoxelCacheFileName = getLocalVoxelCacheFileName();
const int LOCAL_CACHE_PERSIST_INTERVAL = 1000 * 10; // every 10 seconds
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableLocalVoxelCache)) {
_persistThread = new OctreePersistThread(_voxels.getTree(),
localVoxelCacheFileName.toLocal8Bit().constData(),LOCAL_CACHE_PERSIST_INTERVAL);
qDebug() << "updateLocalOctreeCache()... localVoxelCacheFileName=" << localVoxelCacheFileName;
}
if (_persistThread) {
_voxels.beginLoadingLocalVoxelCache(); // while local voxels are importing, don't do individual node VBO updates
connect(_persistThread, SIGNAL(loadCompleted()), &_voxels, SLOT(localVoxelCacheLoaded()));
_persistThread->initialize(true);
}
}
}
void Application::checkVersion() {
QNetworkRequest latestVersionRequest((QUrl(CHECK_VERSION_URL)));
latestVersionRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);

View file

@ -484,11 +484,6 @@ private:
FileLogger* _logger;
OctreePersistThread* _persistThread;
QString getLocalVoxelCacheFileName();
void updateLocalOctreeCache(bool firstTime = false);
void checkVersion();
void displayUpdateDialog();
bool shouldSkipVersion(QString latestVersion);

View file

@ -56,6 +56,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p
_numOutputCallbackBytes(0),
_loopbackAudioOutput(NULL),
_loopbackOutputDevice(NULL),
_proceduralAudioOutput(NULL),
_proceduralOutputDevice(NULL),
_inputRingBuffer(0),
_ringBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL),
_scope(scope),
@ -75,7 +77,7 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p
_muted(false)
{
// clear the array of locally injected samples
memset(_localInjectedSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
}
void Audio::init(QGLWidget *parent) {
@ -272,6 +274,9 @@ void Audio::start() {
// setup a loopback audio output device
_loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
// setup a procedural audio output device
_proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
gettimeofday(&_lastReceiveTime, NULL);
}
@ -332,7 +337,7 @@ void Audio::handleAudioInput() {
memset(monoAudioSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
// zero out the locally injected audio in preparation for audio procedural sounds
memset(_localInjectedSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
if (!_muted) {
// we aren't muted, downsample the input audio
@ -363,6 +368,22 @@ void Audio::handleAudioInput() {
// add procedural effects to the appropriate input samples
addProceduralSounds(monoAudioSamples,
NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
if (!_proceduralOutputDevice) {
_proceduralOutputDevice = _proceduralAudioOutput->start();
}
// send whatever procedural sounds we want to locally loop back to the _proceduralOutputDevice
QByteArray proceduralOutput;
proceduralOutput.resize(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 4 * sizeof(int16_t));
linearResampling(_localProceduralSamples,
reinterpret_cast<int16_t*>(proceduralOutput.data()),
NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL,
NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 4,
_desiredInputFormat, _outputFormat);
_proceduralOutputDevice->write(proceduralOutput);
NodeList* nodeList = NodeList::getInstance();
SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);
@ -396,7 +417,7 @@ void Audio::handleAudioInput() {
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO)
.updateValue(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
}
delete[] inputAudioSamples;
delete[] inputAudioSamples;
}
}
@ -431,12 +452,6 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
static float networkOutputToOutputRatio = (_desiredOutputFormat.sampleRate() / (float) _outputFormat.sampleRate())
* (_desiredOutputFormat.channelCount() / (float) _outputFormat.channelCount());
static int numRequiredOutputSamples = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / networkOutputToOutputRatio;
QByteArray outputBuffer;
outputBuffer.resize(numRequiredOutputSamples * sizeof(int16_t));
if (!_ringBuffer.isStarved() && _audioOutput->bytesFree() == _audioOutput->bufferSize()) {
// we don't have any audio data left in the output buffer
@ -448,6 +463,14 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
// if there is anything in the ring buffer, decide what to do
if (_ringBuffer.samplesAvailable() > 0) {
int numNetworkOutputSamples = _ringBuffer.samplesAvailable();
int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio;
QByteArray outputBuffer;
outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t));
if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO
+ (_jitterBufferSamples * 2))) {
// starved and we don't have enough to start, keep waiting
@ -458,64 +481,28 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
// copy the samples we'll resample from the ring buffer - this also
// pushes the read pointer of the ring buffer forwards
int16_t ringBufferSamples[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO];
_ringBuffer.readSamples(ringBufferSamples, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO);
// add the next NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL from each QByteArray
// in our _localInjectionByteArrays QVector to the _localInjectedSamples
// add to the output samples whatever is in the _localAudioOutput byte array
// that lets this user hear sound effects and loopback (if enabled)
for (int b = 0; b < _localInjectionByteArrays.size(); b++) {
QByteArray audioByteArray = _localInjectionByteArrays.at(b);
int16_t* byteArraySamples = (int16_t*) audioByteArray.data();
int samplesToRead = qMin((int)(audioByteArray.size() / sizeof(int16_t)),
NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
for (int i = 0; i < samplesToRead; i++) {
_localInjectedSamples[i] = glm::clamp(_localInjectedSamples[i] + byteArraySamples[i],
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
}
if (samplesToRead < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
// there isn't anything left to inject from this byte array, remove it from the vector
_localInjectionByteArrays.remove(b);
} else {
// pull out the bytes we just read for outputs
audioByteArray.remove(0, samplesToRead * sizeof(int16_t));
// still data left to read - replace the byte array in the QVector with the smaller one
_localInjectionByteArrays.replace(b, audioByteArray);
}
}
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
ringBufferSamples[i * 2] = glm::clamp(ringBufferSamples[i * 2] + _localInjectedSamples[i],
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
ringBufferSamples[(i * 2) + 1] = glm::clamp(ringBufferSamples[(i * 2) + 1] + _localInjectedSamples[i],
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
}
int16_t* ringBufferSamples= new int16_t[numNetworkOutputSamples];
_ringBuffer.readSamples(ringBufferSamples, numNetworkOutputSamples);
// add the next numNetworkOutputSamples from each QByteArray
// in our _localInjectionByteArrays QVector to the localInjectedSamples
// copy the packet from the RB to the output
linearResampling(ringBufferSamples,
(int16_t*) outputBuffer.data(),
NETWORK_BUFFER_LENGTH_SAMPLES_STEREO,
numRequiredOutputSamples,
numNetworkOutputSamples,
numDeviceOutputSamples,
_desiredOutputFormat, _outputFormat);
if (_outputDevice) {
_outputDevice->write(outputBuffer);
// add output (@speakers) data just written to the scope
QMetaObject::invokeMethod(_scope, "addSamples", Qt::QueuedConnection,
Q_ARG(QByteArray, QByteArray((char*) ringBufferSamples,
NETWORK_BUFFER_LENGTH_BYTES_STEREO)),
Q_ARG(QByteArray, QByteArray((char*) ringBufferSamples, numNetworkOutputSamples)),
Q_ARG(bool, true), Q_ARG(bool, false));
}
delete[] ringBufferSamples;
}
}
@ -672,7 +659,7 @@ void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) {
int16_t collisionSample = (int16_t) sample;
monoInput[i] = glm::clamp(monoInput[i] + collisionSample, MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
_localInjectedSamples[i] = glm::clamp(_localInjectedSamples[i] + collisionSample,
_localProceduralSamples[i] = glm::clamp(_localProceduralSamples[i] + collisionSample,
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
_collisionSoundMagnitude *= _collisionSoundDuration;
@ -696,7 +683,7 @@ void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) {
int16_t collisionSample = (int16_t) sample;
monoInput[i] = glm::clamp(monoInput[i] + collisionSample, MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
_localInjectedSamples[i] = glm::clamp(_localInjectedSamples[i] + collisionSample,
_localProceduralSamples[i] = glm::clamp(_localProceduralSamples[i] + collisionSample,
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
_drumSoundVolume *= (1.f - _drumSoundDecay);
@ -727,8 +714,8 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float
}
void Audio::handleAudioByteArray(const QByteArray& audioByteArray) {
// add this byte array to our QVector
_localInjectionByteArrays.append(audioByteArray);
// TODO: either create a new audio device (up to the limit of the sound card or a hard limit)
// or send to the mixer and use delayed loopback
}
void Audio::renderToolIcon(int screenHeight) {

View file

@ -86,8 +86,7 @@ private:
QAudioFormat _inputFormat;
QIODevice* _inputDevice;
int _numInputCallbackBytes;
int16_t _localInjectedSamples[NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL];
QVector<QByteArray> _localInjectionByteArrays;
int16_t _localProceduralSamples[NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL];
QAudioOutput* _audioOutput;
QAudioFormat _desiredOutputFormat;
QAudioFormat _outputFormat;
@ -95,6 +94,8 @@ private:
int _numOutputCallbackBytes;
QAudioOutput* _loopbackAudioOutput;
QIODevice* _loopbackOutputDevice;
QAudioOutput* _proceduralAudioOutput;
QIODevice* _proceduralOutputDevice;
AudioRingBuffer _inputRingBuffer;
AudioRingBuffer _ringBuffer;

View file

@ -36,6 +36,7 @@ Camera::Camera() {
_modeShiftRate = 1.0f;
_linearModeShift = 0.0f;
_mode = CAMERA_MODE_THIRD_PERSON;
_prevMode = CAMERA_MODE_THIRD_PERSON;
_tightness = 10.0f; // default
_fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES;
_aspectRatio = 16.f/9.f;
@ -123,6 +124,7 @@ void Camera::setModeShiftRate ( float rate ) {
void Camera::setMode(CameraMode m) {
_prevMode = _mode;
_mode = m;
_modeShift = 0.0;
_linearModeShift = 0.0;
@ -199,6 +201,17 @@ bool Camera::getFrustumNeedsReshape() const {
return _frustumNeedsReshape;
}
// call this when deciding whether to render the head or not
CameraMode Camera::getInterpolatedMode() const {
const float SHIFT_THRESHOLD_INTO_FIRST_PERSON = 0.7f;
const float SHIFT_THRESHOLD_OUT_OF_FIRST_PERSON = 0.6f;
if ((_mode == CAMERA_MODE_FIRST_PERSON && _linearModeShift < SHIFT_THRESHOLD_INTO_FIRST_PERSON) ||
(_prevMode == CAMERA_MODE_FIRST_PERSON && _linearModeShift < SHIFT_THRESHOLD_OUT_OF_FIRST_PERSON)) {
return _prevMode;
}
return _mode;
}
// call this after reshaping the view frustum
void Camera::setFrustumWasReshaped() {
_frustumNeedsReshape = false;

View file

@ -61,6 +61,8 @@ public:
const glm::quat& getEyeOffsetOrientation () const { return _eyeOffsetOrientation; }
float getScale () const { return _scale; }
CameraMode getInterpolatedMode() const;
bool getFrustumNeedsReshape() const; // call to find out if the view frustum needs to be reshaped
void setFrustumWasReshaped(); // call this after reshaping the view frustum.
@ -68,6 +70,7 @@ private:
bool _needsToInitialize;
CameraMode _mode;
CameraMode _prevMode;
bool _frustumNeedsReshape;
glm::vec3 _position;
glm::vec3 _idealPosition;

View file

@ -73,12 +73,12 @@ void DatagramProcessor::processDatagrams() {
if (wantExtraDebugging && packetTypeForPacket(incomingPacket) == PacketTypeVoxelData) {
int numBytesPacketHeader = numBytesForPacketHeader(incomingPacket);
unsigned char* dataAt = reinterpret_cast<unsigned char*>(incomingPacket.data()) + numBytesPacketHeader;
dataAt += sizeof(VOXEL_PACKET_FLAGS);
VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt);
dataAt += sizeof(VOXEL_PACKET_SEQUENCE);
VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt);
dataAt += sizeof(VOXEL_PACKET_SENT_TIME);
VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
dataAt += sizeof(OCTREE_PACKET_FLAGS);
OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt);
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
OCTREE_PACKET_SENT_TIME sentAt = (*(OCTREE_PACKET_SENT_TIME*)dataAt);
dataAt += sizeof(OCTREE_PACKET_SENT_TIME);
OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
int flightTime = arrivedAt - sentAt;
printf("got PacketType_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime);

View file

@ -317,7 +317,6 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges);
addActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools()));
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DisableLocalVoxelCache);
QMenu* voxelProtoOptionsMenu = voxelOptionsMenu->addMenu("Voxel Server Protocol Options");

View file

@ -176,7 +176,6 @@ namespace MenuOption {
const QString DestructiveAddVoxel = "Create Voxel is Destructive";
const QString DisableColorVoxels = "Disable Colored Voxels";
const QString DisableDeltaSending = "Disable Delta Sending";
const QString DisableLocalVoxelCache = "Disable Local Voxel Cache";
const QString DisableLowRes = "Disable Lower Resolution While Moving";
const QString DisplayFrustum = "Display Frustum";
const QString DisplayLeapHands = "Display Leap Hands";

View file

@ -84,12 +84,11 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg
const float alpha = 1.0f;
Model* model = getModel(particle.getModelURL());
glm::vec3 translationAdjustment = particle.getModelTranslation();
glm::vec3 translationAdjustment = particle.getModelTranslation() * radius;
// set the position
glm::vec3 translation(position.x, position.y, position.z);
model->setTranslation(translation + translationAdjustment);
glm::vec3 translation = position + translationAdjustment;
model->setTranslation(translation);
// set the rotation
glm::quat rotation = particle.getModelRotation();
@ -99,11 +98,21 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg
// TODO: need to figure out correct scale adjust, this was arbitrarily set to make a couple models work
const float MODEL_SCALE = 0.00575f;
glm::vec3 scale(1.0f,1.0f,1.0f);
model->setScale(scale * MODEL_SCALE * radius * particle.getModelScale());
float modelScale = particle.getModelScale();
model->setScale(scale * MODEL_SCALE * radius * modelScale);
model->simulate(0.0f);
model->render(alpha); // TODO: should we allow particles to have alpha on their models?
const bool wantDebugSphere = false;
if (wantDebugSphere) {
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutWireSphere(radius, 15, 15);
glPopMatrix();
}
glPopMatrix();
} else {
glPushMatrix();

View file

@ -99,8 +99,6 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
_culledOnce = false;
_inhideOutOfView = false;
_treeIsBusy = false;
}
void VoxelSystem::elementDeleted(OctreeElement* element) {
@ -561,30 +559,30 @@ int VoxelSystem::parseData(const QByteArray& packet) {
const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data()) + numBytesPacketHeader;
VOXEL_PACKET_FLAGS flags = (*(VOXEL_PACKET_FLAGS*)(dataAt));
dataAt += sizeof(VOXEL_PACKET_FLAGS);
VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt);
dataAt += sizeof(VOXEL_PACKET_SEQUENCE);
OCTREE_PACKET_FLAGS flags = (*(OCTREE_PACKET_FLAGS*)(dataAt));
dataAt += sizeof(OCTREE_PACKET_FLAGS);
OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt);
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt);
dataAt += sizeof(VOXEL_PACKET_SENT_TIME);
OCTREE_PACKET_SENT_TIME sentAt = (*(OCTREE_PACKET_SENT_TIME*)dataAt);
dataAt += sizeof(OCTREE_PACKET_SENT_TIME);
bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT);
bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT);
VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
int flightTime = arrivedAt - sentAt;
VOXEL_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0;
int dataBytes = packet.size() - VOXEL_PACKET_HEADER_SIZE;
OCTREE_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0;
int dataBytes = packet.size() - (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_SIZE);
int subsection = 1;
while (dataBytes > 0) {
if (packetIsCompressed) {
if (dataBytes > sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE)) {
sectionLength = (*(VOXEL_PACKET_INTERNAL_SECTION_SIZE*)dataAt);
dataAt += sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE);
dataBytes -= sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE);
if (dataBytes > sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE)) {
sectionLength = (*(OCTREE_PACKET_INTERNAL_SECTION_SIZE*)dataAt);
dataAt += sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
dataBytes -= sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
} else {
sectionLength = 0;
dataBytes = 0; // stop looping something is wrong
@ -594,9 +592,10 @@ int VoxelSystem::parseData(const QByteArray& packet) {
}
if (sectionLength) {
PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData() section");
// ask the VoxelTree to read the bitstream into the tree
ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID());
lockTree();
_tree->lockForWrite();
VoxelPacketData packetData(packetIsCompressed);
packetData.loadFinalizedContent(dataAt, sectionLength);
if (Application::getInstance()->getLogger()->extraDebugging()) {
@ -608,7 +607,7 @@ int VoxelSystem::parseData(const QByteArray& packet) {
packetData.getUncompressedSize());
}
_tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args);
unlockTree();
_tree->unlock();
dataBytes -= sectionLength;
dataAt += sectionLength;
@ -1395,9 +1394,11 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {
int VoxelSystem::_nodeCount = 0;
void VoxelSystem::killLocalVoxels() {
lockTree();
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelSystem::killLocalVoxels()");
_tree->lockForWrite();
_tree->eraseAllOctreeElements();
unlockTree();
_tree->unlock();
clearFreeBufferIndexes();
_voxelsInReadArrays = 0; // do we need to do this?
setupNewVoxelsForDrawing();
@ -1416,10 +1417,12 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void
}
void VoxelSystem::clearAllNodesBufferIndex() {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelSystem::clearAllNodesBufferIndex()");
_nodeCount = 0;
lockTree();
_tree->lockForRead(); // we won't change the tree so it's ok to treat this as a read
_tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation);
unlockTree();
_tree->unlock();
if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
qDebug("clearing buffer index of %d nodes", _nodeCount);
}
@ -1481,7 +1484,8 @@ bool VoxelSystem::trueColorizeOperation(OctreeElement* element, void* extraData)
}
void VoxelSystem::trueColorize() {
PerformanceWarning warn(true, "trueColorize()",true);
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"trueColorize()",true);
_nodeCount = 0;
_tree->recurseTreeWithOperation(trueColorizeOperation);
qDebug("setting true color for %d nodes", _nodeCount);
@ -1951,9 +1955,13 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) {
return;
}
lockTree();
_tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args);
unlockTree();
{
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelSystem::... recurseTreeWithOperation(hideOutOfViewOperation)");
_tree->lockForRead();
_tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args);
_tree->unlock();
}
_lastCulledViewFrustum = args.thisViewFrustum; // save last stable
_culledOnce = true;
@ -2150,35 +2158,47 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData
bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
VoxelDetail& detail, float& distance, BoxFace& face) {
lockTree();
OctreeElement* element;
if (!_tree->findRayIntersection(origin, direction, element, distance, face)) {
unlockTree();
return false;
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelSystem::findRayIntersection()");
bool result = false; // assume no intersection
if (_tree->tryLockForRead()) {
OctreeElement* element;
result = _tree->findRayIntersection(origin, direction, element, distance, face);
if (result) {
VoxelTreeElement* voxel = (VoxelTreeElement*)element;
detail.x = voxel->getCorner().x;
detail.y = voxel->getCorner().y;
detail.z = voxel->getCorner().z;
detail.s = voxel->getScale();
detail.red = voxel->getColor()[0];
detail.green = voxel->getColor()[1];
detail.blue = voxel->getColor()[2];
}
_tree->unlock();
}
VoxelTreeElement* voxel = (VoxelTreeElement*)element;
detail.x = voxel->getCorner().x;
detail.y = voxel->getCorner().y;
detail.z = voxel->getCorner().z;
detail.s = voxel->getScale();
detail.red = voxel->getColor()[0];
detail.green = voxel->getColor()[1];
detail.blue = voxel->getColor()[2];
unlockTree();
return true;
return result;
}
bool VoxelSystem::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) {
lockTree();
bool result = _tree->findSpherePenetration(center, radius, penetration);
unlockTree();
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelSystem::findSpherePenetration()");
bool result = false; // assume no penetration
if (_tree->tryLockForRead()) {
result = _tree->findSpherePenetration(center, radius, penetration);
_tree->unlock();
}
return result;
}
bool VoxelSystem::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) {
lockTree();
bool result = _tree->findCapsulePenetration(start, end, radius, penetration);
unlockTree();
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelSystem::findCapsulePenetration()");
bool result = false; // assume no penetration
if (_tree->tryLockForRead()) {
result = _tree->findCapsulePenetration(start, end, radius, penetration);
_tree->unlock();
}
return result;
}
@ -2354,13 +2374,14 @@ void VoxelSystem::collectStatsForTreesAndVBOs() {
void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) {
lockTree();
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelSystem::deleteVoxelAt()");
_tree->lockForWrite();
_tree->deleteVoxelAt(x, y, z, s);
unlockTree();
_tree->unlock();
// redraw!
setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in?
};
VoxelTreeElement* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const {
@ -2370,10 +2391,12 @@ VoxelTreeElement* VoxelSystem::getVoxelAt(float x, float y, float z, float s) co
void VoxelSystem::createVoxel(float x, float y, float z, float s,
unsigned char red, unsigned char green, unsigned char blue, bool destructive) {
//qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s);
lockTree();
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelSystem::createVoxel()");
_tree->lockForWrite();
_tree->createVoxel(x, y, z, s, red, green, blue, destructive);
unlockTree();
_tree->unlock();
setupNewVoxelsForDrawing();
};
@ -2744,37 +2767,3 @@ unsigned long VoxelSystem::getVoxelMemoryUsageGPU() {
return (_initialMemoryUsageGPU - currentFreeMemory);
}
void VoxelSystem::lockTree() {
_treeLock.lock();
_treeIsBusy = true;
}
void VoxelSystem::unlockTree() {
_treeIsBusy = false;
_treeLock.unlock();
}
void VoxelSystem::localVoxelCacheLoaded() {
qDebug() << "localVoxelCacheLoaded()";
// Make sure that the application has properly set up the view frustum for our loaded state
Application::getInstance()->initAvatarAndViewFrustum();
_tree->setDirtyBit(); // make sure the tree thinks it's dirty
_setupNewVoxelsForDrawingLastFinished = 0; // don't allow the setupNewVoxelsForDrawing() shortcuts
_writeRenderFullVBO = true; // this will disable individual node updates, was reset by killLocalVoxels()
setupNewVoxelsForDrawing();
_inhideOutOfView = false; // reenable hideOutOfView behavior
}
void VoxelSystem::beginLoadingLocalVoxelCache() {
qDebug() << "beginLoadingLocalVoxelCache()";
_writeRenderFullVBO = true; // this will disable individual node updates
_inhideOutOfView = true; // this will disable hidOutOfView which we want to do until local cache is loaded
killLocalVoxels();
qDebug() << "DONE beginLoadingLocalVoxelCache()";
}

View file

@ -110,8 +110,6 @@ public:
virtual void elementDeleted(OctreeElement* element);
virtual void elementUpdated(OctreeElement* element);
bool treeIsBusy() const { return _treeIsBusy; }
VoxelTreeElement* getVoxelEnclosing(const glm::vec3& point);
signals:
@ -144,9 +142,6 @@ public slots:
void setUseVoxelShader(bool useVoxelShader);
void setVoxelsAsPoints(bool voxelsAsPoints);
void localVoxelCacheLoaded();
void beginLoadingLocalVoxelCache();
protected:
float _treeScale;
unsigned long _maxVoxels;
@ -304,10 +299,6 @@ private:
bool _useFastVoxelPipeline;
bool _inhideOutOfView;
bool _treeIsBusy; // is the tree mutex locked? if so, it's busy, and if you can avoid it, don't access the tree
void lockTree();
void unlockTree();
};
#endif

View file

@ -242,7 +242,9 @@ void Avatar::renderBody(bool forceRenderHead) {
glm::vec3 pos = getPosition();
//printf("Render other at %.3f, %.2f, %.2f\n", pos.x, pos.y, pos.z);
_skeletonModel.render(1.0f);
_head.render(1.0f);
if (forceRenderHead) {
_head.render(1.0f);
}
_hand.render(false);
}

View file

@ -75,7 +75,6 @@ void AvatarManager::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) {
bool renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors);
if (!selfAvatarOnly) {
// Render avatars of other nodes
foreach (const AvatarSharedPointer& avatarPointer, _avatarHash) {
Avatar* avatar = static_cast<Avatar*>(avatarPointer.data());
if (!avatar->isInitialized()) {
@ -84,7 +83,7 @@ void AvatarManager::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) {
if (avatar == static_cast<Avatar*>(_myAvatar.data())) {
avatar->render(forceRenderHead);
} else {
avatar->render(false);
avatar->render(true);
}
avatar->setDisplayingLookatVectors(renderLookAtVectors);
}

View file

@ -37,7 +37,6 @@ Head::Head(Avatar* owningAvatar) :
_leftEyeBlinkVelocity(0.0f),
_rightEyeBlinkVelocity(0.0f),
_timeWithoutTalking(0.0f),
_cameraYaw(_yaw),
_isCameraMoving(false),
_faceModel(this)
{
@ -189,8 +188,7 @@ glm::quat Head::getOrientation() const {
glm::quat Head::getCameraOrientation () const {
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar);
return owningAvatar->getWorldAlignedOrientation()
* glm::quat(glm::radians(glm::vec3(_pitch, _cameraYaw, 0.0f)));
return owningAvatar->getWorldAlignedOrientation();
}
glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const {

View file

@ -96,7 +96,6 @@ private:
float _leftEyeBlinkVelocity;
float _rightEyeBlinkVelocity;
float _timeWithoutTalking;
float _cameraYaw;
bool _isCameraMoving;
FaceModel _faceModel;

View file

@ -1632,7 +1632,18 @@ FBXGeometry readSVO(const QByteArray& model) {
VoxelTree tree;
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS);
tree.readBitstreamToTree((unsigned char*)model.data(), model.size(), args);
unsigned char* dataAt = (unsigned char*)model.data();
size_t dataSize = model.size();
if (tree.getWantSVOfileVersions()) {
// skip the type/version
dataAt += sizeof(PacketType);
dataSize -= sizeof(PacketType);
dataAt += sizeof(PacketVersion);
dataSize -= sizeof(PacketVersion);
}
tree.readBitstreamToTree(dataAt, dataSize, args);
tree.recurseTreeWithOperation(addMeshVoxelsOperation, &mesh);
geometry.meshes.append(mesh);

View file

@ -70,9 +70,9 @@ qint64 AudioRingBuffer::readData(char *data, qint64 maxSize) {
// read to the end of the buffer
int numSamplesToEnd = (_buffer + _sampleCapacity) - _nextOutput;
memcpy(data, _nextOutput, numSamplesToEnd * sizeof(int16_t));
// read the rest from the beginning of the buffer
memcpy(data + numSamplesToEnd, _buffer, (numReadSamples - numSamplesToEnd) * sizeof(int16_t));
memcpy(data + (numSamplesToEnd * sizeof(int16_t)), _buffer, (numReadSamples - numSamplesToEnd) * sizeof(int16_t));
} else {
// read the data
memcpy(data, _nextOutput, numReadSamples * sizeof(int16_t));

View file

@ -171,7 +171,7 @@ void DatagramSequencer::receivedDatagram(const QByteArray& datagram) {
}
// read and dispatch the high-priority messages
quint32 highPriorityMessageCount;
int highPriorityMessageCount;
_incomingPacketStream >> highPriorityMessageCount;
int newHighPriorityMessages = highPriorityMessageCount - _receivedHighPriorityMessages;
for (int i = 0; i < highPriorityMessageCount; i++) {

View file

@ -1,36 +0,0 @@
cmake_minimum_required(VERSION 2.8)
set(ROOT_DIR ../..)
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
# setup for find modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
set(TARGET_NAME octree-server)
find_package(Qt5Network REQUIRED)
find_package(Qt5Widgets REQUIRED)
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
setup_hifi_library(${TARGET_NAME} ${OPTIONAL_SRCS})
qt5_use_modules(${TARGET_NAME} Network Widgets)
include(${MACRO_DIR}/IncludeGLM.cmake)
include_glm(${TARGET_NAME} ${ROOT_DIR})
# link ZLIB
find_package(ZLIB)
include_directories(${ZLIB_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
# link in the shared library
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
# link in the hifi octree library
link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
# link the embedded webserver
link_hifi_library(embedded-webserver ${TARGET_NAME} ${ROOT_DIR})

View file

@ -30,10 +30,10 @@ typedef uint16_t OCTREE_PACKET_INTERNAL_SECTION_SIZE;
const int MAX_OCTREE_PACKET_SIZE = MAX_PACKET_SIZE;
// this is overly conservative - sizeof(PacketType) is 8 bytes but a packed PacketType could be as small as one byte
const int OCTREE_PACKET_HEADER_SIZE = MAX_PACKET_HEADER_BYTES + sizeof(OCTREE_PACKET_FLAGS)
const int OCTREE_PACKET_EXTRA_HEADERS_SIZE = sizeof(OCTREE_PACKET_FLAGS)
+ sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME);
const int MAX_OCTREE_PACKET_DATA_SIZE = MAX_PACKET_SIZE - OCTREE_PACKET_HEADER_SIZE;
const int MAX_OCTREE_PACKET_DATA_SIZE = MAX_PACKET_SIZE - (MAX_PACKET_HEADER_BYTES + OCTREE_PACKET_EXTRA_HEADERS_SIZE);
const int MAX_OCTREE_UNCOMRESSED_PACKET_SIZE = MAX_OCTREE_PACKET_DATA_SIZE;

View file

@ -64,7 +64,7 @@ void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const Hifi
int flightTime = arrivedAt - sentAt + clockSkew;
OCTREE_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0;
int dataBytes = packetLength - OCTREE_PACKET_HEADER_SIZE;
int dataBytes = packetLength - (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_SIZE);
if (extraDebugging) {
qDebug("OctreeRenderer::processDatagram() ... Got Packet Section"

View file

@ -1,37 +0,0 @@
cmake_minimum_required(VERSION 2.8)
set(ROOT_DIR ../..)
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
# setup for find modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
set(TARGET_NAME particle-server)
find_package(Qt5Widgets REQUIRED)
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
setup_hifi_library(${TARGET_NAME} ${OPTIONAL_SRCS})
qt5_use_modules(${TARGET_NAME} Widgets)
# inluce GLM
include(${MACRO_DIR}/IncludeGLM.cmake)
include_glm(${TARGET_NAME} ${ROOT_DIR})
# link in the shared library
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
# link ZLIB
find_package(ZLIB)
include_directories(${ZLIB_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(octree-server ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR})
# link in the embedded webserver
link_hifi_library(embedded-webserver ${TARGET_NAME} ${ROOT_DIR})

View file

@ -92,6 +92,10 @@ Particle::Particle(const ParticleID& particleID, const ParticleProperties& prope
_script = DEFAULT_SCRIPT;
_inHand = NOT_IN_HAND;
_shouldDie = false;
_modelURL = DEFAULT_MODEL_URL;
_modelTranslation = DEFAULT_MODEL_TRANSLATION;
_modelRotation = DEFAULT_MODEL_ROTATION;
_modelScale = DEFAULT_MODEL_SCALE;
setProperties(properties);
}
@ -124,6 +128,10 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3
_script = updateScript;
_inHand = inHand;
_shouldDie = false;
_modelURL = DEFAULT_MODEL_URL;
_modelTranslation = DEFAULT_MODEL_TRANSLATION;
_modelRotation = DEFAULT_MODEL_ROTATION;
_modelScale = DEFAULT_MODEL_SCALE;
}
void Particle::setMass(float value) {
@ -190,6 +198,12 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
success = packetData->appendRawData((const unsigned char*)qPrintable(_modelURL), modelURLLength);
}
}
// modelScale
if (success) {
success = packetData->appendValue(getModelScale());
}
// modelTranslation
if (success) {
success = packetData->appendValue(getModelTranslation());
@ -198,11 +212,6 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
if (success) {
success = packetData->appendValue(getModelRotation());
}
// modelScale
if (success) {
success = packetData->appendValue(getModelScale());
}
return success;
}
@ -319,6 +328,11 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += modelURLLength;
bytesRead += modelURLLength;
// modelScale
memcpy(&_modelScale, dataAt, sizeof(_modelScale));
dataAt += sizeof(_modelScale);
bytesRead += sizeof(_modelScale);
// modelTranslation
memcpy(&_modelTranslation, dataAt, sizeof(_modelTranslation));
dataAt += sizeof(_modelTranslation);
@ -329,11 +343,6 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += bytes;
bytesRead += bytes;
// modelScale
memcpy(&_modelScale, dataAt, sizeof(_modelScale));
dataAt += sizeof(_modelScale);
bytesRead += sizeof(_modelScale);
//printf("Particle::readParticleDataFromBuffer()... "); debugDump();
}
return bytesRead;
@ -498,6 +507,13 @@ Particle Particle::fromEditPacket(const unsigned char* data, int length, int& pr
processedBytes += modelURLLength;
}
// modelScale
if (isNewParticle || ((packetContainsBits & CONTAINS_MODEL_SCALE) == CONTAINS_MODEL_SCALE)) {
memcpy(&newParticle._modelScale, dataAt, sizeof(newParticle._modelScale));
dataAt += sizeof(newParticle._modelScale);
processedBytes += sizeof(newParticle._modelScale);
}
// modelTranslation
if (isNewParticle || ((packetContainsBits & CONTAINS_MODEL_TRANSLATION) == CONTAINS_MODEL_TRANSLATION)) {
memcpy(&newParticle._modelTranslation, dataAt, sizeof(newParticle._modelTranslation));
@ -512,13 +528,6 @@ Particle Particle::fromEditPacket(const unsigned char* data, int length, int& pr
processedBytes += bytes;
}
// modelScale
if (isNewParticle || ((packetContainsBits & CONTAINS_MODEL_SCALE) == CONTAINS_MODEL_SCALE)) {
memcpy(&newParticle._modelScale, dataAt, sizeof(newParticle._modelScale));
dataAt += sizeof(newParticle._modelScale);
processedBytes += sizeof(newParticle._modelScale);
}
const bool wantDebugging = false;
if (wantDebugging) {
qDebug("Particle::fromEditPacket()...");
@ -696,6 +705,14 @@ bool Particle::encodeParticleEditMessageDetails(PacketType command, ParticleID i
sizeOut += urlLength;
}
// modelScale
if (isNewParticle || ((packetContainsBits & CONTAINS_MODEL_SCALE) == CONTAINS_MODEL_SCALE)) {
float modelScale = properties.getModelScale();
memcpy(copyAt, &modelScale, sizeof(modelScale));
copyAt += sizeof(modelScale);
sizeOut += sizeof(modelScale);
}
// modelTranslation
if (isNewParticle || ((packetContainsBits & CONTAINS_MODEL_TRANSLATION) == CONTAINS_MODEL_TRANSLATION)) {
glm::vec3 modelTranslation = properties.getModelTranslation(); // should this be relative to TREE_SCALE??
@ -711,14 +728,6 @@ bool Particle::encodeParticleEditMessageDetails(PacketType command, ParticleID i
sizeOut += bytes;
}
// modelScale
if (isNewParticle || ((packetContainsBits & CONTAINS_MODEL_SCALE) == CONTAINS_MODEL_SCALE)) {
float modelScale = properties.getModelScale();
memcpy(copyAt, &modelScale, sizeof(modelScale));
copyAt += sizeof(modelScale);
sizeOut += sizeof(modelScale);
}
bool wantDebugging = false;
if (wantDebugging) {
printf("encodeParticleEditMessageDetails()....\n");
@ -931,9 +940,9 @@ ParticleProperties::ParticleProperties() :
_inHand(false),
_shouldDie(false),
_modelURL(""),
_modelScale(DEFAULT_MODEL_SCALE),
_modelTranslation(DEFAULT_MODEL_TRANSLATION),
_modelRotation(DEFAULT_MODEL_ROTATION),
_modelScale(DEFAULT_MODEL_SCALE),
_id(UNKNOWN_PARTICLE_ID),
_idSet(false),
@ -950,9 +959,9 @@ ParticleProperties::ParticleProperties() :
_inHandChanged(false),
_shouldDieChanged(false),
_modelURLChanged(false),
_modelScaleChanged(false),
_modelTranslationChanged(false),
_modelRotationChanged(false),
_modelScaleChanged(false),
_defaultSettings(true)
{
}
@ -1004,6 +1013,10 @@ uint16_t ParticleProperties::getChangedBits() const {
changedBits += CONTAINS_MODEL_URL;
}
if (_modelScaleChanged) {
changedBits += CONTAINS_MODEL_SCALE;
}
if (_modelTranslationChanged) {
changedBits += CONTAINS_MODEL_TRANSLATION;
}
@ -1012,10 +1025,6 @@ uint16_t ParticleProperties::getChangedBits() const {
changedBits += CONTAINS_MODEL_ROTATION;
}
if (_modelScaleChanged) {
changedBits += CONTAINS_MODEL_SCALE;
}
return changedBits;
}
@ -1045,14 +1054,14 @@ QScriptValue ParticleProperties::copyToScriptValue(QScriptEngine* engine) const
properties.setProperty("modelURL", _modelURL);
properties.setProperty("modelScale", _modelScale);
QScriptValue modelTranslation = vec3toScriptValue(engine, _modelTranslation);
properties.setProperty("modelTranslation", modelTranslation);
QScriptValue modelRotation = quatToScriptValue(engine, _modelRotation);
properties.setProperty("modelRotation", modelRotation);
properties.setProperty("modelScale", _modelScale);
if (_idSet) {
properties.setProperty("id", _id);
@ -1203,7 +1212,17 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) {
_modelURLChanged = true;
}
}
QScriptValue modelScale = object.property("modelScale");
if (modelScale.isValid()) {
float newModelScale;
newModelScale = modelScale.toVariant().toFloat();
if (_defaultSettings || newModelScale != _modelScale) {
_modelScale = newModelScale;
_modelScaleChanged = true;
}
}
QScriptValue modelTranslation = object.property("modelTranslation");
if (modelTranslation.isValid()) {
QScriptValue x = modelTranslation.property("x");
@ -1241,16 +1260,6 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) {
}
}
QScriptValue modelScale = object.property("modelScale");
if (modelScale.isValid()) {
float newModelScale;
newModelScale = modelScale.toVariant().toFloat();
if (_defaultSettings || newModelScale != _modelScale) {
_modelScale = newModelScale;
_modelScaleChanged = true;
}
}
_lastEdited = usecTimestampNow();
}
@ -1310,6 +1319,11 @@ void ParticleProperties::copyToParticle(Particle& particle) const {
particle.setModelURL(_modelURL);
somethingChanged = true;
}
if (_modelScaleChanged) {
particle.setModelScale(_modelScale);
somethingChanged = true;
}
if (_modelTranslationChanged) {
particle.setModelTranslation(_modelTranslation);
@ -1321,11 +1335,6 @@ void ParticleProperties::copyToParticle(Particle& particle) const {
somethingChanged = true;
}
if (_modelScaleChanged) {
particle.setModelScale(_modelScale);
somethingChanged = true;
}
if (somethingChanged) {
bool wantDebug = false;
if (wantDebug) {
@ -1350,9 +1359,9 @@ void ParticleProperties::copyFromParticle(const Particle& particle) {
_inHand = particle.getInHand();
_shouldDie = particle.getShouldDie();
_modelURL = particle.getModelURL();
_modelScale = particle.getModelScale();
_modelTranslation = particle.getModelTranslation();
_modelRotation = particle.getModelRotation();
_modelScale = particle.getModelScale();
_id = particle.getID();
_idSet = true;
@ -1368,9 +1377,9 @@ void ParticleProperties::copyFromParticle(const Particle& particle) {
_inHandChanged = false;
_shouldDieChanged = false;
_modelURLChanged = false;
_modelScaleChanged = false;
_modelTranslationChanged = false;
_modelRotationChanged = false;
_modelScaleChanged = false;
_defaultSettings = false;
}

View file

@ -56,13 +56,13 @@ const float DEFAULT_RADIUS = 0.1f / TREE_SCALE;
const float MINIMUM_PARTICLE_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container
const glm::vec3 DEFAULT_GRAVITY(0, (-9.8f / TREE_SCALE), 0);
const QString DEFAULT_SCRIPT("");
const QString DEFAULT_MODEL_URL("");
const glm::vec3 DEFAULT_MODEL_TRANSLATION(0, 0, 0);
const glm::quat DEFAULT_MODEL_ROTATION(0, 0, 0, 0);
const float DEFAULT_MODEL_SCALE = 1.0f;
const bool IN_HAND = true; // it's in a hand
const bool NOT_IN_HAND = !IN_HAND; // it's not in a hand
/// A collection of properties of a particle used in the scripting API. Translates between the actual properties of a particle
/// and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete set of
/// particle properties via JavaScript hashes/QScriptValues
@ -88,9 +88,9 @@ public:
bool getInHand() const { return _inHand; }
bool getShouldDie() const { return _shouldDie; }
const QString& getModelURL() const { return _modelURL; }
float getModelScale() const { return _modelScale; }
const glm::vec3& getModelTranslation() const { return _modelTranslation; }
const glm::quat& getModelRotation() const { return _modelRotation; }
float getModelScale() const { return _modelScale; }
quint64 getLastEdited() const { return _lastEdited; }
uint16_t getChangedBits() const;
@ -113,10 +113,10 @@ public:
// model related properties
void setModelURL(const QString& url) { _modelURL = url; _modelURLChanged = true; }
void setModelScale(float scale) { _modelScale = scale; _modelScaleChanged = true; }
void setModelTranslation(const glm::vec3& translation) { _modelTranslation = translation;
_modelTranslationChanged = true; }
void setModelRotation(const glm::quat& rotation) { _modelRotation = rotation; _modelRotationChanged = true; }
void setModelScale(float scale) { _modelScale = scale; _modelScaleChanged = true; }
/// used by ParticleScriptingInterface to return ParticleProperties for unknown particles
void setIsUnknownID() { _id = UNKNOWN_PARTICLE_ID; _idSet = true; }
@ -133,9 +133,9 @@ private:
bool _inHand;
bool _shouldDie;
QString _modelURL;
float _modelScale;
glm::vec3 _modelTranslation;
glm::quat _modelRotation;
float _modelScale;
uint32_t _id;
bool _idSet;
@ -152,9 +152,9 @@ private:
bool _inHandChanged;
bool _shouldDieChanged;
bool _modelURLChanged;
bool _modelScaleChanged;
bool _modelTranslationChanged;
bool _modelRotationChanged;
bool _modelScaleChanged;
bool _defaultSettings;
};
Q_DECLARE_METATYPE(ParticleProperties);
@ -227,9 +227,9 @@ public:
// model related properties
bool hasModel() const { return !_modelURL.isEmpty(); }
const QString& getModelURL() const { return _modelURL; }
float getModelScale() const { return _modelScale; }
const glm::vec3& getModelTranslation() const { return _modelTranslation; }
const glm::quat& getModelRotation() const { return _modelRotation; }
float getModelScale() const { return _modelScale; }
ParticleID getParticleID() const { return ParticleID(getID(), getCreatorTokenID(), getID() != UNKNOWN_PARTICLE_ID); }
ParticleProperties getProperties() const;
@ -277,9 +277,9 @@ public:
// model related properties
void setModelURL(const QString& url) { _modelURL = url; }
void setModelScale(float scale) { _modelScale = scale; }
void setModelTranslation(const glm::vec3& translation) { _modelTranslation = translation; }
void setModelRotation(const glm::quat& rotation) { _modelRotation = rotation; }
void setModelScale(float scale) { _modelScale = scale; }
void setProperties(const ParticleProperties& properties);
@ -344,9 +344,9 @@ protected:
// model related items
QString _modelURL;
float _modelScale;
glm::vec3 _modelTranslation;
glm::quat _modelRotation;
float _modelScale;
uint32_t _creatorTokenID;
bool _newlyCreated;

View file

@ -337,7 +337,7 @@ void NodeList::processSTUNResponse(const QByteArray& packet) {
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
size_t attributeStartIndex = NUM_BYTES_STUN_HEADER;
int attributeStartIndex = NUM_BYTES_STUN_HEADER;
if (memcmp(packet.data() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,

View file

@ -37,13 +37,15 @@ int packArithmeticallyCodedValue(int value, char* destination) {
return 1;
} else {
// pack 255 and then recursively pack on
destination[0] = 255;
((unsigned char*)destination)[0] = 255;
return 1 + packArithmeticallyCodedValue(value - 255, destination + 1);
}
}
PacketVersion versionForPacketType(PacketType type) {
switch (type) {
case PacketTypeParticleData:
return 1;
default:
return 0;
}

View file

@ -65,6 +65,8 @@ bool shouldDo(float desiredInterval, float deltaTime) {
return randFloat() < deltaTime / desiredInterval;
}
void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) {
for (int i = 0; i < length; i++) {
outputBits(buffer[i], continuedDebug);
@ -76,6 +78,7 @@ void outputBits(unsigned char byte, QDebug* continuedDebug) {
if (continuedDebug) {
debug = *continuedDebug;
debug.nospace();
}
QString resultString;
@ -85,12 +88,12 @@ void outputBits(unsigned char byte, QDebug* continuedDebug) {
} else {
resultString.sprintf("[ %d (0x%x): ", byte, byte);
}
debug << resultString;
debug << qPrintable(resultString);
for (int i = 0; i < 8; i++) {
resultString.sprintf("%d", byte >> (7 - i) & 1);
debug << qPrintable(resultString);
}
debug << resultString;
debug << " ]";
}

View file

@ -1,37 +0,0 @@
cmake_minimum_required(VERSION 2.8)
set(ROOT_DIR ../..)
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
# setup for find modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
set(TARGET_NAME voxel-server)
find_package(Qt5Widgets REQUIRED)
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
setup_hifi_library(${TARGET_NAME} ${OPTIONAL_SRCS})
qt5_use_modules(${TARGET_NAME} Widgets)
include(${MACRO_DIR}/IncludeGLM.cmake)
include_glm(${TARGET_NAME} ${ROOT_DIR})
# link ZLIB
find_package(ZLIB)
include_directories(${ZLIB_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
# link in the shared library
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
# link in the embedded webserver
link_hifi_library(embedded-webserver ${TARGET_NAME} ${ROOT_DIR})
# link in the hifi octree library
link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(octree-server ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})

View file

@ -26,20 +26,6 @@
#include "VoxelConstants.h"
#include "VoxelTreeElement.h"
typedef unsigned char VOXEL_PACKET_FLAGS;
typedef uint16_t VOXEL_PACKET_SEQUENCE;
typedef quint64 VOXEL_PACKET_SENT_TIME;
typedef uint16_t VOXEL_PACKET_INTERNAL_SECTION_SIZE;
const int MAX_VOXEL_PACKET_SIZE = MAX_PACKET_SIZE;
// this is overly conservative - uses 8 bytes for PacketType which could be as compact as a single byte
const int VOXEL_PACKET_HEADER_SIZE = MAX_PACKET_HEADER_BYTES + sizeof(VOXEL_PACKET_FLAGS)
+ sizeof(VOXEL_PACKET_SEQUENCE) + sizeof(VOXEL_PACKET_SENT_TIME);
const int MAX_VOXEL_PACKET_DATA_SIZE = MAX_PACKET_SIZE - VOXEL_PACKET_HEADER_SIZE;
const int MAX_VOXEL_UNCOMRESSED_PACKET_SIZE = MAX_VOXEL_PACKET_DATA_SIZE;
/// Handles packing of the data portion of PacketType_VOXEL_DATA messages.
class VoxelPacketData : public OctreePacketData {
public:

View file

@ -54,6 +54,8 @@ void VoxelTreeElement::splitChildren() {
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
addChildAtIndex(i)->setColor(ourColor);
}
nodeColor noColor = { 0, 0, 0, 0};
setColor(noColor); // set our own color to noColor so we are a pure non-leaf
}
}
@ -143,7 +145,11 @@ void VoxelTreeElement::setColor(const nodeColor& color) {
memcpy(&_currentColor,&color,sizeof(nodeColor));
}
_isDirty = true;
_density = 1.0f; // If color set, assume leaf, re-averaging will update density if needed.
if (color[3]) {
_density = 1.0f; // If color set, assume leaf, re-averaging will update density if needed.
} else {
_density = 0.0f;
}
markWithChangedTime();
}
}