3
0
Fork 0
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:
ZappoMan 2014-08-18 15:16:35 -07:00
commit 32d5eb3cea
159 changed files with 4375 additions and 3623 deletions
CMakeLists.txt
assignment-client
cmake
domain-server
CMakeLists.txt
resources/web/settings
examples
interface
libraries

View file

@ -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)

View file

@ -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()

View file

@ -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) {

View file

@ -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;

View file

@ -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;
};

View file

@ -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());
}

View file

@ -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

View 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);
}
}

View 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

View file

@ -11,6 +11,8 @@
#include <QThread>
#include <GLMHelpers.h>
#include "ScriptableAvatar.h"
ScriptableAvatar::ScriptableAvatar(ScriptEngine* scriptEngine) : _scriptEngine(scriptEngine), _animation(NULL) {

View file

@ -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)

View file

@ -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)

View 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)

View 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)

View file

@ -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)

View 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)

View file

@ -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)

View file

@ -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()

View 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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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()

View file

@ -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)",

View file

@ -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", {

View file

@ -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()

View file

@ -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>&lt;b&gt;Import&lt;/b&gt; %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>

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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));
}

View file

@ -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);
}

View file

@ -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()) {

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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) {

View file

@ -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;

View file

@ -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);
}

View file

@ -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) {

View file

@ -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

View 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()));
}
}

View 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

View file

@ -10,7 +10,7 @@
//
#include "CaraFaceTracker.h"
#include <SharedUtil.h>
#include <GLMHelpers.h>
//qt
#include <QJsonDocument>

View file

@ -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) {

View file

@ -84,6 +84,10 @@ private:
int _mouthSmileRightIndex;
int _jawOpenIndex;
float _leftEye[3];
float _rightEye[3];
};
#endif // hifi_DdeFaceTracker_h

View file

@ -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() {

View file

@ -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:

View file

@ -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;

View file

@ -71,7 +71,7 @@ private:
glm::vec3 _reachUp;
glm::vec3 _reachForward;
float _lastDistance;
#endif
bool _hydrasConnected;
quint64 _lastMovement;

View file

@ -16,6 +16,7 @@
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/transform.hpp>
#include <GLMHelpers.h>
#include <FBXReader.h>
class AngularConstraint;

View file

@ -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);

View file

@ -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;

View file

@ -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);
}

View file

@ -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);

View file

@ -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) {

View file

@ -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

View file

@ -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()));
}

View file

@ -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

View file

@ -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());

View file

@ -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

View file

@ -11,6 +11,8 @@
#ifndef hifi_Base3DOverlay_h
#define hifi_Base3DOverlay_h
#include <glm/glm.hpp>
#include "Overlay.h"
class Base3DOverlay : public Overlay {

View file

@ -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;

View file

@ -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();
}

View file

@ -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

View file

@ -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()

View file

@ -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()

View 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
};

View 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

View file

@ -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),

View file

@ -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;

View file

@ -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"

View file

@ -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()

View file

@ -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>

View file

@ -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),

View file

@ -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"

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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>

View file

@ -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()

View file

@ -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;

View file

@ -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;
};

View file

@ -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);
}

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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()

View file

@ -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