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 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. 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 CMake
----- -----
Hifi uses CMake to generate build files and project files 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 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. 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. 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 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? What can I build on?
We have successfully built on OS X 10.8, Ubuntu and a few other modern Linux 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(voxels ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(metavoxels ${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(script-engine ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(embedded-webserver ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(embedded-webserver ${TARGET_NAME} ${ROOT_DIR})

View file

@ -23,8 +23,12 @@
#include "Agent.h" #include "Agent.h"
Agent::Agent(const QByteArray& packet) : 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) { void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {

View file

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

View file

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

View file

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

View file

@ -92,6 +92,13 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
bool packetSent = false; // did we send a packet? bool packetSent = false; // did we send a packet?
int packetsSent = 0; 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 // 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 // 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. // this rate control savings.
@ -136,14 +143,14 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
// actually send it // actually send it
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength, NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength,
node->getActiveSocket()->getAddress(), nodeAddress->getAddress(),
node->getActiveSocket()->getPort()); nodeAddress->getPort());
packetSent = true; packetSent = true;
} else { } else {
// not enough room in the packet, send two packets // not enough room in the packet, send two packets
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength, NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength,
node->getActiveSocket()->getAddress(), nodeAddress->getAddress(),
node->getActiveSocket()->getPort()); nodeAddress->getPort());
// since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since // 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. // there was nothing else to send.
@ -162,8 +169,8 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
packetsSent++; packetsSent++;
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(),
node->getActiveSocket()->getAddress(), nodeAddress->getAddress(),
node->getActiveSocket()->getPort()); nodeAddress->getPort());
packetSent = true; packetSent = true;
@ -183,8 +190,8 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
if (nodeData->isPacketWaiting()) { if (nodeData->isPacketWaiting()) {
// just send the voxel packet // just send the voxel packet
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(),
node->getActiveSocket()->getAddress(), nodeAddress->getAddress(),
node->getActiveSocket()->getPort()); nodeAddress->getPort());
packetSent = true; packetSent = true;
int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength();

View file

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

View file

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

View file

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

View file

@ -17,8 +17,7 @@
#include <ThreadedAssignment.h> #include <ThreadedAssignment.h>
#include <EnvironmentData.h> #include <EnvironmentData.h>
#include <OctreeServer.h> #include "../octree/OctreeServer.h"
#include "VoxelServerConsts.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 currentCells = [];
var nextCells = []; 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; 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 // randomly populate the cell start values
for (var i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) { for (var i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) {
// create the array to hold this row // create the array to hold this row
@ -108,7 +106,7 @@ function sendNextCells() {
// queue a packet to add a voxel for the new cell // queue a packet to add a voxel for the new cell
var color = (nextCells[i][j] == 1) ? 255 : 1; 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(); sendNextCells();
} }
Agent.willSendVisualDataCallback.connect(step);
Script.willSendVisualDataCallback.connect(step);
Voxels.setPacketsPerSecond(200);

View file

@ -11,7 +11,7 @@
var count = 0; var count = 0;
var stopAfter = 100; var stopAfter = 100;
var modelProperties = { var modelPropertiesA = {
position: { x: 1, y: 1, z: 1 }, position: { x: 1, y: 1, z: 1 },
velocity: { x: 0.5, y: 0, z: 0.5 }, velocity: { x: 0.5, y: 0, z: 0.5 },
gravity: { x: 0, y: 0, z: 0 }, gravity: { x: 0, y: 0, z: 0 },
@ -21,6 +21,18 @@ var modelProperties = {
lifetime: 20 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 = { var ballProperties = {
position: { x: 1, y: 0.5, z: 1 }, position: { x: 1, y: 0.5, z: 1 },
velocity: { x: 0.5, y: 0, z: 0.5 }, velocity: { x: 0.5, y: 0, z: 0.5 },
@ -31,7 +43,8 @@ var ballProperties = {
lifetime: 20 lifetime: 20
}; };
var modelParticleID = Particles.addParticle(modelProperties); var modelAParticleID = Particles.addParticle(modelPropertiesA);
var modelBParticleID = Particles.addParticle(modelPropertiesB);
var ballParticleID = Particles.addParticle(ballProperties); var ballParticleID = Particles.addParticle(ballProperties);
function endAfterAWhile() { function endAfterAWhile() {

View file

@ -10,17 +10,50 @@
var iteration = 0; 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 invaderStepOfCycle = 0; // current iteration in the cycle
var invaderMoveDirection = 1; // 1 for moving to right, -1 for moving to left var invaderMoveDirection = 1; // 1 for moving to right, -1 for moving to left
var itemLifetimes = 60; // game length...
var gameAt = { x: 10, y: 0, z: 10 }; 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 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 middleX = gameAt.x + (gameSize.x/2);
var middleY = gameAt.y + (gameSize.y/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 missileSize = 0.1;
var myShip; var myShip;
var myShipProperties; 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 rowHeight = ((gameAt.y + gameSize.y) - invadersBottomCorner.y) / numberOfRows;
var columnWidth = gameSize.x / (invadersPerRow + emptyColumns); 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 missileFired = false;
var myMissile; 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() { function initializeMyShip() {
myShipProperties = { myShipProperties = {
position: { x: middleX , y: gameAt.y, z: gameAt.z }, position: { x: middleX , y: gameAt.y, z: gameAt.z },
velocity: { x: 0, y: 0, z: 0 }, velocity: { x: 0, y: 0, z: 0 },
gravity: { x: 0, y: 0, z: 0 }, gravity: { x: 0, y: 0, z: 0 },
damping: 0, damping: 0,
radius: shipSize, radius: shipSize,
color: { red: 0, green: 255, blue: 0 }, color: { red: 0, green: 255, blue: 0 },
lifetime: itemLifetimes 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); myShip = Particles.addParticle(myShipProperties);
} }
// calculate the correct invaderPosition for an column row // calculate the correct invaderPosition for an column row
function getInvaderPosition(row, column) { function getInvaderPosition(row, column) {
var xMovePart = 0;
var xBasePart = invadersBottomCorner.x + (column * columnWidth); var xBasePart = invadersBottomCorner.x + (column * columnWidth);
var xMovePart = 0;
if (invaderMoveDirection > 0) { if (invaderMoveDirection > 0) {
xMovePart = (invaderMoveDirection * columnWidth * (invaderStepOfCycle/invaderStepsPerCycle)); xMovePart = (invaderMoveDirection * columnWidth * (invaderStepOfCycle/invaderStepsPerCycle));
} else { } else {
xMovePart = columnWidth + (invaderMoveDirection * columnWidth * (invaderStepOfCycle/invaderStepsPerCycle)); xMovePart = columnWidth + (invaderMoveDirection * columnWidth * (invaderStepOfCycle/invaderStepsPerCycle));
} }
var y = invadersBottomCorner.y + (row * rowHeight) - (invaderRowOffset * rowHeight/stepsPerRow);
var invaderPosition = { var invaderPosition = {
x: xBasePart + xMovePart, x: xBasePart + xMovePart,
y: invadersBottomCorner.y + (row * rowHeight), y: y,
z: invadersBottomCorner.z }; z: invadersBottomCorner.z };
return invaderPosition; return invaderPosition;
@ -77,8 +173,11 @@ function initializeInvaders() {
velocity: { x: 0, y: 0, z: 0 }, velocity: { x: 0, y: 0, z: 0 },
gravity: { x: 0, y: 0, z: 0 }, gravity: { x: 0, y: 0, z: 0 },
damping: 0, damping: 0,
radius: shipSize, radius: invaderSize,
color: { red: 255, green: 0, blue: 0 }, color: { red: 255, green: 0, blue: 0 },
modelURL: invaderModels[row].modelURL,
modelScale: invaderModels[row].modelScale,
modelTranslation: invaderModels[row].modelTranslation,
lifetime: itemLifetimes lifetime: itemLifetimes
}); });
@ -88,31 +187,73 @@ function initializeInvaders() {
} }
function moveInvaders() { function moveInvaders() {
print("moveInvaders()...");
for (var row = 0; row < numberOfRows; row++) { for (var row = 0; row < numberOfRows; row++) {
for (var column = 0; column < invadersPerRow; column++) { for (var column = 0; column < invadersPerRow; column++) {
props = Particles.getParticleProperties(invaders[row][column]); props = Particles.getParticleProperties(invaders[row][column]);
if (props.isKnownID) { if (props.isKnownID) {
invaderPosition = getInvaderPosition(row, column); 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() { function update() {
print("updating space invaders... iteration="+iteration); if (!gameOver) {
iteration++; //print("updating space invaders... iteration="+iteration);
invaderStepOfCycle++; iteration++;
if (invaderStepOfCycle > invaderStepsPerCycle) {
invaderStepOfCycle = 0; if (invaderStepOfCycle % stepsPerSound == 0) {
if (invaderMoveDirection > 0) { // play the move sound
invaderMoveDirection = -1; var options = new AudioInjectionOptions();
} else { if (soundInMyHead) {
invaderMoveDirection = 1; 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 // register the call back so it fires before each data send
@ -134,6 +275,9 @@ function cleanupGame() {
if (missileFired) { if (missileFired) {
Particles.deleteParticle(myMissile); Particles.deleteParticle(myMissile);
} }
Controller.releaseKeyEvents({text: " "});
Script.stop(); Script.stop();
} }
Script.scriptEnding.connect(cleanupGame); Script.scriptEnding.connect(cleanupGame);
@ -182,6 +326,17 @@ function fireMissile() {
lifetime: 5 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; missileFired = true;
} }
} }
@ -219,6 +374,18 @@ function deleteIfInvader(possibleInvaderParticle) {
if (invaders[row][column].id == possibleInvaderParticle.id) { if (invaders[row][column].id == possibleInvaderParticle.id) {
Particles.deleteParticle(possibleInvaderParticle); Particles.deleteParticle(possibleInvaderParticle);
Particles.deleteParticle(myMissile); 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(); initializeMyShip();
initializeInvaders(); 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; const int STATS_PELS_PER_LINE = 20;
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) { void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
QString messageWithNewLine = message + "\n"; if (message.size() > 0) {
fprintf(stdout, "%s", messageWithNewLine.toLocal8Bit().constData()); QString messageWithNewLine = message + "\n";
Application::getInstance()->getLogger()->addMessage(messageWithNewLine.toLocal8Bit().constData()); fprintf(stdout, "%s", messageWithNewLine.toLocal8Bit().constData());
Application::getInstance()->getLogger()->addMessage(messageWithNewLine.toLocal8Bit().constData());
}
} }
Application::Application(int& argc, char** argv, timeval &startup_time) : Application::Application(int& argc, char** argv, timeval &startup_time) :
@ -152,8 +154,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_resetRecentMaxPacketsSoon(true), _resetRecentMaxPacketsSoon(true),
_swatch(NULL), _swatch(NULL),
_pasteMode(false), _pasteMode(false),
_logger(new FileLogger(this)), _logger(new FileLogger(this))
_persistThread(NULL)
{ {
_myAvatar = _avatarManager.getMyAvatar(); _myAvatar = _avatarManager.getMyAvatar();
@ -314,12 +315,7 @@ Application::~Application() {
_voxelHideShowThread.terminate(); _voxelHideShowThread.terminate();
_voxelEditSender.terminate(); _voxelEditSender.terminate();
_particleEditSender.terminate(); _particleEditSender.terminate();
if (_persistThread) {
_persistThread->terminate();
_persistThread->deleteLater();
_persistThread = NULL;
}
storeSizeAndPosition(); storeSizeAndPosition();
saveScripts(); saveScripts();
_sharedVoxelSystem.changeTree(new VoxelTree); _sharedVoxelSystem.changeTree(new VoxelTree);
@ -1260,7 +1256,8 @@ void Application::mousePressEvent(QMouseEvent* event) {
pasteVoxels(); 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[0] = _hoverVoxel.red;
_hoverVoxelOriginalColor[1] = _hoverVoxel.green; _hoverVoxelOriginalColor[1] = _hoverVoxel.green;
_hoverVoxelOriginalColor[2] = _hoverVoxel.blue; _hoverVoxelOriginalColor[2] = _hoverVoxel.blue;
@ -1905,9 +1902,6 @@ void Application::init() {
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView())); connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView())); connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors())); connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
updateLocalOctreeCache(true);
} }
void Application::closeMirrorView() { 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); 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, // 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. // 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()"); PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
_isHoverVoxel = _voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _hoverVoxel, distance, face); _isHoverVoxel = _voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _hoverVoxel, distance, face);
@ -2205,9 +2199,6 @@ void Application::updateThreads(float deltaTime) {
_voxelHideShowThread.threadRoutine(); _voxelHideShowThread.threadRoutine();
_voxelEditSender.threadRoutine(); _voxelEditSender.threadRoutine();
_particleEditSender.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) { if (!selfAvatarOnly) {
// Render the world box // Render the world box
@ -3880,10 +3872,6 @@ void Application::domainChanged(const QString& domainHostname) {
// reset the particle renderer // reset the particle renderer
_particles.clear(); _particles.clear();
// reset our persist thread
qDebug() << "Domain changed to" << domainHostname << ". Swapping persist cache.";
updateLocalOctreeCache();
} }
void Application::nodeKilled(SharedNodePointer node) { void Application::nodeKilled(SharedNodePointer node) {
@ -4153,49 +4141,6 @@ void Application::initAvatarAndViewFrustum() {
updateMyAvatar(0.f); 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() { void Application::checkVersion() {
QNetworkRequest latestVersionRequest((QUrl(CHECK_VERSION_URL))); QNetworkRequest latestVersionRequest((QUrl(CHECK_VERSION_URL)));
latestVersionRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); latestVersionRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);

View file

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

View file

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

View file

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

View file

@ -36,6 +36,7 @@ Camera::Camera() {
_modeShiftRate = 1.0f; _modeShiftRate = 1.0f;
_linearModeShift = 0.0f; _linearModeShift = 0.0f;
_mode = CAMERA_MODE_THIRD_PERSON; _mode = CAMERA_MODE_THIRD_PERSON;
_prevMode = CAMERA_MODE_THIRD_PERSON;
_tightness = 10.0f; // default _tightness = 10.0f; // default
_fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES; _fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES;
_aspectRatio = 16.f/9.f; _aspectRatio = 16.f/9.f;
@ -123,6 +124,7 @@ void Camera::setModeShiftRate ( float rate ) {
void Camera::setMode(CameraMode m) { void Camera::setMode(CameraMode m) {
_prevMode = _mode;
_mode = m; _mode = m;
_modeShift = 0.0; _modeShift = 0.0;
_linearModeShift = 0.0; _linearModeShift = 0.0;
@ -199,6 +201,17 @@ bool Camera::getFrustumNeedsReshape() const {
return _frustumNeedsReshape; 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 // call this after reshaping the view frustum
void Camera::setFrustumWasReshaped() { void Camera::setFrustumWasReshaped() {
_frustumNeedsReshape = false; _frustumNeedsReshape = false;

View file

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

View file

@ -73,12 +73,12 @@ void DatagramProcessor::processDatagrams() {
if (wantExtraDebugging && packetTypeForPacket(incomingPacket) == PacketTypeVoxelData) { if (wantExtraDebugging && packetTypeForPacket(incomingPacket) == PacketTypeVoxelData) {
int numBytesPacketHeader = numBytesForPacketHeader(incomingPacket); int numBytesPacketHeader = numBytesForPacketHeader(incomingPacket);
unsigned char* dataAt = reinterpret_cast<unsigned char*>(incomingPacket.data()) + numBytesPacketHeader; unsigned char* dataAt = reinterpret_cast<unsigned char*>(incomingPacket.data()) + numBytesPacketHeader;
dataAt += sizeof(VOXEL_PACKET_FLAGS); dataAt += sizeof(OCTREE_PACKET_FLAGS);
VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt);
dataAt += sizeof(VOXEL_PACKET_SEQUENCE); dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); OCTREE_PACKET_SENT_TIME sentAt = (*(OCTREE_PACKET_SENT_TIME*)dataAt);
dataAt += sizeof(VOXEL_PACKET_SENT_TIME); dataAt += sizeof(OCTREE_PACKET_SENT_TIME);
VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
int flightTime = arrivedAt - sentAt; int flightTime = arrivedAt - sentAt;
printf("got PacketType_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime); 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::AmbientOcclusion);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges);
addActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools())); addActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools()));
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DisableLocalVoxelCache);
QMenu* voxelProtoOptionsMenu = voxelOptionsMenu->addMenu("Voxel Server Protocol Options"); 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 DestructiveAddVoxel = "Create Voxel is Destructive";
const QString DisableColorVoxels = "Disable Colored Voxels"; const QString DisableColorVoxels = "Disable Colored Voxels";
const QString DisableDeltaSending = "Disable Delta Sending"; const QString DisableDeltaSending = "Disable Delta Sending";
const QString DisableLocalVoxelCache = "Disable Local Voxel Cache";
const QString DisableLowRes = "Disable Lower Resolution While Moving"; const QString DisableLowRes = "Disable Lower Resolution While Moving";
const QString DisplayFrustum = "Display Frustum"; const QString DisplayFrustum = "Display Frustum";
const QString DisplayLeapHands = "Display Leap Hands"; const QString DisplayLeapHands = "Display Leap Hands";

View file

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

View file

@ -99,8 +99,6 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
_culledOnce = false; _culledOnce = false;
_inhideOutOfView = false; _inhideOutOfView = false;
_treeIsBusy = false;
} }
void VoxelSystem::elementDeleted(OctreeElement* element) { 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; const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data()) + numBytesPacketHeader;
VOXEL_PACKET_FLAGS flags = (*(VOXEL_PACKET_FLAGS*)(dataAt)); OCTREE_PACKET_FLAGS flags = (*(OCTREE_PACKET_FLAGS*)(dataAt));
dataAt += sizeof(VOXEL_PACKET_FLAGS); dataAt += sizeof(OCTREE_PACKET_FLAGS);
VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt);
dataAt += sizeof(VOXEL_PACKET_SEQUENCE); dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); OCTREE_PACKET_SENT_TIME sentAt = (*(OCTREE_PACKET_SENT_TIME*)dataAt);
dataAt += sizeof(VOXEL_PACKET_SENT_TIME); dataAt += sizeof(OCTREE_PACKET_SENT_TIME);
bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT);
bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_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; int flightTime = arrivedAt - sentAt;
VOXEL_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0; OCTREE_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0;
int dataBytes = packet.size() - VOXEL_PACKET_HEADER_SIZE; int dataBytes = packet.size() - (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_SIZE);
int subsection = 1; int subsection = 1;
while (dataBytes > 0) { while (dataBytes > 0) {
if (packetIsCompressed) { if (packetIsCompressed) {
if (dataBytes > sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE)) { if (dataBytes > sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE)) {
sectionLength = (*(VOXEL_PACKET_INTERNAL_SECTION_SIZE*)dataAt); sectionLength = (*(OCTREE_PACKET_INTERNAL_SECTION_SIZE*)dataAt);
dataAt += sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); dataAt += sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
dataBytes -= sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); dataBytes -= sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
} else { } else {
sectionLength = 0; sectionLength = 0;
dataBytes = 0; // stop looping something is wrong dataBytes = 0; // stop looping something is wrong
@ -594,9 +592,10 @@ int VoxelSystem::parseData(const QByteArray& packet) {
} }
if (sectionLength) { if (sectionLength) {
PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData() section");
// ask the VoxelTree to read the bitstream into the tree // ask the VoxelTree to read the bitstream into the tree
ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID());
lockTree(); _tree->lockForWrite();
VoxelPacketData packetData(packetIsCompressed); VoxelPacketData packetData(packetIsCompressed);
packetData.loadFinalizedContent(dataAt, sectionLength); packetData.loadFinalizedContent(dataAt, sectionLength);
if (Application::getInstance()->getLogger()->extraDebugging()) { if (Application::getInstance()->getLogger()->extraDebugging()) {
@ -608,7 +607,7 @@ int VoxelSystem::parseData(const QByteArray& packet) {
packetData.getUncompressedSize()); packetData.getUncompressedSize());
} }
_tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args);
unlockTree(); _tree->unlock();
dataBytes -= sectionLength; dataBytes -= sectionLength;
dataAt += sectionLength; dataAt += sectionLength;
@ -1395,9 +1394,11 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {
int VoxelSystem::_nodeCount = 0; int VoxelSystem::_nodeCount = 0;
void VoxelSystem::killLocalVoxels() { void VoxelSystem::killLocalVoxels() {
lockTree(); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelSystem::killLocalVoxels()");
_tree->lockForWrite();
_tree->eraseAllOctreeElements(); _tree->eraseAllOctreeElements();
unlockTree(); _tree->unlock();
clearFreeBufferIndexes(); clearFreeBufferIndexes();
_voxelsInReadArrays = 0; // do we need to do this? _voxelsInReadArrays = 0; // do we need to do this?
setupNewVoxelsForDrawing(); setupNewVoxelsForDrawing();
@ -1416,10 +1417,12 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void
} }
void VoxelSystem::clearAllNodesBufferIndex() { void VoxelSystem::clearAllNodesBufferIndex() {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelSystem::clearAllNodesBufferIndex()");
_nodeCount = 0; _nodeCount = 0;
lockTree(); _tree->lockForRead(); // we won't change the tree so it's ok to treat this as a read
_tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation); _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation);
unlockTree(); _tree->unlock();
if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
qDebug("clearing buffer index of %d nodes", _nodeCount); qDebug("clearing buffer index of %d nodes", _nodeCount);
} }
@ -1481,7 +1484,8 @@ bool VoxelSystem::trueColorizeOperation(OctreeElement* element, void* extraData)
} }
void VoxelSystem::trueColorize() { void VoxelSystem::trueColorize() {
PerformanceWarning warn(true, "trueColorize()",true); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"trueColorize()",true);
_nodeCount = 0; _nodeCount = 0;
_tree->recurseTreeWithOperation(trueColorizeOperation); _tree->recurseTreeWithOperation(trueColorizeOperation);
qDebug("setting true color for %d nodes", _nodeCount); qDebug("setting true color for %d nodes", _nodeCount);
@ -1951,9 +1955,13 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) {
return; return;
} }
lockTree(); {
_tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
unlockTree(); "VoxelSystem::... recurseTreeWithOperation(hideOutOfViewOperation)");
_tree->lockForRead();
_tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args);
_tree->unlock();
}
_lastCulledViewFrustum = args.thisViewFrustum; // save last stable _lastCulledViewFrustum = args.thisViewFrustum; // save last stable
_culledOnce = true; _culledOnce = true;
@ -2150,35 +2158,47 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData
bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
VoxelDetail& detail, float& distance, BoxFace& face) { VoxelDetail& detail, float& distance, BoxFace& face) {
lockTree();
OctreeElement* element; PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
if (!_tree->findRayIntersection(origin, direction, element, distance, face)) { "VoxelSystem::findRayIntersection()");
unlockTree(); bool result = false; // assume no intersection
return false; 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; return result;
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;
} }
bool VoxelSystem::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) { bool VoxelSystem::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) {
lockTree(); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
bool result = _tree->findSpherePenetration(center, radius, penetration); "VoxelSystem::findSpherePenetration()");
unlockTree(); bool result = false; // assume no penetration
if (_tree->tryLockForRead()) {
result = _tree->findSpherePenetration(center, radius, penetration);
_tree->unlock();
}
return result; return result;
} }
bool VoxelSystem::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) { bool VoxelSystem::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) {
lockTree(); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
bool result = _tree->findCapsulePenetration(start, end, radius, penetration); "VoxelSystem::findCapsulePenetration()");
unlockTree(); bool result = false; // assume no penetration
if (_tree->tryLockForRead()) {
result = _tree->findCapsulePenetration(start, end, radius, penetration);
_tree->unlock();
}
return result; return result;
} }
@ -2354,13 +2374,14 @@ void VoxelSystem::collectStatsForTreesAndVBOs() {
void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) { 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); _tree->deleteVoxelAt(x, y, z, s);
unlockTree(); _tree->unlock();
// redraw! // redraw!
setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in? 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 { 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, void VoxelSystem::createVoxel(float x, float y, float z, float s,
unsigned char red, unsigned char green, unsigned char blue, bool destructive) { unsigned char red, unsigned char green, unsigned char blue, bool destructive) {
//qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
lockTree(); "VoxelSystem::createVoxel()");
_tree->lockForWrite();
_tree->createVoxel(x, y, z, s, red, green, blue, destructive); _tree->createVoxel(x, y, z, s, red, green, blue, destructive);
unlockTree(); _tree->unlock();
setupNewVoxelsForDrawing(); setupNewVoxelsForDrawing();
}; };
@ -2744,37 +2767,3 @@ unsigned long VoxelSystem::getVoxelMemoryUsageGPU() {
return (_initialMemoryUsageGPU - currentFreeMemory); 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 elementDeleted(OctreeElement* element);
virtual void elementUpdated(OctreeElement* element); virtual void elementUpdated(OctreeElement* element);
bool treeIsBusy() const { return _treeIsBusy; }
VoxelTreeElement* getVoxelEnclosing(const glm::vec3& point); VoxelTreeElement* getVoxelEnclosing(const glm::vec3& point);
signals: signals:
@ -144,9 +142,6 @@ public slots:
void setUseVoxelShader(bool useVoxelShader); void setUseVoxelShader(bool useVoxelShader);
void setVoxelsAsPoints(bool voxelsAsPoints); void setVoxelsAsPoints(bool voxelsAsPoints);
void localVoxelCacheLoaded();
void beginLoadingLocalVoxelCache();
protected: protected:
float _treeScale; float _treeScale;
unsigned long _maxVoxels; unsigned long _maxVoxels;
@ -304,10 +299,6 @@ private:
bool _useFastVoxelPipeline; bool _useFastVoxelPipeline;
bool _inhideOutOfView; 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 #endif

View file

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

View file

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

View file

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

View file

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

View file

@ -1632,7 +1632,18 @@ FBXGeometry readSVO(const QByteArray& model) {
VoxelTree tree; VoxelTree tree;
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); 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); tree.recurseTreeWithOperation(addMeshVoxelsOperation, &mesh);
geometry.meshes.append(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 // read to the end of the buffer
int numSamplesToEnd = (_buffer + _sampleCapacity) - _nextOutput; int numSamplesToEnd = (_buffer + _sampleCapacity) - _nextOutput;
memcpy(data, _nextOutput, numSamplesToEnd * sizeof(int16_t)); memcpy(data, _nextOutput, numSamplesToEnd * sizeof(int16_t));
// read the rest from the beginning of the buffer // 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 { } else {
// read the data // read the data
memcpy(data, _nextOutput, numReadSamples * sizeof(int16_t)); 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 // read and dispatch the high-priority messages
quint32 highPriorityMessageCount; int highPriorityMessageCount;
_incomingPacketStream >> highPriorityMessageCount; _incomingPacketStream >> highPriorityMessageCount;
int newHighPriorityMessages = highPriorityMessageCount - _receivedHighPriorityMessages; int newHighPriorityMessages = highPriorityMessageCount - _receivedHighPriorityMessages;
for (int i = 0; i < highPriorityMessageCount; i++) { 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; 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 // 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); + 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; 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; int flightTime = arrivedAt - sentAt + clockSkew;
OCTREE_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0; 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) { if (extraDebugging) {
qDebug("OctreeRenderer::processDatagram() ... Got Packet Section" 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; _script = DEFAULT_SCRIPT;
_inHand = NOT_IN_HAND; _inHand = NOT_IN_HAND;
_shouldDie = false; _shouldDie = false;
_modelURL = DEFAULT_MODEL_URL;
_modelTranslation = DEFAULT_MODEL_TRANSLATION;
_modelRotation = DEFAULT_MODEL_ROTATION;
_modelScale = DEFAULT_MODEL_SCALE;
setProperties(properties); setProperties(properties);
} }
@ -124,6 +128,10 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3
_script = updateScript; _script = updateScript;
_inHand = inHand; _inHand = inHand;
_shouldDie = false; _shouldDie = false;
_modelURL = DEFAULT_MODEL_URL;
_modelTranslation = DEFAULT_MODEL_TRANSLATION;
_modelRotation = DEFAULT_MODEL_ROTATION;
_modelScale = DEFAULT_MODEL_SCALE;
} }
void Particle::setMass(float value) { void Particle::setMass(float value) {
@ -190,6 +198,12 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
success = packetData->appendRawData((const unsigned char*)qPrintable(_modelURL), modelURLLength); success = packetData->appendRawData((const unsigned char*)qPrintable(_modelURL), modelURLLength);
} }
} }
// modelScale
if (success) {
success = packetData->appendValue(getModelScale());
}
// modelTranslation // modelTranslation
if (success) { if (success) {
success = packetData->appendValue(getModelTranslation()); success = packetData->appendValue(getModelTranslation());
@ -198,11 +212,6 @@ bool Particle::appendParticleData(OctreePacketData* packetData) const {
if (success) { if (success) {
success = packetData->appendValue(getModelRotation()); success = packetData->appendValue(getModelRotation());
} }
// modelScale
if (success) {
success = packetData->appendValue(getModelScale());
}
return success; return success;
} }
@ -319,6 +328,11 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += modelURLLength; dataAt += modelURLLength;
bytesRead += modelURLLength; bytesRead += modelURLLength;
// modelScale
memcpy(&_modelScale, dataAt, sizeof(_modelScale));
dataAt += sizeof(_modelScale);
bytesRead += sizeof(_modelScale);
// modelTranslation // modelTranslation
memcpy(&_modelTranslation, dataAt, sizeof(_modelTranslation)); memcpy(&_modelTranslation, dataAt, sizeof(_modelTranslation));
dataAt += sizeof(_modelTranslation); dataAt += sizeof(_modelTranslation);
@ -329,11 +343,6 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += bytes; dataAt += bytes;
bytesRead += bytes; bytesRead += bytes;
// modelScale
memcpy(&_modelScale, dataAt, sizeof(_modelScale));
dataAt += sizeof(_modelScale);
bytesRead += sizeof(_modelScale);
//printf("Particle::readParticleDataFromBuffer()... "); debugDump(); //printf("Particle::readParticleDataFromBuffer()... "); debugDump();
} }
return bytesRead; return bytesRead;
@ -498,6 +507,13 @@ Particle Particle::fromEditPacket(const unsigned char* data, int length, int& pr
processedBytes += modelURLLength; 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 // modelTranslation
if (isNewParticle || ((packetContainsBits & CONTAINS_MODEL_TRANSLATION) == CONTAINS_MODEL_TRANSLATION)) { if (isNewParticle || ((packetContainsBits & CONTAINS_MODEL_TRANSLATION) == CONTAINS_MODEL_TRANSLATION)) {
memcpy(&newParticle._modelTranslation, dataAt, sizeof(newParticle._modelTranslation)); memcpy(&newParticle._modelTranslation, dataAt, sizeof(newParticle._modelTranslation));
@ -512,13 +528,6 @@ Particle Particle::fromEditPacket(const unsigned char* data, int length, int& pr
processedBytes += bytes; 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; const bool wantDebugging = false;
if (wantDebugging) { if (wantDebugging) {
qDebug("Particle::fromEditPacket()..."); qDebug("Particle::fromEditPacket()...");
@ -696,6 +705,14 @@ bool Particle::encodeParticleEditMessageDetails(PacketType command, ParticleID i
sizeOut += urlLength; 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 // modelTranslation
if (isNewParticle || ((packetContainsBits & CONTAINS_MODEL_TRANSLATION) == CONTAINS_MODEL_TRANSLATION)) { if (isNewParticle || ((packetContainsBits & CONTAINS_MODEL_TRANSLATION) == CONTAINS_MODEL_TRANSLATION)) {
glm::vec3 modelTranslation = properties.getModelTranslation(); // should this be relative to TREE_SCALE?? 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; 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; bool wantDebugging = false;
if (wantDebugging) { if (wantDebugging) {
printf("encodeParticleEditMessageDetails()....\n"); printf("encodeParticleEditMessageDetails()....\n");
@ -931,9 +940,9 @@ ParticleProperties::ParticleProperties() :
_inHand(false), _inHand(false),
_shouldDie(false), _shouldDie(false),
_modelURL(""), _modelURL(""),
_modelScale(DEFAULT_MODEL_SCALE),
_modelTranslation(DEFAULT_MODEL_TRANSLATION), _modelTranslation(DEFAULT_MODEL_TRANSLATION),
_modelRotation(DEFAULT_MODEL_ROTATION), _modelRotation(DEFAULT_MODEL_ROTATION),
_modelScale(DEFAULT_MODEL_SCALE),
_id(UNKNOWN_PARTICLE_ID), _id(UNKNOWN_PARTICLE_ID),
_idSet(false), _idSet(false),
@ -950,9 +959,9 @@ ParticleProperties::ParticleProperties() :
_inHandChanged(false), _inHandChanged(false),
_shouldDieChanged(false), _shouldDieChanged(false),
_modelURLChanged(false), _modelURLChanged(false),
_modelScaleChanged(false),
_modelTranslationChanged(false), _modelTranslationChanged(false),
_modelRotationChanged(false), _modelRotationChanged(false),
_modelScaleChanged(false),
_defaultSettings(true) _defaultSettings(true)
{ {
} }
@ -1004,6 +1013,10 @@ uint16_t ParticleProperties::getChangedBits() const {
changedBits += CONTAINS_MODEL_URL; changedBits += CONTAINS_MODEL_URL;
} }
if (_modelScaleChanged) {
changedBits += CONTAINS_MODEL_SCALE;
}
if (_modelTranslationChanged) { if (_modelTranslationChanged) {
changedBits += CONTAINS_MODEL_TRANSLATION; changedBits += CONTAINS_MODEL_TRANSLATION;
} }
@ -1012,10 +1025,6 @@ uint16_t ParticleProperties::getChangedBits() const {
changedBits += CONTAINS_MODEL_ROTATION; changedBits += CONTAINS_MODEL_ROTATION;
} }
if (_modelScaleChanged) {
changedBits += CONTAINS_MODEL_SCALE;
}
return changedBits; return changedBits;
} }
@ -1045,14 +1054,14 @@ QScriptValue ParticleProperties::copyToScriptValue(QScriptEngine* engine) const
properties.setProperty("modelURL", _modelURL); properties.setProperty("modelURL", _modelURL);
properties.setProperty("modelScale", _modelScale);
QScriptValue modelTranslation = vec3toScriptValue(engine, _modelTranslation); QScriptValue modelTranslation = vec3toScriptValue(engine, _modelTranslation);
properties.setProperty("modelTranslation", modelTranslation); properties.setProperty("modelTranslation", modelTranslation);
QScriptValue modelRotation = quatToScriptValue(engine, _modelRotation); QScriptValue modelRotation = quatToScriptValue(engine, _modelRotation);
properties.setProperty("modelRotation", modelRotation); properties.setProperty("modelRotation", modelRotation);
properties.setProperty("modelScale", _modelScale);
if (_idSet) { if (_idSet) {
properties.setProperty("id", _id); properties.setProperty("id", _id);
@ -1203,7 +1212,17 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) {
_modelURLChanged = true; _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"); QScriptValue modelTranslation = object.property("modelTranslation");
if (modelTranslation.isValid()) { if (modelTranslation.isValid()) {
QScriptValue x = modelTranslation.property("x"); 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(); _lastEdited = usecTimestampNow();
} }
@ -1310,6 +1319,11 @@ void ParticleProperties::copyToParticle(Particle& particle) const {
particle.setModelURL(_modelURL); particle.setModelURL(_modelURL);
somethingChanged = true; somethingChanged = true;
} }
if (_modelScaleChanged) {
particle.setModelScale(_modelScale);
somethingChanged = true;
}
if (_modelTranslationChanged) { if (_modelTranslationChanged) {
particle.setModelTranslation(_modelTranslation); particle.setModelTranslation(_modelTranslation);
@ -1321,11 +1335,6 @@ void ParticleProperties::copyToParticle(Particle& particle) const {
somethingChanged = true; somethingChanged = true;
} }
if (_modelScaleChanged) {
particle.setModelScale(_modelScale);
somethingChanged = true;
}
if (somethingChanged) { if (somethingChanged) {
bool wantDebug = false; bool wantDebug = false;
if (wantDebug) { if (wantDebug) {
@ -1350,9 +1359,9 @@ void ParticleProperties::copyFromParticle(const Particle& particle) {
_inHand = particle.getInHand(); _inHand = particle.getInHand();
_shouldDie = particle.getShouldDie(); _shouldDie = particle.getShouldDie();
_modelURL = particle.getModelURL(); _modelURL = particle.getModelURL();
_modelScale = particle.getModelScale();
_modelTranslation = particle.getModelTranslation(); _modelTranslation = particle.getModelTranslation();
_modelRotation = particle.getModelRotation(); _modelRotation = particle.getModelRotation();
_modelScale = particle.getModelScale();
_id = particle.getID(); _id = particle.getID();
_idSet = true; _idSet = true;
@ -1368,9 +1377,9 @@ void ParticleProperties::copyFromParticle(const Particle& particle) {
_inHandChanged = false; _inHandChanged = false;
_shouldDieChanged = false; _shouldDieChanged = false;
_modelURLChanged = false; _modelURLChanged = false;
_modelScaleChanged = false;
_modelTranslationChanged = false; _modelTranslationChanged = false;
_modelRotationChanged = false; _modelRotationChanged = false;
_modelScaleChanged = false;
_defaultSettings = 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 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 glm::vec3 DEFAULT_GRAVITY(0, (-9.8f / TREE_SCALE), 0);
const QString DEFAULT_SCRIPT(""); const QString DEFAULT_SCRIPT("");
const QString DEFAULT_MODEL_URL("");
const glm::vec3 DEFAULT_MODEL_TRANSLATION(0, 0, 0); const glm::vec3 DEFAULT_MODEL_TRANSLATION(0, 0, 0);
const glm::quat DEFAULT_MODEL_ROTATION(0, 0, 0, 0); const glm::quat DEFAULT_MODEL_ROTATION(0, 0, 0, 0);
const float DEFAULT_MODEL_SCALE = 1.0f; const float DEFAULT_MODEL_SCALE = 1.0f;
const bool IN_HAND = true; // it's in a hand const bool IN_HAND = true; // it's in a hand
const bool NOT_IN_HAND = !IN_HAND; // it's not 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 /// 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 /// 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 /// particle properties via JavaScript hashes/QScriptValues
@ -88,9 +88,9 @@ public:
bool getInHand() const { return _inHand; } bool getInHand() const { return _inHand; }
bool getShouldDie() const { return _shouldDie; } bool getShouldDie() const { return _shouldDie; }
const QString& getModelURL() const { return _modelURL; } const QString& getModelURL() const { return _modelURL; }
float getModelScale() const { return _modelScale; }
const glm::vec3& getModelTranslation() const { return _modelTranslation; } const glm::vec3& getModelTranslation() const { return _modelTranslation; }
const glm::quat& getModelRotation() const { return _modelRotation; } const glm::quat& getModelRotation() const { return _modelRotation; }
float getModelScale() const { return _modelScale; }
quint64 getLastEdited() const { return _lastEdited; } quint64 getLastEdited() const { return _lastEdited; }
uint16_t getChangedBits() const; uint16_t getChangedBits() const;
@ -113,10 +113,10 @@ public:
// model related properties // model related properties
void setModelURL(const QString& url) { _modelURL = url; _modelURLChanged = true; } 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; void setModelTranslation(const glm::vec3& translation) { _modelTranslation = translation;
_modelTranslationChanged = true; } _modelTranslationChanged = true; }
void setModelRotation(const glm::quat& rotation) { _modelRotation = rotation; _modelRotationChanged = 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 /// used by ParticleScriptingInterface to return ParticleProperties for unknown particles
void setIsUnknownID() { _id = UNKNOWN_PARTICLE_ID; _idSet = true; } void setIsUnknownID() { _id = UNKNOWN_PARTICLE_ID; _idSet = true; }
@ -133,9 +133,9 @@ private:
bool _inHand; bool _inHand;
bool _shouldDie; bool _shouldDie;
QString _modelURL; QString _modelURL;
float _modelScale;
glm::vec3 _modelTranslation; glm::vec3 _modelTranslation;
glm::quat _modelRotation; glm::quat _modelRotation;
float _modelScale;
uint32_t _id; uint32_t _id;
bool _idSet; bool _idSet;
@ -152,9 +152,9 @@ private:
bool _inHandChanged; bool _inHandChanged;
bool _shouldDieChanged; bool _shouldDieChanged;
bool _modelURLChanged; bool _modelURLChanged;
bool _modelScaleChanged;
bool _modelTranslationChanged; bool _modelTranslationChanged;
bool _modelRotationChanged; bool _modelRotationChanged;
bool _modelScaleChanged;
bool _defaultSettings; bool _defaultSettings;
}; };
Q_DECLARE_METATYPE(ParticleProperties); Q_DECLARE_METATYPE(ParticleProperties);
@ -227,9 +227,9 @@ public:
// model related properties // model related properties
bool hasModel() const { return !_modelURL.isEmpty(); } bool hasModel() const { return !_modelURL.isEmpty(); }
const QString& getModelURL() const { return _modelURL; } const QString& getModelURL() const { return _modelURL; }
float getModelScale() const { return _modelScale; }
const glm::vec3& getModelTranslation() const { return _modelTranslation; } const glm::vec3& getModelTranslation() const { return _modelTranslation; }
const glm::quat& getModelRotation() const { return _modelRotation; } const glm::quat& getModelRotation() const { return _modelRotation; }
float getModelScale() const { return _modelScale; }
ParticleID getParticleID() const { return ParticleID(getID(), getCreatorTokenID(), getID() != UNKNOWN_PARTICLE_ID); } ParticleID getParticleID() const { return ParticleID(getID(), getCreatorTokenID(), getID() != UNKNOWN_PARTICLE_ID); }
ParticleProperties getProperties() const; ParticleProperties getProperties() const;
@ -277,9 +277,9 @@ public:
// model related properties // model related properties
void setModelURL(const QString& url) { _modelURL = url; } void setModelURL(const QString& url) { _modelURL = url; }
void setModelScale(float scale) { _modelScale = scale; }
void setModelTranslation(const glm::vec3& translation) { _modelTranslation = translation; } void setModelTranslation(const glm::vec3& translation) { _modelTranslation = translation; }
void setModelRotation(const glm::quat& rotation) { _modelRotation = rotation; } void setModelRotation(const glm::quat& rotation) { _modelRotation = rotation; }
void setModelScale(float scale) { _modelScale = scale; }
void setProperties(const ParticleProperties& properties); void setProperties(const ParticleProperties& properties);
@ -344,9 +344,9 @@ protected:
// model related items // model related items
QString _modelURL; QString _modelURL;
float _modelScale;
glm::vec3 _modelTranslation; glm::vec3 _modelTranslation;
glm::quat _modelRotation; glm::quat _modelRotation;
float _modelScale;
uint32_t _creatorTokenID; uint32_t _creatorTokenID;
bool _newlyCreated; 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); 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, if (memcmp(packet.data() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,

View file

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

View file

@ -65,6 +65,8 @@ bool shouldDo(float desiredInterval, float deltaTime) {
return randFloat() < deltaTime / desiredInterval; return randFloat() < deltaTime / desiredInterval;
} }
void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) { void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
outputBits(buffer[i], continuedDebug); outputBits(buffer[i], continuedDebug);
@ -76,6 +78,7 @@ void outputBits(unsigned char byte, QDebug* continuedDebug) {
if (continuedDebug) { if (continuedDebug) {
debug = *continuedDebug; debug = *continuedDebug;
debug.nospace();
} }
QString resultString; QString resultString;
@ -85,12 +88,12 @@ void outputBits(unsigned char byte, QDebug* continuedDebug) {
} else { } else {
resultString.sprintf("[ %d (0x%x): ", byte, byte); resultString.sprintf("[ %d (0x%x): ", byte, byte);
} }
debug << resultString; debug << qPrintable(resultString);
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
resultString.sprintf("%d", byte >> (7 - i) & 1); resultString.sprintf("%d", byte >> (7 - i) & 1);
debug << qPrintable(resultString);
} }
debug << resultString;
debug << " ]"; 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 "VoxelConstants.h"
#include "VoxelTreeElement.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. /// Handles packing of the data portion of PacketType_VOXEL_DATA messages.
class VoxelPacketData : public OctreePacketData { class VoxelPacketData : public OctreePacketData {
public: public:

View file

@ -54,6 +54,8 @@ void VoxelTreeElement::splitChildren() {
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
addChildAtIndex(i)->setColor(ourColor); 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)); memcpy(&_currentColor,&color,sizeof(nodeColor));
} }
_isDirty = true; _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(); markWithChangedTime();
} }
} }