mirror of
https://github.com/lubosz/overte.git
synced 2025-04-27 13:55:26 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into virtualEntities
Conflicts: assignment-client/CMakeLists.txt interface/CMakeLists.txt libraries/entities/CMakeLists.txt libraries/models/src/ModelEditPacketSender.cpp libraries/models/src/ModelEditPacketSender.h libraries/models/src/ModelItem.cpp libraries/models/src/ModelItem.h libraries/octree/src/OctreeEditPacketSender.cpp libraries/octree/src/OctreeEditPacketSender.h libraries/octree/src/OctreePacketData.h libraries/octree/src/OctreeQuery.cpp libraries/particles/src/ParticleEditPacketSender.cpp libraries/particles/src/ParticleEditPacketSender.h libraries/script-engine/CMakeLists.txt tests/octree/CMakeLists.txt
This commit is contained in:
commit
32d5eb3cea
159 changed files with 4375 additions and 3623 deletions
CMakeLists.txt
assignment-client
cmake
macros
AutoMTC.cmakeIncludeGLM.cmakeIncludeHifiLibraryHeaders.cmakeLinkHifiLibraries.cmakeLinkHifiLibrary.cmakeLinkSharedDependencies.cmakeSetupHifiLibrary.cmakeSetupHifiProject.cmake
modules
domain-server
examples
interface
CMakeLists.txt
external/libovr
interface_en.tsresources/shaders
metavoxel_heightfield.vertmetavoxel_heightfield_cascaded_shadow_map.fragmetavoxel_heightfield_cursor.fragmetavoxel_heightfield_cursor.vertmetavoxel_heightfield_shadow_map.frag
src
Application.cppApplication.hAudio.cppAudio.hMenu.cppMenu.hMetavoxelSystem.cppMetavoxelSystem.h
avatar
devices
CaraFaceTracker.cppDdeFaceTracker.cppDdeFaceTracker.hOculusManager.cppOculusManager.hSixenseManager.cppSixenseManager.h
renderer
scripting
ui
ApplicationOverlay.cppApplicationOverlay.hMetavoxelEditor.cppMetavoxelEditor.hVoxelImportDialog.cppVoxelImportDialog.h
overlays
voxels
libraries
animation
audio
avatars
embedded-webserver
entities
fbx
metavoxels
networking
|
@ -44,6 +44,18 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|||
# Instruct CMake to run moc automatically when needed.
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
set(HIFI_LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries")
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
|
||||
|
||||
set(MACRO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros")
|
||||
|
||||
file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake")
|
||||
foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS})
|
||||
include(${CUSTOM_MACRO})
|
||||
endforeach()
|
||||
|
||||
# targets on all platforms
|
||||
add_subdirectory(assignment-client)
|
||||
add_subdirectory(domain-server)
|
||||
|
|
|
@ -1,47 +1,17 @@
|
|||
set(TARGET_NAME assignment-client)
|
||||
|
||||
set(ROOT_DIR ..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
setup_hifi_project(Core Gui Network Script Widgets)
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
|
||||
|
||||
find_package(Qt5 COMPONENTS Network Script Widgets)
|
||||
|
||||
include("${MACRO_DIR}/SetupHifiProject.cmake")
|
||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
|
||||
# include glm
|
||||
include("${MACRO_DIR}/IncludeGLM.cmake")
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
include_glm()
|
||||
|
||||
# link in the shared libraries
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(audio ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(avatars ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(entities ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(embedded-webserver ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_libraries(
|
||||
audio avatars octree voxels fbx particles entities metavoxels
|
||||
networking animation shared script-engine embedded-webserver
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})
|
||||
list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${CMAKE_DL_LIBS})
|
||||
endif (UNIX)
|
||||
|
||||
IF (WIN32)
|
||||
target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
|
||||
ENDIF(WIN32)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script)
|
||||
|
||||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
link_shared_dependencies()
|
||||
|
|
|
@ -115,7 +115,7 @@ void Agent::readPendingDatagrams() {
|
|||
sourceNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
QByteArray mutablePacket = receivedPacket;
|
||||
ssize_t messageLength = mutablePacket.size();
|
||||
int messageLength = mutablePacket.size();
|
||||
|
||||
if (datagramPacketType == PacketTypeOctreeStats) {
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QJsonValue>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
@ -52,6 +53,7 @@
|
|||
|
||||
#include "AudioRingBuffer.h"
|
||||
#include "AudioMixerClientData.h"
|
||||
#include "AudioMixerDatagramProcessor.h"
|
||||
#include "AvatarAudioStream.h"
|
||||
#include "InjectedAudioStream.h"
|
||||
|
||||
|
@ -71,6 +73,8 @@ bool AudioMixer::_useDynamicJitterBuffers = false;
|
|||
int AudioMixer::_staticDesiredJitterBufferFrames = 0;
|
||||
int AudioMixer::_maxFramesOverDesired = 0;
|
||||
|
||||
bool AudioMixer::_printStreamStats = false;
|
||||
|
||||
AudioMixer::AudioMixer(const QByteArray& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_trailingSleepRatio(1.0f),
|
||||
|
@ -295,38 +299,34 @@ void AudioMixer::prepareMixForListeningNode(Node* node) {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioMixer::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
// pull any new audio data from nodes off of the network stack
|
||||
PacketType mixerPacketType = packetTypeForPacket(receivedPacket);
|
||||
if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho
|
||||
|| mixerPacketType == PacketTypeMicrophoneAudioWithEcho
|
||||
|| mixerPacketType == PacketTypeInjectAudio
|
||||
|| mixerPacketType == PacketTypeSilentAudioFrame
|
||||
|| mixerPacketType == PacketTypeAudioStreamStats) {
|
||||
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
|
||||
} else if (mixerPacketType == PacketTypeMuteEnvironment) {
|
||||
QByteArray packet = receivedPacket;
|
||||
populatePacketHeader(packet, PacketTypeMuteEnvironment);
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) {
|
||||
nodeList->writeDatagram(packet, packet.size(), node);
|
||||
}
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
// pull any new audio data from nodes off of the network stack
|
||||
PacketType mixerPacketType = packetTypeForPacket(receivedPacket);
|
||||
if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho
|
||||
|| mixerPacketType == PacketTypeMicrophoneAudioWithEcho
|
||||
|| mixerPacketType == PacketTypeInjectAudio
|
||||
|| mixerPacketType == PacketTypeSilentAudioFrame
|
||||
|| mixerPacketType == PacketTypeAudioStreamStats) {
|
||||
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
|
||||
} else if (mixerPacketType == PacketTypeMuteEnvironment) {
|
||||
QByteArray packet = receivedPacket;
|
||||
populatePacketHeader(packet, PacketTypeMuteEnvironment);
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) {
|
||||
nodeList->writeDatagram(packet, packet.size(), node);
|
||||
}
|
||||
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioMixer::sendStatsPacket() {
|
||||
|
@ -390,7 +390,35 @@ void AudioMixer::run() {
|
|||
ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer);
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
|
||||
// we do not want this event loop to be the handler for UDP datagrams, so disconnect
|
||||
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||
|
||||
// setup a QThread with us as parent that will house the AudioMixerDatagramProcessor
|
||||
_datagramProcessingThread = new QThread(this);
|
||||
|
||||
// create an AudioMixerDatagramProcessor and move it to that thread
|
||||
AudioMixerDatagramProcessor* datagramProcessor = new AudioMixerDatagramProcessor(nodeList->getNodeSocket(), thread());
|
||||
datagramProcessor->moveToThread(_datagramProcessingThread);
|
||||
|
||||
// remove the NodeList as the parent of the node socket
|
||||
nodeList->getNodeSocket().setParent(NULL);
|
||||
nodeList->getNodeSocket().moveToThread(_datagramProcessingThread);
|
||||
|
||||
// let the datagram processor handle readyRead from node socket
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead,
|
||||
datagramProcessor, &AudioMixerDatagramProcessor::readPendingDatagrams);
|
||||
|
||||
// connect to the datagram processing thread signal that tells us we have to handle a packet
|
||||
connect(datagramProcessor, &AudioMixerDatagramProcessor::packetRequiresProcessing, this, &AudioMixer::readPendingDatagram);
|
||||
|
||||
// delete the datagram processor and the associated thread when the QThread quits
|
||||
connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater);
|
||||
connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater);
|
||||
|
||||
// start the datagram processing thread
|
||||
_datagramProcessingThread->start();
|
||||
|
||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||
|
||||
nodeList->linkedDataCreateCallback = attachNewNodeDataToNode;
|
||||
|
@ -448,7 +476,11 @@ void AudioMixer::run() {
|
|||
}
|
||||
qDebug() << "Max frames over desired:" << _maxFramesOverDesired;
|
||||
|
||||
|
||||
const QString PRINT_STREAM_STATS_JSON_KEY = "H-print-stream-stats";
|
||||
_printStreamStats = audioGroupObject[PRINT_STREAM_STATS_JSON_KEY].toBool();
|
||||
if (_printStreamStats) {
|
||||
qDebug() << "Stream stats will be printed to stdout";
|
||||
}
|
||||
|
||||
const QString UNATTENUATED_ZONE_KEY = "D-unattenuated-zone";
|
||||
|
||||
|
@ -547,6 +579,7 @@ void AudioMixer::run() {
|
|||
sendAudioStreamStats = true;
|
||||
}
|
||||
|
||||
bool streamStatsPrinted = false;
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
if (node->getLinkedData()) {
|
||||
AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData();
|
||||
|
@ -581,12 +614,21 @@ void AudioMixer::run() {
|
|||
// send an audio stream stats packet if it's time
|
||||
if (sendAudioStreamStats) {
|
||||
nodeData->sendAudioStreamStatsPackets(node);
|
||||
|
||||
if (_printStreamStats) {
|
||||
printf("\nStats for agent %s:\n", node->getUUID().toString().toLatin1().data());
|
||||
nodeData->printUpstreamDownstreamStats();
|
||||
streamStatsPrinted = true;
|
||||
}
|
||||
}
|
||||
|
||||
++_sumListeners;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (streamStatsPrinted) {
|
||||
printf("\n----------------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
++_numStatFrames;
|
||||
|
||||
|
|
|
@ -33,7 +33,8 @@ public slots:
|
|||
/// threaded run of assignment
|
||||
void run();
|
||||
|
||||
void readPendingDatagrams();
|
||||
void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle
|
||||
void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
|
||||
|
||||
void sendStatsPacket();
|
||||
|
||||
|
@ -66,6 +67,8 @@ private:
|
|||
static int _staticDesiredJitterBufferFrames;
|
||||
static int _maxFramesOverDesired;
|
||||
|
||||
static bool _printStreamStats;
|
||||
|
||||
quint64 _lastSendAudioStreamStatsTime;
|
||||
};
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
|
||||
AudioMixerClientData::AudioMixerClientData() :
|
||||
_audioStreams(),
|
||||
_outgoingMixedAudioSequenceNumber(0)
|
||||
_outgoingMixedAudioSequenceNumber(0),
|
||||
_downstreamAudioStreamStats()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -263,3 +264,45 @@ QString AudioMixerClientData::getAudioStreamStatsString() const {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void AudioMixerClientData::printUpstreamDownstreamStats() const {
|
||||
// print the upstream (mic stream) stats if the mic stream exists
|
||||
if (_audioStreams.contains(QUuid())) {
|
||||
printf("Upstream:\n");
|
||||
printAudioStreamStats(_audioStreams.value(QUuid())->getAudioStreamStats());
|
||||
}
|
||||
// print the downstream stats if they contain valid info
|
||||
if (_downstreamAudioStreamStats._packetStreamStats._received > 0) {
|
||||
printf("Downstream:\n");
|
||||
printAudioStreamStats(_downstreamAudioStreamStats);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const {
|
||||
printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n",
|
||||
streamStats._packetStreamStats.getLostRate() * 100.0f,
|
||||
streamStats._packetStreamStats._lost,
|
||||
streamStats._packetStreamWindowStats.getLostRate() * 100.0f,
|
||||
streamStats._packetStreamWindowStats._lost);
|
||||
|
||||
printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n",
|
||||
streamStats._desiredJitterBufferFrames,
|
||||
streamStats._framesAvailableAverage,
|
||||
streamStats._framesAvailable);
|
||||
|
||||
printf(" Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u\n",
|
||||
streamStats._starveCount,
|
||||
streamStats._consecutiveNotMixedCount,
|
||||
streamStats._framesDropped,
|
||||
streamStats._overflowCount);
|
||||
|
||||
printf(" Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s\n",
|
||||
formatUsecTime(streamStats._timeGapMin).toLatin1().data(),
|
||||
formatUsecTime(streamStats._timeGapMax).toLatin1().data(),
|
||||
formatUsecTime(streamStats._timeGapAverage).toLatin1().data());
|
||||
|
||||
printf(" Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s\n",
|
||||
formatUsecTime(streamStats._timeGapWindowMin).toLatin1().data(),
|
||||
formatUsecTime(streamStats._timeGapWindowMax).toLatin1().data(),
|
||||
formatUsecTime(streamStats._timeGapWindowAverage).toLatin1().data());
|
||||
}
|
||||
|
|
|
@ -38,6 +38,11 @@ public:
|
|||
void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; }
|
||||
quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; }
|
||||
|
||||
void printUpstreamDownstreamStats() const;
|
||||
|
||||
private:
|
||||
void printAudioStreamStats(const AudioStreamStats& streamStats) const;
|
||||
|
||||
private:
|
||||
QHash<QUuid, PositionalAudioStream*> _audioStreams; // mic stream stored under key of null UUID
|
||||
|
||||
|
|
47
assignment-client/src/audio/AudioMixerDatagramProcessor.cpp
Normal file
47
assignment-client/src/audio/AudioMixerDatagramProcessor.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// AudioMixerDatagramProcessor.cpp
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-08-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
|
||||
//
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <HifiSockAddr.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "AudioMixerDatagramProcessor.h"
|
||||
|
||||
AudioMixerDatagramProcessor::AudioMixerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread) :
|
||||
_nodeSocket(nodeSocket),
|
||||
_previousNodeSocketThread(previousNodeSocketThread)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AudioMixerDatagramProcessor::~AudioMixerDatagramProcessor() {
|
||||
// return the node socket to its previous thread
|
||||
_nodeSocket.moveToThread(_previousNodeSocketThread);
|
||||
}
|
||||
|
||||
void AudioMixerDatagramProcessor::readPendingDatagrams() {
|
||||
|
||||
HifiSockAddr senderSockAddr;
|
||||
static QByteArray incomingPacket;
|
||||
|
||||
// read everything that is available
|
||||
while (_nodeSocket.hasPendingDatagrams()) {
|
||||
incomingPacket.resize(_nodeSocket.pendingDatagramSize());
|
||||
|
||||
// just get this packet off the stack
|
||||
_nodeSocket.readDatagram(incomingPacket.data(), incomingPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
|
||||
// emit the signal to tell AudioMixer it needs to process a packet
|
||||
emit packetRequiresProcessing(incomingPacket, senderSockAddr);
|
||||
}
|
||||
}
|
32
assignment-client/src/audio/AudioMixerDatagramProcessor.h
Normal file
32
assignment-client/src/audio/AudioMixerDatagramProcessor.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// AudioMixerDatagramProcessor.h
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-08-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
|
||||
//
|
||||
|
||||
#ifndef hifi_AudioMixerDatagramProcessor_h
|
||||
#define hifi_AudioMixerDatagramProcessor_h
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qudpsocket.h>
|
||||
|
||||
class AudioMixerDatagramProcessor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AudioMixerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread);
|
||||
~AudioMixerDatagramProcessor();
|
||||
public slots:
|
||||
void readPendingDatagrams();
|
||||
signals:
|
||||
void packetRequiresProcessing(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
|
||||
private:
|
||||
QUdpSocket& _nodeSocket;
|
||||
QThread* _previousNodeSocketThread;
|
||||
};
|
||||
|
||||
#endif // hifi_AudioMixerDatagramProcessor_h
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include <QThread>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include "ScriptableAvatar.h"
|
||||
|
||||
ScriptableAvatar::ScriptableAvatar(ScriptEngine* scriptEngine) : _scriptEngine(scriptEngine), _animation(NULL) {
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(AUTO_MTC TARGET ROOT_DIR)
|
||||
set(AUTOMTC_SRC ${TARGET}_automtc.cpp)
|
||||
macro(AUTO_MTC)
|
||||
set(AUTOMTC_SRC ${TARGET_NAME}_automtc.cpp)
|
||||
|
||||
file(GLOB INCLUDE_FILES src/*.h)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(INCLUDE_GLM TARGET ROOT_DIR)
|
||||
macro(INCLUDE_GLM)
|
||||
|
||||
find_package(GLM REQUIRED)
|
||||
include_directories("${GLM_INCLUDE_DIRS}")
|
||||
|
@ -16,4 +16,4 @@ macro(INCLUDE_GLM TARGET ROOT_DIR)
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${GLM_INCLUDE_DIRS}")
|
||||
endif ()
|
||||
|
||||
endmacro(INCLUDE_GLM _target _root_dir)
|
||||
endmacro(INCLUDE_GLM)
|
14
cmake/macros/IncludeHifiLibraryHeaders.cmake
Normal file
14
cmake/macros/IncludeHifiLibraryHeaders.cmake
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# IncludeHifiLibraryHeaders.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on August 8, 2014
|
||||
#
|
||||
# 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_hifi_library_headers LIBRARY)
|
||||
include_directories("${HIFI_LIBRARY_DIR}/${LIBRARY}/src")
|
||||
endmacro(include_hifi_library_headers _library _root_dir)
|
34
cmake/macros/LinkHifiLibraries.cmake
Normal file
34
cmake/macros/LinkHifiLibraries.cmake
Normal file
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# LinkHifiLibrary.cmake
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
macro(LINK_HIFI_LIBRARIES)
|
||||
|
||||
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
|
||||
|
||||
set(LIBRARIES_TO_LINK ${ARGN})
|
||||
|
||||
foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK})
|
||||
if (NOT TARGET ${HIFI_LIBRARY})
|
||||
add_subdirectory("${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}" "${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}")
|
||||
endif ()
|
||||
|
||||
include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src")
|
||||
|
||||
add_dependencies(${TARGET_NAME} ${HIFI_LIBRARY})
|
||||
|
||||
# link the actual library - it is static so don't bubble it up
|
||||
target_link_libraries(${TARGET_NAME} ${HIFI_LIBRARY})
|
||||
|
||||
# ask the library what its dynamic dependencies are and link them
|
||||
get_target_property(LINKED_TARGET_DEPENDENCY_LIBRARIES ${HIFI_LIBRARY} DEPENDENCY_LIBRARIES)
|
||||
list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${LINKED_TARGET_DEPENDENCY_LIBRARIES})
|
||||
|
||||
endforeach()
|
||||
|
||||
endmacro(LINK_HIFI_LIBRARIES)
|
|
@ -1,27 +0,0 @@
|
|||
#
|
||||
# LinkHifiLibrary.cmake
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
macro(LINK_HIFI_LIBRARY LIBRARY TARGET ROOT_DIR)
|
||||
|
||||
if (NOT TARGET ${LIBRARY})
|
||||
add_subdirectory("${ROOT_DIR}/libraries/${LIBRARY}" "${ROOT_DIR}/libraries/${LIBRARY}")
|
||||
endif ()
|
||||
|
||||
include_directories("${ROOT_DIR}/libraries/${LIBRARY}/src")
|
||||
|
||||
add_dependencies(${TARGET} ${LIBRARY})
|
||||
target_link_libraries(${TARGET} ${LIBRARY})
|
||||
|
||||
if (APPLE)
|
||||
# currently the "shared" library requires CoreServices
|
||||
# link in required OS X framework
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework CoreServices")
|
||||
endif ()
|
||||
|
||||
endmacro(LINK_HIFI_LIBRARY _library _target _root_dir)
|
25
cmake/macros/LinkSharedDependencies.cmake
Normal file
25
cmake/macros/LinkSharedDependencies.cmake
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
# LinkSharedDependencies.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on August 8, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(LINK_SHARED_DEPENDENCIES)
|
||||
if (${TARGET_NAME}_LIBRARIES_TO_LINK)
|
||||
list(REMOVE_DUPLICATES ${TARGET_NAME}_LIBRARIES_TO_LINK)
|
||||
|
||||
# link these libraries to our target
|
||||
target_link_libraries(${TARGET_NAME} ${${TARGET_NAME}_LIBRARIES_TO_LINK})
|
||||
endif ()
|
||||
|
||||
# we've already linked our Qt modules, but we need to bubble them up to parents
|
||||
list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${${TARGET}_QT_MODULES_TO_LINK}")
|
||||
|
||||
# set the property on this target so it can be retreived by targets linking to us
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${${TARGET}_LIBRARIES_TO_LINK}")
|
||||
endmacro(LINK_SHARED_DEPENDENCIES)
|
|
@ -7,20 +7,27 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(SETUP_HIFI_LIBRARY TARGET)
|
||||
macro(SETUP_HIFI_LIBRARY)
|
||||
|
||||
project(${TARGET})
|
||||
project(${TARGET_NAME})
|
||||
|
||||
# grab the implemenation and header files
|
||||
file(GLOB LIB_SRCS src/*.h src/*.cpp)
|
||||
set(LIB_SRCS ${LIB_SRCS} ${WRAPPED_SRCS})
|
||||
set(LIB_SRCS ${LIB_SRCS})
|
||||
|
||||
# create a library and set the property so it can be referenced later
|
||||
add_library(${TARGET} ${LIB_SRCS} ${ARGN})
|
||||
add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOMTC_SRC})
|
||||
|
||||
find_package(Qt5Core REQUIRED)
|
||||
qt5_use_modules(${TARGET} Core)
|
||||
|
||||
target_link_libraries(${TARGET} ${QT_LIBRARIES})
|
||||
|
||||
endmacro(SETUP_HIFI_LIBRARY _target)
|
||||
set(QT_MODULES_TO_LINK ${ARGN})
|
||||
list(APPEND QT_MODULES_TO_LINK Core)
|
||||
|
||||
find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK} REQUIRED)
|
||||
|
||||
foreach(QT_MODULE ${QT_MODULES_TO_LINK})
|
||||
get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION)
|
||||
|
||||
# add the actual path to the Qt module to our LIBRARIES_TO_LINK variable
|
||||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
||||
list(APPEND ${TARGET_NAME}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION})
|
||||
endforeach()
|
||||
endmacro(SETUP_HIFI_LIBRARY)
|
|
@ -7,8 +7,8 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(SETUP_HIFI_PROJECT TARGET INCLUDE_QT)
|
||||
project(${TARGET})
|
||||
macro(SETUP_HIFI_PROJECT)
|
||||
project(${TARGET_NAME})
|
||||
|
||||
# grab the implemenation and header files
|
||||
file(GLOB TARGET_SRCS src/*)
|
||||
|
@ -23,12 +23,19 @@ macro(SETUP_HIFI_PROJECT TARGET INCLUDE_QT)
|
|||
endforeach()
|
||||
|
||||
# add the executable, include additional optional sources
|
||||
add_executable(${TARGET} ${TARGET_SRCS} ${ARGN})
|
||||
add_executable(${TARGET_NAME} ${TARGET_SRCS} "${AUTOMTC_SRC}")
|
||||
|
||||
if (${INCLUDE_QT})
|
||||
find_package(Qt5Core REQUIRED)
|
||||
qt5_use_modules(${TARGET} Core)
|
||||
endif ()
|
||||
set(QT_MODULES_TO_LINK ${ARGN})
|
||||
list(APPEND QT_MODULES_TO_LINK Core)
|
||||
|
||||
find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK} REQUIRED)
|
||||
|
||||
foreach(QT_MODULE ${QT_MODULES_TO_LINK})
|
||||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
||||
|
||||
# add the actual path to the Qt module to our LIBRARIES_TO_LINK variable
|
||||
get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION)
|
||||
list(APPEND ${TARGET_NAME}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION})
|
||||
endforeach()
|
||||
|
||||
target_link_libraries(${TARGET} ${QT_LIBRARIES})
|
||||
endmacro()
|
29
cmake/modules/FindATL.cmake
Normal file
29
cmake/modules/FindATL.cmake
Normal file
|
@ -0,0 +1,29 @@
|
|||
#
|
||||
# FindATL.cmake
|
||||
#
|
||||
# Try to find the ATL library needed to use the LibOVR
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# ATL_FOUND - system found ATL
|
||||
# ATL_LIBRARIES - Link this to use ATL
|
||||
#
|
||||
# Created on 8/13/2013 by Stephen Birarda
|
||||
# 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
|
||||
#
|
||||
|
||||
if (WIN32)
|
||||
find_library(ATL_LIBRARY_RELEASE atls PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK")
|
||||
find_library(ATL_LIBRARY_DEBUG atlsd PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK")
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(ATL)
|
||||
endif ()
|
||||
|
||||
set(ATL_LIBRARIES "${ATL_LIBRARY}")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ATL DEFAULT_MSG ATL_LIBRARIES)
|
|
@ -19,6 +19,6 @@ if (WIN32)
|
|||
endif (WIN32)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(FACEPLUS DEFAULT_MSG FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES)
|
||||
find_package_handle_standard_args(Faceplus DEFAULT_MSG FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES)
|
||||
|
||||
mark_as_advanced(FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES)
|
|
@ -40,6 +40,6 @@ select_library_configurations(FACESHIFT)
|
|||
set(FACESHIFT_LIBRARIES ${FACESHIFT_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(FACESHIFT DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES)
|
||||
find_package_handle_standard_args(Faceshift DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES)
|
||||
|
||||
mark_as_advanced(FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES FACESHIFT_SEARCH_DIRS)
|
|
@ -30,6 +30,6 @@ select_library_configurations(LEAPMOTION)
|
|||
set(LEAPMOTION_LIBRARIES "${LEAPMOTION_LIBRARY}")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LEAPMOTION DEFAULT_MSG LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES)
|
||||
find_package_handle_standard_args(LeapMotion DEFAULT_MSG LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES)
|
||||
|
||||
mark_as_advanced(LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES LEAPMOTION_SEARCH_DIRS)
|
||||
|
|
|
@ -19,16 +19,18 @@
|
|||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("oculus")
|
||||
hifi_library_search_hints("libovr")
|
||||
|
||||
find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${OCULUS_SEARCH_DIRS})
|
||||
find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${OCULUS_SEARCH_DIRS})
|
||||
find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${LIBOVR_SEARCH_DIRS})
|
||||
find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${LIBOVR_SEARCH_DIRS})
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
|
||||
if (APPLE)
|
||||
find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/MacOS/Debug HINTS ${OCULUS_SEARCH_DIRS})
|
||||
find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/MacOS/Release HINTS ${OCULUS_SEARCH_DIRS})
|
||||
find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Mac/Debug HINTS ${LIBOVR_SEARCH_DIRS})
|
||||
find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Mac/Release HINTS ${LIBOVR_SEARCH_DIRS})
|
||||
find_library(ApplicationServices ApplicationServices)
|
||||
find_library(IOKit IOKit)
|
||||
elseif (UNIX)
|
||||
find_library(UDEV_LIBRARY_RELEASE udev /usr/lib/x86_64-linux-gnu/)
|
||||
find_library(XINERAMA_LIBRARY_RELEASE Xinerama /usr/lib/x86_64-linux-gnu/)
|
||||
|
@ -39,29 +41,36 @@ elseif (UNIX)
|
|||
set(LINUX_ARCH_DIR "x86_64")
|
||||
endif()
|
||||
|
||||
find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Linux/Debug/${LINUX_ARCH_DIR} HINTS ${OCULUS_SEARCH_DIRS})
|
||||
find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Linux/Release/${LINUX_ARCH_DIR} HINTS ${OCULUS_SEARCH_DIRS})
|
||||
find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Linux/Debug/${LINUX_ARCH_DIR} HINTS ${LIBOVR_SEARCH_DIRS})
|
||||
find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Linux/Release/${LINUX_ARCH_DIR} HINTS ${LIBOVR_SEARCH_DIRS})
|
||||
|
||||
select_library_configurations(UDEV)
|
||||
select_library_configurations(XINERAMA)
|
||||
|
||||
elseif (WIN32)
|
||||
find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${OCULUS_SEARCH_DIRS})
|
||||
find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${OCULUS_SEARCH_DIRS})
|
||||
find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
|
||||
find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
|
||||
find_package(ATL)
|
||||
endif ()
|
||||
|
||||
select_library_configurations(LIBOVR)
|
||||
set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARY}")
|
||||
set(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY})
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARIES}" "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}")
|
||||
list(APPEND LIBOVR_ARGS_LIST LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARY)
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND LIBOVR_LIBRARIES ${IOKit} ${ApplicationServices})
|
||||
list(APPEND LIBOVR_ARGS_LIST IOKit ApplicationServices)
|
||||
elseif (UNIX)
|
||||
list(APPEND LIBOVR_LIBRARIES "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}")
|
||||
list(APPEND LIBOVR_ARGS_LIST UDEV_LIBRARY XINERAMA_LIBRARY)
|
||||
elseif (WIN32)
|
||||
list(APPEND LIBOVR_LIBRARIES ${ATL_LIBRARIES})
|
||||
list(APPEND LIBOVR_ARGS_LIST ATL_LIBRARIES)
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES UDEV_LIBRARY XINERAMA_LIBRARY)
|
||||
else ()
|
||||
find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES)
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES OCULUS_SEARCH_DIRS)
|
||||
find_package_handle_standard_args(LibOVR DEFAULT_MSG ${LIBOVR_ARGS_LIST})
|
||||
|
||||
mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES LIBOVR_SEARCH_DIRS)
|
||||
|
|
|
@ -19,6 +19,6 @@ if (WIN32)
|
|||
endif (WIN32)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(PRIOVR DEFAULT_MSG PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)
|
||||
find_package_handle_standard_args(PrioVR DEFAULT_MSG PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)
|
||||
|
||||
mark_as_advanced(PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)
|
|
@ -26,12 +26,14 @@ find_path(QXMPP_INCLUDE_DIRS QXmppClient.h PATH_SUFFIXES include/qxmpp HINTS ${Q
|
|||
find_library(QXMPP_LIBRARY_RELEASE NAMES qxmpp PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})
|
||||
find_library(QXMPP_LIBRARY_DEBUG NAMES qxmpp_d PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})
|
||||
|
||||
find_package(Qt5 COMPONENTS Xml REQUIRED)
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(QXMPP)
|
||||
|
||||
set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}")
|
||||
set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}" Qt5::Xml)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(QXMPP DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES)
|
||||
find_package_handle_standard_args(QXmpp DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_LIBRARY)
|
||||
|
||||
mark_as_advanced(QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_SEARCH_DIRS)
|
|
@ -25,6 +25,6 @@ find_path(RTMIDI_INCLUDE_DIRS RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEAR
|
|||
find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES)
|
||||
find_package_handle_standard_args(RtMidi DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES)
|
||||
|
||||
mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES RTMIDI_SEARCH_DIRS)
|
|
@ -40,6 +40,6 @@ select_library_configurations(SIXENSE)
|
|||
set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(SIXENSE DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
|
||||
find_package_handle_standard_args(Sixense DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
|
||||
|
||||
mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS)
|
||||
|
|
|
@ -32,6 +32,9 @@ if (APPLE)
|
|||
find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS})
|
||||
find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib HINTS ${VISAGE_SEARCH_DIRS})
|
||||
|
||||
find_library(AppKit AppKit)
|
||||
find_library(QuartzCore QuartzCore)
|
||||
find_library(QTKit QTKit)
|
||||
elseif (WIN32)
|
||||
find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS})
|
||||
find_path(VISAGE_OPENCV_INCLUDE_DIR opencv/cv.h PATH_SUFFIXES dependencies/OpenCV/include HINTS ${VISAGE_SEARCH_DIRS})
|
||||
|
@ -43,16 +46,22 @@ elseif (WIN32)
|
|||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(VISAGE DEFAULT_MSG
|
||||
VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR
|
||||
VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY
|
||||
)
|
||||
|
||||
list(APPEND VISAGE_ARGS_LIST VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR
|
||||
VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR
|
||||
VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY)
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND VISAGE_ARGS_LIST QuartzCore AppKit QTKit)
|
||||
endif ()
|
||||
|
||||
find_package_handle_standard_args(Visage DEFAULT_MSG ${VISAGE_ARGS_LIST})
|
||||
|
||||
set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR}" "${VISAGE_OPENCV2_INCLUDE_DIR}" "${VISAGE_BASE_INCLUDE_DIR}")
|
||||
set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}")
|
||||
|
||||
mark_as_advanced(
|
||||
VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES
|
||||
VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR
|
||||
VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY VISAGE_SEARCH_DIRS
|
||||
)
|
||||
if (APPLE)
|
||||
list(APPEND VISAGE_LIBRARIES ${QuartzCore} ${AppKit} ${QTKit})
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES)
|
||||
|
|
|
@ -1,24 +1,7 @@
|
|||
if (WIN32)
|
||||
cmake_policy (SET CMP0020 NEW)
|
||||
endif (WIN32)
|
||||
|
||||
set(TARGET_NAME domain-server)
|
||||
|
||||
set(ROOT_DIR ..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
|
||||
|
||||
# set up the external glm library
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
find_package(Qt5Network REQUIRED)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||
|
||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
# setup the project and link required Qt modules
|
||||
setup_hifi_project(Network)
|
||||
|
||||
# remove and then copy the files for the webserver
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
|
@ -29,20 +12,7 @@ add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
|||
"${PROJECT_SOURCE_DIR}/resources/web"
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>/resources/web)
|
||||
|
||||
# link the shared hifi library
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(embedded-webserver ${TARGET_NAME} "${ROOT_DIR}")
|
||||
# link the shared hifi libraries
|
||||
link_hifi_libraries(embedded-webserver networking shared)
|
||||
|
||||
IF (WIN32)
|
||||
target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
|
||||
ENDIF(WIN32)
|
||||
|
||||
# link QtNetwork
|
||||
target_link_libraries(${TARGET_NAME} Qt5::Network)
|
||||
|
||||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
link_shared_dependencies()
|
|
@ -21,6 +21,12 @@
|
|||
"placeholder": "10",
|
||||
"default": "10"
|
||||
},
|
||||
"H-print-stream-stats": {
|
||||
"type": "checkbox",
|
||||
"label": "Print Stream Stats:",
|
||||
"help": "If enabled, audio upstream and downstream stats of each agent will be printed each second to stdout",
|
||||
"default": false
|
||||
},
|
||||
"D-unattenuated-zone": {
|
||||
"label": "Unattenuated Zone",
|
||||
"help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)",
|
||||
|
|
|
@ -24,6 +24,7 @@ function setupMenus() {
|
|||
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");
|
||||
|
||||
|
@ -32,6 +33,7 @@ function setupMenus() {
|
|||
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" });
|
||||
|
@ -60,7 +62,6 @@ function menuItemEvent(menuItem) {
|
|||
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);
|
||||
|
@ -73,6 +74,12 @@ function menuItemEvent(menuItem) {
|
|||
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", {
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
set(ROOT_DIR ..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
|
||||
set(TARGET_NAME interface)
|
||||
project(${TARGET_NAME})
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "faceplus" "faceshift" "oculus" "priovr" "sixense" "visage" "leapmotion" "rtmidi" "qxmpp")
|
||||
set(OPTIONAL_EXTERNALS "Faceplus" "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp")
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL)
|
||||
if (NOT ${UPPER_EXTERNAL}_ROOT_DIR)
|
||||
set(${UPPER_EXTERNAL}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${EXTERNAL}")
|
||||
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
|
||||
string(TOLOWER ${EXTERNAL} ${EXTERNAL}_LOWERCASE)
|
||||
set(${${EXTERNAL}_UPPERCASE}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${${EXTERNAL}_LOWERCASE}")
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
|
@ -38,8 +33,7 @@ elseif (WIN32)
|
|||
endif ()
|
||||
|
||||
# set up the external glm library
|
||||
include("${MACRO_DIR}/IncludeGLM.cmake")
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
include_glm()
|
||||
|
||||
# create the InterfaceConfig.h file based on GL_HEADERS above
|
||||
configure_file(InterfaceConfig.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceConfig.h")
|
||||
|
@ -52,7 +46,7 @@ foreach(SUBDIR avatar devices renderer ui starfield location scripting voxels pa
|
|||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}")
|
||||
endforeach(SUBDIR)
|
||||
|
||||
find_package(Qt5 COMPONENTS Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets Xml UiTools)
|
||||
find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Script Svg WebKitWidgets)
|
||||
|
||||
# grab the ui files in resources/ui
|
||||
file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
|
||||
|
@ -97,60 +91,36 @@ endif()
|
|||
# create the executable, make it a bundle on OS X
|
||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
|
||||
|
||||
# link in the hifi shared library
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(entities ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(avatars ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(audio ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_libraries(shared octree voxels fbx metavoxels networking particles entities avatars audio animation script-engine)
|
||||
|
||||
# find any optional and required libraries
|
||||
find_package(Faceplus)
|
||||
find_package(Faceshift)
|
||||
find_package(LibOVR)
|
||||
find_package(PrioVR)
|
||||
find_package(SDL)
|
||||
find_package(Sixense)
|
||||
find_package(Visage)
|
||||
find_package(LeapMotion)
|
||||
find_package(ZLIB)
|
||||
find_package(Qxmpp)
|
||||
find_package(RtMidi)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
# perform standard include and linking for found externals
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL)
|
||||
|
||||
if (${UPPER_EXTERNAL} MATCHES "OCULUS")
|
||||
# the oculus directory is named OCULUS and not LIBOVR so hack to fix that here
|
||||
set(UPPER_EXTERNAL "LIBOVR")
|
||||
if (${${EXTERNAL}_UPPERCASE}_REQUIRED)
|
||||
find_package(${EXTERNAL} REQUIRED)
|
||||
else ()
|
||||
find_package(${EXTERNAL})
|
||||
endif ()
|
||||
|
||||
if (${UPPER_EXTERNAL}_FOUND AND NOT DISABLE_${UPPER_EXTERNAL})
|
||||
add_definitions(-DHAVE_${UPPER_EXTERNAL})
|
||||
if (${${EXTERNAL}_UPPERCASE}_FOUND AND NOT DISABLE_${${EXTERNAL}_UPPERCASE})
|
||||
add_definitions(-DHAVE_${${EXTERNAL}_UPPERCASE})
|
||||
|
||||
# include the library directories (ignoring warnings)
|
||||
include_directories(SYSTEM ${${UPPER_EXTERNAL}_INCLUDE_DIRS})
|
||||
include_directories(SYSTEM ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
|
||||
|
||||
# perform the system include hack for OS X to ignore warnings
|
||||
if (APPLE)
|
||||
foreach(EXTERNAL_INCLUDE_DIR ${${UPPER_EXTERNAL}_INCLUDE_DIRS})
|
||||
foreach(EXTERNAL_INCLUDE_DIR ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${EXTERNAL_INCLUDE_DIR}")
|
||||
endforeach()
|
||||
endif ()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${${UPPER_EXTERNAL}_LIBRARIES})
|
||||
target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES})
|
||||
|
||||
endif ()
|
||||
endforeach()
|
||||
|
@ -179,17 +149,11 @@ endif ()
|
|||
|
||||
# include headers for interface and InterfaceConfig.
|
||||
include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes")
|
||||
|
||||
# include external library headers
|
||||
# use system flag so warnings are supressed
|
||||
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
||||
include_directories("${OPENSSL_INCLUDE_DIR}")
|
||||
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
"${ZLIB_LIBRARIES}"
|
||||
${OPENSSL_LIBRARIES}
|
||||
Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::Network Qt5::OpenGL
|
||||
Qt5::Script Qt5::Svg Qt5::WebKit Qt5::WebKitWidgets Qt5::Xml Qt5::UiTools
|
||||
${TARGET_NAME} ${ZLIB_LIBRARIES} ${OPENSSL_LIBRARIES}
|
||||
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets
|
||||
)
|
||||
|
||||
# assume we are using a Qt build without bearer management
|
||||
|
@ -197,30 +161,12 @@ add_definitions(-DQT_NO_BEARERMANAGEMENT)
|
|||
|
||||
if (APPLE)
|
||||
# link in required OS X frameworks and include the right GL headers
|
||||
find_library(AppKit AppKit)
|
||||
find_library(CoreAudio CoreAudio)
|
||||
find_library(CoreServices CoreServices)
|
||||
find_library(Carbon Carbon)
|
||||
find_library(Foundation Foundation)
|
||||
find_library(CoreFoundation CoreFoundation)
|
||||
find_library(GLUT GLUT)
|
||||
find_library(OpenGL OpenGL)
|
||||
find_library(IOKit IOKit)
|
||||
find_library(QTKit QTKit)
|
||||
find_library(QuartzCore QuartzCore)
|
||||
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
${AppKit}
|
||||
${CoreAudio}
|
||||
${CoreServices}
|
||||
${Carbon}
|
||||
${Foundation}
|
||||
${GLUT}
|
||||
${OpenGL}
|
||||
${IOKit}
|
||||
${QTKit}
|
||||
${QuartzCore}
|
||||
)
|
||||
target_link_libraries(${TARGET_NAME} ${CoreAudio} ${CoreFoundation} ${GLUT} ${OpenGL})
|
||||
|
||||
# install command for OS X bundle
|
||||
INSTALL(TARGETS ${TARGET_NAME}
|
||||
|
@ -254,9 +200,9 @@ else (APPLE)
|
|||
# we're using static GLEW, so define GLEW_STATIC
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
|
||||
# add a definition for ssize_t so that windows doesn't bail
|
||||
add_definitions(-Dssize_t=long)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib)
|
||||
endif()
|
||||
endif (APPLE)
|
||||
|
||||
# link any dependencies bubbled up from our linked dependencies
|
||||
link_shared_dependencies()
|
||||
|
|
|
@ -245,28 +245,28 @@
|
|||
<context>
|
||||
<name>QObject</name>
|
||||
<message>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="22"/>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="23"/>
|
||||
<location filename="src/ui/VoxelImportDialog.cpp" line="22"/>
|
||||
<location filename="src/ui/VoxelImportDialog.cpp" line="23"/>
|
||||
<source>Import Voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="24"/>
|
||||
<location filename="src/ui/VoxelImportDialog.cpp" line="24"/>
|
||||
<source>Loading ...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="25"/>
|
||||
<location filename="src/ui/VoxelImportDialog.cpp" line="25"/>
|
||||
<source>Place voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="26"/>
|
||||
<location filename="src/ui/VoxelImportDialog.cpp" line="26"/>
|
||||
<source><b>Import</b> %1 as voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="27"/>
|
||||
<location filename="src/ui/VoxelImportDialog.cpp" line="27"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
|
|
@ -17,6 +17,12 @@ uniform sampler2D heightMap;
|
|||
// the distance between height points in texture space
|
||||
uniform float heightScale;
|
||||
|
||||
// the scale between height and color textures
|
||||
uniform float colorScale;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
|
@ -29,13 +35,17 @@ void main(void) {
|
|||
texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r;
|
||||
normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0));
|
||||
|
||||
// pass along the texture coordinates
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
|
||||
// add the height to the position
|
||||
float height = texture2D(heightMap, heightCoord).r;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));
|
||||
position = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));
|
||||
gl_Position = gl_ProjectionMatrix * position;
|
||||
|
||||
// the zero height should be invisible
|
||||
gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0));
|
||||
|
||||
// pass along the scaled/offset texture coordinates
|
||||
gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale;
|
||||
|
||||
// and the shadow texture coordinates
|
||||
gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heightfield.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 7/28/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
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the distances to the cascade sections
|
||||
uniform vec3 shadowDistances;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// compute the index of the cascade to use and the corresponding texture coordinates
|
||||
int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
||||
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
|
||||
dot(gl_EyePlaneR[shadowIndex], position));
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
float diffuse = dot(normalize(normal), gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heightfield_cursor.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 8/7/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
|
||||
//
|
||||
|
||||
// the inner radius of the outline, squared
|
||||
const float SQUARED_OUTLINE_INNER_RADIUS = 0.81;
|
||||
|
||||
// the outer radius of the outline, squared
|
||||
const float SQUARED_OUTLINE_OUTER_RADIUS = 1.0;
|
||||
|
||||
// the inner radius of the inset, squared
|
||||
const float SQUARED_INSET_INNER_RADIUS = 0.855625;
|
||||
|
||||
// the outer radius of the inset, squared
|
||||
const float SQUARED_INSET_OUTER_RADIUS = 0.950625;
|
||||
|
||||
void main(void) {
|
||||
// use the distance to compute the ring color, then multiply it by the varying color
|
||||
float squaredDistance = dot(gl_TexCoord[0].st, gl_TexCoord[0].st);
|
||||
float alpha = step(SQUARED_OUTLINE_INNER_RADIUS, squaredDistance) * step(squaredDistance, SQUARED_OUTLINE_OUTER_RADIUS);
|
||||
float white = step(SQUARED_INSET_INNER_RADIUS, squaredDistance) * step(squaredDistance, SQUARED_INSET_OUTER_RADIUS);
|
||||
gl_FragColor = gl_Color * vec4(white, white, white, alpha);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heighfield_cursor.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 8/7/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
|
||||
//
|
||||
|
||||
// the height texture
|
||||
uniform sampler2D heightMap;
|
||||
|
||||
void main(void) {
|
||||
// compute the view space coordinates
|
||||
float height = texture2D(heightMap, gl_MultiTexCoord0.st).r;
|
||||
vec4 viewPosition = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));
|
||||
gl_Position = gl_ProjectionMatrix * viewPosition;
|
||||
|
||||
// generate the texture coordinates from the view position
|
||||
gl_TexCoord[0] = vec4(dot(viewPosition, gl_EyePlaneS[4]), dot(viewPosition, gl_EyePlaneT[4]), 0.0, 1.0);
|
||||
|
||||
// the zero height should be invisible
|
||||
gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0 - step(height, 0.0));
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_heightfield.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 7/28/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
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// compute the base color based on OpenGL lighting model
|
||||
float diffuse = dot(normalize(normal), gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
}
|
|
@ -137,7 +137,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
_frameCount(0),
|
||||
_fps(60.0f),
|
||||
_justStarted(true),
|
||||
_voxelImporter(NULL),
|
||||
_voxelImportDialog(NULL),
|
||||
_voxelImporter(),
|
||||
_importSucceded(false),
|
||||
_sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard),
|
||||
_entityClipboardRenderer(),
|
||||
|
@ -242,6 +243,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
||||
connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&)));
|
||||
connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle()));
|
||||
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
|
||||
connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived);
|
||||
|
||||
// hookup VoxelEditSender to PaymentManager so we can pay for octree edits
|
||||
|
@ -430,7 +433,7 @@ Application::~Application() {
|
|||
delete idleTimer;
|
||||
|
||||
_sharedVoxelSystem.changeTree(new VoxelTree);
|
||||
delete _voxelImporter;
|
||||
delete _voxelImportDialog;
|
||||
|
||||
// let the avatar mixer know we're out
|
||||
MyAvatar::sendKillAvatar();
|
||||
|
@ -465,8 +468,8 @@ void Application::saveSettings() {
|
|||
Menu::getInstance()->saveSettings();
|
||||
_rearMirrorTools->saveSettings(_settings);
|
||||
|
||||
if (_voxelImporter) {
|
||||
_voxelImporter->saveSettings(_settings);
|
||||
if (_voxelImportDialog) {
|
||||
_voxelImportDialog->saveSettings(_settings);
|
||||
}
|
||||
_settings->sync();
|
||||
_numChangedSettings = 0;
|
||||
|
@ -599,7 +602,7 @@ void Application::paintGL() {
|
|||
|
||||
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
||||
_myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
|
||||
_myCamera.setTargetPosition(_myAvatar->getHead()->getFilteredEyePosition());
|
||||
_myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition());
|
||||
_myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
|
||||
|
||||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||
|
@ -621,7 +624,7 @@ void Application::paintGL() {
|
|||
_myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0));
|
||||
} else {
|
||||
_myCamera.setTightness(0.0f);
|
||||
glm::vec3 eyePosition = _myAvatar->getHead()->getFilteredEyePosition();
|
||||
glm::vec3 eyePosition = _myAvatar->getHead()->getEyePosition();
|
||||
float headHeight = eyePosition.y - _myAvatar->getPosition().y;
|
||||
_myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
||||
_myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0));
|
||||
|
@ -814,9 +817,8 @@ bool Application::event(QEvent* event) {
|
|||
QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
|
||||
bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME);
|
||||
if (isHifiSchemeURL) {
|
||||
Menu::getInstance()->goTo(fileEvent->url().toString());
|
||||
Menu::getInstance()->goToURL(fileEvent->url().toLocalFile());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return QApplication::event(event);
|
||||
|
@ -1440,6 +1442,15 @@ void Application::setEnable3DTVMode(bool enable3DTVMode) {
|
|||
}
|
||||
|
||||
void Application::setEnableVRMode(bool enableVRMode) {
|
||||
if (enableVRMode) {
|
||||
if (!OculusManager::isConnected()) {
|
||||
// attempt to reconnect the Oculus manager - it's possible this was a workaround
|
||||
// for the sixense crash
|
||||
OculusManager::disconnect();
|
||||
OculusManager::connect();
|
||||
}
|
||||
}
|
||||
|
||||
resizeGL(_glWidget->width(), _glWidget->height());
|
||||
}
|
||||
|
||||
|
@ -1599,17 +1610,17 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) {
|
|||
void Application::importVoxels() {
|
||||
_importSucceded = false;
|
||||
|
||||
if (!_voxelImporter) {
|
||||
_voxelImporter = new VoxelImporter(_window);
|
||||
_voxelImporter->loadSettings(_settings);
|
||||
if (!_voxelImportDialog) {
|
||||
_voxelImportDialog = new VoxelImportDialog(_window);
|
||||
_voxelImportDialog->loadSettings(_settings);
|
||||
}
|
||||
|
||||
if (!_voxelImporter->exec()) {
|
||||
if (!_voxelImportDialog->exec()) {
|
||||
qDebug() << "Import succeeded." << endl;
|
||||
_importSucceded = true;
|
||||
} else {
|
||||
qDebug() << "Import failed." << endl;
|
||||
if (_sharedVoxelSystem.getTree() == _voxelImporter->getVoxelTree()) {
|
||||
if (_sharedVoxelSystem.getTree() == _voxelImporter.getVoxelTree()) {
|
||||
_sharedVoxelSystem.killLocalVoxels();
|
||||
_sharedVoxelSystem.changeTree(&_clipboard);
|
||||
}
|
||||
|
@ -1724,7 +1735,7 @@ void Application::init() {
|
|||
// Cleanup of the original shared tree
|
||||
_sharedVoxelSystem.init();
|
||||
|
||||
_voxelImporter = new VoxelImporter(_window);
|
||||
_voxelImportDialog = new VoxelImportDialog(_window);
|
||||
|
||||
_environment.init();
|
||||
|
||||
|
@ -3322,9 +3333,10 @@ void Application::updateWindowTitle(){
|
|||
QString buildVersion = " (build " + applicationVersion() + ")";
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) ";
|
||||
QString username = AccountManager::getInstance().getAccountInfo().getUsername();
|
||||
QString title = QString() + (!username.isEmpty() ? username + " @ " : QString())
|
||||
+ nodeList->getDomainHandler().getHostname() + buildVersion;
|
||||
+ nodeList->getDomainHandler().getHostname() + connectionStatus + buildVersion;
|
||||
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
if (accountManager.getAccountInfo().hasBalance()) {
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
#include "ui/overlays/Overlays.h"
|
||||
#include "ui/ApplicationOverlay.h"
|
||||
#include "ui/RunningScriptsWidget.h"
|
||||
#include "ui/VoxelImportDialog.h"
|
||||
#include "voxels/VoxelFade.h"
|
||||
#include "voxels/VoxelHideShowThread.h"
|
||||
#include "voxels/VoxelImporter.h"
|
||||
|
@ -193,6 +194,7 @@ public:
|
|||
Camera* getCamera() { return &_myCamera; }
|
||||
ViewFrustum* getViewFrustum() { return &_viewFrustum; }
|
||||
ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
|
||||
VoxelImporter* getVoxelImporter() { return &_voxelImporter; }
|
||||
VoxelSystem* getVoxels() { return &_voxels; }
|
||||
VoxelTree* getVoxelTree() { return _voxels.getTree(); }
|
||||
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
|
||||
|
@ -463,7 +465,8 @@ private:
|
|||
|
||||
VoxelSystem _voxels;
|
||||
VoxelTree _clipboard; // if I copy/paste
|
||||
VoxelImporter* _voxelImporter;
|
||||
VoxelImportDialog* _voxelImportDialog;
|
||||
VoxelImporter _voxelImporter;
|
||||
bool _importSucceded;
|
||||
VoxelSystem _sharedVoxelSystem;
|
||||
ViewFrustum _sharedVoxelSystemViewFrustum;
|
||||
|
|
|
@ -56,7 +56,6 @@ static const int MUTE_ICON_SIZE = 24;
|
|||
|
||||
static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100;
|
||||
|
||||
|
||||
Audio::Audio(QObject* parent) :
|
||||
AbstractAudioInterface(parent),
|
||||
_audioInput(NULL),
|
||||
|
@ -83,6 +82,7 @@ Audio::Audio(QObject* parent) :
|
|||
_noiseGateSampleCounter(0),
|
||||
_noiseGateOpen(false),
|
||||
_noiseGateEnabled(true),
|
||||
_peqEnabled(false),
|
||||
_toneInjectionEnabled(false),
|
||||
_noiseGateFramesToClose(0),
|
||||
_totalInputAudioSamples(0),
|
||||
|
@ -132,6 +132,7 @@ void Audio::init(QGLWidget *parent) {
|
|||
void Audio::reset() {
|
||||
_receivedAudioStream.reset();
|
||||
resetStats();
|
||||
_peq.reset();
|
||||
}
|
||||
|
||||
void Audio::resetStats() {
|
||||
|
@ -418,9 +419,15 @@ void Audio::start() {
|
|||
if (!outputFormatSupported) {
|
||||
qDebug() << "Unable to set up audio output because of a problem with output format.";
|
||||
}
|
||||
|
||||
_peq.initialize( _inputFormat.sampleRate(), _audioInput->bufferSize() );
|
||||
|
||||
}
|
||||
|
||||
void Audio::stop() {
|
||||
|
||||
_peq.finalize();
|
||||
|
||||
// "switch" to invalid devices in order to shut down the state
|
||||
switchInputToAudioDevice(QAudioDeviceInfo());
|
||||
switchOutputToAudioDevice(QAudioDeviceInfo());
|
||||
|
@ -462,7 +469,15 @@ void Audio::handleAudioInput() {
|
|||
int inputSamplesRequired = (int)((float)NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio);
|
||||
|
||||
QByteArray inputByteArray = _inputDevice->readAll();
|
||||
|
||||
|
||||
if (_peqEnabled && !_muted) {
|
||||
// we wish to pre-filter our captured input, prior to loopback
|
||||
|
||||
int16_t* ioBuffer = (int16_t*)inputByteArray.data();
|
||||
|
||||
_peq.render( ioBuffer, ioBuffer, inputByteArray.size() / sizeof(int16_t) );
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) {
|
||||
// if this person wants local loopback add that to the locally injected audio
|
||||
|
||||
|
@ -1172,6 +1187,31 @@ void Audio::renderToolBox(int x, int y, bool boxed) {
|
|||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void Audio::toggleAudioFilter() {
|
||||
_peqEnabled = !_peqEnabled;
|
||||
}
|
||||
|
||||
void Audio::selectAudioFilterFlat() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterFlat)) {
|
||||
_peq.loadProfile(0);
|
||||
}
|
||||
}
|
||||
void Audio::selectAudioFilterTrebleCut() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterTrebleCut)) {
|
||||
_peq.loadProfile(1);
|
||||
}
|
||||
}
|
||||
void Audio::selectAudioFilterBassCut() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterBassCut)) {
|
||||
_peq.loadProfile(2);
|
||||
}
|
||||
}
|
||||
void Audio::selectAudioFilterSmiley() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterSmiley)) {
|
||||
_peq.loadProfile(3);
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::toggleScope() {
|
||||
_scopeEnabled = !_scopeEnabled;
|
||||
if (_scopeEnabled) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "AudioStreamStats.h"
|
||||
#include "RingBufferHistory.h"
|
||||
#include "MovingMinMaxAvg.h"
|
||||
#include "AudioFilter.h"
|
||||
|
||||
#include <QAudio>
|
||||
#include <QAudioInput>
|
||||
|
@ -125,7 +126,12 @@ public slots:
|
|||
void selectAudioScopeFiveFrames();
|
||||
void selectAudioScopeTwentyFrames();
|
||||
void selectAudioScopeFiftyFrames();
|
||||
|
||||
void toggleAudioFilter();
|
||||
void selectAudioFilterFlat();
|
||||
void selectAudioFilterTrebleCut();
|
||||
void selectAudioFilterBassCut();
|
||||
void selectAudioFilterSmiley();
|
||||
|
||||
virtual void handleAudioByteArray(const QByteArray& audioByteArray);
|
||||
|
||||
void sendDownstreamAudioStatsPacket();
|
||||
|
@ -252,12 +258,12 @@ private:
|
|||
// Audio scope methods for rendering
|
||||
void renderBackground(const float* color, int x, int y, int width, int height);
|
||||
void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols);
|
||||
void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray);
|
||||
void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray);
|
||||
|
||||
// audio stats methods for rendering
|
||||
void renderAudioStreamStats(const AudioStreamStats& streamStats, int horizontalOffset, int& verticalOffset,
|
||||
float scale, float rotation, int font, const float* color, bool isDownstreamStats = false);
|
||||
|
||||
|
||||
// Audio scope data
|
||||
static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||
static const unsigned int DEFAULT_FRAMES_PER_SCOPE = 5;
|
||||
|
@ -270,6 +276,11 @@ private:
|
|||
int _scopeOutputOffset;
|
||||
int _framesPerScope;
|
||||
int _samplesPerScope;
|
||||
|
||||
// Multi-band parametric EQ
|
||||
bool _peqEnabled;
|
||||
AudioFilterPEQ3 _peq;
|
||||
|
||||
QMutex _guard;
|
||||
QByteArray* _scopeInput;
|
||||
QByteArray* _scopeOutputLeft;
|
||||
|
|
|
@ -486,6 +486,48 @@ Menu::Menu() :
|
|||
true,
|
||||
appInstance->getAudio(),
|
||||
SLOT(toggleAudioNoiseReduction()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioFilter,
|
||||
0,
|
||||
false,
|
||||
appInstance->getAudio(),
|
||||
SLOT(toggleAudioFilter()));
|
||||
|
||||
QMenu* audioFilterMenu = audioDebugMenu->addMenu("Audio Filter Options");
|
||||
addDisabledActionAndSeparator(audioFilterMenu, "Filter Response");
|
||||
{
|
||||
QAction *flat = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterFlat,
|
||||
0,
|
||||
true,
|
||||
appInstance->getAudio(),
|
||||
SLOT(selectAudioFilterFlat()));
|
||||
|
||||
QAction *trebleCut = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterTrebleCut,
|
||||
0,
|
||||
false,
|
||||
appInstance->getAudio(),
|
||||
SLOT(selectAudioFilterTrebleCut()));
|
||||
|
||||
QAction *bassCut = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterBassCut,
|
||||
0,
|
||||
false,
|
||||
appInstance->getAudio(),
|
||||
SLOT(selectAudioFilterBassCut()));
|
||||
|
||||
QAction *smiley = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterSmiley,
|
||||
0,
|
||||
false,
|
||||
appInstance->getAudio(),
|
||||
SLOT(selectAudioFilterSmiley()));
|
||||
|
||||
|
||||
QActionGroup* audioFilterGroup = new QActionGroup(audioFilterMenu);
|
||||
audioFilterGroup->addAction(flat);
|
||||
audioFilterGroup->addAction(trebleCut);
|
||||
audioFilterGroup->addAction(bassCut);
|
||||
audioFilterGroup->addAction(smiley);
|
||||
}
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio);
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio);
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false,
|
||||
|
@ -1111,8 +1153,8 @@ void Menu::goTo() {
|
|||
}
|
||||
|
||||
bool Menu::goToURL(QString location) {
|
||||
if (location.startsWith(CUSTOM_URL_SCHEME + "//")) {
|
||||
QStringList urlParts = location.remove(0, CUSTOM_URL_SCHEME.length() + 2).split('/', QString::SkipEmptyParts);
|
||||
if (location.startsWith(CUSTOM_URL_SCHEME + "/")) {
|
||||
QStringList urlParts = location.remove(0, CUSTOM_URL_SCHEME.length()).split('/', QString::SkipEmptyParts);
|
||||
|
||||
if (urlParts.count() > 1) {
|
||||
// if url has 2 or more parts, the first one is domain name
|
||||
|
|
|
@ -311,6 +311,11 @@ namespace MenuOption {
|
|||
const QString Animations = "Animations...";
|
||||
const QString Atmosphere = "Atmosphere";
|
||||
const QString Attachments = "Attachments...";
|
||||
const QString AudioFilter = "Audio Filter Bank";
|
||||
const QString AudioFilterFlat = "Flat Response";
|
||||
const QString AudioFilterTrebleCut= "Treble Cut";
|
||||
const QString AudioFilterBassCut = "Bass Cut";
|
||||
const QString AudioFilterSmiley = "Smiley Curve";
|
||||
const QString AudioNoiseReduction = "Audio Noise Reduction";
|
||||
const QString AudioScope = "Audio Scope";
|
||||
const QString AudioScopeFiftyFrames = "Fifty";
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -43,6 +43,12 @@ public:
|
|||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
void renderHeightfieldCursor(const glm::vec3& position, float radius);
|
||||
|
||||
bool findFirstRayHeightfieldIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance);
|
||||
|
||||
Q_INVOKABLE float getHeightfieldHeight(const glm::vec3& location);
|
||||
|
||||
Q_INVOKABLE void deleteTextures(int heightID, int colorID);
|
||||
|
||||
protected:
|
||||
|
@ -105,7 +111,7 @@ public:
|
|||
|
||||
virtual ~BufferData();
|
||||
|
||||
virtual void render() = 0;
|
||||
virtual void render(bool cursor = false) = 0;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<BufferData> BufferDataPointer;
|
||||
|
@ -116,7 +122,7 @@ public:
|
|||
|
||||
PointBuffer(const BufferPointVector& points);
|
||||
|
||||
virtual void render();
|
||||
virtual void render(bool cursor = false);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -129,29 +135,50 @@ private:
|
|||
class HeightfieldBuffer : public BufferData {
|
||||
public:
|
||||
|
||||
/// Creates a new heightfield buffer.
|
||||
/// \param clearAfterLoading if true, clear the data arrays after we load them into textures in order to reclaim the space
|
||||
HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color,
|
||||
bool clearAfterLoading = true);
|
||||
static const int HEIGHT_BORDER;
|
||||
static const int SHARED_EDGE;
|
||||
static const int HEIGHT_EXTENSION;
|
||||
|
||||
HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color);
|
||||
~HeightfieldBuffer();
|
||||
|
||||
const glm::vec3& getTranslation() const { return _translation; }
|
||||
float getScale() const { return _scale; }
|
||||
|
||||
const Box& getHeightBounds() const { return _heightBounds; }
|
||||
const Box& getColorBounds() const { return _colorBounds; }
|
||||
|
||||
QByteArray& getHeight() { return _height; }
|
||||
const QByteArray& getHeight() const { return _height; }
|
||||
|
||||
QByteArray& getColor() { return _color; }
|
||||
const QByteArray& getColor() const { return _color; }
|
||||
|
||||
virtual void render();
|
||||
QByteArray getUnextendedHeight() const;
|
||||
QByteArray getUnextendedColor() const;
|
||||
|
||||
int getHeightSize() const { return _heightSize; }
|
||||
float getHeightIncrement() const { return _heightIncrement; }
|
||||
|
||||
int getColorSize() const { return _colorSize; }
|
||||
float getColorIncrement() const { return _colorIncrement; }
|
||||
|
||||
virtual void render(bool cursor = false);
|
||||
|
||||
private:
|
||||
|
||||
glm::vec3 _translation;
|
||||
float _scale;
|
||||
Box _heightBounds;
|
||||
Box _colorBounds;
|
||||
QByteArray _height;
|
||||
QByteArray _color;
|
||||
bool _clearAfterLoading;
|
||||
GLuint _heightTextureID;
|
||||
GLuint _colorTextureID;
|
||||
int _heightSize;
|
||||
float _heightIncrement;
|
||||
int _colorSize;
|
||||
float _colorIncrement;
|
||||
|
||||
typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair;
|
||||
static QHash<int, BufferPair> _bufferPairs;
|
||||
|
@ -180,6 +207,8 @@ public:
|
|||
Q_INVOKABLE BufferDataAttribute(const QString& name = QString());
|
||||
|
||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
|
||||
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
||||
};
|
||||
|
||||
/// Renders metavoxels as points.
|
||||
|
@ -192,7 +221,18 @@ public:
|
|||
|
||||
static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; }
|
||||
static int getHeightScaleLocation() { return _heightScaleLocation; }
|
||||
|
||||
static int getColorScaleLocation() { return _colorScaleLocation; }
|
||||
|
||||
static ProgramObject& getShadowMapHeightfieldProgram() { return _shadowMapHeightfieldProgram; }
|
||||
static int getShadowMapHeightScaleLocation() { return _shadowMapHeightScaleLocation; }
|
||||
static int getShadowMapColorScaleLocation() { return _shadowMapColorScaleLocation; }
|
||||
|
||||
static ProgramObject& getCascadedShadowMapHeightfieldProgram() { return _cascadedShadowMapHeightfieldProgram; }
|
||||
static int getCascadedShadowMapHeightScaleLocation() { return _cascadedShadowMapHeightScaleLocation; }
|
||||
static int getCascadedShadowMapColorScaleLocation() { return _cascadedShadowMapColorScaleLocation; }
|
||||
|
||||
static ProgramObject& getHeightfieldCursorProgram() { return _heightfieldCursorProgram; }
|
||||
|
||||
Q_INVOKABLE DefaultMetavoxelRendererImplementation();
|
||||
|
||||
virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod);
|
||||
|
@ -206,6 +246,18 @@ private:
|
|||
|
||||
static ProgramObject _heightfieldProgram;
|
||||
static int _heightScaleLocation;
|
||||
static int _colorScaleLocation;
|
||||
|
||||
static ProgramObject _shadowMapHeightfieldProgram;
|
||||
static int _shadowMapHeightScaleLocation;
|
||||
static int _shadowMapColorScaleLocation;
|
||||
|
||||
static ProgramObject _cascadedShadowMapHeightfieldProgram;
|
||||
static int _cascadedShadowMapHeightScaleLocation;
|
||||
static int _cascadedShadowMapColorScaleLocation;
|
||||
static int _shadowDistancesLocation;
|
||||
|
||||
static ProgramObject _heightfieldCursorProgram;
|
||||
};
|
||||
|
||||
/// Base class for spanner renderers; provides clipping.
|
||||
|
|
|
@ -163,9 +163,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
|||
}
|
||||
_eyePosition = calculateAverageEyePosition();
|
||||
|
||||
float velocityFilter = glm::clamp(1.0f - glm::length(_filteredEyePosition - _eyePosition), 0.0f, 1.0f);
|
||||
_filteredEyePosition = velocityFilter * _filteredEyePosition + (1.0f - velocityFilter) * _eyePosition;
|
||||
|
||||
}
|
||||
|
||||
void Head::relaxLean(float deltaTime) {
|
||||
|
|
|
@ -88,7 +88,6 @@ public:
|
|||
|
||||
const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
||||
float getAverageLoudness() const { return _averageLoudness; }
|
||||
glm::vec3 getFilteredEyePosition() const { return _filteredEyePosition; }
|
||||
/// \return the point about which scaling occurs.
|
||||
glm::vec3 getScalePivot() const;
|
||||
|
||||
|
@ -121,7 +120,6 @@ private:
|
|||
glm::vec3 _leftEyePosition;
|
||||
glm::vec3 _rightEyePosition;
|
||||
glm::vec3 _eyePosition;
|
||||
glm::vec3 _filteredEyePosition; // velocity filtered world space eye position
|
||||
|
||||
float _scale;
|
||||
float _lastLoudness;
|
||||
|
|
|
@ -83,10 +83,11 @@ MyAvatar::MyAvatar() :
|
|||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||
_driveKeys[i] = 0.0f;
|
||||
}
|
||||
_skeletonModel.setEnableShapes(true);
|
||||
// The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type.
|
||||
_physicsSimulation.setEntity(&_skeletonModel);
|
||||
_physicsSimulation.setRagdoll(&_skeletonModel);
|
||||
|
||||
_skeletonModel.setEnableShapes(true);
|
||||
Ragdoll* ragdoll = _skeletonModel.buildRagdoll();
|
||||
_physicsSimulation.setRagdoll(ragdoll);
|
||||
}
|
||||
|
||||
MyAvatar::~MyAvatar() {
|
||||
|
@ -206,9 +207,9 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
{
|
||||
PerformanceTimer perfTimer("ragdoll");
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
|
||||
const float minError = 0.01f;
|
||||
const float maxIterations = 10;
|
||||
const quint64 maxUsec = 2000;
|
||||
const float minError = 0.00001f;
|
||||
const float maxIterations = 3;
|
||||
const quint64 maxUsec = 4000;
|
||||
_physicsSimulation.setTranslation(_position);
|
||||
_physicsSimulation.stepForward(deltaTime, minError, maxIterations, maxUsec);
|
||||
} else {
|
||||
|
@ -255,6 +256,12 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
|||
estimatedRotation.x *= -1.0f;
|
||||
estimatedRotation.z *= -1.0f;
|
||||
|
||||
} else if (OculusManager::isConnected()) {
|
||||
estimatedPosition = OculusManager::getRelativePosition();
|
||||
estimatedPosition.x *= -1.0f;
|
||||
|
||||
const float OCULUS_LEAN_SCALE = 0.05f;
|
||||
estimatedPosition /= OCULUS_LEAN_SCALE;
|
||||
} else {
|
||||
FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
|
@ -1598,10 +1605,10 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
|
|||
if (simulation != &(_physicsSimulation)) {
|
||||
skeleton->setEnableShapes(true);
|
||||
_physicsSimulation.addEntity(skeleton);
|
||||
_physicsSimulation.addRagdoll(skeleton);
|
||||
_physicsSimulation.addRagdoll(skeleton->getRagdoll());
|
||||
}
|
||||
} else if (simulation == &(_physicsSimulation)) {
|
||||
_physicsSimulation.removeRagdoll(skeleton);
|
||||
_physicsSimulation.removeRagdoll(skeleton->getRagdoll());
|
||||
_physicsSimulation.removeEntity(skeleton);
|
||||
skeleton->setEnableShapes(false);
|
||||
}
|
||||
|
|
|
@ -23,13 +23,19 @@
|
|||
#include "Menu.h"
|
||||
#include "MuscleConstraint.h"
|
||||
#include "SkeletonModel.h"
|
||||
#include "SkeletonRagdoll.h"
|
||||
|
||||
SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
|
||||
Model(parent),
|
||||
Ragdoll(),
|
||||
_owningAvatar(owningAvatar),
|
||||
_boundingShape(),
|
||||
_boundingShapeLocalOffset(0.0f) {
|
||||
_boundingShapeLocalOffset(0.0f),
|
||||
_ragdoll(NULL) {
|
||||
}
|
||||
|
||||
SkeletonModel::~SkeletonModel() {
|
||||
delete _ragdoll;
|
||||
_ragdoll = NULL;
|
||||
}
|
||||
|
||||
void SkeletonModel::setJointStates(QVector<JointState> states) {
|
||||
|
@ -155,9 +161,6 @@ void SkeletonModel::getBodyShapes(QVector<const Shape*>& shapes) const {
|
|||
void SkeletonModel::renderIKConstraints() {
|
||||
renderJointConstraints(getRightHandJointIndex());
|
||||
renderJointConstraints(getLeftHandJointIndex());
|
||||
//if (isActive() && _owningAvatar->isMyAvatar()) {
|
||||
// renderRagdoll();
|
||||
//}
|
||||
}
|
||||
|
||||
class IndexValue {
|
||||
|
@ -432,6 +435,10 @@ bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const {
|
|||
}
|
||||
|
||||
bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const {
|
||||
if (_owningAvatar->isMyAvatar() &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
|
||||
return isActive() && getVisibleJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition);
|
||||
}
|
||||
return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition);
|
||||
}
|
||||
|
||||
|
@ -445,11 +452,16 @@ bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckP
|
|||
}
|
||||
int parentIndex = geometry.joints.at(geometry.neckJointIndex).parentIndex;
|
||||
glm::quat worldFrameRotation;
|
||||
if (getJointRotationInWorldFrame(parentIndex, worldFrameRotation)) {
|
||||
neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation;
|
||||
return true;
|
||||
bool success = false;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
|
||||
success = getVisibleJointRotationInWorldFrame(parentIndex, worldFrameRotation);
|
||||
} else {
|
||||
success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation);
|
||||
}
|
||||
return false;
|
||||
if (success) {
|
||||
neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
|
||||
|
@ -480,21 +492,25 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco
|
|||
}
|
||||
|
||||
void SkeletonModel::renderRagdoll() {
|
||||
if (!_ragdoll) {
|
||||
return;
|
||||
}
|
||||
const QVector<VerletPoint>& points = _ragdoll->getPoints();
|
||||
const int BALL_SUBDIVISIONS = 6;
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glPushMatrix();
|
||||
|
||||
Application::getInstance()->loadTranslatedViewMatrix(_translation);
|
||||
int numPoints = _ragdollPoints.size();
|
||||
int numPoints = points.size();
|
||||
float alpha = 0.3f;
|
||||
float radius1 = 0.008f;
|
||||
float radius2 = 0.01f;
|
||||
glm::vec3 simulationTranslation = getTranslationInSimulationFrame();
|
||||
glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame();
|
||||
for (int i = 0; i < numPoints; ++i) {
|
||||
glPushMatrix();
|
||||
// NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative
|
||||
glm::vec3 position = _ragdollPoints[i]._position - simulationTranslation;
|
||||
glm::vec3 position = points[i]._position - simulationTranslation;
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
// draw each point as a yellow hexagon with black border
|
||||
glColor4f(0.0f, 0.0f, 0.0f, alpha);
|
||||
|
@ -508,109 +524,18 @@ void SkeletonModel::renderRagdoll() {
|
|||
glEnable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void SkeletonModel::initRagdollPoints() {
|
||||
clearRagdollConstraintsAndPoints();
|
||||
_muscleConstraints.clear();
|
||||
|
||||
initRagdollTransform();
|
||||
// one point for each joint
|
||||
int numStates = _jointStates.size();
|
||||
_ragdollPoints.fill(VerletPoint(), numStates);
|
||||
for (int i = 0; i < numStates; ++i) {
|
||||
const JointState& state = _jointStates.at(i);
|
||||
// _ragdollPoints start in model-frame
|
||||
_ragdollPoints[i].initPosition(state.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonModel::buildRagdollConstraints() {
|
||||
// NOTE: the length of DistanceConstraints is computed and locked in at this time
|
||||
// so make sure the ragdoll positions are in a normal configuration before here.
|
||||
const int numPoints = _ragdollPoints.size();
|
||||
assert(numPoints == _jointStates.size());
|
||||
|
||||
float minBone = FLT_MAX;
|
||||
float maxBone = -FLT_MAX;
|
||||
QMultiMap<int, int> families;
|
||||
for (int i = 0; i < numPoints; ++i) {
|
||||
const JointState& state = _jointStates.at(i);
|
||||
int parentIndex = state.getParentIndex();
|
||||
if (parentIndex == -1) {
|
||||
FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i]));
|
||||
_fixedConstraints.push_back(anchor);
|
||||
} else {
|
||||
DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex]));
|
||||
bone->setDistance(state.getDistanceToParent());
|
||||
_boneConstraints.push_back(bone);
|
||||
families.insert(parentIndex, i);
|
||||
}
|
||||
float boneLength = glm::length(state.getPositionInParentFrame());
|
||||
if (boneLength > maxBone) {
|
||||
maxBone = boneLength;
|
||||
} else if (boneLength < minBone) {
|
||||
minBone = boneLength;
|
||||
}
|
||||
}
|
||||
// Joints that have multiple children effectively have rigid constraints between the children
|
||||
// in the parent frame, so we add DistanceConstraints between children in the same family.
|
||||
QMultiMap<int, int>::iterator itr = families.begin();
|
||||
while (itr != families.end()) {
|
||||
QList<int> children = families.values(itr.key());
|
||||
int numChildren = children.size();
|
||||
if (numChildren > 1) {
|
||||
for (int i = 1; i < numChildren; ++i) {
|
||||
DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]]));
|
||||
_boneConstraints.push_back(bone);
|
||||
}
|
||||
if (numChildren > 2) {
|
||||
DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]]));
|
||||
_boneConstraints.push_back(bone);
|
||||
}
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
|
||||
float MAX_STRENGTH = 0.6f;
|
||||
float MIN_STRENGTH = 0.05f;
|
||||
// each joint gets a MuscleConstraint to its parent
|
||||
for (int i = 1; i < numPoints; ++i) {
|
||||
const JointState& state = _jointStates.at(i);
|
||||
int p = state.getParentIndex();
|
||||
if (p == -1) {
|
||||
continue;
|
||||
}
|
||||
MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i]));
|
||||
_muscleConstraints.push_back(constraint);
|
||||
|
||||
// Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length:
|
||||
// long = weak and short = strong.
|
||||
constraint->setIndices(p, i);
|
||||
float boneLength = glm::length(state.getPositionInParentFrame());
|
||||
|
||||
float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone);
|
||||
if (!families.contains(i)) {
|
||||
// Although muscles only pull on the children not parents, nevertheless those joints that have
|
||||
// parents AND children are more stable than joints at the end such as fingers. For such joints we
|
||||
// bestow maximum strength which helps reduce wiggle.
|
||||
strength = MAX_MUSCLE_STRENGTH;
|
||||
}
|
||||
constraint->setStrength(strength);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SkeletonModel::updateVisibleJointStates() {
|
||||
if (_showTrueJointTransforms) {
|
||||
if (_showTrueJointTransforms || !_ragdoll) {
|
||||
// no need to update visible transforms
|
||||
return;
|
||||
}
|
||||
const QVector<VerletPoint>& ragdollPoints = _ragdoll->getPoints();
|
||||
QVector<glm::vec3> points;
|
||||
points.reserve(_jointStates.size());
|
||||
glm::quat invRotation = glm::inverse(_rotation);
|
||||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
JointState& state = _jointStates[i];
|
||||
points.push_back(_ragdollPoints[i]._position);
|
||||
points.push_back(ragdollPoints[i]._position);
|
||||
|
||||
// get the parent state (this is the state that we want to rotate)
|
||||
int parentIndex = state.getParentIndex();
|
||||
|
@ -644,15 +569,14 @@ void SkeletonModel::updateVisibleJointStates() {
|
|||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void SkeletonModel::stepRagdollForward(float deltaTime) {
|
||||
setRagdollTransform(_translation, _rotation);
|
||||
Ragdoll::stepRagdollForward(deltaTime);
|
||||
updateMuscles();
|
||||
int numConstraints = _muscleConstraints.size();
|
||||
for (int i = 0; i < numConstraints; ++i) {
|
||||
_muscleConstraints[i]->enforce();
|
||||
SkeletonRagdoll* SkeletonModel::buildRagdoll() {
|
||||
if (!_ragdoll) {
|
||||
_ragdoll = new SkeletonRagdoll(this);
|
||||
if (_enableShapes) {
|
||||
buildShapes();
|
||||
}
|
||||
}
|
||||
return _ragdoll;
|
||||
}
|
||||
|
||||
float DENSITY_OF_WATER = 1000.0f; // kg/m^3
|
||||
|
@ -670,8 +594,13 @@ void SkeletonModel::buildShapes() {
|
|||
return;
|
||||
}
|
||||
|
||||
initRagdollPoints();
|
||||
float massScale = getMassScale();
|
||||
if (!_ragdoll) {
|
||||
_ragdoll = new SkeletonRagdoll(this);
|
||||
}
|
||||
_ragdoll->initPoints();
|
||||
QVector<VerletPoint>& points = _ragdoll->getPoints();
|
||||
|
||||
float massScale = _ragdoll->getMassScale();
|
||||
|
||||
float uniformScale = extractUniformScale(_scale);
|
||||
const int numStates = _jointStates.size();
|
||||
|
@ -691,14 +620,14 @@ void SkeletonModel::buildShapes() {
|
|||
Shape* shape = NULL;
|
||||
int parentIndex = joint.parentIndex;
|
||||
if (type == Shape::SPHERE_SHAPE) {
|
||||
shape = new VerletSphereShape(radius, &(_ragdollPoints[i]));
|
||||
shape = new VerletSphereShape(radius, &(points[i]));
|
||||
shape->setEntity(this);
|
||||
_ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()));
|
||||
points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()));
|
||||
} else if (type == Shape::CAPSULE_SHAPE) {
|
||||
assert(parentIndex != -1);
|
||||
shape = new VerletCapsuleShape(radius, &(_ragdollPoints[parentIndex]), &(_ragdollPoints[i]));
|
||||
shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i]));
|
||||
shape->setEntity(this);
|
||||
_ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()));
|
||||
points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()));
|
||||
}
|
||||
if (parentIndex != -1) {
|
||||
// always disable collisions between joint and its parent
|
||||
|
@ -708,7 +637,7 @@ void SkeletonModel::buildShapes() {
|
|||
} else {
|
||||
// give the base joint a very large mass since it doesn't actually move
|
||||
// in the local-frame simulation (it defines the origin)
|
||||
_ragdollPoints[i].setMass(VERY_BIG_MASS);
|
||||
points[i].setMass(VERY_BIG_MASS);
|
||||
}
|
||||
_shapes.push_back(shape);
|
||||
}
|
||||
|
@ -720,17 +649,11 @@ void SkeletonModel::buildShapes() {
|
|||
// joints that are currently colliding.
|
||||
disableCurrentSelfCollisions();
|
||||
|
||||
buildRagdollConstraints();
|
||||
_ragdoll->buildConstraints();
|
||||
|
||||
// ... then move shapes back to current joint positions
|
||||
if (_ragdollPoints.size() == numStates) {
|
||||
int numStates = _jointStates.size();
|
||||
for (int i = 0; i < numStates; ++i) {
|
||||
// ragdollPoints start in model-frame
|
||||
_ragdollPoints[i].initPosition(_jointStates.at(i).getPosition());
|
||||
}
|
||||
}
|
||||
enforceRagdollConstraints();
|
||||
_ragdoll->slamPointPositions();
|
||||
_ragdoll->enforceConstraints();
|
||||
}
|
||||
|
||||
void SkeletonModel::moveShapesTowardJoints(float deltaTime) {
|
||||
|
@ -738,8 +661,9 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) {
|
|||
// unravel a skelton that has become tangled in its constraints. So let's keep this
|
||||
// around for a while just in case.
|
||||
const int numStates = _jointStates.size();
|
||||
assert(_jointStates.size() == _ragdollPoints.size());
|
||||
if (_ragdollPoints.size() != numStates) {
|
||||
QVector<VerletPoint>& ragdollPoints = _ragdoll->getPoints();
|
||||
assert(_jointStates.size() == ragdollPoints.size());
|
||||
if (ragdollPoints.size() != numStates) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -748,32 +672,22 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) {
|
|||
float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f);
|
||||
|
||||
float oneMinusFraction = 1.0f - fraction;
|
||||
glm::vec3 simulationTranslation = getTranslationInSimulationFrame();
|
||||
glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame();
|
||||
for (int i = 0; i < numStates; ++i) {
|
||||
// ragdollPoints are in simulation-frame but jointStates are in model-frame
|
||||
_ragdollPoints[i].initPosition(oneMinusFraction * _ragdollPoints[i]._position +
|
||||
ragdollPoints[i].initPosition(oneMinusFraction * ragdollPoints[i]._position +
|
||||
fraction * (simulationTranslation + _rotation * (_jointStates.at(i).getPosition())));
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonModel::updateMuscles() {
|
||||
int numConstraints = _muscleConstraints.size();
|
||||
for (int i = 0; i < numConstraints; ++i) {
|
||||
MuscleConstraint* constraint = _muscleConstraints[i];
|
||||
int j = constraint->getParentIndex();
|
||||
int k = constraint->getChildIndex();
|
||||
assert(j != -1 && k != -1);
|
||||
// ragdollPoints are in simulation-frame but jointStates are in model-frame
|
||||
constraint->setChildOffset(_rotation * (_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition()));
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
|
||||
// compute default joint transforms
|
||||
int numStates = _jointStates.size();
|
||||
QVector<glm::mat4> transforms;
|
||||
transforms.fill(glm::mat4(), numStates);
|
||||
|
||||
QVector<VerletPoint>& ragdollPoints = _ragdoll->getPoints();
|
||||
|
||||
// compute the default transforms and slam the ragdoll positions accordingly
|
||||
// (which puts the shapes where we want them)
|
||||
for (int i = 0; i < numStates; i++) {
|
||||
|
@ -782,7 +696,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
|
|||
int parentIndex = joint.parentIndex;
|
||||
if (parentIndex == -1) {
|
||||
transforms[i] = _jointStates[i].getTransform();
|
||||
_ragdollPoints[i].initPosition(extractTranslation(transforms[i]));
|
||||
ragdollPoints[i].initPosition(extractTranslation(transforms[i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -790,7 +704,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
|
|||
transforms[i] = transforms[parentIndex] * glm::translate(joint.translation)
|
||||
* joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform;
|
||||
// setting the ragdollPoints here slams the VerletShapes into their default positions
|
||||
_ragdollPoints[i].initPosition(extractTranslation(transforms[i]));
|
||||
ragdollPoints[i].initPosition(extractTranslation(transforms[i]));
|
||||
}
|
||||
|
||||
// compute bounding box that encloses all shapes
|
||||
|
@ -909,9 +823,12 @@ const int BALL_SUBDIVISIONS = 10;
|
|||
|
||||
// virtual
|
||||
void SkeletonModel::renderJointCollisionShapes(float alpha) {
|
||||
if (!_ragdoll) {
|
||||
return;
|
||||
}
|
||||
glPushMatrix();
|
||||
Application::getInstance()->loadTranslatedViewMatrix(_translation);
|
||||
glm::vec3 simulationTranslation = getTranslationInSimulationFrame();
|
||||
glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame();
|
||||
for (int i = 0; i < _shapes.size(); i++) {
|
||||
Shape* shape = _shapes[i];
|
||||
if (!shape) {
|
||||
|
|
|
@ -15,18 +15,20 @@
|
|||
#include "renderer/Model.h"
|
||||
|
||||
#include <CapsuleShape.h>
|
||||
#include <Ragdoll.h>
|
||||
#include "SkeletonRagdoll.h"
|
||||
|
||||
class Avatar;
|
||||
class MuscleConstraint;
|
||||
class SkeletonRagdoll;
|
||||
|
||||
/// A skeleton loaded from a model.
|
||||
class SkeletonModel : public Model, public Ragdoll {
|
||||
class SkeletonModel : public Model {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL);
|
||||
~SkeletonModel();
|
||||
|
||||
void setJointStates(QVector<JointState> states);
|
||||
|
||||
|
@ -96,12 +98,11 @@ public:
|
|||
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
||||
|
||||
virtual void updateVisibleJointStates();
|
||||
|
||||
// virtual overrride from Ragdoll
|
||||
virtual void stepRagdollForward(float deltaTime);
|
||||
|
||||
SkeletonRagdoll* buildRagdoll();
|
||||
SkeletonRagdoll* getRagdoll() { return _ragdoll; }
|
||||
|
||||
void moveShapesTowardJoints(float fraction);
|
||||
void updateMuscles();
|
||||
|
||||
void computeBoundingShape(const FBXGeometry& geometry);
|
||||
void renderBoundingCollisionShapes(float alpha);
|
||||
|
@ -115,10 +116,6 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
// virtual overrrides from Ragdoll
|
||||
void initRagdollPoints();
|
||||
void buildRagdollConstraints();
|
||||
|
||||
void buildShapes();
|
||||
|
||||
/// \param jointIndex index of joint in model
|
||||
|
@ -147,7 +144,7 @@ private:
|
|||
|
||||
CapsuleShape _boundingShape;
|
||||
glm::vec3 _boundingShapeLocalOffset;
|
||||
QVector<MuscleConstraint*> _muscleConstraints;
|
||||
SkeletonRagdoll* _ragdoll;
|
||||
};
|
||||
|
||||
#endif // hifi_SkeletonModel_h
|
||||
|
|
148
interface/src/avatar/SkeletonRagdoll.cpp
Normal file
148
interface/src/avatar/SkeletonRagdoll.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
//
|
||||
// SkeletonRagdoll.cpp
|
||||
// interface/src/avatar
|
||||
//
|
||||
// Created by Andrew Meadows 2014.08.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
|
||||
//
|
||||
|
||||
#include <DistanceConstraint.h>
|
||||
#include <FixedConstraint.h>
|
||||
|
||||
#include "SkeletonRagdoll.h"
|
||||
#include "MuscleConstraint.h"
|
||||
#include "../renderer/Model.h"
|
||||
|
||||
SkeletonRagdoll::SkeletonRagdoll(Model* model) : Ragdoll(), _model(model) {
|
||||
assert(_model);
|
||||
}
|
||||
|
||||
SkeletonRagdoll::~SkeletonRagdoll() {
|
||||
}
|
||||
|
||||
// virtual
|
||||
void SkeletonRagdoll::stepForward(float deltaTime) {
|
||||
setTransform(_model->getTranslation(), _model->getRotation());
|
||||
Ragdoll::stepForward(deltaTime);
|
||||
updateMuscles();
|
||||
int numConstraints = _muscleConstraints.size();
|
||||
for (int i = 0; i < numConstraints; ++i) {
|
||||
_muscleConstraints[i]->enforce();
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonRagdoll::slamPointPositions() {
|
||||
QVector<JointState>& jointStates = _model->getJointStates();
|
||||
int numStates = jointStates.size();
|
||||
for (int i = 0; i < numStates; ++i) {
|
||||
_points[i].initPosition(jointStates.at(i).getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void SkeletonRagdoll::initPoints() {
|
||||
clearConstraintsAndPoints();
|
||||
_muscleConstraints.clear();
|
||||
|
||||
initTransform();
|
||||
// one point for each joint
|
||||
QVector<JointState>& jointStates = _model->getJointStates();
|
||||
int numStates = jointStates.size();
|
||||
_points.fill(VerletPoint(), numStates);
|
||||
slamPointPositions();
|
||||
}
|
||||
|
||||
// virtual
|
||||
void SkeletonRagdoll::buildConstraints() {
|
||||
QVector<JointState>& jointStates = _model->getJointStates();
|
||||
|
||||
// NOTE: the length of DistanceConstraints is computed and locked in at this time
|
||||
// so make sure the ragdoll positions are in a normal configuration before here.
|
||||
const int numPoints = _points.size();
|
||||
assert(numPoints == jointStates.size());
|
||||
|
||||
float minBone = FLT_MAX;
|
||||
float maxBone = -FLT_MAX;
|
||||
QMultiMap<int, int> families;
|
||||
for (int i = 0; i < numPoints; ++i) {
|
||||
const JointState& state = jointStates.at(i);
|
||||
int parentIndex = state.getParentIndex();
|
||||
if (parentIndex == -1) {
|
||||
FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_points[i]));
|
||||
_fixedConstraints.push_back(anchor);
|
||||
} else {
|
||||
DistanceConstraint* bone = new DistanceConstraint(&(_points[i]), &(_points[parentIndex]));
|
||||
bone->setDistance(state.getDistanceToParent());
|
||||
_boneConstraints.push_back(bone);
|
||||
families.insert(parentIndex, i);
|
||||
}
|
||||
float boneLength = glm::length(state.getPositionInParentFrame());
|
||||
if (boneLength > maxBone) {
|
||||
maxBone = boneLength;
|
||||
} else if (boneLength < minBone) {
|
||||
minBone = boneLength;
|
||||
}
|
||||
}
|
||||
// Joints that have multiple children effectively have rigid constraints between the children
|
||||
// in the parent frame, so we add DistanceConstraints between children in the same family.
|
||||
QMultiMap<int, int>::iterator itr = families.begin();
|
||||
while (itr != families.end()) {
|
||||
QList<int> children = families.values(itr.key());
|
||||
int numChildren = children.size();
|
||||
if (numChildren > 1) {
|
||||
for (int i = 1; i < numChildren; ++i) {
|
||||
DistanceConstraint* bone = new DistanceConstraint(&(_points[children[i-1]]), &(_points[children[i]]));
|
||||
_boneConstraints.push_back(bone);
|
||||
}
|
||||
if (numChildren > 2) {
|
||||
DistanceConstraint* bone = new DistanceConstraint(&(_points[children[numChildren-1]]), &(_points[children[0]]));
|
||||
_boneConstraints.push_back(bone);
|
||||
}
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
|
||||
float MAX_STRENGTH = 0.6f;
|
||||
float MIN_STRENGTH = 0.05f;
|
||||
// each joint gets a MuscleConstraint to its parent
|
||||
for (int i = 1; i < numPoints; ++i) {
|
||||
const JointState& state = jointStates.at(i);
|
||||
int p = state.getParentIndex();
|
||||
if (p == -1) {
|
||||
continue;
|
||||
}
|
||||
MuscleConstraint* constraint = new MuscleConstraint(&(_points[p]), &(_points[i]));
|
||||
_muscleConstraints.push_back(constraint);
|
||||
|
||||
// Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length:
|
||||
// long = weak and short = strong.
|
||||
constraint->setIndices(p, i);
|
||||
float boneLength = glm::length(state.getPositionInParentFrame());
|
||||
|
||||
float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone);
|
||||
if (!families.contains(i)) {
|
||||
// Although muscles only pull on the children not parents, nevertheless those joints that have
|
||||
// parents AND children are more stable than joints at the end such as fingers. For such joints we
|
||||
// bestow maximum strength which helps reduce wiggle.
|
||||
strength = MAX_MUSCLE_STRENGTH;
|
||||
}
|
||||
constraint->setStrength(strength);
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonRagdoll::updateMuscles() {
|
||||
QVector<JointState>& jointStates = _model->getJointStates();
|
||||
int numConstraints = _muscleConstraints.size();
|
||||
glm::quat rotation = _model->getRotation();
|
||||
for (int i = 0; i < numConstraints; ++i) {
|
||||
MuscleConstraint* constraint = _muscleConstraints[i];
|
||||
int j = constraint->getParentIndex();
|
||||
int k = constraint->getChildIndex();
|
||||
assert(j != -1 && k != -1);
|
||||
// ragdollPoints are in simulation-frame but jointStates are in model-frame
|
||||
constraint->setChildOffset(rotation * (jointStates.at(k).getPosition() - jointStates.at(j).getPosition()));
|
||||
}
|
||||
}
|
42
interface/src/avatar/SkeletonRagdoll.h
Normal file
42
interface/src/avatar/SkeletonRagdoll.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// SkeletonkRagdoll.h
|
||||
// interface/src/avatar
|
||||
//
|
||||
// Created by Andrew Meadows 2014.08.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
|
||||
//
|
||||
|
||||
#ifndef hifi_SkeletonRagdoll_h
|
||||
#define hifi_SkeletonRagdoll_h
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include <Ragdoll.h>
|
||||
|
||||
#include "../renderer/JointState.h"
|
||||
|
||||
class MuscleConstraint;
|
||||
class Model;
|
||||
|
||||
class SkeletonRagdoll : public Ragdoll {
|
||||
public:
|
||||
|
||||
SkeletonRagdoll(Model* model);
|
||||
virtual ~SkeletonRagdoll();
|
||||
|
||||
void slamPointPositions();
|
||||
virtual void stepForward(float deltaTime);
|
||||
|
||||
virtual void initPoints();
|
||||
virtual void buildConstraints();
|
||||
|
||||
void updateMuscles();
|
||||
private:
|
||||
Model* _model;
|
||||
QVector<MuscleConstraint*> _muscleConstraints;
|
||||
};
|
||||
|
||||
#endif // hifi_SkeletonRagdoll_h
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
|
||||
#include "CaraFaceTracker.h"
|
||||
#include <SharedUtil.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
//qt
|
||||
#include <QJsonDocument>
|
||||
|
|
|
@ -178,6 +178,31 @@ float rescaleCoef(float ddeCoef) {
|
|||
return (ddeCoef - DDE_MIN_RANGE) / (DDE_MAX_RANGE - DDE_MIN_RANGE);
|
||||
}
|
||||
|
||||
const int MIN = 0;
|
||||
const int AVG = 1;
|
||||
const int MAX = 2;
|
||||
const float LONG_TERM_AVERAGE = 0.999f;
|
||||
|
||||
|
||||
void resetCoefficient(float * coefficient, float currentValue) {
|
||||
coefficient[MIN] = coefficient[MAX] = coefficient[AVG] = currentValue;
|
||||
}
|
||||
|
||||
float updateAndGetCoefficient(float * coefficient, float currentValue, bool scaleToRange = false) {
|
||||
coefficient[MIN] = (currentValue < coefficient[MIN]) ? currentValue : coefficient[MIN];
|
||||
coefficient[MAX] = (currentValue > coefficient[MAX]) ? currentValue : coefficient[MAX];
|
||||
coefficient[AVG] = LONG_TERM_AVERAGE * coefficient[AVG] + (1.f - LONG_TERM_AVERAGE) * currentValue;
|
||||
if (coefficient[MAX] > coefficient[MIN]) {
|
||||
if (scaleToRange) {
|
||||
return glm::clamp((currentValue - coefficient[AVG]) / (coefficient[MAX] - coefficient[MIN]), 0.f, 1.f);
|
||||
} else {
|
||||
return glm::clamp(currentValue - coefficient[AVG], 0.f, 1.f);
|
||||
}
|
||||
} else {
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
||||
if(buffer.size() > MIN_PACKET_SIZE) {
|
||||
Packet packet;
|
||||
|
@ -189,14 +214,17 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
|||
memcpy(&translation, packet.translation, sizeof(packet.translation));
|
||||
glm::quat rotation;
|
||||
memcpy(&rotation, &packet.rotation, sizeof(packet.rotation));
|
||||
if (_reset) {
|
||||
if (_reset || (_lastReceiveTimestamp == 0)) {
|
||||
memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3));
|
||||
memcpy(&_referenceRotation, &rotation, sizeof(glm::quat));
|
||||
|
||||
resetCoefficient(_rightEye, packet.expressions[0]);
|
||||
resetCoefficient(_leftEye, packet.expressions[1]);
|
||||
_reset = false;
|
||||
}
|
||||
|
||||
// Compute relative translation
|
||||
float LEAN_DAMPING_FACTOR = 40;
|
||||
float LEAN_DAMPING_FACTOR = 200.0f;
|
||||
translation -= _referenceTranslation;
|
||||
translation /= LEAN_DAMPING_FACTOR;
|
||||
translation.x *= -1;
|
||||
|
@ -208,10 +236,19 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
|||
_headTranslation = translation;
|
||||
_headRotation = rotation;
|
||||
|
||||
if (_lastReceiveTimestamp == 0) {
|
||||
// On first packet, reset coefficients
|
||||
}
|
||||
|
||||
// Set blendshapes
|
||||
float BLINK_MAGNIFIER = 2.0f;
|
||||
_blendshapeCoefficients[_leftBlinkIndex] = rescaleCoef(packet.expressions[1]) * BLINK_MAGNIFIER;
|
||||
_blendshapeCoefficients[_rightBlinkIndex] = rescaleCoef(packet.expressions[0]) * BLINK_MAGNIFIER;
|
||||
float EYE_MAGNIFIER = 4.0f;
|
||||
|
||||
float rightEye = (updateAndGetCoefficient(_rightEye, packet.expressions[0])) * EYE_MAGNIFIER;
|
||||
_blendshapeCoefficients[_rightBlinkIndex] = rightEye;
|
||||
float leftEye = (updateAndGetCoefficient(_leftEye, packet.expressions[1])) * EYE_MAGNIFIER;
|
||||
_blendshapeCoefficients[_leftBlinkIndex] = leftEye;
|
||||
|
||||
// Right eye = packet.expressions[0];
|
||||
|
||||
float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]);
|
||||
if (leftBrow < 0.5f) {
|
||||
|
|
|
@ -84,6 +84,10 @@ private:
|
|||
int _mouthSmileRightIndex;
|
||||
|
||||
int _jawOpenIndex;
|
||||
|
||||
float _leftEye[3];
|
||||
float _rightEye[3];
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_DdeFaceTracker_h
|
|
@ -44,7 +44,7 @@ ovrFovPort OculusManager::_eyeFov[ovrEye_Count];
|
|||
ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count];
|
||||
ovrSizei OculusManager::_renderTargetSize;
|
||||
ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2];
|
||||
GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 };
|
||||
GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 };
|
||||
GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 };
|
||||
GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 };
|
||||
ovrFrameTiming OculusManager::_hmdFrameTiming;
|
||||
|
@ -66,12 +66,14 @@ void OculusManager::connect() {
|
|||
UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
|
||||
}
|
||||
_isConnected = true;
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
_eyeFov[0] = _ovrHmd->DefaultEyeFov[0];
|
||||
_eyeFov[1] = _ovrHmd->DefaultEyeFov[1];
|
||||
#else
|
||||
ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc);
|
||||
|
||||
_eyeFov[0] = _ovrHmdDesc.DefaultEyeFov[0];
|
||||
_eyeFov[1] = _ovrHmdDesc.DefaultEyeFov[1];
|
||||
|
||||
#endif
|
||||
//Get texture size
|
||||
ovrSizei recommendedTex0Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left,
|
||||
_eyeFov[0], 1.0f);
|
||||
|
@ -86,11 +88,21 @@ void OculusManager::connect() {
|
|||
_eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]);
|
||||
_eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]);
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence);
|
||||
#else
|
||||
ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_LatencyTest);
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position |
|
||||
ovrTrackingCap_MagYawCorrection,
|
||||
ovrTrackingCap_Orientation);
|
||||
#else
|
||||
ovrHmd_StartSensor(_ovrHmd, ovrSensorCap_Orientation | ovrSensorCap_YawCorrection |
|
||||
ovrSensorCap_Position,
|
||||
ovrSensorCap_Orientation);
|
||||
#endif
|
||||
|
||||
if (!_camera) {
|
||||
_camera = new Camera;
|
||||
|
@ -123,6 +135,10 @@ void OculusManager::connect() {
|
|||
|
||||
} else {
|
||||
_isConnected = false;
|
||||
|
||||
// we're definitely not in "VR mode" so tell the menu that
|
||||
Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false);
|
||||
|
||||
ovrHmd_Destroy(_ovrHmd);
|
||||
ovr_Shutdown();
|
||||
}
|
||||
|
@ -183,6 +199,16 @@ void OculusManager::generateDistortionMesh() {
|
|||
DistortionVertex* v = pVBVerts;
|
||||
ovrDistortionVertex* ov = meshData.pVertexData;
|
||||
for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) {
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
v->pos.x = ov->ScreenPosNDC.x;
|
||||
v->pos.y = ov->ScreenPosNDC.y;
|
||||
v->texR.x = ov->TanEyeAnglesR.x;
|
||||
v->texR.y = ov->TanEyeAnglesR.y;
|
||||
v->texG.x = ov->TanEyeAnglesG.x;
|
||||
v->texG.y = ov->TanEyeAnglesG.y;
|
||||
v->texB.x = ov->TanEyeAnglesB.x;
|
||||
v->texB.y = ov->TanEyeAnglesB.y;
|
||||
#else
|
||||
v->pos.x = ov->Pos.x;
|
||||
v->pos.y = ov->Pos.y;
|
||||
v->texR.x = ov->TexR.x;
|
||||
|
@ -191,6 +217,7 @@ void OculusManager::generateDistortionMesh() {
|
|||
v->texG.y = ov->TexG.y;
|
||||
v->texB.x = ov->TexB.x;
|
||||
v->texB.y = ov->TexB.y;
|
||||
#endif
|
||||
v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f);
|
||||
v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f);
|
||||
v++;
|
||||
|
@ -291,12 +318,23 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
glPushMatrix();
|
||||
|
||||
glm::quat orientation;
|
||||
|
||||
glm::vec3 trackerPosition;
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
|
||||
ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position;
|
||||
|
||||
trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z);
|
||||
trackerPosition = bodyOrientation * trackerPosition;
|
||||
#endif
|
||||
|
||||
//Render each eye into an fbo
|
||||
for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) {
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex];
|
||||
#else
|
||||
ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex];
|
||||
|
||||
#endif
|
||||
//Set the camera rotation for this eye
|
||||
eyeRenderPose[eye] = ovrHmd_GetEyePose(_ovrHmd, eye);
|
||||
orientation.x = eyeRenderPose[eye].Orientation.x;
|
||||
|
@ -305,7 +343,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
orientation.w = eyeRenderPose[eye].Orientation.w;
|
||||
|
||||
_camera->setTargetRotation(bodyOrientation * orientation);
|
||||
_camera->setTargetPosition(position);
|
||||
_camera->setTargetPosition(position + trackerPosition);
|
||||
|
||||
_camera->update(1.0f / Application::getInstance()->getFps());
|
||||
|
||||
Matrix4f proj = ovrMatrix4f_Projection(_eyeRenderDesc[eye].Fov, whichCamera.getNearClip(), whichCamera.getFarClip(), true);
|
||||
|
@ -425,19 +464,32 @@ void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) {
|
|||
//Tries to reconnect to the sensors
|
||||
void OculusManager::reset() {
|
||||
#ifdef HAVE_LIBOVR
|
||||
disconnect();
|
||||
connect();
|
||||
if (_isConnected) {
|
||||
ovrHmd_RecenterPose(_ovrHmd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//Gets the current predicted angles from the oculus sensors
|
||||
void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
|
||||
#ifdef HAVE_LIBOVR
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
|
||||
#else
|
||||
ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds);
|
||||
|
||||
#endif
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) {
|
||||
#else
|
||||
if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) {
|
||||
ovrPosef pose = ss.Predicted.Pose;
|
||||
Quatf orientation = Quatf(pose.Orientation);
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
ovrPosef headPose = ts.HeadPose.ThePose;
|
||||
#else
|
||||
ovrPosef headPose = ss.Predicted.Pose;
|
||||
#endif
|
||||
Quatf orientation = Quatf(headPose.Orientation);
|
||||
orientation.GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
|
||||
} else {
|
||||
yaw = 0.0f;
|
||||
|
@ -450,6 +502,18 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
|
|||
roll = 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
glm::vec3 OculusManager::getRelativePosition() {
|
||||
#if (defined(__APPLE__) || defined(_WIN32)) && HAVE_LIBOVR
|
||||
ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
|
||||
ovrVector3f headPosition = trackingState.HeadPose.ThePose.Position;
|
||||
|
||||
return glm::vec3(headPosition.x, headPosition.y, headPosition.z);
|
||||
#else
|
||||
// no positional tracking in Linux yet
|
||||
return glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
//Used to set the size of the glow framebuffers
|
||||
QSize OculusManager::getRenderTargetSize() {
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
/// param \pitch[out] pitch in radians
|
||||
/// param \roll[out] roll in radians
|
||||
static void getEulerAngles(float& yaw, float& pitch, float& roll);
|
||||
static glm::vec3 getRelativePosition();
|
||||
static QSize getRenderTargetSize();
|
||||
|
||||
private:
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "UserActivityLogger.h"
|
||||
|
||||
#ifdef HAVE_SIXENSE
|
||||
|
||||
const int CALIBRATION_STATE_IDLE = 0;
|
||||
const int CALIBRATION_STATE_X = 1;
|
||||
const int CALIBRATION_STATE_Y = 2;
|
||||
|
@ -41,8 +42,9 @@ SixenseManager::SixenseManager() {
|
|||
// By default we assume the _neckBase (in orb frame) is as high above the orb
|
||||
// as the "torso" is below it.
|
||||
_neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);
|
||||
|
||||
|
||||
sixenseInit();
|
||||
|
||||
#endif
|
||||
_hydrasConnected = false;
|
||||
_triggerPressed[0] = false;
|
||||
|
|
|
@ -71,7 +71,7 @@ private:
|
|||
glm::vec3 _reachUp;
|
||||
glm::vec3 _reachForward;
|
||||
float _lastDistance;
|
||||
|
||||
|
||||
#endif
|
||||
bool _hydrasConnected;
|
||||
quint64 _lastMovement;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <FBXReader.h>
|
||||
|
||||
class AngularConstraint;
|
||||
|
|
|
@ -1449,9 +1449,11 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re
|
|||
if (cascadedShadows) {
|
||||
activeProgram->setUniform(activeLocations->shadowDistances, Application::getInstance()->getShadowDistances());
|
||||
}
|
||||
activeProgram->setUniformValueArray(activeLocations->localLightDirections,
|
||||
(const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4);
|
||||
|
||||
if (mode != SHADOW_RENDER_MODE) {
|
||||
activeProgram->setUniformValueArray(activeLocations->localLightDirections,
|
||||
(const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4);
|
||||
}
|
||||
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) {
|
||||
activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3);
|
||||
|
|
|
@ -164,6 +164,9 @@ public:
|
|||
const QVector<LocalLight>& getLocalLights() const { return _localLights; }
|
||||
|
||||
void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; }
|
||||
|
||||
QVector<JointState>& getJointStates() { return _jointStates; }
|
||||
const QVector<JointState>& getJointStates() const { return _jointStates; }
|
||||
|
||||
protected:
|
||||
QSharedPointer<NetworkGeometry> _geometry;
|
||||
|
|
|
@ -87,6 +87,37 @@ bool ClipboardScriptingInterface::importVoxels() {
|
|||
return Application::getInstance()->getImportSucceded();
|
||||
}
|
||||
|
||||
bool ClipboardScriptingInterface::importVoxels(const QString& filename) {
|
||||
qDebug() << "Importing ... ";
|
||||
|
||||
VoxelImporter* importer = Application::getInstance()->getVoxelImporter();
|
||||
|
||||
if (!importer->validImportFile(filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QEventLoop loop;
|
||||
connect(importer, SIGNAL(importDone()), &loop, SLOT(quit()));
|
||||
importer->import(filename);
|
||||
loop.exec();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClipboardScriptingInterface::importVoxels(const QString& filename, float x, float y, float z, float s) {
|
||||
bool success = importVoxels(filename);
|
||||
|
||||
if (success) {
|
||||
pasteVoxel(x, y, z, s);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ClipboardScriptingInterface::importVoxels(const QString& filename, const VoxelDetail& destinationVoxel) {
|
||||
return importVoxels(filename, destinationVoxel.x, destinationVoxel.y, destinationVoxel.z, destinationVoxel.s);
|
||||
}
|
||||
|
||||
void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) {
|
||||
nudgeVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s, nudgeVec);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,9 @@ public slots:
|
|||
void exportVoxel(float x, float y, float z, float s);
|
||||
|
||||
bool importVoxels();
|
||||
bool importVoxels(const QString& filename);
|
||||
bool importVoxels(const QString& filename, float x, float y, float z, float s);
|
||||
bool importVoxels(const QString& filename, const VoxelDetail& destinationVoxel);
|
||||
|
||||
void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec);
|
||||
void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec);
|
||||
|
|
|
@ -57,6 +57,9 @@ ApplicationOverlay::~ApplicationOverlay() {
|
|||
const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
|
||||
const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };
|
||||
|
||||
const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };
|
||||
const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
|
||||
|
||||
// Renders the overlays either to a texture or to the screen
|
||||
void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
||||
|
||||
|
@ -115,6 +118,8 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
|||
|
||||
renderPointers();
|
||||
|
||||
renderDomainConnectionStatusBorder();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
|
@ -1234,6 +1239,30 @@ void ApplicationOverlay::renderTexturedHemisphere() {
|
|||
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderDomainConnectionStatusBorder() {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
if (nodeList && !nodeList->getDomainHandler().isConnected()) {
|
||||
QGLWidget* glWidget = Application::getInstance()->getGLWidget();
|
||||
int right = glWidget->width();
|
||||
int bottom = glWidget->height();
|
||||
|
||||
glColor3f(CONNECTION_STATUS_BORDER_COLOR[0],
|
||||
CONNECTION_STATUS_BORDER_COLOR[1],
|
||||
CONNECTION_STATUS_BORDER_COLOR[2]);
|
||||
glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH);
|
||||
|
||||
glBegin(GL_LINE_LOOP);
|
||||
|
||||
glVertex2i(0, 0);
|
||||
glVertex2i(0, bottom);
|
||||
glVertex2i(right, bottom);
|
||||
glVertex2i(right, 0);
|
||||
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() {
|
||||
QSize size = Application::getInstance()->getGLWidget()->size();
|
||||
if (!_framebufferObject || _framebufferObject->size() != size) {
|
||||
|
|
|
@ -56,6 +56,7 @@ private:
|
|||
void renderAudioMeter();
|
||||
void renderStatsAndLogs();
|
||||
void renderTexturedHemisphere();
|
||||
void renderDomainConnectionStatusBorder();
|
||||
|
||||
QOpenGLFramebufferObject* _framebufferObject;
|
||||
float _trailingAudioLoudness;
|
||||
|
@ -76,4 +77,4 @@ private:
|
|||
GLuint _crosshairTexture;
|
||||
};
|
||||
|
||||
#endif // hifi_ApplicationOverlay_h
|
||||
#endif // hifi_ApplicationOverlay_h
|
||||
|
|
|
@ -118,6 +118,8 @@ MetavoxelEditor::MetavoxelEditor() :
|
|||
addTool(new SetSpannerTool(this));
|
||||
addTool(new ImportHeightfieldTool(this));
|
||||
addTool(new EraseHeightfieldTool(this));
|
||||
addTool(new HeightfieldHeightBrushTool(this));
|
||||
addTool(new HeightfieldColorBrushTool(this));
|
||||
|
||||
updateAttributes();
|
||||
|
||||
|
@ -954,11 +956,11 @@ void ImportHeightfieldTool::apply() {
|
|||
HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(bufferData.data());
|
||||
MetavoxelData data;
|
||||
data.setSize(scale);
|
||||
HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getHeight()));
|
||||
HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getUnextendedHeight()));
|
||||
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue(
|
||||
AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer))));
|
||||
if (!buffer->getColor().isEmpty()) {
|
||||
HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getColor()));
|
||||
HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getUnextendedColor()));
|
||||
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue(
|
||||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer))));
|
||||
}
|
||||
|
@ -1001,34 +1003,38 @@ void ImportHeightfieldTool::updatePreview() {
|
|||
if (_heightImage.width() > 0 && _heightImage.height() > 0) {
|
||||
float z = 0.0f;
|
||||
int blockSize = pow(2.0, _blockSize->value());
|
||||
int blockAdvancement = blockSize - 1;
|
||||
for (int i = 0; i < _heightImage.height(); i += blockAdvancement, z++) {
|
||||
int heightSize = blockSize + HeightfieldBuffer::HEIGHT_EXTENSION;
|
||||
int colorSize = blockSize + HeightfieldBuffer::SHARED_EDGE;
|
||||
for (int i = 0; i < _heightImage.height(); i += blockSize, z++) {
|
||||
float x = 0.0f;
|
||||
for (int j = 0; j < _heightImage.width(); j += blockAdvancement, x++) {
|
||||
QByteArray height(blockSize * blockSize, 0);
|
||||
int rows = qMin(blockSize, _heightImage.height() - i);
|
||||
int columns = qMin(blockSize, _heightImage.width() - j);
|
||||
const int BYTES_PER_COLOR = 3;
|
||||
for (int j = 0; j < _heightImage.width(); j += blockSize, x++) {
|
||||
QByteArray height(heightSize * heightSize, 0);
|
||||
int extendedI = qMax(i - HeightfieldBuffer::HEIGHT_BORDER, 0);
|
||||
int extendedJ = qMax(j - HeightfieldBuffer::HEIGHT_BORDER, 0);
|
||||
int offsetY = extendedI - i + HeightfieldBuffer::HEIGHT_BORDER;
|
||||
int offsetX = extendedJ - j + HeightfieldBuffer::HEIGHT_BORDER;
|
||||
int rows = qMin(heightSize - offsetY, _heightImage.height() - extendedI);
|
||||
int columns = qMin(heightSize - offsetX, _heightImage.width() - extendedJ);
|
||||
for (int y = 0; y < rows; y++) {
|
||||
uchar* src = _heightImage.scanLine(i + y) + j * BYTES_PER_COLOR;
|
||||
char* dest = height.data() + y * blockSize;
|
||||
uchar* src = _heightImage.scanLine(extendedI + y) + extendedJ * HeightfieldData::COLOR_BYTES;
|
||||
char* dest = height.data() + (y + offsetY) * heightSize + offsetX;
|
||||
for (int x = 0; x < columns; x++) {
|
||||
*dest++ = *src;
|
||||
src += BYTES_PER_COLOR;
|
||||
src += HeightfieldData::COLOR_BYTES;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray color;
|
||||
if (!_colorImage.isNull()) {
|
||||
color = QByteArray(blockSize * blockSize * BYTES_PER_COLOR, 0);
|
||||
rows = qMax(0, qMin(blockSize, _colorImage.height() - i));
|
||||
columns = qMax(0, qMin(blockSize, _colorImage.width() - j));
|
||||
color = QByteArray(colorSize * colorSize * HeightfieldData::COLOR_BYTES, 0);
|
||||
rows = qMax(0, qMin(colorSize, _colorImage.height() - i));
|
||||
columns = qMax(0, qMin(colorSize, _colorImage.width() - j));
|
||||
for (int y = 0; y < rows; y++) {
|
||||
memcpy(color.data() + y * blockSize * BYTES_PER_COLOR,
|
||||
_colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR);
|
||||
memcpy(color.data() + y * colorSize * HeightfieldData::COLOR_BYTES,
|
||||
_colorImage.scanLine(i + y) + j * HeightfieldData::COLOR_BYTES,
|
||||
columns * HeightfieldData::COLOR_BYTES);
|
||||
}
|
||||
}
|
||||
buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color, false)));
|
||||
buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1080,3 +1086,72 @@ void EraseHeightfieldTool::apply() {
|
|||
message.edit = QVariant::fromValue(edit);
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
}
|
||||
|
||||
HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QString& name) :
|
||||
MetavoxelTool(editor, name, false) {
|
||||
|
||||
QWidget* widget = new QWidget();
|
||||
widget->setLayout(_form = new QFormLayout());
|
||||
layout()->addWidget(widget);
|
||||
|
||||
_form->addRow("Radius:", _radius = new QDoubleSpinBox());
|
||||
_radius->setSingleStep(0.01);
|
||||
_radius->setMaximum(FLT_MAX);
|
||||
_radius->setValue(1.0);
|
||||
}
|
||||
|
||||
void HeightfieldBrushTool::render() {
|
||||
if (Application::getInstance()->isMouseHidden()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find the intersection with the heightfield
|
||||
glm::vec3 origin = Application::getInstance()->getMouseRayOrigin();
|
||||
glm::vec3 direction = Application::getInstance()->getMouseRayDirection();
|
||||
|
||||
float distance;
|
||||
if (!Application::getInstance()->getMetavoxels()->findFirstRayHeightfieldIntersection(origin, direction, distance)) {
|
||||
return;
|
||||
}
|
||||
Application::getInstance()->getMetavoxels()->renderHeightfieldCursor(
|
||||
_position = origin + distance * direction, _radius->value());
|
||||
}
|
||||
|
||||
bool HeightfieldBrushTool::eventFilter(QObject* watched, QEvent* event) {
|
||||
if (event->type() == QEvent::Wheel) {
|
||||
float angle = static_cast<QWheelEvent*>(event)->angleDelta().y();
|
||||
const float ANGLE_SCALE = 1.0f / 1000.0f;
|
||||
_radius->setValue(_radius->value() * glm::pow(2.0f, angle * ANGLE_SCALE));
|
||||
return true;
|
||||
|
||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||
MetavoxelEditMessage message = { createEdit(static_cast<QMouseEvent*>(event)->button() == Qt::RightButton) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
HeightfieldHeightBrushTool::HeightfieldHeightBrushTool(MetavoxelEditor* editor) :
|
||||
HeightfieldBrushTool(editor, "Height Brush") {
|
||||
|
||||
_form->addRow("Height:", _height = new QDoubleSpinBox());
|
||||
_height->setMinimum(-FLT_MAX);
|
||||
_height->setMaximum(FLT_MAX);
|
||||
_height->setValue(1.0);
|
||||
}
|
||||
|
||||
QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) {
|
||||
return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(),
|
||||
alternate ? -_height->value() : _height->value()));
|
||||
}
|
||||
|
||||
HeightfieldColorBrushTool::HeightfieldColorBrushTool(MetavoxelEditor* editor) :
|
||||
HeightfieldBrushTool(editor, "Color Brush") {
|
||||
|
||||
_form->addRow("Color:", _color = new QColorEditor(this));
|
||||
}
|
||||
|
||||
QVariant HeightfieldColorBrushTool::createEdit(bool alternate) {
|
||||
return QVariant::fromValue(PaintHeightfieldColorEdit(_position, _radius->value(), _color->getColor()));
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "MetavoxelSystem.h"
|
||||
#include "renderer/ProgramObject.h"
|
||||
|
||||
class QColorEditor;
|
||||
class QComboBox;
|
||||
class QDoubleSpinBox;
|
||||
class QGroupBox;
|
||||
|
@ -282,7 +283,7 @@ private:
|
|||
HeightfieldPreview _preview;
|
||||
};
|
||||
|
||||
// Allows clearing heighfield blocks.
|
||||
/// Allows clearing heighfield blocks.
|
||||
class EraseHeightfieldTool : public HeightfieldTool {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -302,4 +303,60 @@ private:
|
|||
QSpinBox* _length;
|
||||
};
|
||||
|
||||
/// Base class for tools that allow painting on heightfields.
|
||||
class HeightfieldBrushTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldBrushTool(MetavoxelEditor* editor, const QString& name);
|
||||
|
||||
virtual void render();
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(bool alternate) = 0;
|
||||
|
||||
QFormLayout* _form;
|
||||
QDoubleSpinBox* _radius;
|
||||
|
||||
glm::vec3 _position;
|
||||
};
|
||||
|
||||
/// Allows raising or lowering parts of the heightfield.
|
||||
class HeightfieldHeightBrushTool : public HeightfieldBrushTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldHeightBrushTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(bool alternate);
|
||||
|
||||
private:
|
||||
|
||||
QDoubleSpinBox* _height;
|
||||
};
|
||||
|
||||
/// Allows coloring parts of the heightfield.
|
||||
class HeightfieldColorBrushTool : public HeightfieldBrushTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldColorBrushTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(bool alternate);
|
||||
|
||||
private:
|
||||
|
||||
QColorEditor* _color;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelEditor_h
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// ImportDialog.cpp
|
||||
// VoxelImportDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Clement Brisset on 8/12/13.
|
||||
|
@ -20,7 +20,11 @@
|
|||
|
||||
#include "Application.h"
|
||||
|
||||
#include "ImportDialog.h"
|
||||
#include "VoxelImportDialog.h"
|
||||
#include "voxels/VoxelImporter.h"
|
||||
|
||||
const QString SETTINGS_GROUP_NAME = "VoxelImport";
|
||||
const QString IMPORT_DIALOG_SETTINGS_KEY = "VoxelImportDialogSettings";
|
||||
|
||||
const QString WINDOW_NAME = QObject::tr("Import Voxels");
|
||||
const QString IMPORT_BUTTON_NAME = QObject::tr("Import Voxels");
|
||||
|
@ -97,12 +101,14 @@ QString HiFiIconProvider::type(const QFileInfo &info) const {
|
|||
return QFileIconProvider::type(info);
|
||||
}
|
||||
|
||||
ImportDialog::ImportDialog(QWidget* parent) :
|
||||
VoxelImportDialog::VoxelImportDialog(QWidget* parent) :
|
||||
QFileDialog(parent, WINDOW_NAME, DOWNLOAD_LOCATION, NULL),
|
||||
_progressBar(this),
|
||||
_importButton(IMPORT_BUTTON_NAME, this),
|
||||
_cancelButton(CANCEL_BUTTON_NAME, this),
|
||||
_mode(importMode) {
|
||||
_importButton(IMPORT_BUTTON_NAME, this),
|
||||
_importer(Application::getInstance()->getVoxelImporter()),
|
||||
_mode(importMode),
|
||||
_progressBar(this),
|
||||
_didImport(false) {
|
||||
|
||||
setOption(QFileDialog::DontUseNativeDialog, true);
|
||||
setFileMode(QFileDialog::ExistingFile);
|
||||
|
@ -113,41 +119,54 @@ ImportDialog::ImportDialog(QWidget* parent) :
|
|||
|
||||
_progressBar.setRange(0, 100);
|
||||
|
||||
connect(&_importButton, SIGNAL(pressed()), SLOT(accept()));
|
||||
connect(&_cancelButton, SIGNAL(pressed()), SIGNAL(canceled()));
|
||||
connect(&_importButton, SIGNAL(pressed()), this, SLOT(accept()));
|
||||
connect(&_cancelButton, SIGNAL(pressed()), this, SLOT(cancel()));
|
||||
connect(this, SIGNAL(currentChanged(QString)), SLOT(saveCurrentFile(QString)));
|
||||
}
|
||||
|
||||
void ImportDialog::reset() {
|
||||
setMode(importMode);
|
||||
_progressBar.setValue(0);
|
||||
void VoxelImportDialog::cancel() {
|
||||
switch (getMode()) {
|
||||
case importMode:
|
||||
_importer->cancel();
|
||||
close();
|
||||
break;
|
||||
default:
|
||||
_importer->reset();
|
||||
setMode(importMode);
|
||||
break;
|
||||
}
|
||||
emit canceled();
|
||||
}
|
||||
|
||||
void ImportDialog::setMode(dialogMode mode) {
|
||||
void VoxelImportDialog::saveSettings(QSettings* settings) {
|
||||
settings->beginGroup(SETTINGS_GROUP_NAME);
|
||||
settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, saveState());
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
void VoxelImportDialog::loadSettings(QSettings* settings) {
|
||||
settings->beginGroup(SETTINGS_GROUP_NAME);
|
||||
restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray());
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
bool VoxelImportDialog::prompt() {
|
||||
reset();
|
||||
exec();
|
||||
return _didImport;
|
||||
}
|
||||
|
||||
void VoxelImportDialog::reset() {
|
||||
setMode(importMode);
|
||||
_didImport = false;
|
||||
}
|
||||
|
||||
void VoxelImportDialog::setMode(dialogMode mode) {
|
||||
dialogMode previousMode = _mode;
|
||||
_mode = mode;
|
||||
|
||||
switch (_mode) {
|
||||
case loadingMode:
|
||||
_importButton.setEnabled(false);
|
||||
_importButton.setText(LOADING_BUTTON_NAME);
|
||||
findChild<QWidget*>("sidebar")->setEnabled(false);
|
||||
findChild<QWidget*>("treeView")->setEnabled(false);
|
||||
findChild<QWidget*>("backButton")->setEnabled(false);
|
||||
findChild<QWidget*>("forwardButton")->setEnabled(false);
|
||||
findChild<QWidget*>("toParentButton")->setEnabled(false);
|
||||
break;
|
||||
case placeMode:
|
||||
_progressBar.setValue(100);
|
||||
_importButton.setEnabled(true);
|
||||
_importButton.setText(PLACE_BUTTON_NAME);
|
||||
findChild<QWidget*>("sidebar")->setEnabled(false);
|
||||
findChild<QWidget*>("treeView")->setEnabled(false);
|
||||
findChild<QWidget*>("backButton")->setEnabled(false);
|
||||
findChild<QWidget*>("forwardButton")->setEnabled(false);
|
||||
findChild<QWidget*>("toParentButton")->setEnabled(false);
|
||||
break;
|
||||
case importMode:
|
||||
default:
|
||||
_progressBar.setValue(0);
|
||||
_importButton.setEnabled(true);
|
||||
_importButton.setText(IMPORT_BUTTON_NAME);
|
||||
|
@ -157,22 +176,60 @@ void ImportDialog::setMode(dialogMode mode) {
|
|||
findChild<QWidget*>("forwardButton")->setEnabled(true);
|
||||
findChild<QWidget*>("toParentButton")->setEnabled(true);
|
||||
break;
|
||||
case loadingMode:
|
||||
// Connect to VoxelImporter signals
|
||||
connect(_importer, SIGNAL(importProgress(int)), this, SLOT(updateProgressBar(int)));
|
||||
connect(_importer, SIGNAL(importDone()), this, SLOT(afterImport()));
|
||||
|
||||
_importButton.setEnabled(false);
|
||||
_importButton.setText(LOADING_BUTTON_NAME);
|
||||
findChild<QWidget*>("sidebar")->setEnabled(false);
|
||||
findChild<QWidget*>("treeView")->setEnabled(false);
|
||||
findChild<QWidget*>("backButton")->setEnabled(false);
|
||||
findChild<QWidget*>("forwardButton")->setEnabled(false);
|
||||
findChild<QWidget*>("toParentButton")->setEnabled(false);
|
||||
break;
|
||||
case finishedMode:
|
||||
if (previousMode == loadingMode) {
|
||||
// Disconnect from VoxelImporter signals
|
||||
disconnect(_importer, SIGNAL(importProgress(int)), this, SLOT(setProgressBarValue(int)));
|
||||
disconnect(_importer, SIGNAL(importDone()), this, SLOT(afterImport()));
|
||||
}
|
||||
setMode(importMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ImportDialog::setProgressBarValue(int value) {
|
||||
void VoxelImportDialog::setProgressBarValue(int value) {
|
||||
_progressBar.setValue(value);
|
||||
}
|
||||
|
||||
void ImportDialog::accept() {
|
||||
emit accepted();
|
||||
void VoxelImportDialog::accept() {
|
||||
if (getMode() == importMode) {
|
||||
QString filename = getCurrentFile();
|
||||
|
||||
// If file is invalid we ignore the call
|
||||
if (!_importer->validImportFile(filename)) {
|
||||
return;
|
||||
}
|
||||
// Let's prepare the dialog window for import
|
||||
setMode(loadingMode);
|
||||
|
||||
_importer->import(filename);
|
||||
}
|
||||
}
|
||||
|
||||
void ImportDialog::saveCurrentFile(QString filename) {
|
||||
void VoxelImportDialog::afterImport() {
|
||||
setMode(finishedMode);
|
||||
_didImport = true;
|
||||
close();
|
||||
}
|
||||
|
||||
void VoxelImportDialog::saveCurrentFile(QString filename) {
|
||||
_currentFile = QFileInfo(filename).isFile() ? filename : "";
|
||||
}
|
||||
|
||||
void ImportDialog::setLayout() {
|
||||
void VoxelImportDialog::setLayout() {
|
||||
QGridLayout* gridLayout = (QGridLayout*) layout();
|
||||
gridLayout->addWidget(&_progressBar, 2, 0, 2, 1);
|
||||
gridLayout->addWidget(&_cancelButton, 2, 1, 2, 1);
|
||||
|
@ -258,7 +315,7 @@ void ImportDialog::setLayout() {
|
|||
|
||||
}
|
||||
|
||||
void ImportDialog::setImportTypes() {
|
||||
void VoxelImportDialog::setImportTypes() {
|
||||
QFile config(Application::resourcesPath() + "config/config.json");
|
||||
config.open(QFile::ReadOnly | QFile::Text);
|
||||
QJsonDocument document = QJsonDocument::fromJson(config.readAll());
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// ImportDialog.h
|
||||
// VoxelImportDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Clement Brisset on 8/12/13.
|
||||
|
@ -9,8 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ImportDialog_h
|
||||
#define hifi_ImportDialog_h
|
||||
#ifndef hifi_VoxelImportDialog_h
|
||||
#define hifi_VoxelImportDialog_h
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "voxels/VoxelImporter.h"
|
||||
|
||||
class HiFiIconProvider : public QFileIconProvider {
|
||||
public:
|
||||
HiFiIconProvider(const QHash<QString, QString> map) { iconsMap = map; };
|
||||
|
@ -35,39 +37,45 @@ public:
|
|||
enum dialogMode {
|
||||
importMode,
|
||||
loadingMode,
|
||||
placeMode
|
||||
finishedMode
|
||||
};
|
||||
|
||||
class ImportDialog : public QFileDialog {
|
||||
class VoxelImportDialog : public QFileDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ImportDialog(QWidget* parent = NULL);
|
||||
void reset();
|
||||
VoxelImportDialog(QWidget* parent = NULL);
|
||||
|
||||
QString getCurrentFile() const { return _currentFile; }
|
||||
dialogMode getMode() const { return _mode; }
|
||||
|
||||
void setMode(dialogMode mode);
|
||||
void reset();
|
||||
bool prompt();
|
||||
void loadSettings(QSettings* settings);
|
||||
void saveSettings(QSettings* settings);
|
||||
|
||||
signals:
|
||||
void canceled();
|
||||
|
||||
public slots:
|
||||
void setProgressBarValue(int value);
|
||||
|
||||
private slots:
|
||||
void setProgressBarValue(int value);
|
||||
void accept();
|
||||
void cancel();
|
||||
void saveCurrentFile(QString filename);
|
||||
void afterImport();
|
||||
|
||||
private:
|
||||
QString _currentFile;
|
||||
QProgressBar _progressBar;
|
||||
QPushButton _importButton;
|
||||
QPushButton _cancelButton;
|
||||
QString _currentFile;
|
||||
QPushButton _importButton;
|
||||
VoxelImporter* _importer;
|
||||
dialogMode _mode;
|
||||
QProgressBar _progressBar;
|
||||
bool _didImport;
|
||||
|
||||
void setLayout();
|
||||
void setImportTypes();
|
||||
};
|
||||
|
||||
#endif // hifi_ImportDialog_h
|
||||
#endif // hifi_VoxelImportDialog_h
|
|
@ -11,6 +11,8 @@
|
|||
#ifndef hifi_Base3DOverlay_h
|
||||
#define hifi_Base3DOverlay_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Overlay.h"
|
||||
|
||||
class Base3DOverlay : public Overlay {
|
||||
|
|
|
@ -26,7 +26,7 @@ void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode,
|
|||
if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) {
|
||||
qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount());
|
||||
}
|
||||
ssize_t messageLength = mutablePacket.size();
|
||||
int messageLength = mutablePacket.size();
|
||||
|
||||
Application* app = Application::getInstance();
|
||||
bool wasStatsPacket = false;
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
|
||||
#include "voxels/VoxelImporter.h"
|
||||
|
||||
const QString SETTINGS_GROUP_NAME = "VoxelImport";
|
||||
const QString IMPORT_DIALOG_SETTINGS_KEY = "ImportDialogSettings";
|
||||
const QStringList SUPPORTED_EXTENSIONS = QStringList() << "png" << "svo" << "schematic";
|
||||
|
||||
class ImportTask : public QObject, public QRunnable {
|
||||
public:
|
||||
|
@ -32,104 +31,46 @@ private:
|
|||
QString _filename;
|
||||
};
|
||||
|
||||
VoxelImporter::VoxelImporter(QWidget* parent) :
|
||||
QObject(parent),
|
||||
VoxelImporter::VoxelImporter() :
|
||||
_voxelTree(true),
|
||||
_importDialog(parent),
|
||||
_task(NULL),
|
||||
_didImport(false)
|
||||
_task(NULL)
|
||||
{
|
||||
LocalVoxelsList::getInstance()->addPersistantTree(IMPORT_TREE_NAME, &_voxelTree);
|
||||
|
||||
connect(&_voxelTree, SIGNAL(importProgress(int)), &_importDialog, SLOT(setProgressBarValue(int)));
|
||||
connect(&_importDialog, SIGNAL(canceled()), this, SLOT(cancel()));
|
||||
connect(&_importDialog, SIGNAL(accepted()), this, SLOT(import()));
|
||||
}
|
||||
|
||||
void VoxelImporter::saveSettings(QSettings* settings) {
|
||||
settings->beginGroup(SETTINGS_GROUP_NAME);
|
||||
settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, _importDialog.saveState());
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
void VoxelImporter::loadSettings(QSettings* settings) {
|
||||
settings->beginGroup(SETTINGS_GROUP_NAME);
|
||||
_importDialog.restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray());
|
||||
settings->endGroup();
|
||||
connect(&_voxelTree, SIGNAL(importProgress(int)), this, SIGNAL(importProgress(int)));
|
||||
}
|
||||
|
||||
VoxelImporter::~VoxelImporter() {
|
||||
cleanupTask();
|
||||
}
|
||||
|
||||
void VoxelImporter::cancel() {
|
||||
if (_task) {
|
||||
disconnect(_task, 0, 0, 0);
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
void VoxelImporter::reset() {
|
||||
_voxelTree.eraseAllOctreeElements();
|
||||
_importDialog.reset();
|
||||
|
||||
cleanupTask();
|
||||
}
|
||||
|
||||
int VoxelImporter::exec() {
|
||||
reset();
|
||||
_importDialog.exec();
|
||||
|
||||
if (!_didImport) {
|
||||
// if the import is rejected, we make sure to cleanup before leaving
|
||||
void VoxelImporter::import(const QString& filename) {
|
||||
// If present, abort existing import
|
||||
if (_task) {
|
||||
cleanupTask();
|
||||
return 1;
|
||||
} else {
|
||||
_didImport = false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelImporter::import() {
|
||||
switch (_importDialog.getMode()) {
|
||||
case loadingMode:
|
||||
_importDialog.setMode(placeMode);
|
||||
return;
|
||||
case placeMode:
|
||||
// Means the user chose to import
|
||||
_didImport = true;
|
||||
_importDialog.close();
|
||||
return;
|
||||
case importMode:
|
||||
default:
|
||||
QString filename = _importDialog.getCurrentFile();
|
||||
// if it's not a file, we ignore the call
|
||||
if (!QFileInfo(filename).isFile()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's prepare the dialog window for import
|
||||
_importDialog.setMode(loadingMode);
|
||||
|
||||
// If not already done, we switch to the local tree
|
||||
if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) {
|
||||
Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree);
|
||||
}
|
||||
|
||||
// Creation and launch of the import task on the thread pool
|
||||
_task = new ImportTask(filename);
|
||||
connect(_task, SIGNAL(destroyed()), SLOT(import()));
|
||||
QThreadPool::globalInstance()->start(_task);
|
||||
break;
|
||||
// If not already done, we switch to the local tree
|
||||
if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) {
|
||||
Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree);
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelImporter::cancel() {
|
||||
switch (_importDialog.getMode()) {
|
||||
case loadingMode:
|
||||
disconnect(_task, 0, 0, 0);
|
||||
cleanupTask();
|
||||
case placeMode:
|
||||
_importDialog.setMode(importMode);
|
||||
break;
|
||||
case importMode:
|
||||
default:
|
||||
_importDialog.close();
|
||||
break;
|
||||
}
|
||||
// Creation and launch of the import task on the thread pool
|
||||
_task = new ImportTask(filename);
|
||||
connect(_task, SIGNAL(destroyed()), SLOT(finishImport()));
|
||||
QThreadPool::globalInstance()->start(_task);
|
||||
}
|
||||
|
||||
void VoxelImporter::cleanupTask() {
|
||||
|
@ -140,6 +81,16 @@ void VoxelImporter::cleanupTask() {
|
|||
}
|
||||
}
|
||||
|
||||
void VoxelImporter::finishImport() {
|
||||
cleanupTask();
|
||||
emit importDone();
|
||||
}
|
||||
|
||||
bool VoxelImporter::validImportFile(const QString& filename) {
|
||||
QFileInfo fileInfo = QFileInfo(filename);
|
||||
return fileInfo.isFile() && SUPPORTED_EXTENSIONS.indexOf(fileInfo.suffix().toLower()) != -1;
|
||||
}
|
||||
|
||||
ImportTask::ImportTask(const QString &filename)
|
||||
: _filename(filename)
|
||||
{
|
||||
|
@ -151,7 +102,7 @@ void ImportTask::run() {
|
|||
// We start by cleaning up the shared voxel system just in case
|
||||
voxelSystem->killLocalVoxels();
|
||||
|
||||
// Then we call the righ method for the job
|
||||
// Then we call the right method for the job
|
||||
if (_filename.endsWith(".png", Qt::CaseInsensitive)) {
|
||||
voxelSystem->getTree()->readFromSquareARGB32Pixels(_filename.toLocal8Bit().data());
|
||||
} else if (_filename.endsWith(".svo", Qt::CaseInsensitive)) {
|
||||
|
@ -163,6 +114,6 @@ void ImportTask::run() {
|
|||
qDebug() << "[ERROR] Invalid file extension." << endl;
|
||||
}
|
||||
|
||||
// Here we reaverage the tree so that he is ready for preview
|
||||
// Here we reaverage the tree so that it is ready for preview
|
||||
voxelSystem->getTree()->reaverageOctreeElements();
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
#include <QThread>
|
||||
#include <QRunnable>
|
||||
#include <QStringList>
|
||||
|
||||
#include "ui/ImportDialog.h"
|
||||
#include "voxels/VoxelSystem.h"
|
||||
|
||||
class ImportTask;
|
||||
|
@ -23,28 +23,29 @@ class ImportTask;
|
|||
class VoxelImporter : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
VoxelImporter(QWidget* parent = NULL);
|
||||
VoxelImporter();
|
||||
~VoxelImporter();
|
||||
|
||||
void reset();
|
||||
void loadSettings(QSettings* settings);
|
||||
void saveSettings(QSettings* settings);
|
||||
|
||||
void cancel();
|
||||
VoxelTree* getVoxelTree() { return &_voxelTree; }
|
||||
bool validImportFile(const QString& filename);
|
||||
|
||||
public slots:
|
||||
int exec();
|
||||
void import();
|
||||
void cancel();
|
||||
void import(const QString& filename);
|
||||
|
||||
signals:
|
||||
void importDone();
|
||||
void importProgress(int);
|
||||
|
||||
private:
|
||||
VoxelTree _voxelTree;
|
||||
ImportDialog _importDialog;
|
||||
|
||||
ImportTask* _task;
|
||||
bool _didImport;
|
||||
|
||||
void cleanupTask();
|
||||
|
||||
private slots:
|
||||
void finishImport();
|
||||
};
|
||||
|
||||
#endif // hifi_VoxelImporter_h
|
||||
|
|
|
@ -1,29 +1,9 @@
|
|||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||
|
||||
set(TARGET_NAME animation)
|
||||
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network Script)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
link_hifi_libraries(shared fbx)
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
# link ZLIB
|
||||
find_package(ZLIB)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets)
|
||||
|
||||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
|
@ -1,26 +1,11 @@
|
|||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||
|
||||
set(TARGET_NAME audio)
|
||||
|
||||
find_package(Qt5 COMPONENTS Script)
|
||||
include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}")
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network)
|
||||
|
||||
# set up the external glm library
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
include_glm()
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_libraries(networking shared)
|
||||
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
26
libraries/audio/src/AudioFilter.cpp
Normal file
26
libraries/audio/src/AudioFilter.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// AudioFilter.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Craig Hansen-Sturm on 8/10/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
|
||||
//
|
||||
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
#include <SharedUtil.h>
|
||||
#include "AudioRingBuffer.h"
|
||||
#include "AudioFilter.h"
|
||||
|
||||
template<>
|
||||
AudioFilterPEQ3::FilterParameter AudioFilterPEQ3::_profiles[ AudioFilterPEQ3::_profileCount ][ AudioFilterPEQ3::_filterCount ] = {
|
||||
|
||||
// Freq Gain Q Freq Gain Q Freq Gain Q
|
||||
{ { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // flat response (default)
|
||||
{ { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 0.1f, 1.0f } }, // treble cut
|
||||
{ { 300.0f, 0.1f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // bass cut
|
||||
{ { 300.0f, 1.5f, 0.71f }, { 1000.0f, 0.5f, 1.0f }, { 4000.0f, 1.50f, 0.71f } } // smiley curve
|
||||
};
|
298
libraries/audio/src/AudioFilter.h
Normal file
298
libraries/audio/src/AudioFilter.h
Normal file
|
@ -0,0 +1,298 @@
|
|||
//
|
||||
// AudioFilter.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Craig Hansen-Sturm on 8/9/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
|
||||
//
|
||||
|
||||
#ifndef hifi_AudioFilter_h
|
||||
#define hifi_AudioFilter_h
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Implements a standard biquad filter in "Direct Form 1"
|
||||
// Reference http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
|
||||
//
|
||||
class AudioBiquad {
|
||||
|
||||
//
|
||||
// private data
|
||||
//
|
||||
float _a0; // gain
|
||||
float _a1; // feedforward 1
|
||||
float _a2; // feedforward 2
|
||||
float _b1; // feedback 1
|
||||
float _b2; // feedback 2
|
||||
|
||||
float _xm1;
|
||||
float _xm2;
|
||||
float _ym1;
|
||||
float _ym2;
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
// ctor/dtor
|
||||
//
|
||||
AudioBiquad()
|
||||
: _xm1(0.)
|
||||
, _xm2(0.)
|
||||
, _ym1(0.)
|
||||
, _ym2(0.) {
|
||||
setParameters(0.,0.,0.,0.,0.);
|
||||
}
|
||||
|
||||
~AudioBiquad() {
|
||||
}
|
||||
|
||||
//
|
||||
// public interface
|
||||
//
|
||||
void setParameters( const float a0, const float a1, const float a2, const float b1, const float b2 ) {
|
||||
_a0 = a0; _a1 = a1; _a2 = a2; _b1 = b1; _b2 = b2;
|
||||
}
|
||||
|
||||
void getParameters( float& a0, float& a1, float& a2, float& b1, float& b2 ) {
|
||||
a0 = _a0; a1 = _a1; a2 = _a2; b1 = _b1; b2 = _b2;
|
||||
}
|
||||
|
||||
void render( const float* in, float* out, const int frames) {
|
||||
|
||||
float x;
|
||||
float y;
|
||||
|
||||
for (int i = 0; i < frames; ++i) {
|
||||
|
||||
x = *in++;
|
||||
|
||||
// biquad
|
||||
y = (_a0 * x)
|
||||
+ (_a1 * _xm1)
|
||||
+ (_a2 * _xm2)
|
||||
- (_b1 * _ym1)
|
||||
- (_b2 * _ym2);
|
||||
|
||||
// update delay line
|
||||
_xm2 = _xm1;
|
||||
_xm1 = x;
|
||||
_ym2 = _ym1;
|
||||
_ym1 = y;
|
||||
|
||||
*out++ = y;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_xm1 = _xm2 = _ym1 = _ym2 = 0.;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Implements a single-band parametric EQ using a biquad "peaking EQ" configuration
|
||||
//
|
||||
// gain > 1.0 boosts the center frequency
|
||||
// gain < 1.0 cuts the center frequency
|
||||
//
|
||||
class AudioParametricEQ {
|
||||
|
||||
//
|
||||
// private data
|
||||
//
|
||||
AudioBiquad _kernel;
|
||||
float _sampleRate;
|
||||
float _frequency;
|
||||
float _gain;
|
||||
float _slope;
|
||||
|
||||
// helpers
|
||||
void updateKernel() {
|
||||
|
||||
/*
|
||||
a0 = 1 + alpha*A
|
||||
a1 = -2*cos(w0)
|
||||
a2 = 1 - alpha*A
|
||||
b1 = -2*cos(w0)
|
||||
b2 = 1 - alpha/A
|
||||
*/
|
||||
|
||||
const float a = _gain;
|
||||
const float omega = TWO_PI * _frequency / _sampleRate;
|
||||
const float alpha = 0.5f * sinf(omega) / _slope;
|
||||
const float gamma = 1.0f / ( 1.0f + (alpha/a) );
|
||||
|
||||
const float a0 = 1.0f + (alpha*a);
|
||||
const float a1 = -2.0f * cosf(omega);
|
||||
const float a2 = 1.0f - (alpha*a);
|
||||
const float b1 = a1;
|
||||
const float b2 = 1.0f - (alpha/a);
|
||||
|
||||
_kernel.setParameters( a0*gamma,a1*gamma,a2*gamma,b1*gamma,b2*gamma );
|
||||
}
|
||||
|
||||
public:
|
||||
//
|
||||
// ctor/dtor
|
||||
//
|
||||
AudioParametricEQ() {
|
||||
|
||||
setParameters(0.,0.,0.,0.);
|
||||
updateKernel();
|
||||
}
|
||||
|
||||
~AudioParametricEQ() {
|
||||
}
|
||||
|
||||
//
|
||||
// public interface
|
||||
//
|
||||
void setParameters( const float sampleRate, const float frequency, const float gain, const float slope ) {
|
||||
|
||||
_sampleRate = std::max(sampleRate,1.0f);
|
||||
_frequency = std::max(frequency,2.0f);
|
||||
_gain = std::max(gain,0.0f);
|
||||
_slope = std::max(slope,0.00001f);
|
||||
|
||||
updateKernel();
|
||||
}
|
||||
|
||||
void getParameters( float& sampleRate, float& frequency, float& gain, float& slope ) {
|
||||
sampleRate = _sampleRate; frequency = _frequency; gain = _gain; slope = _slope;
|
||||
}
|
||||
|
||||
void render(const float* in, float* out, const int frames ) {
|
||||
_kernel.render(in,out,frames);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_kernel.reset();
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Helper/convenience class that implements a bank of EQ objects
|
||||
//
|
||||
template< typename T, const int N>
|
||||
class AudioFilterBank {
|
||||
|
||||
//
|
||||
// types
|
||||
//
|
||||
struct FilterParameter {
|
||||
float _p1;
|
||||
float _p2;
|
||||
float _p3;
|
||||
};
|
||||
|
||||
//
|
||||
// private static data
|
||||
//
|
||||
static const int _filterCount = N;
|
||||
static const int _profileCount = 4;
|
||||
|
||||
static FilterParameter _profiles[_profileCount][_filterCount];
|
||||
|
||||
//
|
||||
// private data
|
||||
//
|
||||
T _filters[ _filterCount ];
|
||||
float* _buffer;
|
||||
float _sampleRate;
|
||||
uint16_t _frameCount;
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
// ctor/dtor
|
||||
//
|
||||
AudioFilterBank()
|
||||
: _buffer(NULL)
|
||||
, _sampleRate(0.)
|
||||
, _frameCount(0) {
|
||||
}
|
||||
|
||||
~AudioFilterBank() {
|
||||
finalize();
|
||||
}
|
||||
|
||||
//
|
||||
// public interface
|
||||
//
|
||||
void initialize( const float sampleRate, const int frameCount ) {
|
||||
finalize();
|
||||
|
||||
_buffer = (float*)malloc( frameCount * sizeof(float) );
|
||||
if(!_buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
_sampleRate = sampleRate;
|
||||
_frameCount = frameCount;
|
||||
|
||||
reset();
|
||||
loadProfile(0); // load default profile "flat response" into the bank (see AudioFilter.cpp)
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
if (_buffer ) {
|
||||
free (_buffer);
|
||||
_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void loadProfile( int profileIndex ) {
|
||||
if (profileIndex >= 0 && profileIndex < _profileCount) {
|
||||
|
||||
for (int i = 0; i < _filterCount; ++i) {
|
||||
FilterParameter p = _profiles[profileIndex][i];
|
||||
|
||||
_filters[i].setParameters(_sampleRate,p._p1,p._p2,p._p3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void render( const float* in, float* out, const int frameCount ) {
|
||||
for (int i = 0; i < _filterCount; ++i) {
|
||||
_filters[i].render( in, out, frameCount );
|
||||
}
|
||||
}
|
||||
|
||||
void render( const int16_t* in, int16_t* out, const int frameCount ) {
|
||||
if (!_buffer || ( frameCount > _frameCount ))
|
||||
return;
|
||||
|
||||
const int scale = (2 << ((8*sizeof(int16_t))-1));
|
||||
|
||||
// convert int16_t to float32 (normalized to -1. ... 1.)
|
||||
for (int i = 0; i < frameCount; ++i) {
|
||||
_buffer[i] = ((float)(*in++)) / scale;
|
||||
}
|
||||
// for this filter, we share input/output buffers at each stage, but our design does not mandate this
|
||||
render( _buffer, _buffer, frameCount );
|
||||
|
||||
// convert float32 to int16_t
|
||||
for (int i = 0; i < frameCount; ++i) {
|
||||
*out++ = (int16_t)(_buffer[i] * scale);
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
for (int i = 0; i < _filterCount; ++i ) {
|
||||
_filters[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Specializations of AudioFilterBank
|
||||
//
|
||||
typedef AudioFilterBank< AudioParametricEQ, 1> AudioFilterPEQ1; // bank with one band of PEQ
|
||||
typedef AudioFilterBank< AudioParametricEQ, 2> AudioFilterPEQ2; // bank with two bands of PEQ
|
||||
typedef AudioFilterBank< AudioParametricEQ, 3> AudioFilterPEQ3; // bank with three bands of PEQ
|
||||
// etc....
|
||||
|
||||
|
||||
#endif // hifi_AudioFilter_h
|
|
@ -15,9 +15,9 @@
|
|||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "PacketHeaders.h"
|
||||
#include "AudioRingBuffer.h"
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
#include "AudioRingBuffer.h"
|
||||
|
||||
AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) :
|
||||
_frameCapacity(numFramesCapacity),
|
||||
|
|
|
@ -15,12 +15,10 @@
|
|||
#include <limits>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <QtCore/QIODevice>
|
||||
|
||||
#include "NodeData.h"
|
||||
#include "SharedUtil.h"
|
||||
#include <SharedUtil.h>
|
||||
#include <NodeData.h>
|
||||
|
||||
const int SAMPLE_RATE = 24000;
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "InboundAudioStream.h"
|
||||
#include "PacketHeaders.h"
|
||||
|
||||
|
|
|
@ -1,30 +1,12 @@
|
|||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||
|
||||
set(TARGET_NAME avatars)
|
||||
|
||||
find_package(Qt5Script REQUIRED)
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network Script)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
include_glm()
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_libraries(shared octree voxels networking)
|
||||
include_hifi_library_headers(fbx)
|
||||
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
# link in the hifi voxels library
|
||||
link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
target_link_libraries(${TARGET_NAME} Qt5::Script)
|
||||
|
||||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
|
@ -22,7 +22,7 @@
|
|||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <StreamUtils.h>
|
||||
#include <UUID.h>
|
||||
#include <VoxelConstants.h>
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <FBXReader.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <OctreeConstants.h>
|
||||
|
||||
#include "AvatarData.h"
|
||||
#include "HeadData.h"
|
||||
|
||||
#include "../fbx/src/FBXReader.h"
|
||||
|
||||
HeadData::HeadData(AvatarData* owningAvatar) :
|
||||
_baseYaw(0.0f),
|
||||
_basePitch(0.0f),
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include "AvatarData.h"
|
||||
#include "Referential.h"
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||
|
||||
set(TARGET_NAME embedded-webserver)
|
||||
|
||||
find_package(Qt5Network REQUIRED)
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
|
||||
target_link_libraries(${TARGET_NAME} Qt5::Network)
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
|
@ -1,39 +1,11 @@
|
|||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||
|
||||
set(TARGET_NAME entities)
|
||||
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network Script)
|
||||
|
||||
include(${MACRO_DIR}/AutoMTC.cmake)
|
||||
auto_mtc(${TARGET_NAME} "${ROOT_DIR}")
|
||||
include_glm()
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME} "${AUTOMTC_SRC}")
|
||||
link_hifi_libraries(shared octree fbx networking animation)
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
# for streamable
|
||||
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
# link ZLIB
|
||||
find_package(ZLIB)
|
||||
|
||||
include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")
|
||||
target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets)
|
||||
|
||||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
|
|
|
@ -1,30 +1,15 @@
|
|||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||
|
||||
set(TARGET_NAME fbx)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
include_glm()
|
||||
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
# link ZLIB
|
||||
find_package(ZLIB)
|
||||
link_hifi_libraries(shared networking octree voxels)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")
|
||||
target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets)
|
||||
list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}")
|
||||
|
||||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include <GeometryUtil.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <OctalCode.h>
|
||||
#include <Shape.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <VoxelTree.h>
|
||||
|
||||
|
|
|
@ -1,29 +1,14 @@
|
|||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||
|
||||
set(TARGET_NAME metavoxels)
|
||||
|
||||
find_package(Qt5 COMPONENTS Network Script Widgets)
|
||||
auto_mtc()
|
||||
|
||||
include(${MACRO_DIR}/AutoMTC.cmake)
|
||||
auto_mtc(${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME} "${AUTOMTC_SRC}")
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network Script Widgets)
|
||||
|
||||
# link in the networking library
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_libraries(shared networking)
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
include_glm()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script)
|
||||
|
||||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
|
@ -489,22 +489,92 @@ HeightfieldData::HeightfieldData(const QByteArray& contents) :
|
|||
_contents(contents) {
|
||||
}
|
||||
|
||||
const int BYTES_PER_PIXEL = 3;
|
||||
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) {
|
||||
read(in, bytes, color);
|
||||
}
|
||||
|
||||
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) :
|
||||
_encoded(in.readAligned(bytes)) {
|
||||
|
||||
QImage image = QImage::fromData(_encoded).convertToFormat(QImage::Format_RGB888);
|
||||
if (color) {
|
||||
_contents.resize(image.width() * image.height() * BYTES_PER_PIXEL);
|
||||
memcpy(_contents.data(), image.constBits(), _contents.size());
|
||||
enum HeightfieldImage { NULL_HEIGHTFIELD_IMAGE, NORMAL_HEIGHTFIELD_IMAGE, DEFLATED_HEIGHTFIELD_IMAGE };
|
||||
|
||||
static QByteArray encodeHeightfieldImage(const QImage& image) {
|
||||
if (image.isNull()) {
|
||||
return QByteArray(1, NULL_HEIGHTFIELD_IMAGE);
|
||||
}
|
||||
QBuffer buffer;
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
const int JPEG_ENCODE_THRESHOLD = 16;
|
||||
if (image.width() >= JPEG_ENCODE_THRESHOLD && image.height() >= JPEG_ENCODE_THRESHOLD) {
|
||||
qint32 offsetX = image.offset().x(), offsetY = image.offset().y();
|
||||
buffer.write((char*)&offsetX, sizeof(qint32));
|
||||
buffer.write((char*)&offsetY, sizeof(qint32));
|
||||
image.save(&buffer, "JPG");
|
||||
return QByteArray(1, DEFLATED_HEIGHTFIELD_IMAGE) + qCompress(buffer.data());
|
||||
|
||||
} else {
|
||||
_contents.resize(image.width() * image.height());
|
||||
char* dest = _contents.data();
|
||||
for (const uchar* src = image.constBits(), *end = src + _contents.size() * BYTES_PER_PIXEL;
|
||||
src != end; src += BYTES_PER_PIXEL) {
|
||||
*dest++ = *src;
|
||||
buffer.putChar(NORMAL_HEIGHTFIELD_IMAGE);
|
||||
image.save(&buffer, "PNG");
|
||||
return buffer.data();
|
||||
}
|
||||
}
|
||||
|
||||
const QImage decodeHeightfieldImage(const QByteArray& data) {
|
||||
switch (data.at(0)) {
|
||||
case NULL_HEIGHTFIELD_IMAGE:
|
||||
default:
|
||||
return QImage();
|
||||
|
||||
case NORMAL_HEIGHTFIELD_IMAGE:
|
||||
return QImage::fromData(QByteArray::fromRawData(data.constData() + 1, data.size() - 1));
|
||||
|
||||
case DEFLATED_HEIGHTFIELD_IMAGE: {
|
||||
QByteArray inflated = qUncompress((const uchar*)data.constData() + 1, data.size() - 1);
|
||||
const int OFFSET_SIZE = sizeof(qint32) * 2;
|
||||
QImage image = QImage::fromData((const uchar*)inflated.constData() + OFFSET_SIZE, inflated.size() - OFFSET_SIZE);
|
||||
const qint32* offsets = (const qint32*)inflated.constData();
|
||||
image.setOffset(QPoint(offsets[0], offsets[1]));
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color) {
|
||||
if (!reference) {
|
||||
read(in, bytes, color);
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&reference->_encodedDeltaMutex);
|
||||
reference->_encodedDelta = in.readAligned(bytes);
|
||||
reference->_deltaData = this;
|
||||
_contents = reference->_contents;
|
||||
QImage image = decodeHeightfieldImage(reference->_encodedDelta);
|
||||
if (image.isNull()) {
|
||||
return;
|
||||
}
|
||||
QPoint offset = image.offset();
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
if (offset.x() == 0) {
|
||||
set(image, color);
|
||||
return;
|
||||
}
|
||||
int minX = offset.x() - 1;
|
||||
int minY = offset.y() - 1;
|
||||
if (color) {
|
||||
int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
|
||||
char* dest = _contents.data() + (minY * size + minX) * COLOR_BYTES;
|
||||
int destStride = size * COLOR_BYTES;
|
||||
int srcStride = image.width() * COLOR_BYTES;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
memcpy(dest, image.constScanLine(y), srcStride);
|
||||
dest += destStride;
|
||||
}
|
||||
} else {
|
||||
int size = glm::sqrt((float)_contents.size());
|
||||
char* lineDest = _contents.data() + minY * size + minX;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
const uchar* src = image.constScanLine(y);
|
||||
for (char* dest = lineDest, *end = dest + image.width(); dest != end; dest++, src += COLOR_BYTES) {
|
||||
*dest = *src;
|
||||
}
|
||||
lineDest += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -514,7 +584,7 @@ void HeightfieldData::write(Bitstream& out, bool color) {
|
|||
if (_encoded.isEmpty()) {
|
||||
QImage image;
|
||||
if (color) {
|
||||
int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL);
|
||||
int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
|
||||
image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888);
|
||||
} else {
|
||||
int size = glm::sqrt((float)_contents.size());
|
||||
|
@ -526,38 +596,170 @@ void HeightfieldData::write(Bitstream& out, bool color) {
|
|||
*dest++ = *src;
|
||||
}
|
||||
}
|
||||
QBuffer buffer(&_encoded);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
image.save(&buffer, "JPG");
|
||||
_encoded = encodeHeightfieldImage(image);
|
||||
}
|
||||
out << _encoded.size();
|
||||
out.writeAligned(_encoded);
|
||||
}
|
||||
|
||||
void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color) {
|
||||
if (!reference || reference->getContents().size() != _contents.size()) {
|
||||
write(out, color);
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&reference->_encodedDeltaMutex);
|
||||
if (reference->_encodedDelta.isEmpty() || reference->_deltaData != this) {
|
||||
QImage image;
|
||||
int minX, minY;
|
||||
if (color) {
|
||||
int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
|
||||
minX = size;
|
||||
minY = size;
|
||||
int maxX = -1, maxY = -1;
|
||||
const char* src = _contents.constData();
|
||||
const char* ref = reference->_contents.constData();
|
||||
for (int y = 0; y < size; y++) {
|
||||
bool difference = false;
|
||||
for (int x = 0; x < size; x++, src += COLOR_BYTES, ref += COLOR_BYTES) {
|
||||
if (src[0] != ref[0] || src[1] != ref[1] || src[2] != ref[2]) {
|
||||
minX = qMin(minX, x);
|
||||
maxX = qMax(maxX, x);
|
||||
difference = true;
|
||||
}
|
||||
}
|
||||
if (difference) {
|
||||
minY = qMin(minY, y);
|
||||
maxY = qMax(maxY, y);
|
||||
}
|
||||
}
|
||||
if (maxX >= minX) {
|
||||
int width = maxX - minX + 1;
|
||||
int height = maxY - minY + 1;
|
||||
image = QImage(width, height, QImage::Format_RGB888);
|
||||
src = _contents.constData() + (minY * size + minX) * COLOR_BYTES;
|
||||
int srcStride = size * COLOR_BYTES;
|
||||
int destStride = width * COLOR_BYTES;
|
||||
for (int y = 0; y < height; y++) {
|
||||
memcpy(image.scanLine(y), src, destStride);
|
||||
src += srcStride;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int size = glm::sqrt((float)_contents.size());
|
||||
minX = size;
|
||||
minY = size;
|
||||
int maxX = -1, maxY = -1;
|
||||
const char* src = _contents.constData();
|
||||
const char* ref = reference->_contents.constData();
|
||||
for (int y = 0; y < size; y++) {
|
||||
bool difference = false;
|
||||
for (int x = 0; x < size; x++) {
|
||||
if (*src++ != *ref++) {
|
||||
minX = qMin(minX, x);
|
||||
maxX = qMax(maxX, x);
|
||||
difference = true;
|
||||
}
|
||||
}
|
||||
if (difference) {
|
||||
minY = qMin(minY, y);
|
||||
maxY = qMax(maxY, y);
|
||||
}
|
||||
}
|
||||
if (maxX >= minX) {
|
||||
int width = qMax(maxX - minX + 1, 0);
|
||||
int height = qMax(maxY - minY + 1, 0);
|
||||
image = QImage(width, height, QImage::Format_RGB888);
|
||||
const uchar* lineSrc = (const uchar*)_contents.constData() + minY * size + minX;
|
||||
for (int y = 0; y < height; y++) {
|
||||
uchar* dest = image.scanLine(y);
|
||||
for (const uchar* src = lineSrc, *end = src + width; src != end; src++) {
|
||||
*dest++ = *src;
|
||||
*dest++ = *src;
|
||||
*dest++ = *src;
|
||||
}
|
||||
lineSrc += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
image.setOffset(QPoint(minX + 1, minY + 1));
|
||||
reference->_encodedDelta = encodeHeightfieldImage(image);
|
||||
reference->_deltaData = this;
|
||||
}
|
||||
out << reference->_encodedDelta.size();
|
||||
out.writeAligned(reference->_encodedDelta);
|
||||
}
|
||||
|
||||
void HeightfieldData::read(Bitstream& in, int bytes, bool color) {
|
||||
set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888), color);
|
||||
}
|
||||
|
||||
void HeightfieldData::set(const QImage& image, bool color) {
|
||||
if (color) {
|
||||
_contents.resize(image.width() * image.height() * COLOR_BYTES);
|
||||
memcpy(_contents.data(), image.constBits(), _contents.size());
|
||||
|
||||
} else {
|
||||
_contents.resize(image.width() * image.height());
|
||||
char* dest = _contents.data();
|
||||
for (const uchar* src = image.constBits(), *end = src + _contents.size() * COLOR_BYTES;
|
||||
src != end; src += COLOR_BYTES) {
|
||||
*dest++ = *src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HeightfieldAttribute::HeightfieldAttribute(const QString& name) :
|
||||
InlineAttribute<HeightfieldDataPointer>(name) {
|
||||
}
|
||||
|
||||
void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
||||
if (isLeaf) {
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
||||
} else {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false));
|
||||
}
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
||||
} else {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false));
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
||||
if (isLeaf) {
|
||||
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
||||
if (data) {
|
||||
data->write(out, false);
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
||||
if (data) {
|
||||
data->write(out, false);
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
||||
} else {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(
|
||||
in, size, decodeInline<HeightfieldDataPointer>(reference), false));
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
||||
if (data) {
|
||||
data->writeDelta(out, decodeInline<HeightfieldDataPointer>(reference), false);
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -635,25 +837,53 @@ HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) :
|
|||
}
|
||||
|
||||
void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
||||
if (isLeaf) {
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
||||
} else {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true));
|
||||
}
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
||||
} else {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true));
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
||||
if (isLeaf) {
|
||||
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
||||
if (data) {
|
||||
data->write(out, true);
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
||||
if (data) {
|
||||
data->write(out, true);
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldColorAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
||||
} else {
|
||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(
|
||||
in, size, decodeInline<HeightfieldDataPointer>(reference), true));
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldColorAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
||||
if (data) {
|
||||
data->writeDelta(out, decodeInline<HeightfieldDataPointer>(reference), true);
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -669,8 +899,8 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
|
|||
*(HeightfieldDataPointer*)&parent = HeightfieldDataPointer();
|
||||
return true;
|
||||
}
|
||||
int size = glm::sqrt(maxSize / (float)BYTES_PER_PIXEL);
|
||||
QByteArray contents(size * size * BYTES_PER_PIXEL, 0);
|
||||
int size = glm::sqrt(maxSize / (float)HeightfieldData::COLOR_BYTES);
|
||||
QByteArray contents(size * size * HeightfieldData::COLOR_BYTES, 0);
|
||||
int halfSize = size / 2;
|
||||
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||
HeightfieldDataPointer child = decodeInline<HeightfieldDataPointer>(children[i]);
|
||||
|
@ -678,7 +908,7 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
|
|||
continue;
|
||||
}
|
||||
const QByteArray& childContents = child->getContents();
|
||||
int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL);
|
||||
int childSize = glm::sqrt(childContents.size() / (float)HeightfieldData::COLOR_BYTES);
|
||||
const int INDEX_MASK = 1;
|
||||
int xIndex = i & INDEX_MASK;
|
||||
const int Y_SHIFT = 1;
|
||||
|
@ -688,24 +918,25 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
|
|||
}
|
||||
int Z_SHIFT = 2;
|
||||
int zIndex = (i >> Z_SHIFT) & INDEX_MASK;
|
||||
char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL;
|
||||
char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * HeightfieldData::COLOR_BYTES;
|
||||
uchar* src = (uchar*)childContents.data();
|
||||
int childStride = childSize * BYTES_PER_PIXEL;
|
||||
int stride = size * BYTES_PER_PIXEL;
|
||||
int childStride = childSize * HeightfieldData::COLOR_BYTES;
|
||||
int stride = size * HeightfieldData::COLOR_BYTES;
|
||||
int halfStride = stride / 2;
|
||||
int childStep = 2 * BYTES_PER_PIXEL;
|
||||
int redOffset3 = childStride + BYTES_PER_PIXEL;
|
||||
int greenOffset1 = BYTES_PER_PIXEL + 1;
|
||||
int childStep = 2 * HeightfieldData::COLOR_BYTES;
|
||||
int redOffset3 = childStride + HeightfieldData::COLOR_BYTES;
|
||||
int greenOffset1 = HeightfieldData::COLOR_BYTES + 1;
|
||||
int greenOffset2 = childStride + 1;
|
||||
int greenOffset3 = childStride + BYTES_PER_PIXEL + 1;
|
||||
int blueOffset1 = BYTES_PER_PIXEL + 2;
|
||||
int greenOffset3 = childStride + HeightfieldData::COLOR_BYTES + 1;
|
||||
int blueOffset1 = HeightfieldData::COLOR_BYTES + 2;
|
||||
int blueOffset2 = childStride + 2;
|
||||
int blueOffset3 = childStride + BYTES_PER_PIXEL + 2;
|
||||
int blueOffset3 = childStride + HeightfieldData::COLOR_BYTES + 2;
|
||||
if (childSize == size) {
|
||||
// simple case: one destination value for four child values
|
||||
for (int z = 0; z < halfSize; z++) {
|
||||
for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) {
|
||||
*dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2;
|
||||
for (char* end = dest + halfSize * HeightfieldData::COLOR_BYTES; dest != end; src += childStep) {
|
||||
*dest++ = ((int)src[0] + (int)src[HeightfieldData::COLOR_BYTES] +
|
||||
(int)src[childStride] + (int)src[redOffset3]) >> 2;
|
||||
*dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2;
|
||||
*dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2;
|
||||
}
|
||||
|
@ -717,13 +948,14 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
|
|||
int halfChildSize = childSize / 2;
|
||||
int destPerSrc = size / childSize;
|
||||
for (int z = 0; z < halfChildSize; z++) {
|
||||
for (uchar* end = src + childSize * BYTES_PER_PIXEL; src != end; src += childStep) {
|
||||
*dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2;
|
||||
for (uchar* end = src + childSize * HeightfieldData::COLOR_BYTES; src != end; src += childStep) {
|
||||
*dest++ = ((int)src[0] + (int)src[HeightfieldData::COLOR_BYTES] +
|
||||
(int)src[childStride] + (int)src[redOffset3]) >> 2;
|
||||
*dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2;
|
||||
*dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2;
|
||||
for (int j = 1; j < destPerSrc; j++) {
|
||||
memcpy(dest, dest - BYTES_PER_PIXEL, BYTES_PER_PIXEL);
|
||||
dest += BYTES_PER_PIXEL;
|
||||
memcpy(dest, dest - HeightfieldData::COLOR_BYTES, HeightfieldData::COLOR_BYTES);
|
||||
dest += HeightfieldData::COLOR_BYTES;
|
||||
}
|
||||
}
|
||||
dest += halfStride;
|
||||
|
|
|
@ -28,6 +28,7 @@ class QScriptEngine;
|
|||
class QScriptValue;
|
||||
|
||||
class Attribute;
|
||||
class HeightfieldData;
|
||||
class MetavoxelData;
|
||||
class MetavoxelLOD;
|
||||
class MetavoxelNode;
|
||||
|
@ -421,26 +422,37 @@ public:
|
|||
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer;
|
||||
|
||||
/// Contains a block of heightfield data.
|
||||
class HeightfieldData : public QSharedData {
|
||||
public:
|
||||
|
||||
static const int COLOR_BYTES = 3;
|
||||
|
||||
HeightfieldData(const QByteArray& contents);
|
||||
HeightfieldData(Bitstream& in, int bytes, bool color);
|
||||
|
||||
HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color);
|
||||
|
||||
const QByteArray& getContents() const { return _contents; }
|
||||
|
||||
void write(Bitstream& out, bool color);
|
||||
void writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color);
|
||||
|
||||
private:
|
||||
|
||||
void read(Bitstream& in, int bytes, bool color);
|
||||
void set(const QImage& image, bool color);
|
||||
|
||||
QByteArray _contents;
|
||||
QByteArray _encoded;
|
||||
QMutex _encodedMutex;
|
||||
|
||||
HeightfieldDataPointer _deltaData;
|
||||
QByteArray _encodedDelta;
|
||||
QMutex _encodedDeltaMutex;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer;
|
||||
|
||||
/// An attribute that stores heightfield data.
|
||||
class HeightfieldAttribute : public InlineAttribute<HeightfieldDataPointer> {
|
||||
Q_OBJECT
|
||||
|
@ -451,7 +463,10 @@ public:
|
|||
|
||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
||||
|
||||
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
|
||||
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
|
||||
|
||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
};
|
||||
|
||||
|
@ -466,6 +481,9 @@ public:
|
|||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
||||
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
|
||||
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
|
||||
|
||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -318,3 +318,177 @@ SetDataEdit::SetDataEdit(const glm::vec3& minimum, const MetavoxelData& data, bo
|
|||
void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
data.set(minimum, this->data, blend);
|
||||
}
|
||||
|
||||
PaintHeightfieldHeightEdit::PaintHeightfieldHeightEdit(const glm::vec3& position, float radius, float height) :
|
||||
position(position),
|
||||
radius(radius),
|
||||
height(height) {
|
||||
}
|
||||
|
||||
class PaintHeightfieldHeightEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
PaintHeightfieldHeightEdit _edit;
|
||||
Box _bounds;
|
||||
};
|
||||
|
||||
PaintHeightfieldHeightEditVisitor::PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute(),
|
||||
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute()),
|
||||
_edit(edit) {
|
||||
|
||||
glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
|
||||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||
}
|
||||
|
||||
int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.getBounds().intersects(_bounds)) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (!info.isLeaf) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
|
||||
if (!pointer) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
QByteArray contents(pointer->getContents());
|
||||
int size = glm::sqrt((float)contents.size());
|
||||
int highest = size - 1;
|
||||
float heightScale = size / info.size;
|
||||
|
||||
glm::vec3 center = (_edit.position - info.minimum) * heightScale;
|
||||
float scaledRadius = _edit.radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// raise/lower all points within the radius
|
||||
float z = qMax(start.z, 0.0f);
|
||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||
uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
float squaredRadiusReciprocal = 1.0f / squaredRadius;
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size;
|
||||
bool changed = false;
|
||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||
uchar* dest = lineDest;
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
float distanceSquared = dx * dx + dz * dz;
|
||||
if (distanceSquared <= squaredRadius) {
|
||||
// height falls off towards edges
|
||||
int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal;
|
||||
if (value != *dest) {
|
||||
*dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
lineDest += size;
|
||||
}
|
||||
if (changed) {
|
||||
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
|
||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
|
||||
}
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
PaintHeightfieldHeightEditVisitor visitor(*this);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
PaintHeightfieldColorEdit::PaintHeightfieldColorEdit(const glm::vec3& position, float radius, const QColor& color) :
|
||||
position(position),
|
||||
radius(radius),
|
||||
color(color) {
|
||||
}
|
||||
|
||||
class PaintHeightfieldColorEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
PaintHeightfieldColorEdit _edit;
|
||||
Box _bounds;
|
||||
};
|
||||
|
||||
PaintHeightfieldColorEditVisitor::PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute(),
|
||||
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute()),
|
||||
_edit(edit) {
|
||||
|
||||
glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
|
||||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||
}
|
||||
|
||||
int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.getBounds().intersects(_bounds)) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (!info.isLeaf) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
|
||||
if (!pointer) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
QByteArray contents(pointer->getContents());
|
||||
const int BYTES_PER_PIXEL = 3;
|
||||
int size = glm::sqrt((float)contents.size() / BYTES_PER_PIXEL);
|
||||
int highest = size - 1;
|
||||
float heightScale = size / info.size;
|
||||
|
||||
glm::vec3 center = (_edit.position - info.minimum) * heightScale;
|
||||
float scaledRadius = _edit.radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// paint all points within the radius
|
||||
float z = qMax(start.z, 0.0f);
|
||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||
int stride = size * BYTES_PER_PIXEL;
|
||||
char* lineDest = contents.data() + (int)z * stride + (int)startX * BYTES_PER_PIXEL;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
char red = _edit.color.red(), green = _edit.color.green(), blue = _edit.color.blue();
|
||||
bool changed = false;
|
||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||
char* dest = lineDest;
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest += BYTES_PER_PIXEL) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
if (dx * dx + dz * dz <= squaredRadius) {
|
||||
dest[0] = red;
|
||||
dest[1] = green;
|
||||
dest[2] = blue;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
lineDest += stride;
|
||||
}
|
||||
if (changed) {
|
||||
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
|
||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
|
||||
}
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
void PaintHeightfieldColorEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
PaintHeightfieldColorEditVisitor visitor(*this);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
|
|
|
@ -207,4 +207,38 @@ public:
|
|||
|
||||
DECLARE_STREAMABLE_METATYPE(SetDataEdit)
|
||||
|
||||
/// An edit that sets a region of a heightfield height.
|
||||
class PaintHeightfieldHeightEdit : public MetavoxelEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM glm::vec3 position;
|
||||
STREAM float radius;
|
||||
STREAM float height;
|
||||
|
||||
PaintHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, float height = 0.0f);
|
||||
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldHeightEdit)
|
||||
|
||||
/// An edit that sets a region of a heightfield color.
|
||||
class PaintHeightfieldColorEdit : public MetavoxelEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM glm::vec3 position;
|
||||
STREAM float radius;
|
||||
STREAM QColor color;
|
||||
|
||||
PaintHeightfieldColorEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, const QColor& color = QColor());
|
||||
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldColorEdit)
|
||||
|
||||
#endif // hifi_MetavoxelMessages_h
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <QVBoxLayout>
|
||||
#include <QtDebug>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include "MetavoxelUtil.h"
|
||||
#include "ScriptCache.h"
|
||||
#include "StreamUtils.h"
|
||||
|
@ -162,6 +164,11 @@ Box::Box(const glm::vec3& minimum, const glm::vec3& maximum) :
|
|||
minimum(minimum), maximum(maximum) {
|
||||
}
|
||||
|
||||
void Box::add(const Box& other) {
|
||||
minimum = glm::min(minimum, other.minimum);
|
||||
maximum = glm::max(maximum, other.maximum);
|
||||
}
|
||||
|
||||
bool Box::contains(const glm::vec3& point) const {
|
||||
return point.x >= minimum.x && point.x <= maximum.x &&
|
||||
point.y >= minimum.y && point.y <= maximum.y &&
|
||||
|
@ -180,6 +187,14 @@ bool Box::intersects(const Box& other) const {
|
|||
other.maximum.z >= minimum.z && other.minimum.z <= maximum.z;
|
||||
}
|
||||
|
||||
Box Box::getIntersection(const Box& other) const {
|
||||
return Box(glm::max(minimum, other.minimum), glm::min(maximum, other.maximum));
|
||||
}
|
||||
|
||||
bool Box::isEmpty() const {
|
||||
return minimum.x >= maximum.x || minimum.y >= maximum.y || minimum.z >= maximum.z;
|
||||
}
|
||||
|
||||
const int X_MAXIMUM_FLAG = 1;
|
||||
const int Y_MAXIMUM_FLAG = 2;
|
||||
const int Z_MAXIMUM_FLAG = 4;
|
||||
|
|
|
@ -44,12 +44,18 @@ public:
|
|||
|
||||
explicit Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3());
|
||||
|
||||
void add(const Box& other);
|
||||
|
||||
bool contains(const glm::vec3& point) const;
|
||||
|
||||
bool contains(const Box& other) const;
|
||||
|
||||
bool intersects(const Box& other) const;
|
||||
|
||||
Box getIntersection(const Box& other) const;
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
float getLongestSide() const { return qMax(qMax(maximum.x - minimum.x, maximum.y - minimum.y), maximum.z - minimum.z); }
|
||||
|
||||
glm::vec3 getVertex(int index) const;
|
||||
|
@ -138,6 +144,8 @@ public:
|
|||
|
||||
QColorEditor(QWidget* parent);
|
||||
|
||||
const QColor& getColor() const { return _color; }
|
||||
|
||||
signals:
|
||||
|
||||
void colorChanged(const QColor& color);
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
||||
|
||||
set(TARGET_NAME networking)
|
||||
project(${TARGET_NAME})
|
||||
|
||||
find_package(Qt5 COMPONENTS Network)
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
# include GLM
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
target_link_libraries(${TARGET_NAME} Qt5::Network)
|
||||
|
||||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
# we need ws2_32.lib on windows, but it's static so we don't bubble it up
|
||||
target_link_libraries(${TARGET_NAME} ws2_32.lib)
|
||||
endif ()
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
|
@ -36,6 +36,7 @@ DomainHandler::DomainHandler(QObject* parent) :
|
|||
void DomainHandler::clearConnectionInfo() {
|
||||
_uuid = QUuid();
|
||||
_isConnected = false;
|
||||
emit disconnectedFromDomain();
|
||||
|
||||
if (_handshakeTimer) {
|
||||
_handshakeTimer->stop();
|
||||
|
@ -129,6 +130,8 @@ void DomainHandler::setIsConnected(bool isConnected) {
|
|||
|
||||
// we've connected to new domain - time to ask it for global settings
|
||||
requestDomainSettings();
|
||||
} else {
|
||||
emit disconnectedFromDomain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -196,4 +199,4 @@ void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirement
|
|||
_sockAddr.setPort(dtlsPort);
|
||||
|
||||
// initializeDTLSSession();
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue