mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-08 18:57:03 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels
This commit is contained in:
commit
0a6288bda4
56 changed files with 550 additions and 508 deletions
17
README.md
17
README.md
|
@ -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
|
||||||
|
|
|
@ -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})
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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__) */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
@ -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() :
|
|
@ -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"
|
|
@ -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() { };
|
|
@ -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"
|
||||||
|
|
|
@ -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);
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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++) {
|
||||||
|
|
|
@ -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})
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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})
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 << " ]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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})
|
|
|
@ -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:
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue