mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-10 09:02:26 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into 20216
Conflicts: interface/src/Menu.cpp
This commit is contained in:
commit
80a81043ed
591 changed files with 15231 additions and 24724 deletions
3
BUILD.md
3
BUILD.md
|
@ -6,6 +6,7 @@
|
|||
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g
|
||||
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
|
||||
* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
|
||||
* [Bullet Physics Engine](http://bulletphysics.org) ~> 2.82
|
||||
|
||||
### OS Specific Build Guides
|
||||
* [BUILD_OSX.md](BUILD_OSX.md) - additional instructions for OS X.
|
||||
|
@ -59,5 +60,5 @@ OS X users who tap our [homebrew formulas repository](https://github.com/highfid
|
|||
|
||||
####Devices
|
||||
|
||||
You can support external input/output devices such as Leap Motion, Faceplus, Faceshift, PrioVR, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
You can support external input/output devices such as Leap Motion, Faceshift, PrioVR, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
|
||||
|
|
|
@ -12,6 +12,10 @@ if (POLICY CMP0043)
|
|||
cmake_policy(SET CMP0043 OLD)
|
||||
endif ()
|
||||
|
||||
if (POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 OLD)
|
||||
endif ()
|
||||
|
||||
project(hifi)
|
||||
add_definitions(-DGLM_FORCE_RADIANS)
|
||||
|
||||
|
@ -34,17 +38,19 @@ elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-strict-aliasing")
|
||||
endif(WIN32)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
||||
if (NOT MSVC12)
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
||||
|
||||
if (COMPILER_SUPPORTS_CXX11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
elseif(COMPILER_SUPPORTS_CXX0X)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
else()
|
||||
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||
endif()
|
||||
if (COMPILER_SUPPORTS_CXX11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
elseif(COMPILER_SUPPORTS_CXX0X)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
else()
|
||||
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++0x")
|
||||
|
|
|
@ -6,7 +6,7 @@ include_glm()
|
|||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
audio avatars octree voxels fbx entities metavoxels
|
||||
audio avatars octree environment gpu model fbx entities metavoxels
|
||||
networking animation shared script-engine embedded-webserver
|
||||
physics
|
||||
)
|
||||
|
@ -15,4 +15,4 @@ if (UNIX)
|
|||
target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})
|
||||
endif (UNIX)
|
||||
|
||||
link_shared_dependencies()
|
||||
include_dependency_includes()
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
#include <AudioRingBuffer.h>
|
||||
#include <AvatarData.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
|
@ -25,7 +24,6 @@
|
|||
#include <ResourceCache.h>
|
||||
#include <SoundCache.h>
|
||||
#include <UUID.h>
|
||||
#include <VoxelConstants.h>
|
||||
|
||||
#include <EntityScriptingInterface.h> // TODO: consider moving to scriptengine.h
|
||||
|
||||
|
@ -37,9 +35,8 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
|
|||
|
||||
Agent::Agent(const QByteArray& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_voxelEditSender(),
|
||||
_entityEditSender(),
|
||||
_receivedAudioStream(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES,
|
||||
_receivedAudioStream(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES,
|
||||
InboundAudioStream::Settings(0, false, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, false,
|
||||
DEFAULT_WINDOW_STARVE_THRESHOLD, DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES,
|
||||
DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION, false)),
|
||||
|
@ -48,14 +45,13 @@ Agent::Agent(const QByteArray& packet) :
|
|||
// be the parent of the script engine so it gets moved when we do
|
||||
_scriptEngine.setParent(this);
|
||||
|
||||
_scriptEngine.getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender);
|
||||
_scriptEngine.getEntityScriptingInterface()->setPacketSender(&_entityEditSender);
|
||||
}
|
||||
|
||||
void Agent::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
|
@ -69,11 +65,6 @@ void Agent::readPendingDatagrams() {
|
|||
if (matchedNode) {
|
||||
// PacketType_JURISDICTION, first byte is the node type...
|
||||
switch (receivedPacket[headerBytes]) {
|
||||
case NodeType::VoxelServer:
|
||||
_scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener()->
|
||||
queueReceivedPacket(matchedNode,receivedPacket);
|
||||
break;
|
||||
break;
|
||||
case NodeType::EntityServer:
|
||||
_scriptEngine.getEntityScriptingInterface()->getJurisdictionListener()->
|
||||
queueReceivedPacket(matchedNode, receivedPacket);
|
||||
|
@ -93,7 +84,6 @@ void Agent::readPendingDatagrams() {
|
|||
sourceNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
} else if (datagramPacketType == PacketTypeOctreeStats
|
||||
|| datagramPacketType == PacketTypeVoxelData
|
||||
|| datagramPacketType == PacketTypeEntityData
|
||||
|| datagramPacketType == PacketTypeEntityErase
|
||||
) {
|
||||
|
@ -113,7 +103,7 @@ void Agent::readPendingDatagrams() {
|
|||
// TODO: this needs to be fixed, the goal is to test the packet version for the piggyback, but
|
||||
// this is testing the version and hash of the original packet
|
||||
// need to use numBytesArithmeticCodingFromBuffer()...
|
||||
if (!NodeList::getInstance()->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (!DependencyManager::get<NodeList>()->packetVersionAndHashMatch(receivedPacket)) {
|
||||
return; // bail since piggyback data doesn't match our versioning
|
||||
}
|
||||
} else {
|
||||
|
@ -127,10 +117,6 @@ void Agent::readPendingDatagrams() {
|
|||
_entityViewer.processDatagram(mutablePacket, sourceNode);
|
||||
}
|
||||
|
||||
if (datagramPacketType == PacketTypeVoxelData) {
|
||||
_voxelViewer.processDatagram(mutablePacket, sourceNode);
|
||||
}
|
||||
|
||||
} else if (datagramPacketType == PacketTypeMixedAudio || datagramPacketType == PacketTypeSilentAudioFrame) {
|
||||
|
||||
_receivedAudioStream.parseData(receivedPacket);
|
||||
|
@ -141,7 +127,7 @@ void Agent::readPendingDatagrams() {
|
|||
|
||||
// let this continue through to the NodeList so it updates last heard timestamp
|
||||
// for the sending audio mixer
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
|
||||
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
|
||||
} else if (datagramPacketType == PacketTypeBulkAvatarData
|
||||
|| datagramPacketType == PacketTypeAvatarIdentity
|
||||
|| datagramPacketType == PacketTypeAvatarBillboard
|
||||
|
@ -151,9 +137,9 @@ void Agent::readPendingDatagrams() {
|
|||
|
||||
// let this continue through to the NodeList so it updates last heard timestamp
|
||||
// for the sending avatar-mixer
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
|
||||
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
|
||||
} else {
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
|
||||
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,11 +150,10 @@ const QString AGENT_LOGGING_NAME = "agent";
|
|||
void Agent::run() {
|
||||
ThreadedAssignment::commonInit(AGENT_LOGGING_NAME, NodeType::Agent);
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet()
|
||||
<< NodeType::AudioMixer
|
||||
<< NodeType::AvatarMixer
|
||||
<< NodeType::VoxelServer
|
||||
<< NodeType::EntityServer
|
||||
);
|
||||
|
||||
|
@ -176,7 +161,7 @@ void Agent::run() {
|
|||
QUrl scriptURL;
|
||||
if (_payload.isEmpty()) {
|
||||
scriptURL = QUrl(QString("http://%1:%2/assignment/%3")
|
||||
.arg(NodeList::getInstance()->getDomainHandler().getIP().toString())
|
||||
.arg(DependencyManager::get<NodeList>()->getDomainHandler().getIP().toString())
|
||||
.arg(DOMAIN_SERVER_HTTP_PORT)
|
||||
.arg(uuidStringWithoutCurlyBraces(_uuid)));
|
||||
} else {
|
||||
|
@ -199,6 +184,7 @@ void Agent::run() {
|
|||
loop.exec();
|
||||
|
||||
QString scriptContents(reply->readAll());
|
||||
delete reply;
|
||||
|
||||
qDebug() << "Downloaded script:" << scriptContents;
|
||||
|
||||
|
@ -221,12 +207,6 @@ void Agent::run() {
|
|||
|
||||
_scriptEngine.registerGlobalObject("SoundCache", &SoundCache::getInstance());
|
||||
|
||||
_scriptEngine.registerGlobalObject("VoxelViewer", &_voxelViewer);
|
||||
// connect the VoxelViewer and the VoxelScriptingInterface to each other
|
||||
_voxelViewer.setJurisdictionListener(_scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener());
|
||||
_voxelViewer.init();
|
||||
_scriptEngine.getVoxelsScriptingInterface()->setVoxelTree(_voxelViewer.getTree());
|
||||
|
||||
_scriptEngine.registerGlobalObject("EntityViewer", &_entityViewer);
|
||||
_entityViewer.setJurisdictionListener(_scriptEngine.getEntityScriptingInterface()->getJurisdictionListener());
|
||||
_entityViewer.init();
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#include <EntityTreeHeadlessViewer.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <ThreadedAssignment.h>
|
||||
#include <VoxelEditPacketSender.h>
|
||||
#include <VoxelTreeHeadlessViewer.h>
|
||||
|
||||
#include "MixedAudioStream.h"
|
||||
|
||||
|
@ -60,10 +58,7 @@ public slots:
|
|||
|
||||
private:
|
||||
ScriptEngine _scriptEngine;
|
||||
VoxelEditPacketSender _voxelEditSender;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
|
||||
VoxelTreeHeadlessViewer _voxelViewer;
|
||||
EntityTreeHeadlessViewer _entityViewer;
|
||||
|
||||
MixedAudioStream _receivedAudioStream;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QtCore/QTimer>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <Assignment.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <LogHandler.h>
|
||||
|
@ -48,7 +49,12 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
setOrganizationDomain("highfidelity.io");
|
||||
setApplicationName("assignment-client");
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
|
||||
|
||||
// create a NodeList as an unassigned client
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<NodeList>(NodeType::Unassigned);
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
#ifdef _WIN32
|
||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||
|
@ -91,9 +97,6 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID);
|
||||
_requestAssignment.setWalletUUID(walletUUID);
|
||||
}
|
||||
|
||||
// create a NodeList as an unassigned client
|
||||
NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned);
|
||||
|
||||
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
|
||||
|
@ -136,7 +139,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
void AssignmentClient::sendAssignmentRequest() {
|
||||
if (!_currentAssignment) {
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (_assignmentServerHostname == "localhost") {
|
||||
// we want to check again for the local domain-server port in case the DS has restarted
|
||||
|
@ -173,7 +176,7 @@ void AssignmentClient::sendAssignmentRequest() {
|
|||
}
|
||||
|
||||
void AssignmentClient::readPendingDatagrams() {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
@ -260,7 +263,7 @@ void AssignmentClient::assignmentCompleted() {
|
|||
|
||||
qDebug("Assignment finished or never started - waiting for new assignment.");
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// have us handle incoming NodeList datagrams again
|
||||
disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment.data(), 0);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "avatars/AvatarMixer.h"
|
||||
#include "metavoxels/MetavoxelServer.h"
|
||||
#include "entities/EntityServer.h"
|
||||
#include "voxels/VoxelServer.h"
|
||||
|
||||
ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet) {
|
||||
QDataStream packetStream(packet);
|
||||
|
@ -35,8 +34,6 @@ ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet
|
|||
return new AvatarMixer(packet);
|
||||
case Assignment::AgentType:
|
||||
return new Agent(packet);
|
||||
case Assignment::VoxelServerType:
|
||||
return new VoxelServer(packet);
|
||||
case Assignment::MetavoxelServerType:
|
||||
return new MetavoxelServer(packet);
|
||||
case Assignment::EntityServerType:
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
#include "AudioMixer.h"
|
||||
|
||||
const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
|
||||
const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18;
|
||||
const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18f;
|
||||
const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f;
|
||||
const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer";
|
||||
const QString AUDIO_ENV_GROUP_KEY = "audio_env";
|
||||
|
@ -273,8 +273,8 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
|
|||
|
||||
// Mono input to stereo output (item 1 above)
|
||||
int OUTPUT_SAMPLES_PER_INPUT_SAMPLE = 2;
|
||||
int inputSampleCount = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / OUTPUT_SAMPLES_PER_INPUT_SAMPLE;
|
||||
int maxOutputIndex = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO;
|
||||
int inputSampleCount = AudioConstants::NETWORK_FRAME_SAMPLES_STEREO / OUTPUT_SAMPLES_PER_INPUT_SAMPLE;
|
||||
int maxOutputIndex = AudioConstants::NETWORK_FRAME_SAMPLES_STEREO;
|
||||
|
||||
// attenuation and fade applied to all samples (item 2 above)
|
||||
float attenuationAndFade = attenuationCoefficient * repeatedFrameFadeFactor;
|
||||
|
@ -352,9 +352,10 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
|
|||
|
||||
float attenuationAndFade = attenuationCoefficient * repeatedFrameFadeFactor;
|
||||
|
||||
for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s++) {
|
||||
for (int s = 0; s < AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; s++) {
|
||||
_preMixSamples[s] = glm::clamp(_preMixSamples[s] + (int)(streamPopOutput[s / stereoDivider] * attenuationAndFade),
|
||||
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
|
||||
AudioConstants::MIN_SAMPLE_VALUE,
|
||||
AudioConstants::MAX_SAMPLE_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,14 +417,15 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
|
|||
AudioFilterHSF1s& penumbraFilter = listenerNodeData->getListenerSourcePairData(streamUUID)->getPenumbraFilter();
|
||||
|
||||
// set the gain on both filter channels
|
||||
penumbraFilter.setParameters(0, 0, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainL, penumbraFilterSlope);
|
||||
penumbraFilter.setParameters(0, 1, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainR, penumbraFilterSlope);
|
||||
penumbraFilter.render(_preMixSamples, _preMixSamples, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / 2);
|
||||
penumbraFilter.setParameters(0, 0, AudioConstants::SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainL, penumbraFilterSlope);
|
||||
penumbraFilter.setParameters(0, 1, AudioConstants::SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainR, penumbraFilterSlope);
|
||||
penumbraFilter.render(_preMixSamples, _preMixSamples, AudioConstants::NETWORK_FRAME_SAMPLES_STEREO / 2);
|
||||
}
|
||||
|
||||
// Actually mix the _preMixSamples into the _mixSamples here.
|
||||
for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s++) {
|
||||
_mixSamples[s] = glm::clamp(_mixSamples[s] + _preMixSamples[s], MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
|
||||
for (int s = 0; s < AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; s++) {
|
||||
_mixSamples[s] = glm::clamp(_mixSamples[s] + _preMixSamples[s], AudioConstants::MIN_SAMPLE_VALUE,
|
||||
AudioConstants::MAX_SAMPLE_VALUE);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -440,7 +442,7 @@ int AudioMixer::prepareMixForListeningNode(Node* node) {
|
|||
// loop through all other nodes that have sufficient audio to mix
|
||||
int streamsMixed = 0;
|
||||
|
||||
NodeList::getInstance()->eachNode([&](const SharedNodePointer& otherNode){
|
||||
DependencyManager::get<NodeList>()->eachNode([&](const SharedNodePointer& otherNode){
|
||||
if (otherNode->getLinkedData()) {
|
||||
AudioMixerClientData* otherNodeClientData = (AudioMixerClientData*) otherNode->getLinkedData();
|
||||
|
||||
|
@ -520,12 +522,12 @@ void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) {
|
|||
memcpy(envDataAt, &wetLevel, sizeof(float));
|
||||
envDataAt += sizeof(float);
|
||||
}
|
||||
NodeList::getInstance()->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node);
|
||||
DependencyManager::get<NodeList>()->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
// pull any new audio data from nodes off of the network stack
|
||||
|
@ -606,7 +608,7 @@ void AudioMixer::sendStatsPacket() {
|
|||
somethingToSend = true;
|
||||
sizeOfStats += property.size() + value.size();
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
int clientNumber = 0;
|
||||
|
||||
|
||||
|
@ -639,7 +641,7 @@ void AudioMixer::run() {
|
|||
|
||||
ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer);
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// we do not want this event loop to be the handler for UDP datagrams, so disconnect
|
||||
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||
|
@ -702,7 +704,7 @@ void AudioMixer::run() {
|
|||
|
||||
char clientMixBuffer[MAX_PACKET_SIZE];
|
||||
|
||||
int usecToSleep = BUFFER_SEND_INTERVAL_USECS;
|
||||
int usecToSleep = AudioConstants::NETWORK_FRAME_USECS;
|
||||
|
||||
const int TRAILING_AVERAGE_FRAMES = 100;
|
||||
int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES;
|
||||
|
@ -721,7 +723,7 @@ void AudioMixer::run() {
|
|||
}
|
||||
|
||||
_trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio)
|
||||
+ (usecToSleep * CURRENT_FRAME_RATIO / (float) BUFFER_SEND_INTERVAL_USECS);
|
||||
+ (usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS);
|
||||
|
||||
float lastCutoffRatio = _performanceThrottlingRatio;
|
||||
bool hasRatioChanged = false;
|
||||
|
@ -800,8 +802,8 @@ void AudioMixer::run() {
|
|||
mixDataAt += sizeof(quint16);
|
||||
|
||||
// pack mixed audio samples
|
||||
memcpy(mixDataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO);
|
||||
mixDataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO;
|
||||
memcpy(mixDataAt, _mixSamples, AudioConstants::NETWORK_FRAME_BYTES_STEREO);
|
||||
mixDataAt += AudioConstants::NETWORK_FRAME_BYTES_STEREO;
|
||||
} else {
|
||||
// pack header
|
||||
int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame);
|
||||
|
@ -813,7 +815,7 @@ void AudioMixer::run() {
|
|||
mixDataAt += sizeof(quint16);
|
||||
|
||||
// pack number of silent audio samples
|
||||
quint16 numSilentSamples = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO;
|
||||
quint16 numSilentSamples = AudioConstants::NETWORK_FRAME_SAMPLES_STEREO;
|
||||
memcpy(mixDataAt, &numSilentSamples, sizeof(quint16));
|
||||
mixDataAt += sizeof(quint16);
|
||||
}
|
||||
|
@ -844,7 +846,7 @@ void AudioMixer::run() {
|
|||
break;
|
||||
}
|
||||
|
||||
usecToSleep = (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - timer.nsecsElapsed() / 1000; // ns to us
|
||||
usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000; // ns to us
|
||||
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
|
@ -892,7 +894,7 @@ void AudioMixer::perSecondActions() {
|
|||
_timeSpentPerHashMatchCallStats.getWindowSum() / WINDOW_LENGTH_USECS * 100.0,
|
||||
_timeSpentPerHashMatchCallStats.getCurrentIntervalSum() / USECS_PER_SECOND * 100.0);
|
||||
|
||||
NodeList::getInstance()->eachNode([](const SharedNodePointer& node) {
|
||||
DependencyManager::get<NodeList>()->eachNode([](const SharedNodePointer& node) {
|
||||
if (node->getLinkedData()) {
|
||||
AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData();
|
||||
|
||||
|
|
|
@ -55,11 +55,11 @@ private:
|
|||
|
||||
// used on a per stream basis to run the filter on before mixing, large enough to handle the historical
|
||||
// data from a phase delay as well as an entire network buffer
|
||||
int16_t _preMixSamples[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)];
|
||||
int16_t _preMixSamples[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)];
|
||||
|
||||
// client samples capacity is larger than what will be sent to optimize mixing
|
||||
// we are MMX adding 4 samples at a time so we need client samples to have an extra 4
|
||||
int16_t _mixSamples[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)];
|
||||
int16_t _mixSamples[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)];
|
||||
|
||||
void perSecondActions();
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ void AudioMixerClientData::sendAudioStreamStatsPackets(const SharedNodePointer&
|
|||
removeDeadInjectedStreams();
|
||||
|
||||
char packet[MAX_PACKET_SIZE];
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// The append flag is a boolean value that will be packed right after the header. The first packet sent
|
||||
// inside this method will have 0 for this flag, while every subsequent packet will have 1 for this flag.
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
class PerListenerSourcePairData {
|
||||
public:
|
||||
PerListenerSourcePairData() {
|
||||
_penumbraFilter.initialize(SAMPLE_RATE, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / 2);
|
||||
_penumbraFilter.initialize(AudioConstants::SAMPLE_RATE, AudioConstants::NETWORK_FRAME_SAMPLES_STEREO / 2);
|
||||
};
|
||||
AudioFilterHSF1s& getPenumbraFilter() { return _penumbraFilter; }
|
||||
|
||||
|
|
|
@ -40,7 +40,9 @@ int AvatarAudioStream::parseStreamProperties(PacketType type, const QByteArray&
|
|||
|
||||
// if isStereo value has changed, restart the ring buffer with new frame size
|
||||
if (isStereo != _isStereo) {
|
||||
_ringBuffer.resizeForFrameSize(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||
_ringBuffer.resizeForFrameSize(isStereo
|
||||
? AudioConstants::NETWORK_FRAME_SAMPLES_STEREO
|
||||
: AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
|
||||
_isStereo = isStereo;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ AvatarMixer::AvatarMixer(const QByteArray& packet) :
|
|||
_sumIdentityPackets(0)
|
||||
{
|
||||
// make sure we hear about node kills so we can tell the other nodes
|
||||
connect(NodeList::getInstance(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled);
|
||||
connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled);
|
||||
}
|
||||
|
||||
AvatarMixer::~AvatarMixer() {
|
||||
|
@ -117,7 +117,7 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
|
||||
int numPacketHeaderBytes = populatePacketHeader(mixedAvatarByteArray, PacketTypeBulkAvatarData);
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
AvatarMixerClientData* nodeData = NULL;
|
||||
AvatarMixerClientData* otherNodeData = NULL;
|
||||
|
@ -222,7 +222,7 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
|
|||
QByteArray killPacket = byteArrayWithPopulatedHeader(PacketTypeKillAvatar);
|
||||
killPacket += killedNode->getUUID().toRfc4122();
|
||||
|
||||
NodeList::getInstance()->broadcastToNodes(killPacket,
|
||||
DependencyManager::get<NodeList>()->broadcastToNodes(killPacket,
|
||||
NodeSet() << NodeType::Agent);
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ void AvatarMixer::readPendingDatagrams() {
|
|||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
|
@ -309,7 +309,7 @@ void AvatarMixer::sendStatsPacket() {
|
|||
void AvatarMixer::run() {
|
||||
ThreadedAssignment::commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer);
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||
|
||||
nodeList->linkedDataCreateCallback = attachAvatarDataToNode;
|
||||
|
|
|
@ -76,7 +76,7 @@ void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePo
|
|||
copyAt += sizeof(entityID);
|
||||
packetLength += sizeof(entityID);
|
||||
|
||||
NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, senderNode);
|
||||
DependencyManager::get<NodeList>()->writeDatagram((char*) outputBuffer, packetLength, senderNode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -114,7 +114,8 @@ int EntityServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNo
|
|||
hasMoreToSend = tree->encodeEntitiesDeletedSince(queryNode->getSequenceNumber(), deletedEntitiesSentAt,
|
||||
outputBuffer, MAX_PACKET_SIZE, packetLength);
|
||||
|
||||
NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node));
|
||||
DependencyManager::get<NodeList>()->writeDatagram((char*) outputBuffer, packetLength,
|
||||
SharedNodePointer(node));
|
||||
queryNode->packetSent(outputBuffer, packetLength);
|
||||
packetsSent++;
|
||||
}
|
||||
|
@ -132,7 +133,7 @@ void EntityServer::pruneDeletedEntities() {
|
|||
|
||||
quint64 earliestLastDeletedEntitiesSent = usecTimestampNow() + 1; // in the future
|
||||
|
||||
NodeList::getInstance()->eachNode([&earliestLastDeletedEntitiesSent](const SharedNodePointer& node) {
|
||||
DependencyManager::get<NodeList>()->eachNode([&earliestLastDeletedEntitiesSent](const SharedNodePointer& node) {
|
||||
if (node->getLinkedData()) {
|
||||
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
||||
quint64 nodeLastDeletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
||||
|
|
|
@ -60,11 +60,11 @@ const QString METAVOXEL_SERVER_LOGGING_NAME = "metavoxel-server";
|
|||
void MetavoxelServer::run() {
|
||||
commonInit(METAVOXEL_SERVER_LOGGING_NAME, NodeType::MetavoxelServer);
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||
|
||||
connect(nodeList, &NodeList::nodeAdded, this, &MetavoxelServer::maybeAttachSession);
|
||||
connect(nodeList, &NodeList::nodeKilled, this, &MetavoxelServer::maybeDeleteSession);
|
||||
connect(nodeList.data(), &NodeList::nodeAdded, this, &MetavoxelServer::maybeAttachSession);
|
||||
connect(nodeList.data(), &NodeList::nodeKilled, this, &MetavoxelServer::maybeDeleteSession);
|
||||
|
||||
// initialize Bitstream before using it in multiple threads
|
||||
Bitstream::preThreadingInit();
|
||||
|
@ -101,7 +101,7 @@ void MetavoxelServer::readPendingDatagrams() {
|
|||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
|
|
|
@ -148,7 +148,7 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin
|
|||
qDebug() << " --- inside while loop ---";
|
||||
qDebug() << " maxSize=" << maxSize;
|
||||
qDebug("OctreeInboundPacketProcessor::processPacket() %c "
|
||||
"packetData=%p packetLength=%d voxelData=%p atByte=%d maxSize=%d",
|
||||
"packetData=%p packetLength=%d editData=%p atByte=%d maxSize=%d",
|
||||
packetType, packetData, packet.size(), editData, atByte, maxSize);
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin
|
|||
processTime += thisProcessTime;
|
||||
lockWaitTime += thisLockWaitTime;
|
||||
|
||||
// skip to next voxel edit record in the packet
|
||||
// skip to next edit record in the packet
|
||||
editData += editDataBytesRead;
|
||||
atByte += editDataBytesRead;
|
||||
|
||||
|
@ -188,7 +188,7 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin
|
|||
|
||||
if (debugProcessPacket) {
|
||||
qDebug("OctreeInboundPacketProcessor::processPacket() DONE LOOPING FOR %c "
|
||||
"packetData=%p packetLength=%d voxelData=%p atByte=%d",
|
||||
"packetData=%p packetLength=%d editData=%p atByte=%d",
|
||||
packetType, packetData, packet.size(), editData, atByte);
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,7 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
|
|||
continue;
|
||||
}
|
||||
|
||||
const SharedNodePointer& destinationNode = NodeList::getInstance()->nodeWithUUID(nodeUUID);
|
||||
const SharedNodePointer& destinationNode = DependencyManager::get<NodeList>()->nodeWithUUID(nodeUUID);
|
||||
|
||||
// retrieve sequence number stats of node, prune its missing set
|
||||
SequenceNumberStats& sequenceNumberStats = nodeStats.getIncomingEditSequenceNumberStats();
|
||||
|
@ -299,7 +299,7 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
|
|||
numSequenceNumbersAvailable -= numSequenceNumbers;
|
||||
|
||||
// send it
|
||||
NodeList::getInstance()->writeUnverifiedDatagram(packet, dataAt - packet, destinationNode);
|
||||
DependencyManager::get<NodeList>()->writeUnverifiedDatagram(packet, dataAt - packet, destinationNode);
|
||||
packetsSent++;
|
||||
|
||||
qDebug() << "NACK Sent back to editor/client... destinationNode=" << nodeUUID;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// Created by Brad Hefta-Gaub on 8/21/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Threaded or non-threaded network packet processor for the voxel-server
|
||||
// Threaded or non-threaded network packet processor for octree servers
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -53,7 +53,7 @@ typedef QHash<QUuid, SingleSenderStats>::iterator NodeToSenderStatsMapIterator;
|
|||
typedef QHash<QUuid, SingleSenderStats>::const_iterator NodeToSenderStatsMapConstIterator;
|
||||
|
||||
|
||||
/// Handles processing of incoming network packets for the voxel-server. As with other ReceivedPacketProcessor classes
|
||||
/// Handles processing of incoming network packets for the octee servers. As with other ReceivedPacketProcessor classes
|
||||
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
|
||||
class OctreeInboundPacketProcessor : public ReceivedPacketProcessor {
|
||||
Q_OBJECT
|
||||
|
@ -89,7 +89,7 @@ private:
|
|||
|
||||
private:
|
||||
void trackInboundPacket(const QUuid& nodeUUID, unsigned short int sequence, quint64 transitTime,
|
||||
int voxelsInPacket, quint64 processTime, quint64 lockWaitTime);
|
||||
int elementsInPacket, quint64 processTime, quint64 lockWaitTime);
|
||||
|
||||
OctreeServer* _myServer;
|
||||
int _receivedPacketCount;
|
||||
|
|
|
@ -147,10 +147,10 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes
|
|||
int statsMessageLength = nodeData->stats.getStatsMessageLength();
|
||||
int piggyBackSize = nodeData->getPacketLength() + statsMessageLength;
|
||||
|
||||
// If the size of the stats message and the voxel message will fit in a packet, then piggyback them
|
||||
// If the size of the stats message and the octree message will fit in a packet, then piggyback them
|
||||
if (piggyBackSize < MAX_PACKET_SIZE) {
|
||||
|
||||
// copy voxel message to back of stats message
|
||||
// copy octree message to back of stats message
|
||||
memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength());
|
||||
statsMessageLength += nodeData->getPacketLength();
|
||||
|
||||
|
@ -179,12 +179,12 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes
|
|||
|
||||
// actually send it
|
||||
OctreeServer::didCallWriteDatagram(this);
|
||||
NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, _node);
|
||||
DependencyManager::get<NodeList>()->writeDatagram((char*) statsMessage, statsMessageLength, _node);
|
||||
packetSent = true;
|
||||
} else {
|
||||
// not enough room in the packet, send two packets
|
||||
OctreeServer::didCallWriteDatagram(this);
|
||||
NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, _node);
|
||||
DependencyManager::get<NodeList>()->writeDatagram((char*) statsMessage, statsMessageLength, _node);
|
||||
|
||||
// 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.
|
||||
|
@ -213,7 +213,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes
|
|||
packetsSent++;
|
||||
|
||||
OctreeServer::didCallWriteDatagram(this);
|
||||
NodeList::getInstance()->writeDatagram((char*)nodeData->getPacket(), nodeData->getPacketLength(), _node);
|
||||
DependencyManager::get<NodeList>()->writeDatagram((char*)nodeData->getPacket(), nodeData->getPacketLength(), _node);
|
||||
packetSent = true;
|
||||
|
||||
thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength();
|
||||
|
@ -240,9 +240,9 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes
|
|||
} else {
|
||||
// If there's actually a packet waiting, then send it.
|
||||
if (nodeData->isPacketWaiting() && !nodeData->isShuttingDown()) {
|
||||
// just send the voxel packet
|
||||
// just send the octree packet
|
||||
OctreeServer::didCallWriteDatagram(this);
|
||||
NodeList::getInstance()->writeDatagram((char*)nodeData->getPacket(), nodeData->getPacketLength(), _node);
|
||||
DependencyManager::get<NodeList>()->writeDatagram((char*)nodeData->getPacket(), nodeData->getPacketLength(), _node);
|
||||
packetSent = true;
|
||||
|
||||
int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength();
|
||||
|
@ -279,7 +279,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes
|
|||
return packetsSent;
|
||||
}
|
||||
|
||||
/// Version of voxel distributor that sends the deepest LOD level at once
|
||||
/// Version of octree element distributor that sends the deepest LOD level at once
|
||||
int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged) {
|
||||
|
||||
OctreeServer::didPacketDistributor(this);
|
||||
|
@ -404,6 +404,13 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
|
|||
|
||||
bool lastNodeDidntFit = false; // assume each node fits
|
||||
if (!nodeData->elementBag.isEmpty()) {
|
||||
|
||||
quint64 lockWaitStart = usecTimestampNow();
|
||||
_myServer->getOctree()->lockForRead();
|
||||
quint64 lockWaitEnd = usecTimestampNow();
|
||||
lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart);
|
||||
quint64 encodeStart = usecTimestampNow();
|
||||
|
||||
OctreeElement* subTree = nodeData->elementBag.extract();
|
||||
|
||||
/* TODO: Looking for a way to prevent locking and encoding a tree that is not
|
||||
|
@ -430,7 +437,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
|
|||
bool wantOcclusionCulling = nodeData->getWantOcclusionCulling();
|
||||
CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP;
|
||||
|
||||
float voxelSizeScale = nodeData->getOctreeSizeScale();
|
||||
float octreeSizeScale = nodeData->getOctreeSizeScale();
|
||||
int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust();
|
||||
|
||||
int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving()
|
||||
|
@ -438,7 +445,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
|
|||
|
||||
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor,
|
||||
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
|
||||
wantOcclusionCulling, coverageMap, boundaryLevelAdjust, voxelSizeScale,
|
||||
wantOcclusionCulling, coverageMap, boundaryLevelAdjust, octreeSizeScale,
|
||||
nodeData->getLastTimeBagEmpty(),
|
||||
isFullScene, &nodeData->stats, _myServer->getJurisdiction(),
|
||||
&nodeData->extraEncodeData);
|
||||
|
@ -447,12 +454,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
|
|||
// it seems like it may be a good idea to include the lock time as part of the encode time
|
||||
// are reported to client. Since you can encode without the lock
|
||||
nodeData->stats.encodeStarted();
|
||||
|
||||
quint64 lockWaitStart = usecTimestampNow();
|
||||
_myServer->getOctree()->lockForRead();
|
||||
quint64 lockWaitEnd = usecTimestampNow();
|
||||
lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart);
|
||||
quint64 encodeStart = usecTimestampNow();
|
||||
|
||||
bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->elementBag, params);
|
||||
|
||||
|
@ -574,7 +575,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
|
|||
while (nodeData->hasNextNackedPacket() && packetsSentThisInterval < maxPacketsPerInterval) {
|
||||
const QByteArray* packet = nodeData->getNextNackedPacket();
|
||||
if (packet) {
|
||||
NodeList::getInstance()->writeDatagram(*packet, _node);
|
||||
DependencyManager::get<NodeList>()->writeDatagram(*packet, _node);
|
||||
truePacketsSent++;
|
||||
packetsSentThisInterval++;
|
||||
|
||||
|
@ -595,7 +596,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
|
|||
//int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs;
|
||||
|
||||
// if after sending packets we've emptied our bag, then we want to remember that we've sent all
|
||||
// the voxels from the current view frustum
|
||||
// the octree elements from the current view frustum
|
||||
if (nodeData->elementBag.isEmpty()) {
|
||||
nodeData->updateLastKnownViewFrustum();
|
||||
nodeData->setViewSent(true);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// Created by Brad Hefta-Gaub on 8/21/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Threaded or non-threaded object for sending voxels to a client
|
||||
// Threaded or non-threaded object for sending octree data packets to a client
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -22,7 +22,7 @@
|
|||
|
||||
class OctreeServer;
|
||||
|
||||
/// Threaded processor for sending voxel packets to a single client
|
||||
/// Threaded processor for sending octree packets to a single client
|
||||
class OctreeSendThread : public GenericThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QTimer>
|
||||
|
@ -358,7 +359,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
statsString += "Uptime: " + getUptime();
|
||||
statsString += "\r\n\r\n";
|
||||
|
||||
// display voxel file load time
|
||||
// display octree file load time
|
||||
if (isInitialLoadComplete()) {
|
||||
if (isPersistEnabled()) {
|
||||
statsString += QString("%1 File Persist Enabled...\r\n").arg(getMyServerName());
|
||||
|
@ -373,7 +374,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
statsString += "\r\n";
|
||||
|
||||
} else {
|
||||
statsString += "Voxels not yet loaded...\r\n";
|
||||
statsString += "Octree file not yet loaded...\r\n";
|
||||
}
|
||||
|
||||
statsString += "\r\n\r\n";
|
||||
|
@ -712,7 +713,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
}
|
||||
|
||||
statsString += QString().sprintf("Element Node Memory Usage: %8.2f %s\r\n",
|
||||
OctreeElement::getVoxelMemoryUsage() / memoryScale, memoryScaleLabel);
|
||||
OctreeElement::getOctreeMemoryUsage() / memoryScale, memoryScaleLabel);
|
||||
statsString += QString().sprintf("Octcode Memory Usage: %8.2f %s\r\n",
|
||||
OctreeElement::getOctcodeMemoryUsage() / memoryScale, memoryScaleLabel);
|
||||
statsString += QString().sprintf("External Children Memory Usage: %8.2f %s\r\n",
|
||||
|
@ -829,7 +830,7 @@ void OctreeServer::parsePayload() {
|
|||
}
|
||||
|
||||
void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
PacketType packetType = packetTypeForPacket(receivedPacket);
|
||||
|
@ -865,13 +866,13 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H
|
|||
_octreeInboundPacketProcessor->queueReceivedPacket(matchingNode, receivedPacket);
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
|
||||
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeServer::setupDatagramProcessingThread() {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// we do not want this event loop to be the handler for UDP datagrams, so disconnect
|
||||
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||
|
@ -960,7 +961,7 @@ void OctreeServer::readConfiguration() {
|
|||
}
|
||||
|
||||
// wait until we have the domain-server settings, otherwise we bail
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
DomainHandler& domainHandler = nodeList->getDomainHandler();
|
||||
|
||||
qDebug() << "Waiting for domain settings from domain-server.";
|
||||
|
@ -978,6 +979,7 @@ void OctreeServer::readConfiguration() {
|
|||
const QJsonObject& settingsObject = domainHandler.getSettingsObject();
|
||||
QString settingsKey = getMyDomainSettingsKey();
|
||||
QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject();
|
||||
_settings = settingsSectionObject; // keep this for later
|
||||
|
||||
if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) {
|
||||
_statusHost = getLocalAddress().toString();
|
||||
|
@ -1042,20 +1044,8 @@ void OctreeServer::readConfiguration() {
|
|||
_wantBackup = !noBackup;
|
||||
qDebug() << "wantBackup=" << _wantBackup;
|
||||
|
||||
if (_wantBackup) {
|
||||
_backupExtensionFormat = OctreePersistThread::DEFAULT_BACKUP_EXTENSION_FORMAT;
|
||||
readOptionString(QString("backupExtensionFormat"), settingsSectionObject, _backupExtensionFormat);
|
||||
qDebug() << "backupExtensionFormat=" << _backupExtensionFormat;
|
||||
|
||||
_backupInterval = OctreePersistThread::DEFAULT_BACKUP_INTERVAL;
|
||||
readOptionInt(QString("backupInterval"), settingsSectionObject, _backupInterval);
|
||||
qDebug() << "backupInterval=" << _backupInterval;
|
||||
|
||||
_maxBackupVersions = OctreePersistThread::DEFAULT_MAX_BACKUP_VERSIONS;
|
||||
readOptionInt(QString("maxBackupVersions"), settingsSectionObject, _maxBackupVersions);
|
||||
qDebug() << "maxBackupVersions=" << _maxBackupVersions;
|
||||
}
|
||||
|
||||
//qDebug() << "settingsSectionObject:" << settingsSectionObject;
|
||||
|
||||
} else {
|
||||
qDebug("persistFilename= DISABLED");
|
||||
}
|
||||
|
@ -1106,7 +1096,7 @@ void OctreeServer::run() {
|
|||
_tree->setIsServer(true);
|
||||
|
||||
// make sure our NodeList knows what type we are
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->setOwnerType(getMyNodeType());
|
||||
|
||||
|
||||
|
@ -1120,8 +1110,8 @@ void OctreeServer::run() {
|
|||
|
||||
beforeRun(); // after payload has been processed
|
||||
|
||||
connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
|
||||
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)),SLOT(nodeKilled(SharedNodePointer)));
|
||||
connect(nodeList.data(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
|
||||
connect(nodeList.data(), SIGNAL(nodeKilled(SharedNodePointer)),SLOT(nodeKilled(SharedNodePointer)));
|
||||
|
||||
|
||||
// we need to ask the DS about agents so we can ping/reply with them
|
||||
|
@ -1140,8 +1130,7 @@ void OctreeServer::run() {
|
|||
|
||||
// now set up PersistThread
|
||||
_persistThread = new OctreePersistThread(_tree, _persistFilename, _persistInterval,
|
||||
_wantBackup, _backupInterval, _backupExtensionFormat,
|
||||
_maxBackupVersions, _debugTimestampNow);
|
||||
_wantBackup, _settings, _debugTimestampNow);
|
||||
if (_persistThread) {
|
||||
_persistThread->initialize(true);
|
||||
}
|
||||
|
@ -1223,7 +1212,7 @@ void OctreeServer::aboutToFinish() {
|
|||
qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down...";
|
||||
_octreeInboundPacketProcessor->shuttingDown();
|
||||
|
||||
NodeList::getInstance()->eachNode([this](const SharedNodePointer& node) {
|
||||
DependencyManager::get<NodeList>()->eachNode([this](const SharedNodePointer& node) {
|
||||
qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node;
|
||||
forceNodeShutdown(node);
|
||||
});
|
||||
|
@ -1388,7 +1377,7 @@ void OctreeServer::sendStatsPacket() {
|
|||
statsObject2[baseName + QString(".2.outbound.timing.5.avgSendTime")] = getAveragePacketSendingTime();
|
||||
statsObject2[baseName + QString(".2.outbound.timing.5.nodeWaitTime")] = getAverageNodeWaitTime();
|
||||
|
||||
NodeList::getInstance()->sendStatsToDomainServer(statsObject2);
|
||||
DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject2);
|
||||
|
||||
static QJsonObject statsObject3;
|
||||
|
||||
|
@ -1407,7 +1396,7 @@ void OctreeServer::sendStatsPacket() {
|
|||
statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] =
|
||||
(double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement();
|
||||
|
||||
NodeList::getInstance()->sendStatsToDomainServer(statsObject3);
|
||||
DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject3);
|
||||
}
|
||||
|
||||
QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidProcess;
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
void forceNodeShutdown(SharedNodePointer node);
|
||||
|
||||
public slots:
|
||||
/// runs the voxel server assignment
|
||||
/// runs the octree server assignment
|
||||
void run();
|
||||
void nodeAdded(SharedNodePointer node);
|
||||
void nodeKilled(SharedNodePointer node);
|
||||
|
@ -150,6 +150,7 @@ protected:
|
|||
int _argc;
|
||||
const char** _argv;
|
||||
char** _parsedArgV;
|
||||
QJsonObject _settings;
|
||||
|
||||
HTTPManager* _httpManager;
|
||||
int _statusPort;
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
const int MAX_FILENAME_LENGTH = 1024;
|
||||
const int INTERVALS_PER_SECOND = 60;
|
||||
const int OCTREE_SEND_INTERVAL_USECS = (1000 * 1000)/INTERVALS_PER_SECOND;
|
||||
const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels
|
||||
const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for sending octree elements
|
||||
|
||||
#endif // hifi_OctreeServerConsts_h
|
||||
|
|
|
@ -45,7 +45,7 @@ void OctreeServerDatagramProcessor::readPendingDatagrams() {
|
|||
|
||||
PacketType packetType = packetTypeForPacket(incomingPacket);
|
||||
if (packetType == PacketTypePing) {
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, incomingPacket);
|
||||
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, incomingPacket);
|
||||
return; // don't emit
|
||||
}
|
||||
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// VoxelNodeData.h
|
||||
// assignment-client/src/voxels
|
||||
//
|
||||
// Created by Stephen Birarda on 3/21/13.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_VoxelNodeData_h
|
||||
#define hifi_VoxelNodeData_h
|
||||
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
#include "../octree/OctreeQueryNode.h"
|
||||
|
||||
class VoxelNodeData : public OctreeQueryNode {
|
||||
public:
|
||||
VoxelNodeData() : OctreeQueryNode() { }
|
||||
virtual PacketType getMyPacketType() const { return PacketTypeVoxelData; }
|
||||
};
|
||||
|
||||
#endif // hifi_VoxelNodeData_h
|
|
@ -1,102 +0,0 @@
|
|||
//
|
||||
// VoxelServer.cpp
|
||||
// assignment-client/src/voxels
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 9/16/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <VoxelTree.h>
|
||||
|
||||
#include "VoxelServer.h"
|
||||
#include "VoxelServerConsts.h"
|
||||
#include "VoxelNodeData.h"
|
||||
|
||||
const char* VOXEL_SERVER_NAME = "Voxel";
|
||||
const char* VOXEL_SERVER_LOGGING_TARGET_NAME = "voxel-server";
|
||||
const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo";
|
||||
|
||||
VoxelServer::VoxelServer(const QByteArray& packet) : OctreeServer(packet) {
|
||||
// nothing special to do here...
|
||||
}
|
||||
|
||||
VoxelServer::~VoxelServer() {
|
||||
// nothing special to do here...
|
||||
}
|
||||
|
||||
OctreeQueryNode* VoxelServer::createOctreeQueryNode() {
|
||||
return new VoxelNodeData();
|
||||
}
|
||||
|
||||
Octree* VoxelServer::createTree() {
|
||||
return new VoxelTree(true);
|
||||
}
|
||||
|
||||
bool VoxelServer::hasSpecialPacketToSend(const SharedNodePointer& node) {
|
||||
bool shouldSendEnvironments = _sendEnvironments && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, OCTREE_SEND_INTERVAL_USECS);
|
||||
return shouldSendEnvironments;
|
||||
}
|
||||
|
||||
int VoxelServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) {
|
||||
|
||||
unsigned char* copyAt = _tempOutputBuffer;
|
||||
|
||||
int numBytesPacketHeader = populatePacketHeader(reinterpret_cast<char*>(_tempOutputBuffer), PacketTypeEnvironmentData);
|
||||
copyAt += numBytesPacketHeader;
|
||||
int envPacketLength = numBytesPacketHeader;
|
||||
|
||||
// pack in flags
|
||||
OCTREE_PACKET_FLAGS flags = 0;
|
||||
OCTREE_PACKET_FLAGS* flagsAt = (OCTREE_PACKET_FLAGS*)copyAt;
|
||||
*flagsAt = flags;
|
||||
copyAt += sizeof(OCTREE_PACKET_FLAGS);
|
||||
envPacketLength += sizeof(OCTREE_PACKET_FLAGS);
|
||||
|
||||
// pack in sequence number
|
||||
OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)copyAt;
|
||||
*sequenceAt = queryNode->getSequenceNumber();
|
||||
copyAt += sizeof(OCTREE_PACKET_SEQUENCE);
|
||||
envPacketLength += sizeof(OCTREE_PACKET_SEQUENCE);
|
||||
|
||||
// pack in timestamp
|
||||
OCTREE_PACKET_SENT_TIME now = usecTimestampNow();
|
||||
OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)copyAt;
|
||||
*timeAt = now;
|
||||
copyAt += sizeof(OCTREE_PACKET_SENT_TIME);
|
||||
envPacketLength += sizeof(OCTREE_PACKET_SENT_TIME);
|
||||
|
||||
int environmentsToSend = getSendMinimalEnvironment() ? 1 : getEnvironmentDataCount();
|
||||
|
||||
for (int i = 0; i < environmentsToSend; i++) {
|
||||
envPacketLength += getEnvironmentData(i)->getBroadcastData(_tempOutputBuffer + envPacketLength);
|
||||
}
|
||||
|
||||
NodeList::getInstance()->writeDatagram((char*) _tempOutputBuffer, envPacketLength, SharedNodePointer(node));
|
||||
queryNode->packetSent(_tempOutputBuffer, envPacketLength);
|
||||
packetsSent = 1;
|
||||
|
||||
return envPacketLength;
|
||||
}
|
||||
|
||||
|
||||
void VoxelServer::readAdditionalConfiguration(const QJsonObject& settingsSectionObject) {
|
||||
// should we send environments? Default is yes, but this command line suppresses sending
|
||||
readOptionBool(QString("sendEnvironments"), settingsSectionObject, _sendEnvironments);
|
||||
bool dontSendEnvironments = !_sendEnvironments;
|
||||
if (dontSendEnvironments) {
|
||||
qDebug("Sending environments suppressed...");
|
||||
} else {
|
||||
// should we send environments? Default is yes, but this command line suppresses sending
|
||||
//const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment";
|
||||
//_sendMinimalEnvironment = cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT);
|
||||
|
||||
readOptionBool(QString("minimalEnvironment"), settingsSectionObject, _sendMinimalEnvironment);
|
||||
qDebug("Using Minimal Environment=%s", debug::valueOf(_sendMinimalEnvironment));
|
||||
}
|
||||
qDebug("Sending environments=%s", debug::valueOf(_sendEnvironments));
|
||||
|
||||
NodeList::getInstance()->addNodeTypeToInterestSet(NodeType::AnimationServer);
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
//
|
||||
// VoxelServer.h
|
||||
// assignment-client/src/voxels
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 8/21/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_VoxelServer_h
|
||||
#define hifi_VoxelServer_h
|
||||
|
||||
#include <QStringList>
|
||||
#include <QDateTime>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <ThreadedAssignment.h>
|
||||
#include <EnvironmentData.h>
|
||||
|
||||
#include "../octree/OctreeServer.h"
|
||||
|
||||
#include "VoxelServerConsts.h"
|
||||
|
||||
/// Handles assignments of type VoxelServer - sending voxels to various clients.
|
||||
class VoxelServer : public OctreeServer {
|
||||
public:
|
||||
VoxelServer(const QByteArray& packet);
|
||||
~VoxelServer();
|
||||
|
||||
bool wantSendEnvironments() const { return _sendEnvironments; }
|
||||
bool getSendMinimalEnvironment() const { return _sendMinimalEnvironment; }
|
||||
EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; }
|
||||
int getEnvironmentDataCount() const { return sizeof(_environmentData)/sizeof(EnvironmentData); }
|
||||
|
||||
// Subclasses must implement these methods
|
||||
virtual OctreeQueryNode* createOctreeQueryNode();
|
||||
virtual char getMyNodeType() const { return NodeType::VoxelServer; }
|
||||
virtual PacketType getMyQueryMessageType() const { return PacketTypeVoxelQuery; }
|
||||
virtual const char* getMyServerName() const { return VOXEL_SERVER_NAME; }
|
||||
virtual const char* getMyLoggingServerTargetName() const { return VOXEL_SERVER_LOGGING_TARGET_NAME; }
|
||||
virtual const char* getMyDefaultPersistFilename() const { return LOCAL_VOXELS_PERSIST_FILE; }
|
||||
virtual PacketType getMyEditNackType() const { return PacketTypeVoxelEditNack; }
|
||||
virtual QString getMyDomainSettingsKey() const { return QString("voxel_server_settings"); }
|
||||
|
||||
// subclass may implement these method
|
||||
virtual bool hasSpecialPacketToSend(const SharedNodePointer& node);
|
||||
virtual int sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent);
|
||||
|
||||
protected:
|
||||
virtual Octree* createTree();
|
||||
virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject);
|
||||
|
||||
private:
|
||||
bool _sendEnvironments;
|
||||
bool _sendMinimalEnvironment;
|
||||
EnvironmentData _environmentData[3];
|
||||
unsigned char _tempOutputBuffer[MAX_PACKET_SIZE];
|
||||
};
|
||||
|
||||
#endif // hifi_VoxelServer_h
|
|
@ -1,21 +0,0 @@
|
|||
//
|
||||
// VoxelServerConsts.h
|
||||
// assignment-client/src/voxels
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 8/21/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_VoxelServerConsts_h
|
||||
#define hifi_VoxelServerConsts_h
|
||||
|
||||
extern const char* VOXEL_SERVER_NAME;
|
||||
extern const char* VOXEL_SERVER_LOGGING_TARGET_NAME;
|
||||
extern const char* LOCAL_VOXELS_PERSIST_FILE;
|
||||
|
||||
const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000;
|
||||
|
||||
#endif // hifi_VoxelServerConsts_h
|
83
cmake/macros/AutoScribeShader.cmake
Executable file
83
cmake/macros/AutoScribeShader.cmake
Executable file
|
@ -0,0 +1,83 @@
|
|||
#
|
||||
# AutoScribeShader.cmake
|
||||
#
|
||||
# Created by Sam Gateau on 12/17/14.
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
function(AUTOSCRIBE_SHADER SHADER_FILE)
|
||||
|
||||
# Grab include files
|
||||
foreach(includeFile ${ARGN})
|
||||
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
|
||||
endforeach()
|
||||
|
||||
#Extract the unique include shader paths
|
||||
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
|
||||
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
|
||||
endforeach()
|
||||
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
|
||||
|
||||
# make the scribe include arguments
|
||||
set(SCRIBE_INCLUDES)
|
||||
foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS})
|
||||
set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/)
|
||||
endforeach()
|
||||
|
||||
# Define the final name of the generated shader file
|
||||
get_filename_component(SHADER_TARGET ${SHADER_FILE} NAME_WE)
|
||||
get_filename_component(SHADER_EXT ${SHADER_FILE} EXT)
|
||||
if(SHADER_EXT STREQUAL .slv)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_vert.h)
|
||||
elseif(${SHADER_EXT} STREQUAL .slf)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_frag.h)
|
||||
endif()
|
||||
|
||||
# Target dependant Custom rule on the SHADER_FILE
|
||||
if (APPLE)
|
||||
set(GLPROFILE MAC_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
else (APPLE)
|
||||
set(GLPROFILE PC_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
endif()
|
||||
|
||||
#output the generated file name
|
||||
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE)
|
||||
|
||||
file(GLOB INCLUDE_FILES ${SHADER_TARGET})
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(AUTOSCRIBE_SHADER_LIB)
|
||||
|
||||
file(GLOB_RECURSE SHADER_INCLUDE_FILES src/*.slh)
|
||||
file(GLOB_RECURSE SHADER_SOURCE_FILES src/*.slv src/*.slf)
|
||||
|
||||
#message(${SHADER_INCLUDE_FILES})
|
||||
foreach(SHADER_FILE ${SHADER_SOURCE_FILES})
|
||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_SHADER_RETURN})
|
||||
endforeach()
|
||||
#message(${AUTOSCRIBE_SHADER_SRC})
|
||||
|
||||
if (WIN32)
|
||||
source_group("Shaders" FILES ${SHADER_INCLUDE_FILES})
|
||||
source_group("Shaders" FILES ${SHADER_SOURCE_FILES})
|
||||
source_group("Shaders" FILES ${AUTOSCRIBE_SHADER_SRC})
|
||||
endif()
|
||||
|
||||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${SHADER_INCLUDE_FILES})
|
||||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${SHADER_SOURCE_FILES})
|
||||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${AUTOSCRIBE_SHADER_SRC})
|
||||
|
||||
endmacro()
|
18
cmake/macros/IncludeBullet.cmake
Normal file
18
cmake/macros/IncludeBullet.cmake
Normal file
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# IncludeBullet.cmake
|
||||
#
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(INCLUDE_BULLET)
|
||||
find_package(Bullet)
|
||||
if (BULLET_FOUND)
|
||||
include_directories("${BULLET_INCLUDE_DIRS}")
|
||||
if (APPLE OR UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_BULLET_PHYSICS -isystem ${BULLET_INCLUDE_DIRS}")
|
||||
endif ()
|
||||
endif (BULLET_FOUND)
|
||||
endmacro(INCLUDE_BULLET)
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# LinkSharedDependencies.cmake
|
||||
# IncludeDependencyIncludes.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -9,14 +9,14 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(LINK_SHARED_DEPENDENCIES)
|
||||
macro(INCLUDE_DEPENDENCY_INCLUDES)
|
||||
if (${TARGET_NAME}_DEPENDENCY_INCLUDES)
|
||||
list(REMOVE_DUPLICATES ${TARGET_NAME}_DEPENDENCY_INCLUDES)
|
||||
|
||||
# include those in our own target
|
||||
include_directories(SYSTEM ${${TARGET_NAME}_DEPENDENCY_INCLUDES})
|
||||
endif ()
|
||||
|
||||
# set the property on this target so it can be retreived by targets linking to us
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_INCLUDES "${${TARGET_NAME}_DEPENDENCY_INCLUDES}")
|
||||
endmacro(LINK_SHARED_DEPENDENCIES)
|
||||
|
||||
# set the property on this target so it can be retreived by targets linking to us
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_INCLUDES "${${TARGET_NAME}_DEPENDENCY_INCLUDES}")
|
||||
endif()
|
||||
endmacro(INCLUDE_DEPENDENCY_INCLUDES)
|
|
@ -27,7 +27,10 @@ macro(LINK_HIFI_LIBRARIES)
|
|||
|
||||
# ask the library what its include dependencies are and link them
|
||||
get_target_property(LINKED_TARGET_DEPENDENCY_INCLUDES ${HIFI_LIBRARY} DEPENDENCY_INCLUDES)
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_INCLUDES ${LINKED_TARGET_DEPENDENCY_INCLUDES})
|
||||
|
||||
if(LINKED_TARGET_DEPENDENCY_INCLUDES)
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_INCLUDES ${LINKED_TARGET_DEPENDENCY_INCLUDES})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
endmacro(LINK_HIFI_LIBRARIES)
|
|
@ -16,7 +16,7 @@ macro(SETUP_HIFI_LIBRARY)
|
|||
set(LIB_SRCS ${LIB_SRCS})
|
||||
|
||||
# create a library and set the property so it can be referenced later
|
||||
add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOMTC_SRC})
|
||||
add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC})
|
||||
|
||||
set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN})
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
# Try to find the Faceplus library
|
||||
#
|
||||
# You must provide a FACEPLUS_ROOT_DIR which contains lib and include directories
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# FACEPLUS_FOUND - system found Faceplus
|
||||
# FACEPLUS_INCLUDE_DIRS - the Faceplus include directory
|
||||
# FACEPLUS_LIBRARIES - Link this to use Faceplus
|
||||
#
|
||||
# Created on 4/8/2014 by Andrzej Kapolka
|
||||
# Copyright (c) 2014 High Fidelity
|
||||
#
|
||||
|
||||
find_path(FACEPLUS_INCLUDE_DIRS faceplus.h ${FACEPLUS_ROOT_DIR}/include)
|
||||
|
||||
if (WIN32)
|
||||
find_library(FACEPLUS_LIBRARIES faceplus.lib ${FACEPLUS_ROOT_DIR}/win32/)
|
||||
endif (WIN32)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Faceplus DEFAULT_MSG FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES)
|
||||
|
||||
mark_as_advanced(FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES)
|
|
@ -21,17 +21,17 @@
|
|||
if (WIN32)
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("glew")
|
||||
|
||||
find_path(GLEW_INCLUDE_DIRS GL/glew.h PATH_SUFFIXES include HINTS ${GLEW_SEARCH_DIRS})
|
||||
|
||||
find_library(GLEW_LIBRARY_RELEASE glew32s PATH_SUFFIXES "lib/Release/Win32" "lib" HINTS ${GLEW_SEARCH_DIRS})
|
||||
find_library(GLEW_LIBRARY_DEBUG glew32s PATH_SUFFIXES "lib/Debug/Win32" "lib" HINTS ${GLEW_SEARCH_DIRS})
|
||||
find_path(GLEW_INCLUDE_DIRS GL/glew.h PATH_SUFFIXES include HINTS ${GLEW_SEARCH_DIRS})
|
||||
|
||||
find_library(GLEW_LIBRARY_RELEASE glew32s PATH_SUFFIXES "lib/Release/Win32" "lib" HINTS ${GLEW_SEARCH_DIRS})
|
||||
find_library(GLEW_LIBRARY_DEBUG glew32sd PATH_SUFFIXES "lib/Debug/Win32" "lib" HINTS ${GLEW_SEARCH_DIRS})
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(GLEW)
|
||||
endif ()
|
||||
|
||||
set(GLEW_LIBRARIES "${GLEW_LIBRARY}")
|
||||
set(GLEW_LIBRARIES ${GLEW_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
#
|
||||
# FindGLUT.cmake
|
||||
#
|
||||
# Try to find GLUT library and include path.
|
||||
# Once done this will define
|
||||
#
|
||||
# GLUT_FOUND
|
||||
# GLUT_INCLUDE_DIRS
|
||||
# GLUT_LIBRARIES
|
||||
#
|
||||
# Created on 2/6/2014 by Stephen Birarda
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
#
|
||||
# Adapted from FindGLUT.cmake available in tlorach's OpenGLText Repository
|
||||
# https://raw.github.com/tlorach/OpenGLText/master/cmake/FindGLUT.cmake
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("freeglut")
|
||||
|
||||
if (WIN32)
|
||||
set(GLUT_HINT_DIRS "${FREEGLUT_SEARCH_DIRS} ${OPENGL_INCLUDE_DIR}")
|
||||
|
||||
find_path(GLUT_INCLUDE_DIRS GL/glut.h PATH_SUFFIXES include HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
find_library(GLUT_LIBRARY freeglut PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
else ()
|
||||
find_path(GLUT_INCLUDE_DIRS GL/glut.h PATH_SUFFIXES include HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
find_library(GLUT_LIBRARY glut PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
set(GLUT_LIBRARIES "${GLUT_LIBRARY}" "${XMU_LIBRARY}" "${XI_LIBRARY}")
|
||||
|
||||
if (UNIX)
|
||||
find_library(XI_LIBRARY Xi PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
find_library(XMU_LIBRARY Xmu PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
|
||||
find_package_handle_standard_args(GLUT DEFAULT_MSG GLUT_INCLUDE_DIRS GLUT_LIBRARIES XI_LIBRARY XMU_LIBRARY)
|
||||
else ()
|
||||
find_package_handle_standard_args(GLUT DEFAULT_MSG GLUT_INCLUDE_DIRS GLUT_LIBRARIES)
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(GLUT_INCLUDE_DIRS GLUT_LIBRARIES GLUT_LIBRARY XI_LIBRARY XMU_LIBRARY FREEGLUT_SEARCH_DIRS)
|
|
@ -52,4 +52,4 @@ include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
|||
# append OpenSSL to our list of libraries to link
|
||||
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})
|
||||
|
||||
link_shared_dependencies()
|
||||
include_dependency_includes()
|
|
@ -305,20 +305,66 @@
|
|||
"settings": [
|
||||
{
|
||||
"name": "persistFilename",
|
||||
"label": "Persistant Filename",
|
||||
"help": "the filename for your entities",
|
||||
"label": "Entities Filename",
|
||||
"help": "the path to the file entities are stored in. Make sure the path exists.",
|
||||
"placeholder": "resources/models.svo",
|
||||
"default": "resources/models.svo",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "persistInterval",
|
||||
"label": "Persist Interval",
|
||||
"help": "Interval between persist checks in msecs.",
|
||||
"label": "Save Check Interval",
|
||||
"help": "Milliseconds between checks for saving the current state of entities.",
|
||||
"placeholder": "30000",
|
||||
"default": "30000",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "backups",
|
||||
"type": "table",
|
||||
"label": "Backup Rules",
|
||||
"help": "In this table you can define a set of rules for how frequently to backup copies of your entites content file.",
|
||||
"numbered": false,
|
||||
"default": [
|
||||
{"Name":"Half Hourly Rolling","backupInterval":1800,"format":".backup.halfhourly.%N","maxBackupVersions":5},
|
||||
{"Name":"Daily Rolling","backupInterval":86400,"format":".backup.daily.%N","maxBackupVersions":7},
|
||||
{"Name":"Weekly Rolling","backupInterval":604800,"format":".backup.weekly.%N","maxBackupVersions":4},
|
||||
{"Name":"Thirty Day Rolling","backupInterval":2592000,"format":".backup.thirtyday.%N","maxBackupVersions":12}
|
||||
],
|
||||
"columns": [
|
||||
{
|
||||
"name": "Name",
|
||||
"label": "Name",
|
||||
"can_set": true,
|
||||
"placeholder": "Example",
|
||||
"default": "Example"
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"label": "Rule Format",
|
||||
"can_set": true,
|
||||
"help": "Format used to create the extension for the backup of your persisted entities. Use a format with %N to get rolling. Or use date formatting like %Y-%m-%d.%H:%M:%S.%z",
|
||||
"placeholder": ".backup.example.%N",
|
||||
"default": ".backup.example.%N"
|
||||
},
|
||||
{
|
||||
"name": "backupInterval",
|
||||
"label": "Backup Interval in Seconds",
|
||||
"help": "Interval between backup checks in seconds.",
|
||||
"placeholder": 1800,
|
||||
"default": 1800,
|
||||
"can_set": true
|
||||
},
|
||||
{
|
||||
"name": "maxBackupVersions",
|
||||
"label": "Max Rolled Backup Versions",
|
||||
"help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?",
|
||||
"placeholder": 5,
|
||||
"default": 5,
|
||||
"can_set": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NoPersist",
|
||||
"type": "checkbox",
|
||||
|
@ -326,30 +372,6 @@
|
|||
"default": false,
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "backupExtensionFormat",
|
||||
"label": "Backup File Extension Format:",
|
||||
"help": "Format used to create the extension for the backup of your persisted entities. Use a format with %N to get rolling. Or use date formatting like %Y-%m-%d.%H:%M:%S.%z",
|
||||
"placeholder": ".backup.%N",
|
||||
"default": ".backup.%N",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "backupInterval",
|
||||
"label": "Backup Interval",
|
||||
"help": "Interval between backup checks in msecs.",
|
||||
"placeholder": "1800000",
|
||||
"default": "1800000",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "maxBackupVersions",
|
||||
"label": "Max Rolled Backup Versions",
|
||||
"help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?",
|
||||
"placeholder": "5",
|
||||
"default": "5",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "NoBackup",
|
||||
"type": "checkbox",
|
||||
|
@ -410,99 +432,5 @@
|
|||
"advanced": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name": "voxel_server_settings",
|
||||
"label": "Voxel Server Settings",
|
||||
"assignment-types": [3],
|
||||
"settings": [
|
||||
{
|
||||
"name": "persistFilename",
|
||||
"label": "Persistant Filename",
|
||||
"help": "the filename for your voxels",
|
||||
"placeholder": "resources/voxels.svo",
|
||||
"default": "resources/voxels.svo",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "persistInterval",
|
||||
"label": "Persist Interval",
|
||||
"help": "Interval between persist checks in msecs.",
|
||||
"placeholder": "30000",
|
||||
"default": "30000",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "NoPersist",
|
||||
"type": "checkbox",
|
||||
"help": "Don't persist your voxels to a file.",
|
||||
"default": false,
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "backupExtensionFormat",
|
||||
"label": "Backup File Extension Format:",
|
||||
"help": "Format used to create the extension for the backup of your persisted voxels.",
|
||||
"placeholder": ".backup.%Y-%m-%d.%H:%M:%S.%z",
|
||||
"default": ".backup.%Y-%m-%d.%H:%M:%S.%z",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "backupInterval",
|
||||
"label": "Backup Interval",
|
||||
"help": "Interval between backup checks in msecs.",
|
||||
"placeholder": "1800000",
|
||||
"default": "1800000",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "NoBackup",
|
||||
"type": "checkbox",
|
||||
"help": "Don't regularly backup your persisted voxels to a backup file.",
|
||||
"default": false,
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "statusHost",
|
||||
"label": "Status Hostname",
|
||||
"help": "host name or IP address of the server for accessing the status page",
|
||||
"placeholder": "",
|
||||
"default": "",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "statusPort",
|
||||
"label": "Status Port",
|
||||
"help": "port of the server for accessing the status page",
|
||||
"placeholder": "",
|
||||
"default": "",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "clockSkew",
|
||||
"label": "Clock Skew",
|
||||
"help": "Number of msecs to skew the server clock by to test clock skew",
|
||||
"placeholder": "0",
|
||||
"default": "0",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "sendEnvironments",
|
||||
"type": "checkbox",
|
||||
"help": "send environmental data",
|
||||
"default": false,
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "minimalEnvironment",
|
||||
"type": "checkbox",
|
||||
"help": "send minimal environmental data if sending environmental data",
|
||||
"default": false,
|
||||
"advanced": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
]
|
|
@ -364,7 +364,7 @@ function makeTableInputs(setting) {
|
|||
_.each(setting.columns, function(col) {
|
||||
html += "<td class='" + Settings.DATA_COL_CLASS + "'name='" + col.name + "'>\
|
||||
<input type='text' class='form-control' placeholder='" + (col.placeholder ? col.placeholder : "") + "'\
|
||||
value='" + (col.default ? col.default : "") + "'>\
|
||||
value='" + (col.default ? col.default : "") + "' data-default='" + (col.default ? col.default : "") + "'>\
|
||||
</td>"
|
||||
})
|
||||
|
||||
|
@ -504,7 +504,7 @@ function addTableRow(add_glyphicon) {
|
|||
})
|
||||
|
||||
input_clone.find('input').each(function(){
|
||||
$(this).val('')
|
||||
$(this).val($(this).attr('data-default'));
|
||||
});
|
||||
|
||||
if (isArray) {
|
||||
|
@ -525,9 +525,9 @@ function deleteTableRow(delete_glyphicon) {
|
|||
var table = $(row).closest('table')
|
||||
var isArray = table.data('setting-type') === 'array'
|
||||
|
||||
row.empty();
|
||||
|
||||
if (!isArray) {
|
||||
// this is a hash row, so we empty it but leave the hidden input blank so it is cleared when we save
|
||||
row.empty()
|
||||
row.html("<input type='hidden' class='form-control' name='"
|
||||
+ row.attr('name') + "' data-changed='true' value=''>");
|
||||
} else {
|
||||
|
@ -538,7 +538,6 @@ function deleteTableRow(delete_glyphicon) {
|
|||
row.remove()
|
||||
} else {
|
||||
// this is the last row, we can't remove it completely since we need to post an empty array
|
||||
row.empty()
|
||||
|
||||
row.removeClass(Settings.DATA_ROW_CLASS).removeClass(Settings.NEW_ROW_CLASS)
|
||||
row.addClass('empty-array-row')
|
||||
|
@ -592,7 +591,7 @@ function updateDataChangedForSiblingRows(row, forceTrue) {
|
|||
var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName]
|
||||
|
||||
// if they are equal, we don't need data-changed
|
||||
isTrue = _.isEqual(panelSettingJSON, initialPanelSettingJSON)
|
||||
isTrue = !_.isEqual(panelSettingJSON, initialPanelSettingJSON)
|
||||
} else {
|
||||
isTrue = true
|
||||
}
|
||||
|
|
|
@ -237,7 +237,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
// check for scripts the user wants to persist from their domain-server config
|
||||
populateStaticScriptedAssignmentsFromSettings();
|
||||
|
||||
LimitedNodeList* nodeList = LimitedNodeList::createInstance(domainServerPort, domainServerDTLSPort);
|
||||
auto nodeList = DependencyManager::set<LimitedNodeList>(domainServerPort, domainServerDTLSPort);
|
||||
|
||||
// no matter the local port, save it to shared mem so that local assignment clients can ask what it is
|
||||
QSharedMemory* sharedPortMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
|
||||
|
@ -262,11 +262,11 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
nodeList->setSessionUUID(idValueVariant->toString());
|
||||
}
|
||||
|
||||
connect(nodeList, &LimitedNodeList::nodeAdded, this, &DomainServer::nodeAdded);
|
||||
connect(nodeList, &LimitedNodeList::nodeKilled, this, &DomainServer::nodeKilled);
|
||||
connect(nodeList.data(), &LimitedNodeList::nodeAdded, this, &DomainServer::nodeAdded);
|
||||
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &DomainServer::nodeKilled);
|
||||
|
||||
QTimer* silentNodeTimer = new QTimer(this);
|
||||
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
|
||||
connect(silentNodeTimer, SIGNAL(timeout()), nodeList.data(), SLOT(removeSilentNodes()));
|
||||
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS);
|
||||
|
||||
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(readAvailableDatagrams()));
|
||||
|
@ -346,8 +346,7 @@ bool DomainServer::optionallySetupAssignmentPayment() {
|
|||
}
|
||||
|
||||
void DomainServer::setupAutomaticNetworking() {
|
||||
|
||||
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
const int STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS = 10 * 1000;
|
||||
const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000;
|
||||
|
@ -368,8 +367,10 @@ void DomainServer::setupAutomaticNetworking() {
|
|||
iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
|
||||
|
||||
// call our sendHeartbeatToIceServer immediately anytime a local or public socket changes
|
||||
connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
|
||||
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
|
||||
connect(nodeList.data(), &LimitedNodeList::localSockAddrChanged,
|
||||
this, &DomainServer::sendHeartbeatToIceServer);
|
||||
connect(nodeList.data(), &LimitedNodeList::publicSockAddrChanged,
|
||||
this, &DomainServer::sendHeartbeatToIceServer);
|
||||
|
||||
// attempt to update our public socket now, this will send a heartbeat once we get public socket
|
||||
requestCurrentPublicSocketViaSTUN();
|
||||
|
@ -400,7 +401,8 @@ void DomainServer::setupAutomaticNetworking() {
|
|||
dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS);
|
||||
|
||||
// send public socket changes to the data server so nodes can find us at our new IP
|
||||
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::performIPAddressUpdate);
|
||||
connect(nodeList.data(), &LimitedNodeList::publicSockAddrChanged,
|
||||
this, &DomainServer::performIPAddressUpdate);
|
||||
|
||||
// attempt to update our sockets now
|
||||
requestCurrentPublicSocketViaSTUN();
|
||||
|
@ -549,7 +551,10 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
|||
for (Assignment::Type defaultedType = Assignment::AudioMixerType;
|
||||
defaultedType != Assignment::AllTypes;
|
||||
defaultedType = static_cast<Assignment::Type>(static_cast<int>(defaultedType) + 1)) {
|
||||
if (!excludedTypes.contains(defaultedType) && defaultedType != Assignment::AgentType) {
|
||||
if (!excludedTypes.contains(defaultedType)
|
||||
&& defaultedType != Assignment::UNUSED_0
|
||||
&& defaultedType != Assignment::UNUSED_1
|
||||
&& defaultedType != Assignment::AgentType) {
|
||||
// type has not been set from a command line or config file config, use the default
|
||||
// by clearing whatever exists and writing a single default assignment with no payload
|
||||
Assignment* newAssignment = new Assignment(Assignment::CreateCommand, (Assignment::Type) defaultedType);
|
||||
|
@ -559,7 +564,7 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
|||
}
|
||||
|
||||
const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
|
||||
<< NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::EntityServer
|
||||
<< NodeType::AvatarMixer << NodeType::EntityServer
|
||||
<< NodeType::MetavoxelServer;
|
||||
|
||||
void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSockAddr& senderSockAddr) {
|
||||
|
@ -614,7 +619,7 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
|
|||
QByteArray usernameRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeDomainConnectionDenied);
|
||||
|
||||
// send this oauth request datagram back to the client
|
||||
LimitedNodeList::getInstance()->writeUnverifiedDatagram(usernameRequestByteArray, senderSockAddr);
|
||||
DependencyManager::get<LimitedNodeList>()->writeUnverifiedDatagram(usernameRequestByteArray, senderSockAddr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -634,7 +639,7 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
|
|||
}
|
||||
|
||||
|
||||
SharedNodePointer newNode = LimitedNodeList::getInstance()->addOrUpdateNode(nodeUUID, nodeType,
|
||||
SharedNodePointer newNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode(nodeUUID, nodeType,
|
||||
publicSockAddr, localSockAddr);
|
||||
// when the newNode is created the linked data is also created
|
||||
// if this was a static assignment set the UUID, set the sendingSockAddr
|
||||
|
@ -667,7 +672,7 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
|
|||
QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList();
|
||||
|
||||
// we always let in a user who is sending a packet from our local socket or from the localhost address
|
||||
if (senderSockAddr.getAddress() == LimitedNodeList::getInstance()->getLocalSockAddr().getAddress()
|
||||
if (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress()
|
||||
|| senderSockAddr.getAddress() == QHostAddress::LocalHost) {
|
||||
return true;
|
||||
}
|
||||
|
@ -840,8 +845,8 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
|||
int numBroadcastPacketLeadBytes = broadcastDataStream.device()->pos();
|
||||
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||
|
||||
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
|
||||
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
// if we've established a connection via ICE with this peer, use that socket
|
||||
// otherwise just try to reply back to them on their sending socket (although that may not work)
|
||||
|
@ -907,7 +912,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
|||
}
|
||||
|
||||
void DomainServer::readAvailableDatagrams() {
|
||||
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
HifiSockAddr senderSockAddr;
|
||||
QByteArray receivedPacket;
|
||||
|
@ -995,7 +1000,7 @@ void DomainServer::readAvailableDatagrams() {
|
|||
|
||||
void DomainServer::setupPendingAssignmentCredits() {
|
||||
// enumerate the NodeList to find the assigned nodes
|
||||
NodeList::getInstance()->eachNode([&](const SharedNodePointer& node){
|
||||
DependencyManager::get<LimitedNodeList>()->eachNode([&](const SharedNodePointer& node){
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||
|
||||
if (!nodeData->getAssignmentUUID().isNull() && !nodeData->getWalletUUID().isNull()) {
|
||||
|
@ -1109,7 +1114,7 @@ void DomainServer::transactionJSONCallback(const QJsonObject& data) {
|
|||
}
|
||||
|
||||
void DomainServer::requestCurrentPublicSocketViaSTUN() {
|
||||
LimitedNodeList::getInstance()->sendSTUNRequest();
|
||||
DependencyManager::get<LimitedNodeList>()->sendSTUNRequest();
|
||||
}
|
||||
|
||||
QJsonObject jsonForDomainSocketUpdate(const HifiSockAddr& socket) {
|
||||
|
@ -1131,7 +1136,8 @@ void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr)
|
|||
|
||||
void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
|
||||
const QString DOMAIN_UPDATE = "/api/v1/domains/%1";
|
||||
const QUuid& domainID = LimitedNodeList::getInstance()->getSessionUUID();
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
const QUuid& domainID = nodeList->getSessionUUID();
|
||||
|
||||
// setup the domain object to send to the data server
|
||||
const QString PUBLIC_NETWORK_ADDRESS_KEY = "network_address";
|
||||
|
@ -1155,7 +1161,7 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
|
|||
// add the number of currently connected agent users
|
||||
int numConnectedAuthedUsers = 0;
|
||||
|
||||
NodeList::getInstance()->eachNode([&numConnectedAuthedUsers](const SharedNodePointer& node){
|
||||
nodeList->eachNode([&numConnectedAuthedUsers](const SharedNodePointer& node){
|
||||
if (node->getLinkedData() && !static_cast<DomainServerNodeData*>(node->getLinkedData())->getUsername().isEmpty()) {
|
||||
++numConnectedAuthedUsers;
|
||||
}
|
||||
|
@ -1184,11 +1190,11 @@ void DomainServer::performICEUpdates() {
|
|||
}
|
||||
|
||||
void DomainServer::sendHeartbeatToIceServer() {
|
||||
LimitedNodeList::getInstance()->sendHeartbeatToIceServer(_iceServerSocket);
|
||||
DependencyManager::get<LimitedNodeList>()->sendHeartbeatToIceServer(_iceServerSocket);
|
||||
}
|
||||
|
||||
void DomainServer::sendICEPingPackets() {
|
||||
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
QHash<QUuid, NetworkPeer>::iterator peer = _connectingICEPeers.begin();
|
||||
|
||||
|
@ -1256,7 +1262,7 @@ void DomainServer::processICEPingReply(const QByteArray& packet, const HifiSockA
|
|||
}
|
||||
|
||||
void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
PacketType requestType = packetTypeForPacket(receivedPacket);
|
||||
|
@ -1407,6 +1413,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
|
||||
const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
||||
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
// allow sub-handlers to handle requests that do not require authentication
|
||||
if (_settingsManager.handlePublicHTTPRequest(connection, url)) {
|
||||
return true;
|
||||
|
@ -1449,7 +1457,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
const QString URI_ID = "/id";
|
||||
if (connection->requestOperation() == QNetworkAccessManager::GetOperation
|
||||
&& url.path() == URI_ID) {
|
||||
QUuid domainID = LimitedNodeList::getInstance()->getSessionUUID();
|
||||
QUuid domainID = nodeList->getSessionUUID();
|
||||
|
||||
connection->respond(HTTPConnection::StatusCode200, uuidStringWithoutCurlyBraces(domainID).toLocal8Bit());
|
||||
return true;
|
||||
|
@ -1471,7 +1479,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
QJsonObject assignedNodesJSON;
|
||||
|
||||
// enumerate the NodeList to find the assigned nodes
|
||||
NodeList::getInstance()->eachNode([this, &assignedNodesJSON](const SharedNodePointer& node){
|
||||
nodeList->eachNode([this, &assignedNodesJSON](const SharedNodePointer& node){
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||
|
||||
if (!nodeData->getAssignmentUUID().isNull()) {
|
||||
|
@ -1533,7 +1541,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
QJsonArray nodesJSONArray;
|
||||
|
||||
// enumerate the NodeList to find the assigned nodes
|
||||
LimitedNodeList::getInstance()->eachNode([this, &nodesJSONArray](const SharedNodePointer& node){
|
||||
nodeList->eachNode([this, &nodesJSONArray](const SharedNodePointer& node){
|
||||
// add the node using the UUID as the key
|
||||
nodesJSONArray.append(jsonObjectForNode(node));
|
||||
});
|
||||
|
@ -1556,7 +1564,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
QUuid matchingUUID = QUuid(nodeShowRegex.cap(1));
|
||||
|
||||
// see if we have a node that matches this ID
|
||||
SharedNodePointer matchingNode = LimitedNodeList::getInstance()->nodeWithUUID(matchingUUID);
|
||||
SharedNodePointer matchingNode = nodeList->nodeWithUUID(matchingUUID);
|
||||
if (matchingNode) {
|
||||
// create a QJsonDocument with the stats QJsonObject
|
||||
QJsonObject statsObject =
|
||||
|
@ -1650,14 +1658,14 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
// pull the captured string, if it exists
|
||||
QUuid deleteUUID = QUuid(nodeDeleteRegex.cap(1));
|
||||
|
||||
SharedNodePointer nodeToKill = LimitedNodeList::getInstance()->nodeWithUUID(deleteUUID);
|
||||
SharedNodePointer nodeToKill = nodeList->nodeWithUUID(deleteUUID);
|
||||
|
||||
if (nodeToKill) {
|
||||
// start with a 200 response
|
||||
connection->respond(HTTPConnection::StatusCode200);
|
||||
|
||||
// we have a valid UUID and node - kill the node that has this assignment
|
||||
QMetaObject::invokeMethod(LimitedNodeList::getInstance(), "killNodeWithUUID", Q_ARG(const QUuid&, deleteUUID));
|
||||
QMetaObject::invokeMethod(nodeList.data(), "killNodeWithUUID", Q_ARG(const QUuid&, deleteUUID));
|
||||
|
||||
// successfully processed request
|
||||
return true;
|
||||
|
@ -1666,7 +1674,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
return true;
|
||||
} else if (allNodesDeleteRegex.indexIn(url.path()) != -1) {
|
||||
qDebug() << "Received request to kill all nodes.";
|
||||
LimitedNodeList::getInstance()->eraseAllNodes();
|
||||
nodeList->eraseAllNodes();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1733,6 +1741,9 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
|
|||
connection->respond(HTTPConnection::StatusCode302, QByteArray(),
|
||||
HTTPConnection::DefaultContentType, cookieHeaders);
|
||||
|
||||
delete tokenReply;
|
||||
delete profileReply;
|
||||
|
||||
// we've redirected the user back to our homepage
|
||||
return true;
|
||||
|
||||
|
@ -1983,7 +1994,7 @@ void DomainServer::nodeKilled(SharedNodePointer node) {
|
|||
|
||||
// cleanup the connection secrets that we set up for this node (on the other nodes)
|
||||
foreach (const QUuid& otherNodeSessionUUID, nodeData->getSessionSecretHash().keys()) {
|
||||
SharedNodePointer otherNode = LimitedNodeList::getInstance()->nodeWithUUID(otherNodeSessionUUID);
|
||||
SharedNodePointer otherNode = DependencyManager::get<LimitedNodeList>()->nodeWithUUID(otherNodeSessionUUID);
|
||||
if (otherNode) {
|
||||
reinterpret_cast<DomainServerNodeData*>(otherNode->getLinkedData())->getSessionSecretHash().remove(node->getUUID());
|
||||
}
|
||||
|
@ -2066,7 +2077,7 @@ void DomainServer::addStaticAssignmentsToQueue() {
|
|||
// add any of the un-matched static assignments to the queue
|
||||
|
||||
// enumerate the nodes and check if there is one with an attached assignment with matching UUID
|
||||
if (!NodeList::getInstance()->nodeWithUUID(staticAssignment->data()->getUUID())) {
|
||||
if (!DependencyManager::get<LimitedNodeList>()->nodeWithUUID(staticAssignment->data()->getUUID())) {
|
||||
// this assignment has not been fulfilled - reset the UUID and add it to the assignment queue
|
||||
refreshStaticAssignmentAndAddToQueue(*staticAssignment);
|
||||
}
|
||||
|
|
|
@ -145,13 +145,9 @@ function sendCommand(id, action) {
|
|||
return;
|
||||
}
|
||||
|
||||
Voxels.setVoxel(controlVoxelPosition.x + id * controlVoxelSize,
|
||||
controlVoxelPosition.y,
|
||||
controlVoxelPosition.z,
|
||||
controlVoxelSize,
|
||||
COLORS[action].red,
|
||||
COLORS[action].green,
|
||||
COLORS[action].blue);
|
||||
// TODO: Fix this to use some mechanism other than voxels
|
||||
//Voxels.setVoxel(controlVoxelPosition.x + id * controlVoxelSize, controlVoxelPosition.y, controlVoxelPosition.z,
|
||||
// controlVoxelSize, COLORS[action].red, COLORS[action].green, COLORS[action].blue);
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
|
@ -82,10 +82,9 @@ function getAction(controlVoxel) {
|
|||
if (controlVoxel.red === COLORS[i].red &&
|
||||
controlVoxel.green === COLORS[i].green &&
|
||||
controlVoxel.blue === COLORS[i].blue) {
|
||||
Voxels.eraseVoxel(controlVoxelPosition.x,
|
||||
controlVoxelPosition.y,
|
||||
controlVoxelPosition.z,
|
||||
controlVoxelSize);
|
||||
|
||||
// TODO: Fix this to use some mechanism other than voxels
|
||||
//Voxels.eraseVoxel(controlVoxelPosition.x, controlVoxelPosition.y, controlVoxelPosition.z, controlVoxelSize);
|
||||
return parseInt(i);
|
||||
}
|
||||
}
|
||||
|
@ -101,10 +100,9 @@ function update(event) {
|
|||
return;
|
||||
}
|
||||
|
||||
var controlVoxel = Voxels.getVoxelAt(controlVoxelPosition.x,
|
||||
controlVoxelPosition.y,
|
||||
controlVoxelPosition.z,
|
||||
controlVoxelSize);
|
||||
// TODO: Fix this to use some mechanism other than voxels
|
||||
// Voxels.getVoxelAt(controlVoxelPosition.x, controlVoxelPosition.y, controlVoxelPosition.z, controlVoxelSize);
|
||||
var controlVoxel = false;
|
||||
var action = getAction(controlVoxel);
|
||||
|
||||
switch(action) {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
//
|
||||
|
||||
//For procedural walk animation
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../libraries/globals.js");
|
||||
Script.include(HIFI_PUBLIC_BUCKET + "scripts/proceduralAnimationAPI.js");
|
||||
|
||||
var procAnimAPI = new ProcAnimAPI();
|
|
@ -11,8 +11,8 @@
|
|||
//
|
||||
|
||||
//For procedural walk animation
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include(HIFI_PUBLIC_BUCKET + "scripts/proceduralAnimationAPI.js");
|
||||
Script.include("../libraries/globals.js");
|
||||
Script.include("proceduralAnimationAPI.js");
|
||||
|
||||
var procAnimAPI = new ProcAnimAPI();
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../libraries/globals.js");
|
||||
|
||||
function getRandomFloat(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
|
@ -1,64 +0,0 @@
|
|||
//
|
||||
// addVoxelOnMouseClickExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/6/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates use of the Camera and Voxels class to implement
|
||||
// clicking on a voxel and adding a new voxel on the clicked on face
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
function mousePressEvent(event) {
|
||||
print("mousePressEvent event.x,y=" + event.x + ", " + event.y);
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
if (intersection.intersects) {
|
||||
|
||||
// Note: due to the current C++ "click on voxel" behavior, these values may be the animated color for the voxel
|
||||
print("clicked on voxel.red/green/blue=" + intersection.voxel.red + ", "
|
||||
+ intersection.voxel.green + ", " + intersection.voxel.blue);
|
||||
print("clicked on voxel.x/y/z/s=" + intersection.voxel.x + ", "
|
||||
+ intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s);
|
||||
print("clicked on face=" + intersection.face);
|
||||
print("clicked on distance=" + intersection.distance);
|
||||
|
||||
var newVoxel = {
|
||||
x: intersection.voxel.x,
|
||||
y: intersection.voxel.y,
|
||||
z: intersection.voxel.z,
|
||||
s: intersection.voxel.s,
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 255 };
|
||||
|
||||
if (intersection.face == "MIN_X_FACE") {
|
||||
newVoxel.x -= newVoxel.s;
|
||||
} else if (intersection.face == "MAX_X_FACE") {
|
||||
newVoxel.x += newVoxel.s;
|
||||
} else if (intersection.face == "MIN_Y_FACE") {
|
||||
newVoxel.y -= newVoxel.s;
|
||||
} else if (intersection.face == "MAX_Y_FACE") {
|
||||
newVoxel.y += newVoxel.s;
|
||||
} else if (intersection.face == "MIN_Z_FACE") {
|
||||
newVoxel.z -= newVoxel.s;
|
||||
} else if (intersection.face == "MAX_Z_FACE") {
|
||||
newVoxel.z += newVoxel.s;
|
||||
}
|
||||
|
||||
print("Voxels.setVoxel("+newVoxel.x + ", "
|
||||
+ newVoxel.y + ", " + newVoxel.z + ", " + newVoxel.s + ", "
|
||||
+ newVoxel.red + ", " + newVoxel.green + ", " + newVoxel.blue + ")" );
|
||||
|
||||
Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -1,72 +0,0 @@
|
|||
//
|
||||
// avatarCollision.js
|
||||
// examples
|
||||
//
|
||||
// Created by Andrew Meadows on 2014-04-09
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Play a sound on collisions with your avatar
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
|
||||
var SOUND_TRIGGER_CLEAR = 1000; // milliseconds
|
||||
var SOUND_TRIGGER_DELAY = 200; // milliseconds
|
||||
var soundExpiry = 0;
|
||||
var DateObj = new Date();
|
||||
|
||||
var audioOptions = {
|
||||
volume: 0.5,
|
||||
position: { x: 0, y: 0, z: 0 }
|
||||
}
|
||||
|
||||
var hitSounds = new Array();
|
||||
hitSounds[0] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit1.raw");
|
||||
hitSounds[1] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit2.raw");
|
||||
hitSounds[2] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit3.raw");
|
||||
hitSounds[3] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit4.raw");
|
||||
hitSounds[4] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit5.raw");
|
||||
hitSounds[5] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit6.raw");
|
||||
hitSounds[6] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit7.raw");
|
||||
hitSounds[7] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit8.raw");
|
||||
hitSounds[8] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit9.raw");
|
||||
hitSounds[9] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit10.raw");
|
||||
hitSounds[10] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit11.raw");
|
||||
hitSounds[11] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit12.raw");
|
||||
hitSounds[12] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit13.raw");
|
||||
hitSounds[13] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit14.raw");
|
||||
hitSounds[14] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit15.raw");
|
||||
hitSounds[15] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit16.raw");
|
||||
hitSounds[16] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit17.raw");
|
||||
hitSounds[17] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit18.raw");
|
||||
hitSounds[18] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit19.raw");
|
||||
hitSounds[19] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit20.raw");
|
||||
hitSounds[20] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit21.raw");
|
||||
hitSounds[21] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit22.raw");
|
||||
|
||||
function playHitSound(mySessionID, theirSessionID, collision) {
|
||||
var now = new Date();
|
||||
var msec = now.getTime();
|
||||
if (msec > soundExpiry) {
|
||||
// this is a new contact --> play a new sound
|
||||
var soundIndex = Math.floor((Math.random() * hitSounds.length) % hitSounds.length);
|
||||
audioOptions.position = collision.contactPoint;
|
||||
Audio.playSound(hitSounds[soundIndex], audioOptions);
|
||||
|
||||
// bump the expiry
|
||||
soundExpiry = msec + SOUND_TRIGGER_CLEAR;
|
||||
|
||||
// log the collision info
|
||||
Uuid.print("my sessionID = ", mySessionID);
|
||||
Uuid.print(" their sessionID = ", theirSessionID);
|
||||
Vec3.print(" penetration = ", collision.penetration);
|
||||
Vec3.print(" contactPoint = ", collision.contactPoint);
|
||||
} else {
|
||||
// this is a recurring contact --> continue to delay sound trigger
|
||||
soundExpiry = msec + SOUND_TRIGGER_DELAY;
|
||||
}
|
||||
}
|
||||
MyAvatar.collisionWithAvatar.connect(playHitSound);
|
|
@ -1,139 +0,0 @@
|
|||
//
|
||||
// avatarLocalLight.js
|
||||
//
|
||||
// Created by Tony Peng on July 2nd, 2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Set the local light direction and color on the avatar
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var localLightDirections = [ {x: 1.0, y:0.0, z: 0.0}, {x: 0.0, y:0.0, z: 1.0} ];
|
||||
var localLightColors = [ {x: 0.4, y:0.335, z: 0.266}, {x: 0.4, y:0.335, z: 0.266} ];
|
||||
|
||||
var currentSelection = 0;
|
||||
var currentNumLights = 2;
|
||||
var maxNumLights = 2;
|
||||
var currentNumAvatars = 0;
|
||||
var changeDelta = 0.1;
|
||||
var lightsDirty = true;
|
||||
|
||||
function keyPressEvent(event) {
|
||||
|
||||
var choice = parseInt(event.text);
|
||||
|
||||
if (event.text == "1") {
|
||||
currentSelection = 0;
|
||||
print("light election = " + currentSelection);
|
||||
}
|
||||
else if (event.text == "2" ) {
|
||||
currentSelection = 1;
|
||||
print("light selection = " + currentSelection);
|
||||
}
|
||||
else if (event.text == "3" ) {
|
||||
currentSelection = 2;
|
||||
print("light selection = " + currentSelection);
|
||||
}
|
||||
else if (event.text == "4" ) {
|
||||
currentSelection = 3;
|
||||
print("light selection = " + currentSelection);
|
||||
}
|
||||
else if (event.text == "5" ) {
|
||||
localLightColors[currentSelection].x += changeDelta;
|
||||
if ( localLightColors[currentSelection].x > 1.0) {
|
||||
localLightColors[currentSelection].x = 0.0;
|
||||
}
|
||||
|
||||
lightsDirty = true;
|
||||
print("CHANGE RED light " + currentSelection + " color (" + localLightColors[currentSelection].x + ", " + localLightColors[currentSelection].y + ", " + localLightColors[currentSelection].z + " )" );
|
||||
}
|
||||
else if (event.text == "6" ) {
|
||||
localLightColors[currentSelection].y += changeDelta;
|
||||
if ( localLightColors[currentSelection].y > 1.0) {
|
||||
localLightColors[currentSelection].y = 0.0;
|
||||
}
|
||||
|
||||
lightsDirty = true;
|
||||
print("CHANGE GREEN light " + currentSelection + " color (" + localLightColors[currentSelection].x + ", " + localLightColors[currentSelection].y + ", " + localLightColors[currentSelection].z + " )" );
|
||||
}
|
||||
else if (event.text == "7" ) {
|
||||
localLightColors[currentSelection].z += changeDelta;
|
||||
if ( localLightColors[currentSelection].z > 1.0) {
|
||||
localLightColors[currentSelection].z = 0.0;
|
||||
}
|
||||
|
||||
lightsDirty = true;
|
||||
print("CHANGE BLUE light " + currentSelection + " color (" + localLightColors[currentSelection].x + ", " + localLightColors[currentSelection].y + ", " + localLightColors[currentSelection].z + " )" );
|
||||
}
|
||||
else if (event.text == "8" ) {
|
||||
localLightDirections[currentSelection].x += changeDelta;
|
||||
if (localLightDirections[currentSelection].x > 1.0) {
|
||||
localLightDirections[currentSelection].x = -1.0;
|
||||
}
|
||||
|
||||
lightsDirty = true;
|
||||
print("PLUS X light " + currentSelection + " direction (" + localLightDirections[currentSelection].x + ", " + localLightDirections[currentSelection].y + ", " + localLightDirections[currentSelection].z + " )" );
|
||||
}
|
||||
else if (event.text == "9" ) {
|
||||
localLightDirections[currentSelection].x -= changeDelta;
|
||||
if (localLightDirections[currentSelection].x < -1.0) {
|
||||
localLightDirections[currentSelection].x = 1.0;
|
||||
}
|
||||
|
||||
lightsDirty = true;
|
||||
print("MINUS X light " + currentSelection + " direction (" + localLightDirections[currentSelection].x + ", " + localLightDirections[currentSelection].y + ", " + localLightDirections[currentSelection].z + " )" );
|
||||
}
|
||||
else if (event.text == "0" ) {
|
||||
localLightDirections[currentSelection].y += changeDelta;
|
||||
if (localLightDirections[currentSelection].y > 1.0) {
|
||||
localLightDirections[currentSelection].y = -1.0;
|
||||
}
|
||||
|
||||
lightsDirty = true;
|
||||
print("PLUS Y light " + currentSelection + " direction (" + localLightDirections[currentSelection].x + ", " + localLightDirections[currentSelection].y + ", " + localLightDirections[currentSelection].z + " )" );
|
||||
}
|
||||
else if (event.text == "-" ) {
|
||||
localLightDirections[currentSelection].y -= changeDelta;
|
||||
if (localLightDirections[currentSelection].y < -1.0) {
|
||||
localLightDirections[currentSelection].y = 1.0;
|
||||
}
|
||||
|
||||
lightsDirty = true;
|
||||
print("MINUS Y light " + currentSelection + " direction (" + localLightDirections[currentSelection].x + ", " + localLightDirections[currentSelection].y + ", " + localLightDirections[currentSelection].z + " )" );
|
||||
}
|
||||
else if (event.text == "," ) {
|
||||
if (currentNumLights + 1 <= maxNumLights) {
|
||||
++currentNumLights;
|
||||
lightsDirty = true;
|
||||
}
|
||||
|
||||
print("ADD LIGHT, number of lights " + currentNumLights);
|
||||
}
|
||||
else if (event.text == "." ) {
|
||||
if (currentNumLights - 1 >= 0 ) {
|
||||
--currentNumLights;
|
||||
lightsDirty = true;
|
||||
}
|
||||
|
||||
print("REMOVE LIGHT, number of lights " + currentNumLights);
|
||||
}
|
||||
}
|
||||
|
||||
function updateLocalLights()
|
||||
{
|
||||
if (lightsDirty) {
|
||||
var localLights = [];
|
||||
for (var i = 0; i < currentNumLights; i++) {
|
||||
localLights.push({ direction: localLightDirections[i], color: localLightColors[i] });
|
||||
}
|
||||
AvatarManager.setLocalLights(localLights);
|
||||
lightsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
// main
|
||||
Script.update.connect(updateLocalLights);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
|
233
examples/bot.js
233
examples/bot.js
|
@ -1,233 +0,0 @@
|
|||
//
|
||||
// bot.js
|
||||
// examples
|
||||
//
|
||||
// Created by Stephen Birarda on 2/20/14.
|
||||
// Modified by Philip on 3/3/14
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates an NPC avatar.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
|
||||
function getRandomFloat(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
||||
function getRandomInt (min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function printVector(string, vector) {
|
||||
print(string + " " + vector.x + ", " + vector.y + ", " + vector.z);
|
||||
}
|
||||
|
||||
var CHANCE_OF_MOVING = 0.005;
|
||||
var CHANCE_OF_SOUND = 0.005;
|
||||
var CHANCE_OF_HEAD_TURNING = 0.05;
|
||||
var CHANCE_OF_BIG_MOVE = 0.1;
|
||||
var CHANCE_OF_WAVING = 0.009;
|
||||
|
||||
var shouldReceiveVoxels = true;
|
||||
var VOXEL_FPS = 60.0;
|
||||
var lastVoxelQueryTime = 0.0;
|
||||
|
||||
var isMoving = false;
|
||||
var isTurningHead = false;
|
||||
var isPlayingAudio = false;
|
||||
var isWaving = false;
|
||||
var waveFrequency = 0.0;
|
||||
var waveAmplitude = 0.0;
|
||||
|
||||
var X_MIN = 5.0;
|
||||
var X_MAX = 15.0;
|
||||
var Z_MIN = 5.0;
|
||||
var Z_MAX = 15.0;
|
||||
var Y_PELVIS = 1.0;
|
||||
var SPINE_JOINT_NUMBER = 13;
|
||||
var SHOULDER_JOINT_NUMBER = 17;
|
||||
var ELBOW_JOINT_NUMBER = 18;
|
||||
var JOINT_R_HIP = 1;
|
||||
var JOINT_R_KNEE = 2;
|
||||
|
||||
var MOVE_RANGE_SMALL = 0.5;
|
||||
var MOVE_RANGE_BIG = Math.max(X_MAX - X_MIN, Z_MAX - Z_MIN) / 2.0;
|
||||
var TURN_RANGE = 70.0;
|
||||
var STOP_TOLERANCE = 0.05;
|
||||
var MOVE_RATE = 0.05;
|
||||
var TURN_RATE = 0.15;
|
||||
var PITCH_RATE = 0.20;
|
||||
var PITCH_RANGE = 30.0;
|
||||
|
||||
var firstPosition = { x: getRandomFloat(X_MIN, X_MAX), y: Y_PELVIS, z: getRandomFloat(Z_MIN, Z_MAX) };
|
||||
var targetPosition = { x: 0, y: 0, z: 0 };
|
||||
var targetDirection = { x: 0, y: 0, z: 0, w: 0 };
|
||||
var currentDirection = { x: 0, y: 0, z: 0, w: 0 };
|
||||
var targetHeadPitch = 0.0;
|
||||
|
||||
var walkFrequency = 5.0;
|
||||
var walkAmplitude = 45.0;
|
||||
|
||||
var cumulativeTime = 0.0;
|
||||
|
||||
var sounds = [];
|
||||
loadSounds();
|
||||
|
||||
function clamp(val, min, max){
|
||||
return Math.max(min, Math.min(max, val))
|
||||
}
|
||||
|
||||
// Play a random sound from a list of conversational audio clips
|
||||
var AVERAGE_AUDIO_LENGTH = 8000;
|
||||
function playRandomSound() {
|
||||
if (!Agent.isPlayingAvatarSound) {
|
||||
var whichSound = Math.floor((Math.random() * sounds.length) % sounds.length);
|
||||
Agent.playAvatarSound(sounds[whichSound]);
|
||||
}
|
||||
}
|
||||
|
||||
// pick an integer between 1 and 20 for the face model for this bot
|
||||
botNumber = getRandomInt(1, 100);
|
||||
|
||||
if (botNumber <= 20) {
|
||||
newFaceFilePrefix = "bot" + botNumber;
|
||||
newBodyFilePrefix = "defaultAvatar_body"
|
||||
} else {
|
||||
if (botNumber <= 40) {
|
||||
newFaceFilePrefix = "superhero";
|
||||
} else if (botNumber <= 60) {
|
||||
newFaceFilePrefix = "amber";
|
||||
} else if (botNumber <= 80) {
|
||||
newFaceFilePrefix = "ron";
|
||||
} else {
|
||||
newFaceFilePrefix = "angie";
|
||||
}
|
||||
|
||||
newBodyFilePrefix = "bot" + botNumber;
|
||||
}
|
||||
|
||||
// set the face model fst using the bot number
|
||||
// there is no need to change the body model - we're using the default
|
||||
Avatar.faceModelURL = HIFI_PUBLIC_BUCKET + "meshes/" + newFaceFilePrefix + ".fst";
|
||||
Avatar.skeletonModelURL = HIFI_PUBLIC_BUCKET + "meshes/" + newBodyFilePrefix + ".fst";
|
||||
Avatar.billboardURL = HIFI_PUBLIC_BUCKET + "meshes/billboards/bot" + botNumber + ".png";
|
||||
|
||||
Agent.isAvatar = true;
|
||||
Agent.isListeningToAudioStream = true;
|
||||
|
||||
// change the avatar's position to the random one
|
||||
Avatar.position = firstPosition;
|
||||
printVector("New bot, position = ", Avatar.position);
|
||||
|
||||
function stopWaving() {
|
||||
isWaving = false;
|
||||
Avatar.clearJointData(SHOULDER_JOINT_NUMBER);
|
||||
Avatar.clearJointData(ELBOW_JOINT_NUMBER);
|
||||
Avatar.clearJointData(SPINE_JOINT_NUMBER);
|
||||
}
|
||||
|
||||
function keepWalking() {
|
||||
Avatar.setJointData(JOINT_R_HIP, Quat.fromPitchYawRollDegrees(walkAmplitude * Math.sin(cumulativeTime * walkFrequency), 0.0, 0.0));
|
||||
Avatar.setJointData(JOINT_R_KNEE, Quat.fromPitchYawRollDegrees(walkAmplitude * Math.sin(cumulativeTime * walkFrequency), 0.0, 0.0));
|
||||
}
|
||||
|
||||
function stopWalking() {
|
||||
Avatar.clearJointData(JOINT_R_HIP);
|
||||
Avatar.clearJointData(JOINT_R_KNEE);
|
||||
}
|
||||
|
||||
function updateBehavior(deltaTime) {
|
||||
|
||||
cumulativeTime += deltaTime;
|
||||
|
||||
// Hack - right now you need to set the avatar position a bit after the avatar is made to make sure it's there.
|
||||
|
||||
if (CHANCE_OF_MOVING == 0.000) {
|
||||
Avatar.position = firstPosition;
|
||||
}
|
||||
|
||||
if (shouldReceiveVoxels && ((cumulativeTime - lastVoxelQueryTime) > (1.0 / VOXEL_FPS))) {
|
||||
VoxelViewer.setPosition(Avatar.position);
|
||||
VoxelViewer.setOrientation(Avatar.orientation);
|
||||
VoxelViewer.queryOctree();
|
||||
lastVoxelQueryTime = cumulativeTime;
|
||||
/*
|
||||
if (Math.random() < (1.0 / VOXEL_FPS)) {
|
||||
print("Voxels in view = " + VoxelViewer.getOctreeElementsCount());
|
||||
}*/
|
||||
}
|
||||
|
||||
if (!isWaving && (Math.random() < CHANCE_OF_WAVING)) {
|
||||
isWaving = true;
|
||||
waveFrequency = 3.0 + Math.random() * 5.0;
|
||||
waveAmplitude = 5.0 + Math.random() * 60.0;
|
||||
Script.setTimeout(stopWaving, 1000 + Math.random() * 2000);
|
||||
Avatar.setJointData(ELBOW_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 45, 0.0)); // Initially turn the palm outward
|
||||
} else if (isWaving) {
|
||||
Avatar.setJointData(SHOULDER_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, 60 + waveAmplitude * Math.sin((cumulativeTime - 0.25) * waveFrequency)));
|
||||
Avatar.setJointData(ELBOW_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, 25 + waveAmplitude/2.0 * Math.sin(cumulativeTime * 1.2 * waveFrequency)));
|
||||
Avatar.setJointData(SPINE_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, 60 + waveAmplitude/4.0 * Math.sin(cumulativeTime * waveFrequency)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (Math.random() < CHANCE_OF_SOUND) {
|
||||
playRandomSound();
|
||||
}
|
||||
|
||||
if (!isTurningHead && (Math.random() < CHANCE_OF_HEAD_TURNING)) {
|
||||
targetHeadPitch = getRandomFloat(-PITCH_RANGE, PITCH_RANGE);
|
||||
isTurningHead = true;
|
||||
} else {
|
||||
Avatar.headPitch = Avatar.headPitch + (targetHeadPitch - Avatar.headPitch) * PITCH_RATE;
|
||||
if (Math.abs(Avatar.headPitch - targetHeadPitch) < STOP_TOLERANCE) {
|
||||
isTurningHead = false;
|
||||
}
|
||||
}
|
||||
if (!isMoving && (Math.random() < CHANCE_OF_MOVING)) {
|
||||
// Set new target location
|
||||
targetDirection = Quat.multiply(Avatar.orientation, Quat.angleAxis(getRandomFloat(-TURN_RANGE, TURN_RANGE), { x:0, y:1, z:0 }));
|
||||
var front = Quat.getFront(targetDirection);
|
||||
if (Math.random() < CHANCE_OF_BIG_MOVE) {
|
||||
targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, MOVE_RANGE_BIG)));
|
||||
} else {
|
||||
targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, MOVE_RANGE_SMALL)));
|
||||
}
|
||||
targetPosition.x = clamp(targetPosition.x, X_MIN, X_MAX);
|
||||
targetPosition.z = clamp(targetPosition.z, Z_MIN, Z_MAX);
|
||||
targetPosition.y = Y_PELVIS;
|
||||
|
||||
isMoving = true;
|
||||
} else if (isMoving) {
|
||||
keepWalking();
|
||||
Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(Vec3.subtract(targetPosition, Avatar.position), MOVE_RATE));
|
||||
Avatar.orientation = Quat.mix(Avatar.orientation, targetDirection, TURN_RATE);
|
||||
if (Vec3.length(Vec3.subtract(Avatar.position, targetPosition)) < STOP_TOLERANCE) {
|
||||
isMoving = false;
|
||||
stopWalking();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Script.update.connect(updateBehavior);
|
||||
|
||||
function loadSounds() {
|
||||
var sound_filenames = ["AB1.raw", "Anchorman2.raw", "B1.raw", "B1.raw", "Bale1.raw", "Bandcamp.raw",
|
||||
"Big1.raw", "Big2.raw", "Brian1.raw", "Buster1.raw", "CES1.raw", "CES2.raw", "CES3.raw", "CES4.raw",
|
||||
"Carrie1.raw", "Carrie3.raw", "Charlotte1.raw", "EN1.raw", "EN2.raw", "EN3.raw", "Eugene1.raw", "Francesco1.raw",
|
||||
"Italian1.raw", "Japanese1.raw", "Leigh1.raw", "Lucille1.raw", "Lucille2.raw", "MeanGirls.raw", "Murray2.raw",
|
||||
"Nigel1.raw", "PennyLane.raw", "Pitt1.raw", "Ricardo.raw", "SN.raw", "Sake1.raw", "Samantha1.raw", "Samantha2.raw",
|
||||
"Spicoli1.raw", "Supernatural.raw", "Swearengen1.raw", "TheDude.raw", "Tony.raw", "Triumph1.raw", "Uma1.raw",
|
||||
"Walken1.raw", "Walken2.raw", "Z1.raw", "Z2.raw"
|
||||
];
|
||||
|
||||
var SOUND_BASE_URL = HIFI_PUBLIC_BUCKET + "sounds/Cocktail+Party+Snippets/Raws/";
|
||||
|
||||
for (var i = 0; i < sound_filenames.length; i++) {
|
||||
sounds.push(SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i]));
|
||||
}
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
//
|
||||
// clipboardExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 1/28/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates use of the Clipboard class
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var selectedVoxel = { x: 0, y: 0, z: 0, s: 0 };
|
||||
var selectedSize = 4;
|
||||
|
||||
function setupMenus() {
|
||||
// hook up menus
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
|
||||
// delete the standard application menu item
|
||||
Menu.removeMenuItem("Edit", "Cut");
|
||||
Menu.removeMenuItem("Edit", "Copy");
|
||||
Menu.removeMenuItem("Edit", "Paste");
|
||||
Menu.removeMenuItem("Edit", "Delete");
|
||||
Menu.removeMenuItem("Edit", "Nudge");
|
||||
Menu.removeMenuItem("Edit", "Replace from File");
|
||||
Menu.removeMenuItem("File", "Export Voxels");
|
||||
Menu.removeMenuItem("File", "Import Voxels");
|
||||
|
||||
// delete the standard application menu item
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Cut", shortcutKey: "CTRL+X", afterItem: "Voxels" });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Copy", shortcutKey: "CTRL+C", afterItem: "Cut" });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste", shortcutKey: "CTRL+V", afterItem: "Copy" });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Nudge", shortcutKey: "CTRL+N", afterItem: "Paste" });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Replace from File", shortcutKey: "CTRL+R", afterItem: "Nudge" });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Nudge" });
|
||||
Menu.addMenuItem({ menuName: "File", menuItemName: "Export Voxels", shortcutKey: "CTRL+E", afterItem: "Voxels" });
|
||||
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Voxels", shortcutKey: "CTRL+I", afterItem: "Export Voxels" });
|
||||
}
|
||||
|
||||
function menuItemEvent(menuItem) {
|
||||
var debug = true;
|
||||
if (debug) {
|
||||
print("menuItemEvent " + menuItem);
|
||||
}
|
||||
|
||||
// Note: this sample uses Alt+ as the key codes for these clipboard items
|
||||
if (menuItem == "Copy") {
|
||||
print("copying...");
|
||||
Clipboard.copyVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
}
|
||||
if (menuItem == "Cut") {
|
||||
print("cutting...");
|
||||
Clipboard.cutVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
}
|
||||
if (menuItem == "Paste") {
|
||||
print("pasting...");
|
||||
Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
}
|
||||
if (menuItem == "Delete") {
|
||||
print("deleting...");
|
||||
Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
}
|
||||
if (menuItem == "Export Voxels") {
|
||||
print("export");
|
||||
Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
|
||||
}
|
||||
if (menuItem == "Import Voxels") {
|
||||
print("import");
|
||||
Clipboard.importVoxels();
|
||||
}
|
||||
if (menuItem == "Nudge") {
|
||||
print("nudge");
|
||||
Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 });
|
||||
}
|
||||
if (menuItem == "Replace from File") {
|
||||
var filename = Window.browse("Select file to load replacement", "", "Voxel Files (*.png *.svo *.schematic)");
|
||||
if (filename) {
|
||||
Clipboard.importVoxel(filename, selectedVoxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var selectCube = Overlays.addOverlay("cube", {
|
||||
position: { x: 0, y: 0, z: 0},
|
||||
size: selectedSize,
|
||||
color: { red: 255, green: 255, blue: 0},
|
||||
alpha: 1,
|
||||
solid: false,
|
||||
visible: false,
|
||||
lineWidth: 4
|
||||
});
|
||||
|
||||
|
||||
function mouseMoveEvent(event) {
|
||||
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
|
||||
var debug = false;
|
||||
if (debug) {
|
||||
print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y);
|
||||
print("called Camera.computePickRay()");
|
||||
print("computePickRay origin=" + pickRay.origin.x + ", " + pickRay.origin.y + ", " + pickRay.origin.z);
|
||||
print("computePickRay direction=" + pickRay.direction.x + ", " + pickRay.direction.y + ", " + pickRay.direction.z);
|
||||
}
|
||||
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
|
||||
if (intersection.intersects) {
|
||||
if (debug) {
|
||||
print("intersection voxel.red/green/blue=" + intersection.voxel.red + ", "
|
||||
+ intersection.voxel.green + ", " + intersection.voxel.blue);
|
||||
print("intersection voxel.x/y/z/s=" + intersection.voxel.x + ", "
|
||||
+ intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s);
|
||||
print("intersection face=" + intersection.face);
|
||||
print("intersection distance=" + intersection.distance);
|
||||
print("intersection intersection.x/y/z=" + intersection.intersection.x + ", "
|
||||
+ intersection.intersection.y + ", " + intersection.intersection.z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
var x = Math.floor(intersection.voxel.x / selectedSize) * selectedSize;
|
||||
var y = Math.floor(intersection.voxel.y / selectedSize) * selectedSize;
|
||||
var z = Math.floor(intersection.voxel.z / selectedSize) * selectedSize;
|
||||
selectedVoxel = { x: x, y: y, z: z, s: selectedSize };
|
||||
Overlays.editOverlay(selectCube, { position: selectedVoxel, size: selectedSize, visible: true } );
|
||||
} else {
|
||||
Overlays.editOverlay(selectCube, { visible: false } );
|
||||
selectedVoxel = { x: 0, y: 0, z: 0, s: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
|
||||
function wheelEvent(event) {
|
||||
var debug = false;
|
||||
if (debug) {
|
||||
print("wheelEvent");
|
||||
print(" event.x,y=" + event.x + ", " + event.y);
|
||||
print(" event.delta=" + event.delta);
|
||||
print(" event.orientation=" + event.orientation);
|
||||
print(" event.isLeftButton=" + event.isLeftButton);
|
||||
print(" event.isRightButton=" + event.isRightButton);
|
||||
print(" event.isMiddleButton=" + event.isMiddleButton);
|
||||
print(" event.isShifted=" + event.isShifted);
|
||||
print(" event.isControl=" + event.isControl);
|
||||
print(" event.isMeta=" + event.isMeta);
|
||||
print(" event.isAlt=" + event.isAlt);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.wheelEvent.connect(wheelEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
Overlays.deleteOverlay(selectCube);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
setupMenus();
|
|
@ -75,7 +75,7 @@ var warpSphere = Overlays.addOverlay("sphere", {
|
|||
|
||||
var WARP_LINE_HEIGHT = 10;
|
||||
var warpLine = Overlays.addOverlay("line3d", {
|
||||
position: { x: 0, y: 0, z:0 },
|
||||
start: { x: 0, y: 0, z:0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: { red: 0, green: 255, blue: 255},
|
||||
alpha: 1,
|
||||
|
@ -116,7 +116,7 @@ function updateWarp() {
|
|||
direction: { x: 0, y: -1, z: 0 }
|
||||
};
|
||||
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
var intersection = Entities.findRayIntersection(pickRay);
|
||||
|
||||
if (intersection.intersects && intersection.distance < WARP_PICK_MAX_DISTANCE) {
|
||||
// Warp 1 meter above the object - this is an approximation
|
||||
|
@ -131,7 +131,7 @@ function updateWarp() {
|
|||
visible: true,
|
||||
});
|
||||
Overlays.editOverlay(warpLine, {
|
||||
position: warpPosition,
|
||||
start: warpPosition,
|
||||
end: Vec3.sum(warpPosition, { x: 0, y: WARP_LINE_HEIGHT, z: 0 }),
|
||||
visible: true,
|
||||
});
|
|
@ -10,7 +10,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../../libraries/globals.js");
|
||||
|
||||
function length(v) {
|
||||
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
|
||||
|
@ -73,7 +73,7 @@ var soundPlaying = false;
|
|||
var selectorPressed = false;
|
||||
var position;
|
||||
|
||||
MyAvatar.attach(guitarModel, "Hips", {x: -0.0, y: -0.0, z: 0.0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.0);
|
||||
MyAvatar.attach(guitarModel, "Hips", {x: -0.2, y: 0.0, z: 0.1}, Quat.fromPitchYawRollDegrees(90, 00, 90), 1.0);
|
||||
|
||||
function checkHands(deltaTime) {
|
||||
for (var palm = 0; palm < 2; palm++) {
|
|
@ -10,7 +10,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../../libraries/globals.js");
|
||||
|
||||
function length(v) {
|
||||
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
|
|
@ -15,8 +15,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("libraries/toolBars.js");
|
||||
Script.include("../../libraries/globals.js");
|
||||
Script.include("../../libraries/toolBars.js");
|
||||
|
||||
const LEFT_PALM = 0;
|
||||
const LEFT_TIP = 1;
|
||||
|
@ -192,15 +192,18 @@ function cleanupFrisbees() {
|
|||
}
|
||||
|
||||
function checkControllerSide(hand) {
|
||||
// print("cCS");
|
||||
// If I don't currently have a frisbee in my hand, then try to catch closest one
|
||||
if (!hand.holdingFrisbee && hand.grabButtonPressed()) {
|
||||
var closestEntity = Entities.findClosestEntity(hand.palmPosition(), CATCH_RADIUS);
|
||||
var modelUrl = Entities.getEntityProperties(closestEntity).modelURL;
|
||||
print("lol2"+closestEntity.isKnownID);
|
||||
if (closestEntity.isKnownID && validFrisbeeURL(Entities.getEntityProperties(closestEntity).modelURL)) {
|
||||
print("lol");
|
||||
Entities.editEntity(closestEntity, {modelScale: 1, inHand: true, position: hand.holdPosition(), shouldDie: true});
|
||||
Entities.deleteEntity(closestEntity);
|
||||
debugPrint(hand.message + " HAND- CAUGHT SOMETHING!!");
|
||||
|
||||
print("lol");
|
||||
var properties = {
|
||||
type: "Model",
|
||||
position: hand.holdPosition(),
|
||||
|
@ -210,8 +213,8 @@ function checkControllerSide(hand) {
|
|||
dimensions: { x: FRISBEE_RADIUS, y: FRISBEE_RADIUS / 5, z: FRISBEE_RADIUS },
|
||||
damping: 0.999,
|
||||
modelURL: modelUrl,
|
||||
modelScale: FRISBEE_MODEL_SCALE,
|
||||
modelRotation: hand.holdRotation(),
|
||||
scale: FRISBEE_MODEL_SCALE,
|
||||
rotation: hand.holdRotation(),
|
||||
lifetime: FRISBEE_LIFETIME
|
||||
};
|
||||
|
||||
|
@ -235,10 +238,10 @@ function checkControllerSide(hand) {
|
|||
gravity: { x: 0, y: 0, z: 0},
|
||||
inHand: true,
|
||||
dimensions: { x: FRISBEE_RADIUS, y: FRISBEE_RADIUS / 5, z: FRISBEE_RADIUS },
|
||||
damping: 0.999,
|
||||
damping: 0,
|
||||
modelURL: frisbeeURL(),
|
||||
modelScale: FRISBEE_MODEL_SCALE,
|
||||
modelRotation: hand.holdRotation(),
|
||||
scale: FRISBEE_MODEL_SCALE,
|
||||
rotation: hand.holdRotation(),
|
||||
lifetime: FRISBEE_LIFETIME
|
||||
};
|
||||
|
||||
|
@ -270,7 +273,7 @@ function checkControllerSide(hand) {
|
|||
inHand: false,
|
||||
lifetime: FRISBEE_LIFETIME,
|
||||
gravity: { x: 0, y: -GRAVITY_STRENGTH, z: 0},
|
||||
modelRotation: hand.holdRotation()
|
||||
rotation: hand.holdRotation()
|
||||
};
|
||||
|
||||
Entities.editEntity(hand.entity, properties);
|
||||
|
@ -304,7 +307,7 @@ function hydraCheck() {
|
|||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2);
|
||||
return hydrasConnected;
|
||||
return true;//hydrasConnected;
|
||||
}
|
||||
|
||||
function checkController(deltaTime) {
|
||||
|
@ -314,6 +317,7 @@ function checkController(deltaTime) {
|
|||
}
|
||||
// this is expected for hydras
|
||||
if (hydraCheck()) {
|
||||
///print("testrr ");
|
||||
checkControllerSide(leftHand);
|
||||
checkControllerSide(rightHand);
|
||||
}
|
||||
|
@ -333,7 +337,7 @@ function controlFrisbees(deltaTime) {
|
|||
killSimulations.push(frisbee);
|
||||
continue;
|
||||
}
|
||||
Entities.editEntity(simulatedFrisbees[frisbee], {modelRotation: Quat.multiply(properties.modelRotation, Quat.fromPitchYawRollDegrees(0, speed * deltaTime * SPIN_MULTIPLIER, 0))});
|
||||
Entities.editEntity(simulatedFrisbees[frisbee], {rotation: Quat.multiply(properties.modelRotation, Quat.fromPitchYawRollDegrees(0, speed * deltaTime * SPIN_MULTIPLIER, 0))});
|
||||
|
||||
}
|
||||
for (var i = killSimulations.length - 1; i >= 0; i--) {
|
|
@ -14,7 +14,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../../libraries/globals.js");
|
||||
|
||||
function getRandomFloat(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
|
@ -26,14 +26,19 @@ var yawFromMouse = 0;
|
|||
var pitchFromMouse = 0;
|
||||
var isMouseDown = false;
|
||||
|
||||
var BULLET_VELOCITY = 5.0;
|
||||
var BULLET_VELOCITY = 20.0;
|
||||
var MIN_THROWER_DELAY = 1000;
|
||||
var MAX_THROWER_DELAY = 1000;
|
||||
var LEFT_BUTTON_3 = 3;
|
||||
var RELOAD_INTERVAL = 5;
|
||||
|
||||
var KICKBACK_ANGLE = 15;
|
||||
var elbowKickAngle = 0.0;
|
||||
var rotationBeforeKickback;
|
||||
|
||||
var showScore = false;
|
||||
|
||||
|
||||
// Load some sound to use for loading and firing
|
||||
var fireSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw");
|
||||
var loadSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw");
|
||||
|
@ -48,10 +53,11 @@ var audioOptions = {
|
|||
}
|
||||
|
||||
var shotsFired = 0;
|
||||
|
||||
var shotTime = new Date();
|
||||
|
||||
// initialize our triggers
|
||||
var activeControllers = 0;
|
||||
|
||||
// initialize our controller triggers
|
||||
var triggerPulled = new Array();
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
for (t = 0; t < numberOfTriggers; t++) {
|
||||
|
@ -59,9 +65,11 @@ for (t = 0; t < numberOfTriggers; t++) {
|
|||
}
|
||||
|
||||
var isLaunchButtonPressed = false;
|
||||
|
||||
var score = 0;
|
||||
|
||||
var bulletID = false;
|
||||
var targetID = false;
|
||||
|
||||
// Create a reticle image in center of screen
|
||||
var screenSize = Controller.getViewportDimensions();
|
||||
var reticle = Overlays.addOverlay("image", {
|
||||
|
@ -74,6 +82,16 @@ var reticle = Overlays.addOverlay("image", {
|
|||
alpha: 1
|
||||
});
|
||||
|
||||
var offButton = Overlays.addOverlay("image", {
|
||||
x: screenSize.x - 48,
|
||||
y: 96,
|
||||
width: 32,
|
||||
height: 32,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
if (showScore) {
|
||||
var text = Overlays.addOverlay("text", {
|
||||
x: screenSize.x / 2 - 100,
|
||||
|
@ -95,18 +113,20 @@ function printVector(string, vector) {
|
|||
}
|
||||
|
||||
function shootBullet(position, velocity) {
|
||||
var BULLET_SIZE = 0.01;
|
||||
var BULLET_LIFETIME = 20.0;
|
||||
var BULLET_SIZE = 0.07;
|
||||
var BULLET_LIFETIME = 10.0;
|
||||
var BULLET_GRAVITY = -0.02;
|
||||
Entities.addEntity(
|
||||
bulletID = Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: position,
|
||||
dimensions: { x: BULLET_SIZE, y: BULLET_SIZE, z: BULLET_SIZE },
|
||||
color: { red: 10, green: 10, blue: 10 },
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
velocity: velocity,
|
||||
lifetime: BULLET_LIFETIME,
|
||||
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
|
||||
damping: 0 });
|
||||
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
|
||||
// Play firing sounds
|
||||
audioOptions.position = position;
|
||||
|
@ -115,36 +135,45 @@ function shootBullet(position, velocity) {
|
|||
if ((shotsFired % RELOAD_INTERVAL) == 0) {
|
||||
Audio.playSound(loadSound, audioOptions);
|
||||
}
|
||||
|
||||
// Kickback the arm
|
||||
rotationBeforeKickback = MyAvatar.getJointRotation("LeftForeArm");
|
||||
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
|
||||
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, KICKBACK_ANGLE));
|
||||
MyAvatar.setJointData("LeftForeArm", armRotation);
|
||||
elbowKickAngle = KICKBACK_ANGLE;
|
||||
}
|
||||
|
||||
function shootTarget() {
|
||||
var TARGET_SIZE = 0.25;
|
||||
var TARGET_GRAVITY = -0.6;
|
||||
var TARGET_SIZE = 0.50;
|
||||
var TARGET_GRAVITY = -0.25;
|
||||
var TARGET_LIFETIME = 300.0;
|
||||
var TARGET_UP_VELOCITY = 3.0;
|
||||
var TARGET_FWD_VELOCITY = 5.0;
|
||||
var TARGET_UP_VELOCITY = 0.5;
|
||||
var TARGET_FWD_VELOCITY = 1.0;
|
||||
var DISTANCE_TO_LAUNCH_FROM = 3.0;
|
||||
var ANGLE_RANGE_FOR_LAUNCH = 20.0;
|
||||
var camera = Camera.getPosition();
|
||||
//printVector("camera", camera);
|
||||
var targetDirection = Quat.angleAxis(getRandomFloat(-20.0, 20.0), { x:0, y:1, z:0 });
|
||||
var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), { x:0, y:1, z:0 });
|
||||
targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection);
|
||||
var forwardVector = Quat.getFront(targetDirection);
|
||||
//printVector("forwardVector", forwardVector);
|
||||
|
||||
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM));
|
||||
//printVector("newPosition", newPosition);
|
||||
|
||||
var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY);
|
||||
velocity.y += TARGET_UP_VELOCITY;
|
||||
//printVector("velocity", velocity);
|
||||
|
||||
Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
|
||||
targetID = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: newPosition,
|
||||
dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE },
|
||||
color: { red: 0, green: 200, blue: 200 },
|
||||
//angularVelocity: { x: 1, y: 0, z: 0 },
|
||||
velocity: velocity,
|
||||
gravity: { x: 0, y: TARGET_GRAVITY, z: 0 },
|
||||
lifetime: TARGET_LIFETIME,
|
||||
damping: 0.99 });
|
||||
damping: 0.0001,
|
||||
collisionsWillMove: true });
|
||||
|
||||
// Record start time
|
||||
shotTime = new Date();
|
||||
|
@ -156,38 +185,26 @@ function shootTarget() {
|
|||
|
||||
|
||||
|
||||
function entityCollisionWithVoxel(entity, voxel, collision) {
|
||||
var HOLE_SIZE = 0.125;
|
||||
var entityProperties = Entities.getEntityProperties(entity);
|
||||
var position = entityProperties.position;
|
||||
Entities.deleteEntity(entity);
|
||||
// Make a hole in this voxel
|
||||
//Vec3.print("voxel penetration", collision.penetration);
|
||||
//Vec3.print("voxel contactPoint", collision.contactPoint);
|
||||
Voxels.eraseVoxel(collision.contactPoint.x, collision.contactPoint.y, collision.contactPoint.z, HOLE_SIZE);
|
||||
audioOptions.position = collision.contactPoint;
|
||||
Audio.playSound(impactSound, audioOptions);
|
||||
}
|
||||
|
||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||
score++;
|
||||
if (showScore) {
|
||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||
}
|
||||
|
||||
// Sort out which entity is which
|
||||
|
||||
// Record shot time
|
||||
var endTime = new Date();
|
||||
var msecs = endTime.valueOf() - shotTime.valueOf();
|
||||
//print("hit, msecs = " + msecs);
|
||||
//Vec3.print("penetration = ", collision.penetration);
|
||||
//Vec3.print("contactPoint = ", collision.contactPoint);
|
||||
Entities.deleteEntity(entity1);
|
||||
Entities.deleteEntity(entity2);
|
||||
// play the sound near the camera so the shooter can hear it
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(targetHitSound, audioOptions);
|
||||
if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) &&
|
||||
((entity2.id == bulletID.id) || (entity2.id == targetID.id))) {
|
||||
score++;
|
||||
if (showScore) {
|
||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||
}
|
||||
|
||||
// We will delete the bullet and target in 1/2 sec, but for now we can see them bounce!
|
||||
Script.setTimeout(deleteBulletAndTarget, 500);
|
||||
|
||||
// Turn the target and the bullet white
|
||||
Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }});
|
||||
Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }});
|
||||
|
||||
// play the sound near the camera so the shooter can hear it
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(targetHitSound, audioOptions);
|
||||
}
|
||||
}
|
||||
|
||||
function keyPressEvent(event) {
|
||||
|
@ -199,32 +216,94 @@ function keyPressEvent(event) {
|
|||
shootFromMouse();
|
||||
} else if (event.text == "r") {
|
||||
playLoadSound();
|
||||
} else if (event.text == "s") {
|
||||
// Hit this key to dump a posture from hydra to log
|
||||
Quat.print("arm = ", MyAvatar.getJointRotation("LeftArm"));
|
||||
Quat.print("forearm = ", MyAvatar.getJointRotation("LeftForeArm"));
|
||||
Quat.print("hand = ", MyAvatar.getJointRotation("LeftHand"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function playLoadSound() {
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(loadSound, audioOptions);
|
||||
// Raise arm to firing posture
|
||||
takeFiringPose();
|
||||
}
|
||||
|
||||
//MyAvatar.attach(gunModel, "RightHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
|
||||
MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
|
||||
function clearPose() {
|
||||
MyAvatar.clearJointData("LeftForeArm");
|
||||
MyAvatar.clearJointData("LeftArm");
|
||||
MyAvatar.clearJointData("LeftHand");
|
||||
}
|
||||
|
||||
function deleteBulletAndTarget() {
|
||||
Entities.deleteEntity(bulletID);
|
||||
Entities.deleteEntity(targetID);
|
||||
bulletID = false;
|
||||
targetID = false;
|
||||
}
|
||||
|
||||
function takeFiringPose() {
|
||||
clearPose();
|
||||
if (Controller.getNumberOfSpatialControls() == 0) {
|
||||
MyAvatar.setJointData("LeftForeArm", {x: -0.251919, y: -0.0415449, z: 0.499487, w: 0.827843});
|
||||
MyAvatar.setJointData("LeftArm", { x: 0.470196, y: -0.132559, z: 0.494033, w: 0.719219});
|
||||
MyAvatar.setJointData("LeftHand", { x: -0.0104815, y: -0.110551, z: -0.352111, w: 0.929333});
|
||||
}
|
||||
}
|
||||
|
||||
//MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20);
|
||||
MyAvatar.attach(gunModel, "LeftHand", {x:-0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(0, 0, 79), 0.20);
|
||||
|
||||
// Give a bit of time to load before playing sound
|
||||
Script.setTimeout(playLoadSound, 2000);
|
||||
|
||||
function update(deltaTime) {
|
||||
if (bulletID && !bulletID.isKnownID) {
|
||||
print("Trying to identify bullet");
|
||||
bulletID = Entities.identifyEntity(bulletID);
|
||||
}
|
||||
if (targetID && !targetID.isKnownID) {
|
||||
targetID = Entities.identifyEntity(targetID);
|
||||
}
|
||||
// Check for mouseLook movement, update rotation
|
||||
// rotate body yaw for yaw received from mouse
|
||||
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } ));
|
||||
MyAvatar.orientation = newOrientation;
|
||||
//MyAvatar.orientation = newOrientation;
|
||||
yawFromMouse = 0;
|
||||
|
||||
// apply pitch from mouse
|
||||
var newPitch = MyAvatar.headPitch + pitchFromMouse;
|
||||
MyAvatar.headPitch = newPitch;
|
||||
//MyAvatar.headPitch = newPitch;
|
||||
pitchFromMouse = 0;
|
||||
|
||||
|
||||
if (activeControllers == 0) {
|
||||
if (Controller.getNumberOfSpatialControls() > 0) {
|
||||
activeControllers = Controller.getNumberOfSpatialControls();
|
||||
clearPose();
|
||||
}
|
||||
}
|
||||
|
||||
var KICKBACK_DECAY_RATE = 0.125;
|
||||
if (elbowKickAngle > 0.0) {
|
||||
if (elbowKickAngle > 0.5) {
|
||||
var newAngle = elbowKickAngle * KICKBACK_DECAY_RATE;
|
||||
elbowKickAngle -= newAngle;
|
||||
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
|
||||
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, -newAngle));
|
||||
MyAvatar.setJointData("LeftForeArm", armRotation);
|
||||
} else {
|
||||
MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback);
|
||||
if (Controller.getNumberOfSpatialControls() > 0) {
|
||||
clearPose();
|
||||
}
|
||||
elbowKickAngle = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check hydra controller for launch button press
|
||||
if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) {
|
||||
isLaunchButtonPressed = true;
|
||||
|
@ -235,15 +314,13 @@ function update(deltaTime) {
|
|||
|
||||
}
|
||||
|
||||
// Check hydra controller for trigger press
|
||||
// check for trigger press
|
||||
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
var numberOfTriggers = 2;
|
||||
var controllersPerTrigger = 2;
|
||||
|
||||
// this is expected for hydras
|
||||
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
|
||||
for (var t = 0; t < numberOfTriggers; t++) {
|
||||
for (var t = 0; t < 2; t++) {
|
||||
var shootABullet = false;
|
||||
var triggerValue = Controller.getTriggerValue(t);
|
||||
if (triggerPulled[t]) {
|
||||
|
@ -252,14 +329,13 @@ function update(deltaTime) {
|
|||
triggerPulled[t] = false; // unpulled
|
||||
}
|
||||
} else {
|
||||
// must pull to at least 0.9
|
||||
if (triggerValue > 0.9) {
|
||||
// must pull to at least
|
||||
if (triggerValue > 0.5) {
|
||||
triggerPulled[t] = true; // pulled
|
||||
shootABullet = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (shootABullet) {
|
||||
var palmController = t * controllersPerTrigger;
|
||||
var palmPosition = Controller.getSpatialControlPosition(palmController);
|
||||
|
@ -276,12 +352,8 @@ function update(deltaTime) {
|
|||
var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2,
|
||||
y: fingerTipPosition.y + palmToFingerTipVector.y/2,
|
||||
z: fingerTipPosition.z + palmToFingerTipVector.z/2};
|
||||
|
||||
var linearVelocity = 25;
|
||||
|
||||
var velocity = { x: palmToFingerTipVector.x * linearVelocity,
|
||||
y: palmToFingerTipVector.y * linearVelocity,
|
||||
z: palmToFingerTipVector.z * linearVelocity };
|
||||
|
||||
var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(palmToFingerTipVector));
|
||||
|
||||
shootBullet(position, velocity);
|
||||
}
|
||||
|
@ -293,8 +365,12 @@ function mousePressEvent(event) {
|
|||
isMouseDown = true;
|
||||
lastX = event.x;
|
||||
lastY = event.y;
|
||||
//audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
//Audio.playSound(loadSound, audioOptions);
|
||||
|
||||
if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) === offButton) {
|
||||
Script.stop();
|
||||
} else {
|
||||
shootFromMouse();
|
||||
}
|
||||
}
|
||||
|
||||
function shootFromMouse() {
|
||||
|
@ -325,11 +401,12 @@ function mouseMoveEvent(event) {
|
|||
|
||||
function scriptEnding() {
|
||||
Overlays.deleteOverlay(reticle);
|
||||
Overlays.deleteOverlay(offButton);
|
||||
Overlays.deleteOverlay(text);
|
||||
MyAvatar.detachOne(gunModel);
|
||||
clearPose();
|
||||
}
|
||||
|
||||
Entities.entityCollisionWithVoxel.connect(entityCollisionWithVoxel);
|
||||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.update.connect(update);
|
742
examples/controllers/hydra/hydraGrab.js
Normal file
742
examples/controllers/hydra/hydraGrab.js
Normal file
|
@ -0,0 +1,742 @@
|
|||
//
|
||||
// hydraGrab.js
|
||||
// examples
|
||||
//
|
||||
// Created by Clément Brisset on 4/24/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This script allows you to edit models either with the razor hydras or with your mouse
|
||||
//
|
||||
// Using the hydras :
|
||||
// grab models with the triggers, you can then move the models around or scale them with both hands.
|
||||
// You can switch mode using the bumpers so that you can move models around more easily.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
Script.include("libraries/entityPropertyDialogBox.js");
|
||||
var entityPropertyDialogBox = EntityPropertyDialogBox;
|
||||
|
||||
var LASER_WIDTH = 4;
|
||||
var LASER_COLOR = { red: 255, green: 0, blue: 0 };
|
||||
var LASER_LENGTH_FACTOR = 500;
|
||||
|
||||
var MIN_ANGULAR_SIZE = 2;
|
||||
var MAX_ANGULAR_SIZE = 45;
|
||||
var allowLargeModels = false;
|
||||
var allowSmallModels = false;
|
||||
var wantEntityGlow = false;
|
||||
|
||||
var LEFT = 0;
|
||||
var RIGHT = 1;
|
||||
|
||||
var jointList = MyAvatar.getJointNames();
|
||||
|
||||
var mode = 0;
|
||||
|
||||
function controller(wichSide) {
|
||||
this.side = wichSide;
|
||||
this.palm = 2 * wichSide;
|
||||
this.tip = 2 * wichSide + 1;
|
||||
this.trigger = wichSide;
|
||||
this.bumper = 6 * wichSide + 5;
|
||||
|
||||
this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
|
||||
this.oldTipPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
|
||||
this.oldUp = Controller.getSpatialControlNormal(this.palm);
|
||||
this.up = this.oldUp;
|
||||
|
||||
this.oldFront = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition));
|
||||
this.front = this.oldFront;
|
||||
|
||||
this.oldRight = Vec3.cross(this.front, this.up);
|
||||
this.right = this.oldRight;
|
||||
|
||||
this.oldRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
|
||||
this.rotation = this.oldRotation;
|
||||
|
||||
this.triggerValue = Controller.getTriggerValue(this.trigger);
|
||||
this.bumperValue = Controller.isButtonPressed(this.bumper);
|
||||
|
||||
this.pressed = false; // is trigger pressed
|
||||
this.pressing = false; // is trigger being pressed (is pressed now but wasn't previously)
|
||||
|
||||
this.grabbing = false;
|
||||
this.entityID = { isKnownID: false };
|
||||
this.modelURL = "";
|
||||
this.oldModelRotation;
|
||||
this.oldModelPosition;
|
||||
this.oldModelHalfDiagonal;
|
||||
|
||||
this.positionAtGrab;
|
||||
this.rotationAtGrab;
|
||||
this.modelPositionAtGrab;
|
||||
this.rotationAtGrab;
|
||||
this.jointsIntersectingFromStart = [];
|
||||
|
||||
this.laser = Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: LASER_COLOR,
|
||||
alpha: 1,
|
||||
visible: false,
|
||||
lineWidth: LASER_WIDTH,
|
||||
anchor: "MyAvatar"
|
||||
});
|
||||
|
||||
this.guideScale = 0.02;
|
||||
this.ball = Overlays.addOverlay("sphere", {
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
size: this.guideScale,
|
||||
solid: true,
|
||||
color: { red: 0, green: 255, blue: 0 },
|
||||
alpha: 1,
|
||||
visible: false,
|
||||
anchor: "MyAvatar"
|
||||
});
|
||||
this.leftRight = Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: { red: 0, green: 0, blue: 255 },
|
||||
alpha: 1,
|
||||
visible: false,
|
||||
lineWidth: LASER_WIDTH,
|
||||
anchor: "MyAvatar"
|
||||
});
|
||||
this.topDown = Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: { red: 0, green: 0, blue: 255 },
|
||||
alpha: 1,
|
||||
visible: false,
|
||||
lineWidth: LASER_WIDTH,
|
||||
anchor: "MyAvatar"
|
||||
});
|
||||
|
||||
|
||||
|
||||
this.grab = function (entityID, properties) {
|
||||
print("Grabbing " + entityID.id);
|
||||
this.grabbing = true;
|
||||
this.entityID = entityID;
|
||||
this.modelURL = properties.modelURL;
|
||||
|
||||
this.oldModelPosition = properties.position;
|
||||
this.oldModelRotation = properties.rotation;
|
||||
this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||
|
||||
this.positionAtGrab = this.palmPosition;
|
||||
this.rotationAtGrab = this.rotation;
|
||||
this.modelPositionAtGrab = properties.position;
|
||||
this.rotationAtGrab = properties.rotation;
|
||||
this.jointsIntersectingFromStart = [];
|
||||
for (var i = 0; i < jointList.length; i++) {
|
||||
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
|
||||
if (distance < this.oldModelHalfDiagonal) {
|
||||
this.jointsIntersectingFromStart.push(i);
|
||||
}
|
||||
}
|
||||
this.showLaser(false);
|
||||
}
|
||||
|
||||
this.release = function () {
|
||||
if (this.grabbing) {
|
||||
jointList = MyAvatar.getJointNames();
|
||||
|
||||
var closestJointIndex = -1;
|
||||
var closestJointDistance = 10;
|
||||
for (var i = 0; i < jointList.length; i++) {
|
||||
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
|
||||
if (distance < closestJointDistance) {
|
||||
closestJointDistance = distance;
|
||||
closestJointIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (closestJointIndex != -1) {
|
||||
print("closestJoint: " + jointList[closestJointIndex]);
|
||||
print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelHalfDiagonal + ")");
|
||||
}
|
||||
|
||||
if (closestJointDistance < this.oldModelHalfDiagonal) {
|
||||
|
||||
if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 ||
|
||||
(leftController.grabbing && rightController.grabbing &&
|
||||
leftController.entityID.id == rightController.entityID.id)) {
|
||||
// Do nothing
|
||||
} else {
|
||||
print("Attaching to " + jointList[closestJointIndex]);
|
||||
var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]);
|
||||
var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]);
|
||||
|
||||
var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition);
|
||||
attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset);
|
||||
var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation);
|
||||
|
||||
MyAvatar.attach(this.modelURL, jointList[closestJointIndex],
|
||||
attachmentOffset, attachmentRotation, 2.0 * this.oldModelHalfDiagonal,
|
||||
true, false);
|
||||
Entities.deleteEntity(this.entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.grabbing = false;
|
||||
this.entityID.isKnownID = false;
|
||||
this.jointsIntersectingFromStart = [];
|
||||
this.showLaser(true);
|
||||
}
|
||||
|
||||
this.checkTrigger = function () {
|
||||
if (this.triggerValue > 0.9) {
|
||||
if (this.pressed) {
|
||||
this.pressing = false;
|
||||
} else {
|
||||
this.pressing = true;
|
||||
}
|
||||
this.pressed = true;
|
||||
} else {
|
||||
this.pressing = false;
|
||||
this.pressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.checkEntity = function (properties) {
|
||||
// P P - Model
|
||||
// /| A - Palm
|
||||
// / | d B - unit vector toward tip
|
||||
// / | X - base of the perpendicular line
|
||||
// A---X----->B d - distance fom axis
|
||||
// x x - distance from A
|
||||
//
|
||||
// |X-A| = (P-A).B
|
||||
// X == A + ((P-A).B)B
|
||||
// d = |P-X|
|
||||
|
||||
var A = this.palmPosition;
|
||||
var B = this.front;
|
||||
var P = properties.position;
|
||||
|
||||
var x = Vec3.dot(Vec3.subtract(P, A), B);
|
||||
var y = Vec3.dot(Vec3.subtract(P, A), this.up);
|
||||
var z = Vec3.dot(Vec3.subtract(P, A), this.right);
|
||||
var X = Vec3.sum(A, Vec3.multiply(B, x));
|
||||
var d = Vec3.length(Vec3.subtract(P, X));
|
||||
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||
|
||||
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
|
||||
|
||||
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
||||
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
||||
|
||||
if (0 < x && sizeOK) {
|
||||
return { valid: true, x: x, y: y, z: z };
|
||||
}
|
||||
return { valid: false };
|
||||
}
|
||||
|
||||
this.glowedIntersectingModel = { isKnownID: false };
|
||||
this.moveLaser = function () {
|
||||
// the overlays here are anchored to the avatar, which means they are specified in the avatar's local frame
|
||||
|
||||
var inverseRotation = Quat.inverse(MyAvatar.orientation);
|
||||
var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position));
|
||||
var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition));
|
||||
var distance = Vec3.length(direction);
|
||||
direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / distance);
|
||||
var endPosition = Vec3.sum(startPosition, direction);
|
||||
|
||||
Overlays.editOverlay(this.laser, {
|
||||
start: startPosition,
|
||||
end: endPosition
|
||||
});
|
||||
|
||||
|
||||
Overlays.editOverlay(this.ball, {
|
||||
position: endPosition
|
||||
});
|
||||
Overlays.editOverlay(this.leftRight, {
|
||||
start: Vec3.sum(endPosition, Vec3.multiply(this.right, 2 * this.guideScale)),
|
||||
end: Vec3.sum(endPosition, Vec3.multiply(this.right, -2 * this.guideScale))
|
||||
});
|
||||
Overlays.editOverlay(this.topDown, {
|
||||
start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)),
|
||||
end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale))
|
||||
});
|
||||
this.showLaser(!this.grabbing || mode == 0);
|
||||
|
||||
if (this.glowedIntersectingModel.isKnownID) {
|
||||
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 });
|
||||
this.glowedIntersectingModel.isKnownID = false;
|
||||
}
|
||||
if (!this.grabbing) {
|
||||
var intersection = Entities.findRayIntersection({
|
||||
origin: this.palmPosition,
|
||||
direction: this.front
|
||||
});
|
||||
|
||||
var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0;
|
||||
|
||||
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), intersection.properties.position)) * 180 / 3.14;
|
||||
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
||||
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
||||
if (intersection.accurate && intersection.entityID.isKnownID && sizeOK) {
|
||||
this.glowedIntersectingModel = intersection.entityID;
|
||||
|
||||
if (wantEntityGlow) {
|
||||
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.25 });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.showLaser = function (show) {
|
||||
Overlays.editOverlay(this.laser, { visible: show });
|
||||
Overlays.editOverlay(this.ball, { visible: show });
|
||||
Overlays.editOverlay(this.leftRight, { visible: show });
|
||||
Overlays.editOverlay(this.topDown, { visible: show });
|
||||
}
|
||||
this.moveEntity = function () {
|
||||
if (this.grabbing) {
|
||||
if (!this.entityID.isKnownID) {
|
||||
print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
|
||||
this.entityID = Entities.findRayIntersection({
|
||||
origin: this.palmPosition,
|
||||
direction: this.front
|
||||
}).entityID;
|
||||
print("Identified ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
|
||||
}
|
||||
var newPosition;
|
||||
var newRotation;
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
newPosition = Vec3.sum(this.palmPosition,
|
||||
Vec3.multiply(this.front, this.x));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
Vec3.multiply(this.up, this.y));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
Vec3.multiply(this.right, this.z));
|
||||
|
||||
|
||||
newRotation = Quat.multiply(this.rotation,
|
||||
Quat.inverse(this.oldRotation));
|
||||
newRotation = Quat.multiply(newRotation,
|
||||
this.oldModelRotation);
|
||||
break;
|
||||
case 1:
|
||||
var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 });
|
||||
var d = Vec3.dot(forward, MyAvatar.position);
|
||||
|
||||
var factor1 = Vec3.dot(forward, this.positionAtGrab) - d;
|
||||
var factor2 = Vec3.dot(forward, this.modelPositionAtGrab) - d;
|
||||
var vector = Vec3.subtract(this.palmPosition, this.positionAtGrab);
|
||||
|
||||
if (factor2 < 0) {
|
||||
factor2 = 0;
|
||||
}
|
||||
if (factor1 <= 0) {
|
||||
factor1 = 1;
|
||||
factor2 = 1;
|
||||
}
|
||||
|
||||
newPosition = Vec3.sum(this.modelPositionAtGrab,
|
||||
Vec3.multiply(vector,
|
||||
factor2 / factor1));
|
||||
|
||||
newRotation = Quat.multiply(this.rotation,
|
||||
Quat.inverse(this.rotationAtGrab));
|
||||
newRotation = Quat.multiply(newRotation,
|
||||
this.rotationAtGrab);
|
||||
break;
|
||||
}
|
||||
Entities.editEntity(this.entityID, {
|
||||
position: newPosition,
|
||||
rotation: newRotation
|
||||
});
|
||||
this.oldModelRotation = newRotation;
|
||||
this.oldModelPosition = newPosition;
|
||||
|
||||
var indicesToRemove = [];
|
||||
for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) {
|
||||
var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition);
|
||||
if (distance >= this.oldModelHalfDiagonal) {
|
||||
indicesToRemove.push(this.jointsIntersectingFromStart[i]);
|
||||
}
|
||||
|
||||
}
|
||||
for (var i = 0; i < indicesToRemove.length; ++i) {
|
||||
this.jointsIntersectingFromStart.splice(this.jointsIntersectingFromStart.indexOf(indicesToRemove[i], 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.update = function () {
|
||||
this.oldPalmPosition = this.palmPosition;
|
||||
this.oldTipPosition = this.tipPosition;
|
||||
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
|
||||
this.oldUp = this.up;
|
||||
this.up = Vec3.normalize(Controller.getSpatialControlNormal(this.palm));
|
||||
|
||||
this.oldFront = this.front;
|
||||
this.front = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition));
|
||||
|
||||
this.oldRight = this.right;
|
||||
this.right = Vec3.normalize(Vec3.cross(this.front, this.up));
|
||||
|
||||
this.oldRotation = this.rotation;
|
||||
this.rotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
|
||||
|
||||
this.triggerValue = Controller.getTriggerValue(this.trigger);
|
||||
|
||||
var bumperValue = Controller.isButtonPressed(this.bumper);
|
||||
if (bumperValue && !this.bumperValue) {
|
||||
if (mode == 0) {
|
||||
mode = 1;
|
||||
Overlays.editOverlay(leftController.laser, { color: { red: 0, green: 0, blue: 255 } });
|
||||
Overlays.editOverlay(rightController.laser, { color: { red: 0, green: 0, blue: 255 } });
|
||||
} else {
|
||||
mode = 0;
|
||||
Overlays.editOverlay(leftController.laser, { color: { red: 255, green: 0, blue: 0 } });
|
||||
Overlays.editOverlay(rightController.laser, { color: { red: 255, green: 0, blue: 0 } });
|
||||
}
|
||||
}
|
||||
this.bumperValue = bumperValue;
|
||||
|
||||
|
||||
this.checkTrigger();
|
||||
|
||||
this.moveLaser();
|
||||
|
||||
if (!this.pressed && this.grabbing) {
|
||||
// release if trigger not pressed anymore.
|
||||
this.release();
|
||||
}
|
||||
|
||||
if (this.pressing) {
|
||||
// Checking for attachments intersecting
|
||||
var attachments = MyAvatar.getAttachmentData();
|
||||
var attachmentIndex = -1;
|
||||
var attachmentX = LASER_LENGTH_FACTOR;
|
||||
|
||||
var newModel;
|
||||
var newProperties;
|
||||
|
||||
for (var i = 0; i < attachments.length; ++i) {
|
||||
var position = Vec3.sum(MyAvatar.getJointPosition(attachments[i].jointName),
|
||||
Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[i].jointName), attachments[i].translation));
|
||||
var scale = attachments[i].scale;
|
||||
|
||||
var A = this.palmPosition;
|
||||
var B = this.front;
|
||||
var P = position;
|
||||
|
||||
var x = Vec3.dot(Vec3.subtract(P, A), B);
|
||||
var X = Vec3.sum(A, Vec3.multiply(B, x));
|
||||
var d = Vec3.length(Vec3.subtract(P, X));
|
||||
|
||||
if (d < scale / 2.0 && 0 < x && x < attachmentX) {
|
||||
attachmentIndex = i;
|
||||
attachmentX = d;
|
||||
}
|
||||
}
|
||||
|
||||
if (attachmentIndex != -1) {
|
||||
print("Detaching: " + attachments[attachmentIndex].modelURL);
|
||||
MyAvatar.detachOne(attachments[attachmentIndex].modelURL, attachments[attachmentIndex].jointName);
|
||||
|
||||
newProperties = {
|
||||
type: "Model",
|
||||
position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName),
|
||||
Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)),
|
||||
rotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName),
|
||||
attachments[attachmentIndex].rotation),
|
||||
|
||||
// TODO: how do we know the correct dimensions for detachment???
|
||||
dimensions: { x: attachments[attachmentIndex].scale / 2.0,
|
||||
y: attachments[attachmentIndex].scale / 2.0,
|
||||
z: attachments[attachmentIndex].scale / 2.0 },
|
||||
|
||||
modelURL: attachments[attachmentIndex].modelURL
|
||||
};
|
||||
|
||||
newModel = Entities.addEntity(newProperties);
|
||||
|
||||
|
||||
} else {
|
||||
// There is none so ...
|
||||
// Checking model tree
|
||||
Vec3.print("Looking at: ", this.palmPosition);
|
||||
var pickRay = { origin: this.palmPosition,
|
||||
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) };
|
||||
var foundIntersection = Entities.findRayIntersection(pickRay);
|
||||
|
||||
if(!foundIntersection.accurate) {
|
||||
print("No accurate intersection");
|
||||
return;
|
||||
}
|
||||
newModel = foundIntersection.entityID;
|
||||
if (!newModel.isKnownID) {
|
||||
var identify = Entities.identifyEntity(newModel);
|
||||
if (!identify.isKnownID) {
|
||||
print("Unknown ID " + identify.id + " (update loop " + newModel.id + ")");
|
||||
return;
|
||||
}
|
||||
newModel = identify;
|
||||
}
|
||||
newProperties = Entities.getEntityProperties(newModel);
|
||||
}
|
||||
print("foundEntity.modelURL=" + newProperties.modelURL);
|
||||
var check = this.checkEntity(newProperties);
|
||||
if (!check.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.grab(newModel, newProperties);
|
||||
|
||||
this.x = check.x;
|
||||
this.y = check.y;
|
||||
this.z = check.z;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.cleanup = function () {
|
||||
Overlays.deleteOverlay(this.laser);
|
||||
Overlays.deleteOverlay(this.ball);
|
||||
Overlays.deleteOverlay(this.leftRight);
|
||||
Overlays.deleteOverlay(this.topDown);
|
||||
}
|
||||
}
|
||||
|
||||
var leftController = new controller(LEFT);
|
||||
var rightController = new controller(RIGHT);
|
||||
|
||||
function moveEntities() {
|
||||
if (leftController.grabbing && rightController.grabbing && rightController.entityID.id == leftController.entityID.id) {
|
||||
var newPosition = leftController.oldModelPosition;
|
||||
var rotation = leftController.oldModelRotation;
|
||||
var ratio = 1;
|
||||
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x));
|
||||
var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x));
|
||||
|
||||
var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5);
|
||||
var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint));
|
||||
|
||||
|
||||
var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x));
|
||||
var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x));
|
||||
|
||||
var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5);
|
||||
var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint));
|
||||
|
||||
|
||||
ratio = length / oldLength;
|
||||
newPosition = Vec3.sum(middle,
|
||||
Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio));
|
||||
break;
|
||||
case 1:
|
||||
var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition));
|
||||
var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition));
|
||||
|
||||
var cos_theta = Vec3.dot(u, v);
|
||||
if (cos_theta > 1) {
|
||||
cos_theta = 1;
|
||||
}
|
||||
var angle = Math.acos(cos_theta) / Math.PI * 180;
|
||||
if (angle < 0.1) {
|
||||
return;
|
||||
|
||||
}
|
||||
var w = Vec3.normalize(Vec3.cross(u, v));
|
||||
|
||||
rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation);
|
||||
|
||||
|
||||
leftController.positionAtGrab = leftController.palmPosition;
|
||||
leftController.rotationAtGrab = leftController.rotation;
|
||||
leftController.modelPositionAtGrab = leftController.oldModelPosition;
|
||||
leftController.rotationAtGrab = rotation;
|
||||
rightController.positionAtGrab = rightController.palmPosition;
|
||||
rightController.rotationAtGrab = rightController.rotation;
|
||||
rightController.modelPositionAtGrab = rightController.oldModelPosition;
|
||||
rightController.rotationAtGrab = rotation;
|
||||
break;
|
||||
}
|
||||
Entities.editEntity(leftController.entityID, {
|
||||
position: newPosition,
|
||||
rotation: rotation,
|
||||
// TODO: how do we know the correct dimensions for detachment???
|
||||
//radius: leftController.oldModelHalfDiagonal * ratio
|
||||
dimensions: { x: leftController.oldModelHalfDiagonal * ratio,
|
||||
y: leftController.oldModelHalfDiagonal * ratio,
|
||||
z: leftController.oldModelHalfDiagonal * ratio }
|
||||
|
||||
|
||||
});
|
||||
leftController.oldModelPosition = newPosition;
|
||||
leftController.oldModelRotation = rotation;
|
||||
leftController.oldModelHalfDiagonal *= ratio;
|
||||
|
||||
rightController.oldModelPosition = newPosition;
|
||||
rightController.oldModelRotation = rotation;
|
||||
rightController.oldModelHalfDiagonal *= ratio;
|
||||
return;
|
||||
}
|
||||
leftController.moveEntity();
|
||||
rightController.moveEntity();
|
||||
}
|
||||
|
||||
var hydraConnected = false;
|
||||
function checkController(deltaTime) {
|
||||
var numberOfButtons = Controller.getNumberOfButtons();
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
|
||||
// this is expected for hydras
|
||||
if (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2) {
|
||||
if (!hydraConnected) {
|
||||
hydraConnected = true;
|
||||
}
|
||||
|
||||
leftController.update();
|
||||
rightController.update();
|
||||
moveEntities();
|
||||
} else {
|
||||
if (hydraConnected) {
|
||||
hydraConnected = false;
|
||||
|
||||
leftController.showLaser(false);
|
||||
rightController.showLaser(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var glowedEntityID = { id: -1, isKnownID: false };
|
||||
|
||||
// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already
|
||||
// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that
|
||||
// added it.
|
||||
var modelMenuAddedDelete = false;
|
||||
var originalLightsArePickable = Entities.getLightsArePickable();
|
||||
function setupModelMenus() {
|
||||
print("setupModelMenus()");
|
||||
// adj our menuitems
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...",
|
||||
shortcutKeyEvent: { text: "`" }, afterItem: "Models" });
|
||||
if (!Menu.menuItemExists("Edit", "Delete")) {
|
||||
print("no delete... adding ours");
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete",
|
||||
shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" });
|
||||
modelMenuAddedDelete = true;
|
||||
} else {
|
||||
print("delete exists... don't add ours");
|
||||
}
|
||||
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L",
|
||||
afterItem: "Paste Models", isCheckable: true });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S",
|
||||
afterItem: "Allow Selecting of Large Models", isCheckable: true });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L",
|
||||
afterItem: "Allow Selecting of Small Models", isCheckable: true });
|
||||
|
||||
Entities.setLightsArePickable(false);
|
||||
}
|
||||
|
||||
function cleanupModelMenus() {
|
||||
Menu.removeMenuItem("Edit", "Edit Properties...");
|
||||
if (modelMenuAddedDelete) {
|
||||
// delete our menuitems
|
||||
Menu.removeMenuItem("Edit", "Delete");
|
||||
}
|
||||
|
||||
Menu.removeMenuItem("Edit", "Allow Selecting of Large Models");
|
||||
Menu.removeMenuItem("Edit", "Allow Selecting of Small Models");
|
||||
Menu.removeMenuItem("Edit", "Allow Selecting of Lights");
|
||||
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
leftController.cleanup();
|
||||
rightController.cleanup();
|
||||
cleanupModelMenus();
|
||||
Entities.setLightsArePickable(originalLightsArePickable);
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(checkController);
|
||||
|
||||
setupModelMenus();
|
||||
|
||||
var editModelID = -1;
|
||||
function showPropertiesForm(editModelID) {
|
||||
entityPropertyDialogBox.openDialog(editModelID);
|
||||
}
|
||||
|
||||
Menu.menuItemEvent.connect(function (menuItem) {
|
||||
print("menuItemEvent() in JS... menuItem=" + menuItem);
|
||||
if (menuItem == "Allow Selecting of Small Models") {
|
||||
allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models");
|
||||
} else if (menuItem == "Allow Selecting of Large Models") {
|
||||
allowLargeModels = Menu.isOptionChecked("Allow Selecting of Large Models");
|
||||
} else if (menuItem == "Allow Selecting of Lights") {
|
||||
Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights"));
|
||||
} else if (menuItem == "Delete") {
|
||||
if (leftController.grabbing) {
|
||||
print(" Delete Entity.... leftController.entityID="+ leftController.entityID);
|
||||
Entities.deleteEntity(leftController.entityID);
|
||||
leftController.grabbing = false;
|
||||
if (glowedEntityID.id == leftController.entityID.id) {
|
||||
glowedEntityID = { id: -1, isKnownID: false };
|
||||
}
|
||||
} else if (rightController.grabbing) {
|
||||
print(" Delete Entity.... rightController.entityID="+ rightController.entityID);
|
||||
Entities.deleteEntity(rightController.entityID);
|
||||
rightController.grabbing = false;
|
||||
if (glowedEntityID.id == rightController.entityID.id) {
|
||||
glowedEntityID = { id: -1, isKnownID: false };
|
||||
}
|
||||
} else {
|
||||
print(" Delete Entity.... not holding...");
|
||||
}
|
||||
} else if (menuItem == "Edit Properties...") {
|
||||
editModelID = -1;
|
||||
if (leftController.grabbing) {
|
||||
print(" Edit Properties.... leftController.entityID="+ leftController.entityID);
|
||||
editModelID = leftController.entityID;
|
||||
} else if (rightController.grabbing) {
|
||||
print(" Edit Properties.... rightController.entityID="+ rightController.entityID);
|
||||
editModelID = rightController.entityID;
|
||||
} else {
|
||||
print(" Edit Properties.... not holding...");
|
||||
}
|
||||
if (editModelID != -1) {
|
||||
print(" Edit Properties.... about to edit properties...");
|
||||
showPropertiesForm(editModelID);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Controller.keyReleaseEvent.connect(function (event) {
|
||||
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
|
||||
if (event.text == "`") {
|
||||
handeMenuEvent("Edit Properties...");
|
||||
}
|
||||
if (event.text == "BACKSPACE") {
|
||||
handeMenuEvent("Delete");
|
||||
}
|
||||
});
|
||||
|
93
examples/controllers/hydra/laserPointer.js
Normal file
93
examples/controllers/hydra/laserPointer.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
//
|
||||
// laserPointer.js
|
||||
// examples
|
||||
//
|
||||
// Created by Clément Brisset on 7/18/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// If using Hydra controllers, pulling the triggers makes laser pointers emanate from the respective hands.
|
||||
// If using a Leap Motion or similar to control your avatar's hands and fingers, pointing with your index fingers makes
|
||||
// laser pointers emanate from the respective index fingers.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var laserPointer = (function () {
|
||||
|
||||
var NUM_FINGERs = 4, // Excluding thumb
|
||||
fingers = [
|
||||
[ "LeftHandIndex", "LeftHandMiddle", "LeftHandRing", "LeftHandPinky" ],
|
||||
[ "RightHandIndex", "RightHandMiddle", "RightHandRing", "RightHandPinky" ]
|
||||
];
|
||||
|
||||
function isHandPointing(hand) {
|
||||
var MINIMUM_TRIGGER_PULL = 0.9;
|
||||
return Controller.getTriggerValue(hand) > MINIMUM_TRIGGER_PULL;
|
||||
}
|
||||
|
||||
function isFingerPointing(hand) {
|
||||
// Index finger is pointing if final two bones of middle, ring, and pinky fingers are > 90 degrees w.r.t. index finger
|
||||
|
||||
var pointing,
|
||||
indexDirection,
|
||||
otherDirection,
|
||||
f;
|
||||
|
||||
pointing = true;
|
||||
|
||||
indexDirection = Vec3.subtract(
|
||||
MyAvatar.getJointPosition(fingers[hand][0] + "4"),
|
||||
MyAvatar.getJointPosition(fingers[hand][0] + "2")
|
||||
);
|
||||
|
||||
for (f = 1; f < NUM_FINGERs; f += 1) {
|
||||
otherDirection = Vec3.subtract(
|
||||
MyAvatar.getJointPosition(fingers[hand][f] + "4"),
|
||||
MyAvatar.getJointPosition(fingers[hand][f] + "2")
|
||||
);
|
||||
pointing = pointing && Vec3.dot(indexDirection, otherDirection) < 0;
|
||||
}
|
||||
|
||||
return pointing;
|
||||
}
|
||||
|
||||
function update() {
|
||||
var LEFT_HAND = 0,
|
||||
RIGHT_HAND = 1,
|
||||
LEFT_HAND_POINTING_FLAG = 1,
|
||||
RIGHT_HAND_POINTING_FLAG = 2,
|
||||
FINGER_POINTING_FLAG = 4,
|
||||
handState;
|
||||
|
||||
handState = 0;
|
||||
|
||||
if (isHandPointing(LEFT_HAND)) {
|
||||
handState += LEFT_HAND_POINTING_FLAG;
|
||||
}
|
||||
if (isHandPointing(RIGHT_HAND)) {
|
||||
handState += RIGHT_HAND_POINTING_FLAG;
|
||||
}
|
||||
|
||||
if (handState === 0) {
|
||||
if (isFingerPointing(LEFT_HAND)) {
|
||||
handState += LEFT_HAND_POINTING_FLAG;
|
||||
}
|
||||
if (isFingerPointing(RIGHT_HAND)) {
|
||||
handState += RIGHT_HAND_POINTING_FLAG;
|
||||
}
|
||||
if (handState !== 0) {
|
||||
handState += FINGER_POINTING_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
MyAvatar.setHandState(handState);
|
||||
}
|
||||
|
||||
return {
|
||||
update: update
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
Script.update.connect(laserPointer.update);
|
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../../libraries/globals.js");
|
||||
|
||||
var rightHandAnimation = HIFI_PUBLIC_BUCKET + "animations/RightHandAnimPhilip.fbx";
|
||||
var leftHandAnimation = HIFI_PUBLIC_BUCKET + "animations/LeftHandAnimPhilip.fbx";
|
|
@ -15,7 +15,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../../libraries/globals.js");
|
||||
|
||||
// maybe we should make these constants...
|
||||
var LEFT_PALM = 0;
|
||||
|
@ -29,7 +29,7 @@ var RIGHT_BUTTON_FWD = 11;
|
|||
var RIGHT_BUTTON_3 = 9;
|
||||
|
||||
var BALL_RADIUS = 0.08;
|
||||
var GRAVITY_STRENGTH = 0.5;
|
||||
var GRAVITY_STRENGTH = 1.0;
|
||||
|
||||
var HELD_COLOR = { red: 240, green: 0, blue: 0 };
|
||||
var THROWN_COLOR = { red: 128, green: 0, blue: 0 };
|
||||
|
@ -136,8 +136,8 @@ function checkControllerSide(whichSide) {
|
|||
velocity: { x: 0, y: 0, z: 0},
|
||||
gravity: { x: 0, y: 0, z: 0},
|
||||
inHand: true,
|
||||
radius: { x: BALL_RADIUS * 2, y: BALL_RADIUS * 2, z: BALL_RADIUS * 2 },
|
||||
damping: 0.999,
|
||||
dimensions: { x: BALL_RADIUS * 2, y: BALL_RADIUS * 2, z: BALL_RADIUS * 2 },
|
||||
damping: 0.00001,
|
||||
color: HELD_COLOR,
|
||||
|
||||
lifetime: 600 // 10 seconds - same as default, not needed but here as an example
|
||||
|
@ -185,6 +185,7 @@ function checkControllerSide(whichSide) {
|
|||
velocity: { x: tipVelocity.x * THROWN_VELOCITY_SCALING,
|
||||
y: tipVelocity.y * THROWN_VELOCITY_SCALING,
|
||||
z: tipVelocity.z * THROWN_VELOCITY_SCALING } ,
|
||||
collisionsWillMove: true,
|
||||
inHand: false,
|
||||
color: THROWN_COLOR,
|
||||
lifetime: 10,
|
93
examples/controllers/leap/laserPointer.js
Normal file
93
examples/controllers/leap/laserPointer.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
//
|
||||
// laserPointer.js
|
||||
// examples
|
||||
//
|
||||
// Created by Clément Brisset on 7/18/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// If using Hydra controllers, pulling the triggers makes laser pointers emanate from the respective hands.
|
||||
// If using a Leap Motion or similar to control your avatar's hands and fingers, pointing with your index fingers makes
|
||||
// laser pointers emanate from the respective index fingers.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var laserPointer = (function () {
|
||||
|
||||
var NUM_FINGERs = 4, // Excluding thumb
|
||||
fingers = [
|
||||
[ "LeftHandIndex", "LeftHandMiddle", "LeftHandRing", "LeftHandPinky" ],
|
||||
[ "RightHandIndex", "RightHandMiddle", "RightHandRing", "RightHandPinky" ]
|
||||
];
|
||||
|
||||
function isHandPointing(hand) {
|
||||
var MINIMUM_TRIGGER_PULL = 0.9;
|
||||
return Controller.getTriggerValue(hand) > MINIMUM_TRIGGER_PULL;
|
||||
}
|
||||
|
||||
function isFingerPointing(hand) {
|
||||
// Index finger is pointing if final two bones of middle, ring, and pinky fingers are > 90 degrees w.r.t. index finger
|
||||
|
||||
var pointing,
|
||||
indexDirection,
|
||||
otherDirection,
|
||||
f;
|
||||
|
||||
pointing = true;
|
||||
|
||||
indexDirection = Vec3.subtract(
|
||||
MyAvatar.getJointPosition(fingers[hand][0] + "4"),
|
||||
MyAvatar.getJointPosition(fingers[hand][0] + "2")
|
||||
);
|
||||
|
||||
for (f = 1; f < NUM_FINGERs; f += 1) {
|
||||
otherDirection = Vec3.subtract(
|
||||
MyAvatar.getJointPosition(fingers[hand][f] + "4"),
|
||||
MyAvatar.getJointPosition(fingers[hand][f] + "2")
|
||||
);
|
||||
pointing = pointing && Vec3.dot(indexDirection, otherDirection) < 0;
|
||||
}
|
||||
|
||||
return pointing;
|
||||
}
|
||||
|
||||
function update() {
|
||||
var LEFT_HAND = 0,
|
||||
RIGHT_HAND = 1,
|
||||
LEFT_HAND_POINTING_FLAG = 1,
|
||||
RIGHT_HAND_POINTING_FLAG = 2,
|
||||
FINGER_POINTING_FLAG = 4,
|
||||
handState;
|
||||
|
||||
handState = 0;
|
||||
|
||||
if (isHandPointing(LEFT_HAND)) {
|
||||
handState += LEFT_HAND_POINTING_FLAG;
|
||||
}
|
||||
if (isHandPointing(RIGHT_HAND)) {
|
||||
handState += RIGHT_HAND_POINTING_FLAG;
|
||||
}
|
||||
|
||||
if (handState === 0) {
|
||||
if (isFingerPointing(LEFT_HAND)) {
|
||||
handState += LEFT_HAND_POINTING_FLAG;
|
||||
}
|
||||
if (isFingerPointing(RIGHT_HAND)) {
|
||||
handState += RIGHT_HAND_POINTING_FLAG;
|
||||
}
|
||||
if (handState !== 0) {
|
||||
handState += FINGER_POINTING_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
MyAvatar.setHandState(handState);
|
||||
}
|
||||
|
||||
return {
|
||||
update: update
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
Script.update.connect(laserPointer.update);
|
|
@ -15,7 +15,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../../libraries/globals.js");
|
||||
|
||||
const KBD_UPPERCASE_DEFAULT = 0;
|
||||
const KBD_LOWERCASE_DEFAULT = 1;
|
|
@ -1,30 +0,0 @@
|
|||
//
|
||||
// count.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/31/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that runs in a loop and displays a counter to the log
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
//
|
||||
|
||||
var count = 0;
|
||||
|
||||
function displayCount(deltaTime) {
|
||||
print("count =" + count + " deltaTime=" + deltaTime);
|
||||
count++;
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
print("SCRIPT ENDNG!!!\n");
|
||||
}
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(displayCount);
|
||||
|
||||
// register our scriptEnding callback
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -15,3 +15,4 @@ Script.load("hydraMove.js");
|
|||
Script.load("headMove.js");
|
||||
Script.load("inspect.js");
|
||||
Script.load("lobby.js");
|
||||
Script.load("notifications.js");
|
||||
|
|
|
@ -42,7 +42,15 @@ gridTool = GridTool({ horizontalGrid: grid });
|
|||
Script.include("libraries/entityList.js");
|
||||
var entityListTool = EntityListTool();
|
||||
|
||||
selectionManager.addEventListener(selectionDisplay.updateHandles);
|
||||
var hasShownPropertiesTool = false;
|
||||
|
||||
selectionManager.addEventListener(function() {
|
||||
selectionDisplay.updateHandles();
|
||||
if (selectionManager.hasSelection() && !hasShownPropertiesTool) {
|
||||
propertiesTool.setVisible(true);
|
||||
hasShownPropertiesTool = true;
|
||||
}
|
||||
});
|
||||
|
||||
var windowDimensions = Controller.getViewportDimensions();
|
||||
var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/";
|
||||
|
@ -77,7 +85,6 @@ var modelURLs = [
|
|||
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx",
|
||||
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush1.fbx",
|
||||
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush6.fbx",
|
||||
HIFI_PUBLIC_BUCKET + "meshes/newInvader16x16-large-purple.svo",
|
||||
HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed.fbx",
|
||||
HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed2.fbx",
|
||||
HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed4.fbx",
|
||||
|
@ -192,8 +199,7 @@ var toolBar = (function () {
|
|||
});
|
||||
|
||||
newTextButton = toolBar.addTool({
|
||||
//imageURL: toolIconUrl + "add-text.svg",
|
||||
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/tools/add-text.svg", // temporarily
|
||||
imageURL: toolIconUrl + "add-text.svg",
|
||||
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||
width: toolWidth,
|
||||
height: toolHeight,
|
||||
|
@ -225,10 +231,9 @@ var toolBar = (function () {
|
|||
selectionManager.clearSelections();
|
||||
cameraManager.disable();
|
||||
} else {
|
||||
hasShownPropertiesTool = false;
|
||||
cameraManager.enable();
|
||||
entityListTool.setVisible(true);
|
||||
gridTool.setVisible(true);
|
||||
propertiesTool.setVisible(true);
|
||||
grid.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
@ -494,8 +499,10 @@ var mouseHasMovedSincePress = false;
|
|||
|
||||
function mousePressEvent(event) {
|
||||
mouseHasMovedSincePress = false;
|
||||
mouseCapturedByTool = false;
|
||||
|
||||
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
|
||||
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event) || gridTool.mousePressEvent(event)) {
|
||||
mouseCapturedByTool = true;
|
||||
return;
|
||||
}
|
||||
if (isActive) {
|
||||
|
@ -519,6 +526,7 @@ function mousePressEvent(event) {
|
|||
}
|
||||
|
||||
var highlightedEntityID = { isKnownID: false };
|
||||
var mouseCapturedByTool = false;
|
||||
|
||||
function mouseMoveEvent(event) {
|
||||
mouseHasMovedSincePress = true;
|
||||
|
@ -563,6 +571,9 @@ function mouseReleaseEvent(event) {
|
|||
if (isActive && selectionManager.hasSelection()) {
|
||||
tooltip.show(false);
|
||||
}
|
||||
if (mouseCapturedByTool) {
|
||||
return;
|
||||
}
|
||||
|
||||
cameraManager.mouseReleaseEvent(event);
|
||||
|
||||
|
@ -651,8 +662,6 @@ function setupModelMenus() {
|
|||
print("setupModelMenus()");
|
||||
// adj our menuitems
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...",
|
||||
shortcutKeyEvent: { text: "`" }, afterItem: "Models" });
|
||||
if (!Menu.menuItemExists("Edit", "Delete")) {
|
||||
print("no delete... adding ours");
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete",
|
||||
|
@ -663,7 +672,7 @@ function setupModelMenus() {
|
|||
}
|
||||
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Model List..." });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L",
|
||||
afterItem: "Paste Models", isCheckable: true, isChecked: true });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S",
|
||||
|
@ -685,7 +694,6 @@ setupModelMenus(); // do this when first running our script.
|
|||
|
||||
function cleanupModelMenus() {
|
||||
Menu.removeSeparator("Edit", "Models");
|
||||
Menu.removeMenuItem("Edit", "Edit Properties...");
|
||||
if (modelMenuAddedDelete) {
|
||||
// delete our menuitems
|
||||
Menu.removeMenuItem("Edit", "Delete");
|
||||
|
@ -787,22 +795,6 @@ function handeMenuEvent(menuItem) {
|
|||
MyAvatar.position = selectedModel.properties.position;
|
||||
}
|
||||
}
|
||||
} else if (menuItem == "Edit Properties...") {
|
||||
// good place to put the properties dialog
|
||||
|
||||
editModelID = -1;
|
||||
if (selectionManager.selections.length == 1) {
|
||||
print(" Edit Properties.... selectedEntityID="+ selectedEntityID);
|
||||
editModelID = selectionManager.selections[0];
|
||||
} else {
|
||||
print(" Edit Properties.... not holding...");
|
||||
}
|
||||
if (editModelID != -1) {
|
||||
print(" Edit Properties.... about to edit properties...");
|
||||
entityPropertyDialogBox.openDialog(editModelID);
|
||||
selectionManager._update();
|
||||
}
|
||||
|
||||
} else if (menuItem == "Paste Models") {
|
||||
modelImporter.paste();
|
||||
} else if (menuItem == "Export Models") {
|
||||
|
@ -830,9 +822,6 @@ Controller.keyPressEvent.connect(function(event) {
|
|||
|
||||
Controller.keyReleaseEvent.connect(function (event) {
|
||||
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
|
||||
if (event.text == "`") {
|
||||
handeMenuEvent("Edit Properties...");
|
||||
}
|
||||
if (event.text == "BACKSPACE" || event.text == "DELETE") {
|
||||
handeMenuEvent("Delete");
|
||||
} else if (event.text == "TAB") {
|
||||
|
@ -1066,6 +1055,19 @@ PropertiesTool = function(opts) {
|
|||
pushCommandForSelections();
|
||||
selectionManager._update();
|
||||
}
|
||||
} else if (data.action == "rescaleDimensions") {
|
||||
var multiplier = data.percentage / 100;
|
||||
if (selectionManager.hasSelection()) {
|
||||
selectionManager.saveProperties();
|
||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||
var properties = selectionManager.savedProperties[selectionManager.selections[i].id];
|
||||
Entities.editEntity(selectionManager.selections[i], {
|
||||
dimensions: Vec3.multiply(multiplier, properties.dimensions),
|
||||
});
|
||||
}
|
||||
pushCommandForSelections();
|
||||
selectionManager._update();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,202 +0,0 @@
|
|||
//
|
||||
// particleBirds.js
|
||||
// examples
|
||||
//
|
||||
// Created by Benjamin Arnold on May 29, 2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This sample script creates a swarm of tweeting bird entities that fly around the avatar.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
|
||||
// Multiply vector by scalar
|
||||
function vScalarMult(v, s) {
|
||||
var rval = { x: v.x * s, y: v.y * s, z: v.z * s };
|
||||
return rval;
|
||||
}
|
||||
|
||||
function printVector(v) {
|
||||
print(v.x + ", " + v.y + ", " + v.z + "\n");
|
||||
}
|
||||
// Create a random vector with individual lengths between a,b
|
||||
function randVector(a, b) {
|
||||
var rval = { x: a + Math.random() * (b - a), y: a + Math.random() * (b - a), z: a + Math.random() * (b - a) };
|
||||
return rval;
|
||||
}
|
||||
|
||||
// Returns a vector which is fraction of the way between a and b
|
||||
function vInterpolate(a, b, fraction) {
|
||||
var rval = { x: a.x + (b.x - a.x) * fraction, y: a.y + (b.y - a.y) * fraction, z: a.z + (b.z - a.z) * fraction };
|
||||
return rval;
|
||||
}
|
||||
|
||||
var startTimeInSeconds = new Date().getTime() / 1000;
|
||||
|
||||
var birdLifetime = 20; // lifetime of the birds in seconds!
|
||||
var range = 1.0; // Over what distance in meters do you want the flock to fly around
|
||||
var frame = 0;
|
||||
|
||||
var CHANCE_OF_MOVING = 0.1;
|
||||
var CHANCE_OF_TWEETING = 0.05;
|
||||
var BIRD_GRAVITY = -0.1;
|
||||
var BIRD_FLAP_SPEED = 10.0;
|
||||
var BIRD_VELOCITY = 0.5;
|
||||
var myPosition = MyAvatar.position;
|
||||
|
||||
var range = 1.0; // Distance around avatar where I can move
|
||||
|
||||
// This is our Bird object
|
||||
function Bird (particleID, tweetSound, targetPosition) {
|
||||
this.particleID = particleID;
|
||||
this.tweetSound = tweetSound;
|
||||
this.previousFlapOffset = 0;
|
||||
this.targetPosition = targetPosition;
|
||||
this.moving = false;
|
||||
this.tweeting = -1;
|
||||
}
|
||||
|
||||
// Array of birds
|
||||
var birds = [];
|
||||
|
||||
function addBird()
|
||||
{
|
||||
// Decide what kind of bird we are
|
||||
var tweet;
|
||||
var color;
|
||||
var size;
|
||||
var which = Math.random();
|
||||
if (which < 0.2) {
|
||||
tweet = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/bushtit_1.raw");
|
||||
color = { red: 100, green: 50, blue: 120 };
|
||||
size = 0.08;
|
||||
} else if (which < 0.4) {
|
||||
tweet = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/rosyfacedlovebird.raw");
|
||||
color = { red: 100, green: 150, blue: 75 };
|
||||
size = 0.09;
|
||||
} else if (which < 0.6) {
|
||||
tweet = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/saysphoebe.raw");
|
||||
color = { red: 84, green: 121, blue: 36 };
|
||||
size = 0.05;
|
||||
} else if (which < 0.8) {
|
||||
tweet = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/mexicanWhipoorwill.raw");
|
||||
color = { red: 23, green: 197, blue: 230 };
|
||||
size = 0.12;
|
||||
} else {
|
||||
tweet = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/westernscreechowl.raw");
|
||||
color = { red: 50, green: 67, blue: 144 };
|
||||
size = 0.15;
|
||||
}
|
||||
var properties = {
|
||||
type: "Sphere",
|
||||
lifetime: birdLifetime,
|
||||
position: Vec3.sum(randVector(-range, range), myPosition),
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: BIRD_GRAVITY, z: 0 },
|
||||
dimensions: { x: size * 2, y: size * 2, z: size * 2 },
|
||||
color: color
|
||||
};
|
||||
|
||||
birds.push(new Bird(Entities.addEntity(properties), tweet, properties.position));
|
||||
}
|
||||
|
||||
var numBirds = 30;
|
||||
|
||||
// Generate the birds
|
||||
for (var i = 0; i < numBirds; i++) {
|
||||
addBird();
|
||||
}
|
||||
|
||||
// Main update function
|
||||
function updateBirds(deltaTime) {
|
||||
|
||||
// Check to see if we've been running long enough that our birds are dead
|
||||
var nowTimeInSeconds = new Date().getTime() / 1000;
|
||||
if ((nowTimeInSeconds - startTimeInSeconds) >= birdLifetime) {
|
||||
|
||||
print("our birds are dying, stop our script");
|
||||
Script.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
frame++;
|
||||
// Only update every third frame
|
||||
if ((frame % 3) == 0) {
|
||||
myPosition = MyAvatar.position;
|
||||
|
||||
// Update all the birds
|
||||
for (var i = 0; i < numBirds; i++) {
|
||||
particleID = birds[i].particleID;
|
||||
var properties = Entities.getEntityProperties(particleID);
|
||||
|
||||
// Tweeting behavior
|
||||
if (birds[i].tweeting == 0) {
|
||||
if (Math.random() < CHANCE_OF_TWEETING) {
|
||||
Audio.playSound(birds[i].tweetSound, {
|
||||
position: properties.position,
|
||||
volume: 0.75
|
||||
});
|
||||
birds[i].tweeting = 10;
|
||||
}
|
||||
} else {
|
||||
birds[i].tweeting -= 1;
|
||||
}
|
||||
|
||||
// Begin movement by getting a target
|
||||
if (birds[i].moving == false) {
|
||||
if (Math.random() < CHANCE_OF_MOVING) {
|
||||
var targetPosition = Vec3.sum(randVector(-range, range), myPosition);
|
||||
|
||||
if (targetPosition.x < 0) {
|
||||
targetPosition.x = 0;
|
||||
}
|
||||
if (targetPosition.y < 0) {
|
||||
targetPosition.y = 0;
|
||||
}
|
||||
if (targetPosition.z < 0) {
|
||||
targetPosition.z = 0;
|
||||
}
|
||||
if (targetPosition.x > TREE_SCALE) {
|
||||
targetPosition.x = TREE_SCALE;
|
||||
}
|
||||
if (targetPosition.y > TREE_SCALE) {
|
||||
targetPosition.y = TREE_SCALE;
|
||||
}
|
||||
if (targetPosition.z > TREE_SCALE) {
|
||||
targetPosition.z = TREE_SCALE;
|
||||
}
|
||||
|
||||
birds[i].targetPosition = targetPosition;
|
||||
|
||||
birds[i].moving = true;
|
||||
}
|
||||
}
|
||||
// If we are moving, move towards the target
|
||||
if (birds[i].moving) {
|
||||
var desiredVelocity = Vec3.subtract(birds[i].targetPosition, properties.position);
|
||||
desiredVelocity = vScalarMult(Vec3.normalize(desiredVelocity), BIRD_VELOCITY);
|
||||
|
||||
properties.velocity = vInterpolate(properties.velocity, desiredVelocity, 0.2);
|
||||
// If we are near the target, we should get a new target
|
||||
if (Vec3.length(Vec3.subtract(properties.position, birds[i].targetPosition)) < (properties.dimensions.x / 5.0)) {
|
||||
birds[i].moving = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Use a cosine wave offset to make it look like its flapping.
|
||||
var offset = Math.cos(nowTimeInSeconds * BIRD_FLAP_SPEED) * properties.dimensions.x;
|
||||
properties.position.y = properties.position.y + (offset - birds[i].previousFlapOffset);
|
||||
// Change position relative to previous offset.
|
||||
birds[i].previousFlapOffset = offset;
|
||||
|
||||
// Update the particle
|
||||
Entities.editEntity(particleID, properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(updateBirds);
|
|
@ -13,34 +13,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function(){
|
||||
this.oldColor = {};
|
||||
this.oldColorKnown = false;
|
||||
this.storeOldColor = function(entityID) {
|
||||
var oldProperties = Entities.getEntityProperties(entityID);
|
||||
this.oldColor = oldProperties.color;
|
||||
this.oldColorKnown = true;
|
||||
print("storing old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue);
|
||||
};
|
||||
|
||||
this.preload = function(entityID) {
|
||||
print("preload");
|
||||
this.storeOldColor(entityID);
|
||||
};
|
||||
|
||||
this.hoverEnterEntity = function(entityID, mouseEvent) {
|
||||
print("hoverEnterEntity");
|
||||
if (!this.oldColorKnown) {
|
||||
this.storeOldColor(entityID);
|
||||
}
|
||||
Entities.editEntity(entityID, { color: { red: 0, green: 255, blue: 255} });
|
||||
};
|
||||
this.hoverLeaveEntity = function(entityID, mouseEvent) {
|
||||
print("hoverLeaveEntity");
|
||||
if (this.oldColorKnown) {
|
||||
print("leave restoring old color... this.oldColor="
|
||||
+ this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue);
|
||||
Entities.editEntity(entityID, { color: this.oldColor });
|
||||
}
|
||||
};
|
||||
})
|
||||
(function() {
|
||||
Script.include("changeColorOnHoverClass.js");
|
||||
return new ChangeColorOnHover();
|
||||
})
|
||||
|
|
55
examples/entityScripts/changeColorOnHoverClass.js
Normal file
55
examples/entityScripts/changeColorOnHoverClass.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// changeColorOnHover.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 11/1/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example of an entity script which when assigned to a non-model entity like a box or sphere, will
|
||||
// change the color of the entity when you hover over it. This script uses the JavaScript prototype/class functionality
|
||||
// to construct an object that has methods for hoverEnterEntity and hoverLeaveEntity;
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
ChangeColorOnHover = function(){
|
||||
this.oldColor = {};
|
||||
this.oldColorKnown = false;
|
||||
};
|
||||
|
||||
ChangeColorOnHover.prototype = {
|
||||
|
||||
storeOldColor: function(entityID) {
|
||||
var oldProperties = Entities.getEntityProperties(entityID);
|
||||
this.oldColor = oldProperties.color;
|
||||
this.oldColorKnown = true;
|
||||
print("storing old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue);
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
print("preload");
|
||||
this.storeOldColor(entityID);
|
||||
},
|
||||
|
||||
hoverEnterEntity: function(entityID, mouseEvent) {
|
||||
print("hoverEnterEntity");
|
||||
if (!this.oldColorKnown) {
|
||||
this.storeOldColor(entityID);
|
||||
}
|
||||
Entities.editEntity(entityID, { color: { red: 0, green: 255, blue: 255} });
|
||||
},
|
||||
|
||||
|
||||
hoverLeaveEntity: function(entityID, mouseEvent) {
|
||||
print("hoverLeaveEntity");
|
||||
if (this.oldColorKnown) {
|
||||
print("leave restoring old color... this.oldColor="
|
||||
+ this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue);
|
||||
Entities.editEntity(entityID, { color: this.oldColor });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -27,10 +27,12 @@
|
|||
};
|
||||
|
||||
this.enterEntity = function(entityID) {
|
||||
print("enterEntity("+entityID.id+")");
|
||||
playSound();
|
||||
};
|
||||
|
||||
this.leaveEntity = function(entityID) {
|
||||
print("leaveEntity("+entityID.id+")");
|
||||
playSound();
|
||||
};
|
||||
})
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../../libraries/globals.js");
|
||||
|
||||
var sound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/mexicanWhipoorwill.raw");
|
||||
var CHANCE_OF_PLAYING_SOUND = 0.01;
|
|
@ -4,6 +4,10 @@
|
|||
//
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
//
|
||||
// Gives the ability to be set various reverb settings.
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
@ -14,7 +18,7 @@ var audioOptions = new AudioEffectOptions({
|
|||
roomSize: 50,
|
||||
|
||||
// Seconds
|
||||
reverbTime: 4,
|
||||
reverbTime: 10,
|
||||
|
||||
// Between 0 - 1
|
||||
damping: 0.50,
|
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../libraries/globals.js");
|
||||
|
||||
var modelURL = HIFI_PUBLIC_BUCKET + "models/entities/radio/Speakers.fbx";
|
||||
var soundURL = HIFI_PUBLIC_BUCKET + "sounds/family.stereo.raw";
|
|
@ -11,7 +11,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var damping = 0.9;
|
||||
var damping = 0.001;
|
||||
var yaw = 0.0;
|
||||
var pitch = 0.0;
|
||||
var roll = 0.0;
|
|
@ -12,7 +12,7 @@
|
|||
//
|
||||
|
||||
function keyReleaseEvent(event) {
|
||||
if (event.text == "F2") {
|
||||
if (event.text == "r") {
|
||||
MyAvatar.shouldRenderLocally = !MyAvatar.shouldRenderLocally;
|
||||
}
|
||||
}
|
|
@ -8,8 +8,8 @@
|
|||
// This is an example script that demonstrates use of the Camera class's lookAt(), keepLookingAt(), and stopLookingAt()
|
||||
// features.
|
||||
//
|
||||
// To use the script, click on a voxel, and the camera will switch into independent mode and fix it's lookAt on the point
|
||||
// on the face of the voxel that you clicked. Click again and it will stop looking at that point. While in this fixed mode
|
||||
// To use the script, click on a entity, and the camera will switch into independent mode and fix it's lookAt on the point
|
||||
// on the face of the entity that you clicked. Click again and it will stop looking at that point. While in this fixed mode
|
||||
// you can use the arrow keys to change the position of the camera.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -61,7 +61,7 @@ function mousePressEvent(event) {
|
|||
cancelLookAt();
|
||||
} else {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
var intersection = Entities.findRayIntersection(pickRay);
|
||||
if (intersection.intersects) {
|
||||
|
||||
// remember the old mode we were in
|
66
examples/example/downloadInfoExample.js
Normal file
66
examples/example/downloadInfoExample.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// downloadInfoExample.js
|
||||
// examples/example
|
||||
//
|
||||
// Created by David Rowe on 5 Jan 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Display downloads information the same as in the stats.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var downloadInfo,
|
||||
downloadInfoOverlay;
|
||||
|
||||
function formatInfo(info) {
|
||||
var string = "Downloads: ",
|
||||
i;
|
||||
|
||||
for (i = 0; i < info.downloading.length; i += 1) {
|
||||
string += info.downloading[i].toFixed(0) + "% ";
|
||||
}
|
||||
|
||||
string += "(" + info.pending.toFixed(0) + " pending)";
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
// Get and log the current downloads info ...
|
||||
|
||||
downloadInfo = GlobalServices.getDownloadInfo();
|
||||
print(formatInfo(downloadInfo));
|
||||
|
||||
|
||||
// Display and update the downloads info in an overlay ...
|
||||
|
||||
function setUp() {
|
||||
downloadInfoOverlay = Overlays.addOverlay("text", {
|
||||
x: 300,
|
||||
y: 200,
|
||||
width: 300,
|
||||
height: 50,
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
alpha: 1.0,
|
||||
backgroundColor: { red: 127, green: 127, blue: 127 },
|
||||
backgroundAlpha: 0.5,
|
||||
topMargin: 15,
|
||||
leftMargin: 20,
|
||||
text: ""
|
||||
});
|
||||
}
|
||||
|
||||
function updateInfo(info) {
|
||||
Overlays.editOverlay(downloadInfoOverlay, { text: formatInfo(info) });
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
Overlays.deleteOverlay(downloadInfoOverlay);
|
||||
}
|
||||
|
||||
setUp();
|
||||
GlobalServices.downloadInfoChanged.connect(updateInfo);
|
||||
GlobalServices.updateDownloadInfo();
|
||||
Script.scriptEnding.connect(tearDown);
|
|
@ -12,7 +12,7 @@
|
|||
//
|
||||
|
||||
var count = 0;
|
||||
var moveUntil = 6000;
|
||||
var moveUntil = 1000;
|
||||
var stopAfter = moveUntil + 100;
|
||||
|
||||
var pitch = 0.0;
|
||||
|
@ -25,16 +25,19 @@ var originalProperties = {
|
|||
position: { x: MyAvatar.position.x,
|
||||
y: MyAvatar.position.y,
|
||||
z: MyAvatar.position.z },
|
||||
|
||||
radius : 1,
|
||||
dimensions: {
|
||||
x: 1.62,
|
||||
y: 0.41,
|
||||
z: 1.13
|
||||
},
|
||||
|
||||
color: { red: 0,
|
||||
green: 255,
|
||||
blue: 0 },
|
||||
|
||||
modelURL: "http://www.fungibleinsight.com/faces/beta.fst",
|
||||
modelURL: "http://public.highfidelity.io/cozza13/club/dragon/dragon.fbx",
|
||||
rotation: rotation,
|
||||
animationURL: "http://www.fungibleinsight.com/faces/gangnam_style_2.fbx",
|
||||
animationURL: "http://public.highfidelity.io/cozza13/club/dragon/flying.fbx",
|
||||
animationIsPlaying: true,
|
||||
};
|
||||
|
|
@ -79,12 +79,12 @@ function addButterfly() {
|
|||
rotation: Quat.fromPitchYawRollDegrees(-80 + Math.random() * 20, Math.random() * 360.0, 0.0),
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
damping: 0.9999,
|
||||
damping: 0.00001,
|
||||
dimensions: dimensions,
|
||||
color: color,
|
||||
animationURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/content/butterfly/butterfly.fbx",
|
||||
animationURL: "http://public.highfidelity.io/models/content/butterfly/butterfly.fbx",
|
||||
animationSettings: "{\"firstFrame\":0,\"fps\":" + newFrameRate + ",\"frameIndex\":0,\"hold\":false,\"lastFrame\":10000,\"loop\":true,\"running\":true,\"startAutomatically\":false}",
|
||||
modelURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/content/butterfly/butterfly.fbx"
|
||||
modelURL: "http://public.highfidelity.io/models/content/butterfly/butterfly.fbx"
|
||||
};
|
||||
butterflies.push(Entities.addEntity(properties));
|
||||
}
|
||||
|
@ -138,4 +138,4 @@ Script.scriptEnding.connect(function() {
|
|||
for (var i = 0; i < numButterflies; i++) {
|
||||
Entities.deleteEntity(butterflies[i]);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -64,7 +64,7 @@ function draw(deltaTime) {
|
|||
y: 1,
|
||||
z: 0 };
|
||||
|
||||
var entitySize = 0.1;
|
||||
var entitySize = 1.1;
|
||||
|
||||
print("number of entitys=" + numberEntitiesAdded +"\n");
|
||||
|
||||
|
@ -99,7 +99,7 @@ function draw(deltaTime) {
|
|||
Script.stop();
|
||||
}
|
||||
|
||||
print("Particles Stats: " + Entities.getLifetimeInSeconds() + " seconds," +
|
||||
print("Entity Stats: " + Entities.getLifetimeInSeconds() + " seconds," +
|
||||
" Queued packets:" + Entities.getLifetimePacketsQueued() + "," +
|
||||
" PPS:" + Entities.getLifetimePPSQueued() + "," +
|
||||
" BPS:" + Entities.getLifetimeBPSQueued() + "," +
|
|
@ -5,7 +5,7 @@
|
|||
// Created by Brad Hefta-Gaub on 12/31/13.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates creating and editing a particle
|
||||
// This is an example script that demonstrates creating and editing a particle. Go to the origin of the domain to see the results (0,0,0).
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -29,6 +29,11 @@ var originalProperties = {
|
|||
gravity: { x: 0,
|
||||
y: 0,
|
||||
z: 0 },
|
||||
dimensions: {
|
||||
x: 1,
|
||||
y: 1,
|
||||
z: 1
|
||||
},
|
||||
|
||||
|
||||
color: { red: 0,
|
||||
|
@ -74,7 +79,6 @@ function moveEntity(deltaTime) {
|
|||
y: originalProperties.position.y + (count * positionDelta.y),
|
||||
z: originalProperties.position.z + (count * positionDelta.z)
|
||||
},
|
||||
radius : 0.25,
|
||||
|
||||
};
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../../libraries/globals.js");
|
||||
|
||||
var count = 0;
|
||||
var moveUntil = 2000;
|
||||
|
@ -23,22 +23,22 @@ var roll = 180.0;
|
|||
var rotation = Quat.fromPitchYawRollDegrees(pitch, yaw, roll)
|
||||
|
||||
var originalProperties = {
|
||||
type: "Model",
|
||||
position: { x: 2.0,
|
||||
y: 2.0,
|
||||
z: 0.5 },
|
||||
|
||||
radius : 0.25,
|
||||
|
||||
color: { red: 0,
|
||||
dimensions: {
|
||||
x: 2.16,
|
||||
y: 3.34,
|
||||
z: 0.54
|
||||
},
|
||||
color: { red: 0,
|
||||
green: 255,
|
||||
blue: 0 },
|
||||
|
||||
modelURL: HIFI_PUBLIC_BUCKET + "meshes/Feisar_Ship.FBX",
|
||||
//modelURL: HIFI_PUBLIC_BUCKET + "meshes/birarda/birarda_head.fbx",
|
||||
//modelURL: HIFI_PUBLIC_BUCKET + "meshes/pug.fbx",
|
||||
//modelURL: HIFI_PUBLIC_BUCKET + "meshes/newInvader16x16-large-purple.svo",
|
||||
//modelURL: HIFI_PUBLIC_BUCKET + "meshes/minotaur/mino_full.fbx",
|
||||
//modelURL: HIFI_PUBLIC_BUCKET + "meshes/Combat_tank_V01.FBX",
|
||||
|
||||
|
||||
rotation: rotation
|
||||
};
|
||||
|
@ -67,10 +67,10 @@ function moveEntity(deltaTime) {
|
|||
return; // break early
|
||||
}
|
||||
|
||||
//print("count =" + count);
|
||||
print("count =" + count);
|
||||
count++;
|
||||
|
||||
//print("entityID.creatorTokenID = " + entityID.creatorTokenID);
|
||||
print("entityID.creatorTokenID = " + entityID.creatorTokenID);
|
||||
|
||||
var newProperties = {
|
||||
position: {
|
|
@ -11,30 +11,25 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("libraries/globals.js");
|
||||
Script.include("../libraries/globals.js");
|
||||
|
||||
var count = 0;
|
||||
var stopAfter = 100;
|
||||
var stopAfter = 1000;
|
||||
|
||||
var modelPropertiesA = {
|
||||
type: "Model",
|
||||
position: { x: 1, y: 1, z: 1 },
|
||||
velocity: { x: 0.5, y: 0, z: 0.5 },
|
||||
damping: 0,
|
||||
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
|
||||
dimensions: {
|
||||
x: 2.16,
|
||||
y: 3.34,
|
||||
z: 0.54
|
||||
},
|
||||
modelURL: HIFI_PUBLIC_BUCKET + "meshes/Feisar_Ship.FBX",
|
||||
lifetime: 20
|
||||
};
|
||||
|
||||
var modelPropertiesB = {
|
||||
type: "Model",
|
||||
position: { x: 1, y: 1.5, z: 1 },
|
||||
velocity: { x: 0.5, y: 0, z: 0.5 },
|
||||
damping: 0,
|
||||
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
|
||||
modelURL: HIFI_PUBLIC_BUCKET + "meshes/orc.fbx",
|
||||
lifetime: 20
|
||||
};
|
||||
|
||||
var ballProperties = {
|
||||
type: "Sphere",
|
||||
|
@ -47,7 +42,6 @@ var ballProperties = {
|
|||
};
|
||||
|
||||
var modelAEntityID = Entities.addEntity(modelPropertiesA);
|
||||
var modelBEntityID = Entities.addEntity(modelPropertiesB);
|
||||
var ballEntityID = Entities.addEntity(ballProperties);
|
||||
|
||||
function endAfterAWhile(deltaTime) {
|
|
@ -5,7 +5,7 @@
|
|||
// Created by Brad Hefta-Gaub on 3/4/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that generates particles that act like flocking birds
|
||||
// This is an example script that generates entities that act like flocking birds
|
||||
//
|
||||
// All birds, even flying solo...
|
||||
// birds don't like to fall too fast
|
|
@ -27,7 +27,7 @@ var lightID = Entities.addEntity({
|
|||
angularVelocity: { x: 0, y: 0, z: 0 },
|
||||
angularDamping: 0,
|
||||
|
||||
isSpotlight: false,
|
||||
isSpotlight: true,
|
||||
diffuseColor: { red: 255, green: 255, blue: 0 },
|
||||
ambientColor: { red: 0, green: 0, blue: 0 },
|
||||
specularColor: { red: 255, green: 255, blue: 255 },
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue